菜鳥江濤帶你學最小物聯網系統之模組篇(02)——STM32通過串列埠傳送AT指令控制ESP模組連線伺服器
阿新 • • 發佈:2018-12-18
接著上一篇繼續,這篇部落格我將帶大家使用STM32的串列埠來發送AT指令給ESP模組連線伺服器。當然目前測試使用的是區域網,自己的電腦當伺服器使用。使用TCP連線伺服器,STM32通過ESP12F模組透傳上傳溫溼度資料到伺服器。看下效果圖片
好了,看下主要的實現程式碼:
#include "stm32f10x.h" #include "delay.h" #include "oled.h" #include "bmp.h" #include "dth11.h" #include "usart.h" #include "esp_at_cmd.h" #include "string.h" unsigned char buffer[5]; unsigned int hum , temp ; unsigned char t1[5]; unsigned char t2[5]; char tx1[] = "TEMP:"; char tx2[] = "HUM:"; /************ * [ESP8266_SendCmd 傳送命令到ESP8266] * @param cmd [需要傳送的AT指令] * @param reply [期望模組回顯的內容] * @param wait [等待的時間(ms)] * @return [期望內容等於實際回顯內容返回1,否則0] *************/ int ESP8266_SendCmd(u8* cmd, char* reply, int wait) { USART1_Send_String(cmd); // 傳送指令,等待回顯接收 DelayMs(wait); // 等待接收回顯內容 if(strcmp(reply , "") == 0) return 0 ; // 不進入回顯判斷 if((USART_RX_STA&0x8000) == 1) // 接收完成 { USART_RX_STA = 0 ; // 重置標誌位 if(strstr((char*)USART_RX_BUF , reply)) // 如果返回的字串中包含有期望的返回值 { return 1 ; } } return 0 ; } /************** * 初始化 *************/ int Esp_mode() { int res = 0 ; res = ESP8266_SendCmd(AT_INIT , "OK" , 500); // 初始化 return res ; } /************** * 連線WIFI *************/ int Esp_joinAp() { int res = 0 ; res = ESP8266_SendCmd(AT_WIFI , "WIFI CONNECTED" , 5000); // 連線WIFI return res ; } /************** * 連線TCP *************/ int Esp_connectTcp() { int res = 0 ; res = ESP8266_SendCmd(AT_TCP , "CONNECT" , 5000); // 連線TCP return res ; } /************** * 設定透傳模式 *************/ int Esp_sendMode() { int res = 0 ; res = ESP8266_SendCmd(AT_MODE , "OK" , 500); // 設定模組的透傳模式 return res ; } /************** * 啟動傳送 *************/ int Esp_sendStart() { int res = 0 ; res = ESP8266_SendCmd(AT_START , "OK" , 500); // 啟動傳送 return res ; } /************** * 退出 *************/ void Esp_exit() { ESP8266_SendCmd(AT_EXIT , "" , 500); // 關閉 } int ESP_Init() { if(Esp_mode()) // 初始化成功 { if(Esp_joinAp()) // 連線WIFI成功 { if(Esp_connectTcp()) // 連線TCP伺服器 { if(Esp_sendMode()) // 設定透傳模式 { if(Esp_sendStart()) // 啟動傳送 { return 1 ; // 所有初始化成功之後返回1 } } } } } return 0; } int main(void) { u8 count = 0 ; DelayInit(); OLED_Init(); //初始化OLED OLED_Clear() ; uart_init(115200); // 一定要注意使用115200波特率 DelayMs(100); ESP_Init(); // 初始化ESP while(1){ GPIO_WriteBit(GPIOD,GPIO_Pin_2,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_2))); //IO的電平翻轉 if (dht11_read_data(buffer) == 0) { hum = buffer[0]*10 + buffer[1]; temp = buffer[2]*10 + buffer[3]; t1[0] = hum/100 + '0'; t1[1] = hum%100/10 + '0'; t1[2] = 0x2e; t1[3] = hum%10 + '0'; t2[0] = temp/100 + '0'; t2[1] = temp%100/10 + '0'; t2[2] = 0x2e; t2[3] = temp%10 + '0'; OLED_ShowString(0,2,(u8*)"hum: "); OLED_ShowString(8*6,2,t1); OLED_ShowString(0,4,(u8*)"temp: "); OLED_ShowString(8*6,4,t2); } DelayS(2); count ++ ; if(count == 5) // 計時10秒鐘傳送一次資料 { count = 0 ; USART1_Send_String((u8*)tx1); USART1_Send_String(t1); USART1_Send_String((u8*)" -- "); USART1_Send_String((u8*)tx2); USART1_Send_String(t2); } } }
再貼下串列埠的 .c檔案和 .h檔案
#ifndef __USART_H #define __USART_H #include "stdio.h" #include "stm32f10x.h" #define USART_REC_LEN 200 //定義最大接收位元組數 200 #define EN_USART1_RX 1 //使能(1)/禁止(0)串列埠1接收 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大USART_REC_LEN個位元組.末位元組為換行符 extern u16 USART_RX_STA; //接收狀態標記 void uart_init(u32 bound); // 初始化串列埠 void USART1_Send_Byte(u8 Data); // 傳送一個位元組 void USART1_Send_String(u8 *Data); // 傳送字串 #endif
#include "usart.h" ////////////////////////////////////////////////////////////////// //加入以下程式碼,支援printf函式,而不需要選擇use MicroLIB #if 1 #pragma import(__use_no_semihosting) //標準庫需要的支援函式 struct __FILE { int handle; }; FILE __stdout; //定義_sys_exit()以避免使用半主機模式 _sys_exit(int x) { x = x; } //重定義fputc函式 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//迴圈傳送,直到傳送完畢 USART1->DR = (u8) ch; return ch; } #endif /*使用microLib的方法*/ /* int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} return ch; } int GetKey (void) { while (!(USART1->SR & USART_FLAG_RXNE)); return ((int)(USART1->DR & 0x1FF)); } */ #if EN_USART1_RX //如果使能了接收 //串列埠1中斷服務程式 //注意,讀取USARTx->SR能避免莫名其妙的錯誤 u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大USART_REC_LEN個位元組. //接收狀態 //bit15, 接收完成標誌 //bit14, 接收到0x0d //bit13~0, 接收到的有效位元組數目 u16 USART_RX_STA=0; //接收狀態標記 void uart_init(u32 bound){ //GPIO埠設定 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能USART1,GPIOA時鐘以及複用功能時鐘 //USART1_TX PA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推輓輸出 GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX PA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入 GPIO_Init(GPIOA, &GPIO_InitStructure); //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//搶佔優先順序3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子優先順序3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根據指定的引數初始化VIC暫存器 //USART 初始化設定 USART_InitStructure.USART_BaudRate = bound;//一般設定為9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位資料格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬體資料流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式 USART_Init(USART1, &USART_InitStructure); //初始化串列埠 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟中斷 USART_Cmd(USART1, ENABLE); //使能串列埠 } void USART1_Send_Byte(u8 Data) //傳送一個位元組; { USART_SendData(USART1,Data); while( USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET ); } void USART1_Send_String(u8 *Data) //傳送字串; { while(*Data) USART1_Send_Byte(*Data++); } void USART1_IRQHandler(void) //串列埠1中斷服務程式 { u8 Res; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的資料必須是0x0d 0x0a結尾) { Res =USART_ReceiveData(USART1);//(USART1->DR); //讀取接收到的資料 if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始 else USART_RX_STA|=0x8000; //接收完成了 } else //還沒收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收資料錯誤,重新開始接收 } } } } } #endif
我使用的是dth11溫溼度感測器來測量溫溼度的,使用OLED來顯示,這部分不是最重要的,所以就不貼出來佔篇幅了,大家有需要的可以留言,看到我會發你的。