本文的開發(fā)項目由開發(fā)者發(fā)布在CSDN博客(F l e)分享,該設(shè)計采用esp8266燒寫機智云固件。并且esp8266與stm32進行通信,則stm32可以通過esp8266與機智云服務(wù)器進行數(shù)據(jù)交互,而機智云服務(wù)器可以和機智云app進行數(shù)據(jù)交互。為此,實現(xiàn)stm32通過esp8266可以與機智云app進行數(shù)據(jù)交互。
stm32作為MCU與傳感器進行數(shù)據(jù)交互,得到傳感器采集的數(shù)值,所以完成的是傳感器和app的數(shù)據(jù)交互。由于本次實驗增加了對光照強度的采集,所以又增加了一個三色RGB燈外設(shè)。通過機智云app可以調(diào)節(jié)RGB燈的光強,以此來模擬光照強度的變化。整個設(shè)計的傳感器數(shù)據(jù)流向如下圖所示:
另外,對于用機智云app調(diào)節(jié)RGB燈的光強的數(shù)據(jù)流向如下圖:
01
傳感器的測試
本次設(shè)計利用STM32CubeMX進行開發(fā),代碼設(shè)計過程分模塊進行,分別編寫測試用例驗證各模塊的功能,包括oled模塊、按鍵模塊、dht11模塊、光敏電阻模塊、rgb模塊。1、oled模塊① 接線:
②代碼編寫:
本次設(shè)計中oled采用硬件SPI2驅(qū)動,STM32CubeMX的設(shè)計如下圖:
利用STM32CubeMX生成的SPI主要代碼如上所示。在生成的SPI代碼上進一步編寫oled.c和oled.h文件。
oled.c封裝了以下的函數(shù):
測試函數(shù):
int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI2_Init(); OLED_Init(); OLED_ShowString(0, 0, "wait for set esp8266,press key1 to set esp8266 with AIRLINK_MODE");}
③測試用例實驗結(jié)果:
由上圖可知,oled模塊的顯示函數(shù)能夠正確顯示。
2、按鍵模塊
①接線:
KEY_R0接地,KEY_L0和KEY_L1可以用于檢測按鍵狀態(tài)。對應(yīng)的引腳為:
②代碼編寫:
STM32CubeMX設(shè)計如下:
PC11設(shè)置為輸出模式,PC10和PB5設(shè)置為輸入模式。
Key.c封裝了以下函數(shù):
void key_init(void){ HAL_GPIO_WritePin(KEY_COM_GND_GPIO_Port,KEY_COM_GND_Pin,GPIO_PIN_RESET);}
void Test_key(void){ if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)==GPIO_PIN_SET) { OLED_ShowString(0,0,"key1_up"); } else { OLED_ShowString(0,0,"key1_down"); } if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)==GPIO_PIN_SET) { OLED_ShowString(0,10,"key2_up"); } else { OLED_ShowString(0,10,"key2_down"); } OLED_Refresh_Gram();}
測試用例:
int main(void){ MX_GPIO_Init(); key_init(); while(1) { Test_key(); }}
③測試用例實驗結(jié)果:
由圖中可以看出,按鍵一被按下時顯示key1_down和key2_up,與理論相符。
3、dht11模塊
①接線:
②代碼編寫:
由于dht11的數(shù)據(jù)引腳有時需要作為輸入,有時需要作為輸出,所以不在STM32CubeMX設(shè)置。
Dht11.c主要封裝了以下函數(shù):
這里的us延時并沒有使用定時器來產(chǎn)生,而是用系統(tǒng)時鐘來實現(xiàn):
void delay_us(uint32_t us){ uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us); while (delay--) { ; }}
測試用例:
int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI2_Init(); OLED_Init(); while(1) { Test_dht11(); }
void Test_dht11(void){ char txt[16]; while(1) { DHT11_Read_Data(&humidity_integer,&humidity_decimal,&temperature_integer,&temperature_decimal); sprintf(txt, "temp:%d.%d", temperature_integer,temperature_decimal); OLED_ShowString(0,0,txt); sprintf(txt, "humi:%d.%d", humidity_integer,humidity_decimal); OLED_ShowString(0,10,txt); OLED_Refresh_Gram(); }}
③測試用例實驗結(jié)果:
由上圖可以看出,溫度為23.3℃,濕度為53.0%,濕度的小數(shù)為0,與理論相符。
4、光敏電阻模塊
①接線:
②代碼編寫:
STM32CubeMX設(shè)置ADC1的IN0如下:
Stm32Rct6的ADC是12位的,這里沒有更改的選項,則ADC讀取的最大值是2^12=4096。
這里采樣時間Sampling Time選擇1.5個周期。ADC采樣時間 = (采樣周期+12.5周期)* 1/ADC時鐘頻率,這里ADC采樣時間=(1.5+12.5)*1/12 = 1.167us。light_check5506.c主要封裝以下函數(shù):
void light_check5506_init(void){ HAL_ADCEx_Calibration_Start(&hadc1); HAL_Delay(200);}
uint32_t light_check5506_getinitvalue(void){ HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1,50);//?Tê±50ms return HAL_ADC_GetValue(&hadc1);}
uint32_t light_check5506_get0to100value(void){ //°μ-->áá£o0~100 uint32_t value; value=light_check5506_getinitvalue(); value=4096-value;//?ê?êy?Yê???°μêy?Y??′ó value=(value*100/4096);//?ˉ?a0~100μ?êy,±?D??è3?ò?100?ù3y£?òò?aè?2?ê???êy return value;}
void Test_5506(void){ uint32_t value; char txt[16]; while(1) { value=light_check5506_get0to100value(); sprintf(txt, "light(0-100):%d", value); OLED_ShowString(0,0,txt); OLED_Refresh_Gram(); }}
測試用例:
main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI2_Init(); MX_ADC1_Init(); OLED_Init(); light_check5506_init(); while(1)` { Test_5506(); }}
③測試用例實驗結(jié)果:
將ADC讀取的值歸一化到0~100后光照強度的數(shù)值為18。
5、rgb模塊
①接線:
②代碼編寫:
STM32CubeMX設(shè)置TIM8的三個通道如下:
計數(shù)周期Counter Period設(shè)置為255,這是為了便于查找RGB顏色表進行顏色設(shè)置,占空比Pulse設(shè)置為50%Rgb.c封裝了以下函數(shù):
void rgb_init(void){ HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim8,TIM_CHANNEL_3);}void Test_rgb(void){ rgb_setpwm(10.0,100.0,200.0);}void rgb_setpwm(uint8_t pwm_r,uint8_t pwm_g,uint8_t pwm_b){ __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1,pwm_r); __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_2,pwm_g); __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_3,pwm_b);}
測試用例:
main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_SPI2_Init(); MX_TIM8_Init(); rgb_init(); OLED_Init(); while(1)` { Test_rgb(); }}
③測試用例實驗結(jié)果:
由上圖可知RGB燈被點亮。
02
通過esp8266實現(xiàn)數(shù)據(jù)上傳和數(shù)據(jù)回傳
在進行數(shù)據(jù)上傳與數(shù)據(jù)回傳之前,首先進行用于打印數(shù)據(jù)的串口1的設(shè)置和用于stm32與esp8266通信的串口2。串口1:
串口1設(shè)置PA9和PA10分別作為TX和RX,波特率為115200,不使能中斷。
串口2:
串口2設(shè)置PA2和PA3分別作為TX和RX,波特率為9600,使能中斷。
1、數(shù)據(jù)上傳:溫濕度數(shù)據(jù)、關(guān)照強度數(shù)據(jù)
①主要代碼
void userHandle(void){ DHT11_Read_Data( & humidity_integer, & humidity_decimal, & temperature_integer, & temperature_decimal); currentDataPoint.valuehumidity = humidity_integer; currentDataPoint.valueLight_intensity = light_check5506_get0to100value(); currentDataPoint.valueDHT11 = temperature_integer + 0.1 * temperature_decimal; }
在userHandle(void)中添加溫濕度數(shù)據(jù)的采集以及光照強度的讀取。userHandle()是main函數(shù)中while循環(huán)的內(nèi)容。
由上圖可以看出,userHandle對于用戶來說是最頂層的,數(shù)據(jù)在userHandle中采集,依次經(jīng)過gizCheckReport判斷是否上報當(dāng)前狀態(tài)的數(shù)據(jù)、gizDataPoints2ReportData完成用戶區(qū)數(shù)據(jù)到上報型數(shù)據(jù)的轉(zhuǎn)換、gizReportData將轉(zhuǎn)換后的上報數(shù)據(jù)通過串口發(fā)送給 WiFi 模塊。
②設(shè)計結(jié)果:
首先確保esp8266和手機都已經(jīng)連接到同一個網(wǎng)絡(luò),這里用電腦作為這個網(wǎng)絡(luò)。
由上圖可知手機和esp8266已經(jīng)連接上了電腦。機智云app連接上esp8266后得到上傳來的數(shù)據(jù):
Oled上的數(shù)據(jù)是stm32收集的,上圖的數(shù)據(jù)是機智云app通過esp8266收到的,兩者一致,說明數(shù)據(jù)交互是正確的。2、數(shù)據(jù)回傳:RGB三數(shù)值
①主要代碼
int8_t gizwitsEventProcess(eventInfo_t * info, uint8_t * gizdata, uint32_t len){ uint8_t i = 0; dataPoint_t * dataPointPtr = (dataPoint_t *)gizdata; moduleStatusInfo_t * wifiData = (moduleStatusInfo_t *)gizdata; protocolTime_t * ptime = (protocolTime_t *) gizdata; # if MODULE_TYPE gprsInfo_t * gprsInfoData = (gprsInfo_t *)gizdata; # else moduleInfo_t * ptModuleInfo = (moduleInfo_t *) gizdata; # endif if ((NULL == info) || (NULL == gizdata)) { return -1; } for (i=0; i < info->num; i++) { switch(info->event[i]) { case EVENT_LED_R: currentDataPoint.valueLED_R = dataPointPtr->valueLED_R; GIZWITS_LOG("Evt:EVENT_LED_R %d\n", currentDataPoint.valueLED_R); rgb_setpwm(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B); break; case EVENT_LED_G: currentDataPoint.valueLED_G = dataPointPtr->valueLED_G; GIZWITS_LOG("Evt:EVENT_LED_G %d\n", currentDataPoint.valueLED_G); rgb_setpwm(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B); break; case EVENT_LED_B: currentDataPoint.valueLED_B = dataPointPtr->valueLED_B; GIZWITS_LOG("Evt:EVENT_LED_B %d\n", currentDataPoint.valueLED_B); rgb_setpwm(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B); break; } }}
在gizwitsEventProcess中的EVENT_LED_R、EVENT_LED_G、EVENT_LED_B分別添加對對RGB三個PWM的賦值,賦值之后使其立即生效。
protocolIssuedProcess被 gizwitsHandle 調(diào)用,接收來自云端或 app端下發(fā)的相關(guān)協(xié)議數(shù)據(jù)。ACTION_CONTROL_DEVICE進行“控制型協(xié)議”的相關(guān)處理,gizDataPoint2Event根據(jù)協(xié)議生成“控制型事件”,并進行相應(yīng)數(shù)據(jù)類型的轉(zhuǎn)化轉(zhuǎn)換,gizwitsEventProcess是位于數(shù)據(jù)回傳過程中的最底層,根據(jù)已生成的“控制型事件”進行相應(yīng)處理。
②設(shè)計結(jié)果:
首先確保esp8266和手機都已經(jīng)連接到同一個網(wǎng)絡(luò),這里用電腦作為這個網(wǎng)絡(luò)。
由上圖可知手機和esp8266已經(jīng)連接上了電腦。機智云app設(shè)置RGB三個PWM數(shù)值,得到oled上的數(shù)據(jù)為:
由上圖可知,右圖為機智云app設(shè)置的三個PWM數(shù)值,左圖再oled上為同樣的數(shù)值,說明數(shù)據(jù)交互正確。
03
總 結(jié)
①通過這次設(shè)計接觸了STM32CubeMX這個軟件,相比與之前的標準庫,STM32CubeMX生成的Hal庫不僅封裝度更高,而且更有利于開發(fā)者進行快速開發(fā),而且在本次實驗中機智云生成的代碼也是基于Hal庫的,這說明以后對于stm32來說,會越來越趨向于Hal開發(fā)。②官網(wǎng)永遠是對解決問題的最好地方,機智云的官方文檔給了我極大幫助。
③esp8266的燒錄對于供電要求十分苛刻,導(dǎo)致多次燒錄都失敗了,所以在制pcb的時候加上了esp8266的燒錄接口,以及GPIO的接地開關(guān),還有復(fù)位電路。PCB擴展板圖如下:
④stmRct6板的供電十分差,由于剛開始只是接了ST-LINK進行供電,導(dǎo)致dht11和oled一起使用時dht11的VCC口只有2.6V,進而使得dht11通信一直不成功,這也說明了一切先從電源管理開始,確保供電沒問題再查找軟件問題。
-
傳感器
+關(guān)注
關(guān)注
2551文章
51171瀏覽量
754196 -
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7067瀏覽量
89117 -
物聯(lián)網(wǎng)
+關(guān)注
關(guān)注
2909文章
44704瀏覽量
374037 -
STM32
+關(guān)注
關(guān)注
2270文章
10904瀏覽量
356373 -
機智云
+關(guān)注
關(guān)注
2文章
590瀏覽量
26425
發(fā)布評論請先 登錄
相關(guān)推薦
評論