STM32代码编写
STM32端不需要写关于连接MQTT服务器的代码,连接的工作交给ESP8266来做,STM32只需要通过串口接收和发送数据,间接的与服务器交互。
- 串口三配置
串口一已经与电脑连接了,为了避免干扰,使用其它串口与ESP8266串口通信。这里我用的串口三,串口三的输入输出在PB10和PB11,配置这两个GPIO,然后配置中断就可以了。
串口三配置代码:
usart3.c
#include "usart3.h"
#include "sys.h"
u8 USART_RX_BUF3[USART_REC_LEN3]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
u16 USART_RX_STA3; //接收状态标记
void USART3_Config(uint32_t MyBaudRate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //使能IO口始终
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3 , ENABLE); //使能串口三
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB , &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = MyBaudRate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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_Tx|USART_Mode_Rx;
USART_Init(USART3,&USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_Cmd(USART3,ENABLE);
}
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx,ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendArray( USART_TypeDef * pUSARTx, char *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
Usart_SendByte(pUSARTx,array[i]);
}
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str) //将传进来字符串,相当于char *str="xyz"
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) ); //去除此str指针下一个地址指向的值
k++;
} while(*(str + k)!='\0');
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
void USART3_IRQHandler(void)
{
uint8_t Res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART3);//(USART3->DR); //读取接收到的数据
if((USART_RX_STA3&0x8000)==0)//接收未完成
{
if(USART_RX_STA3&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA3=0;//接收错误,重新开始
else USART_RX_STA3|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA3|=0x4000;
else
{
USART_RX_BUF3[USART_RX_STA3&0X3FFF]=Res ;
USART_RX_STA3++;
if(USART_RX_STA3>(USART_REC_LEN3-1))USART_RX_STA3=0;//接收数据错误,重新开始接收
}
}
}
}
usart3.h
#ifndef __USART3_H
#define __USART3_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN3 200 //定义最大接收字节数 200
#define EN_USART1_RX3 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF3[USART_REC_LEN3]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA3; //接收状态标记
void USART3_Config(uint32_t MyBaudRate);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendArray( USART_TypeDef * pUSARTx, char *array, uint16_t num);
void Usart_SendString( USART_TypeDef * pUSARTx,char *str);
#endif
- 串口数据处理
因为设备之间传输的数据是JSON格式的,所以当我STM32在串口中接收完数据之后,需要对JSON数据进行解析,得到真正需要的数据,我用的是cJSON这个库来解析,百度网盘cJSON库下载:
链接:https://pan.baidu.com/s/1uae-wtAgU8U2UMOfCeayRw
提取码:fpad
下载好后把里面的cJSON.c和cJSON.h引入项目中即可,编译时会有几个警告,但不影响使用。
data.c
#include "data.h"
#include "usart.h"
#include "usart3.h"
#include "cJSON.h"
#include "led.h"
#include "lcd.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "delay.h"
#include "dht11.h"
u8 ProcessData(){
u8 i;
u8 temp;
u8 humi;
cJSON *json;
if(USART_RX_STA3&0x8000) //数据接收完毕
{
if(USART_RX_BUF3[0]=='{'){//检测是不是JSON数据
json=cJSON_Parse((char *)USART_RX_BUF3);//解析JSON数据
if (!json) { //如果解析失败
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
return 0;
}
else{
cJSON *src=cJSON_GetObjectItem(json,"src"); //获取src字段
cJSON *des=cJSON_GetObjectItem(json,"des");
cJSON *msg=cJSON_GetObjectItem(json,"msg");
cJSON *content=cJSON_GetObjectItem(msg,"content"); //获取msg下的content字段
cJSON *type=cJSON_GetObjectItem(msg,"type");
cJSON *which=cJSON_GetObjectItem(msg,"which");
char *source=src->valuestring; //获取字段数据
char *command=content->valuestring;
char *tp=type->valuestring;
char *wih=which->valuestring;
printf("content:%s\r\n",content->valuestring);
if(strcmp(source, "wx")==0){
if(strcmp(tp, "ask")==0){
if(strcmp(wih, "stm32")==0){ //收到询问在线消息
STfeedback(); //发送在线回应
}
if(strcmp(wih, "data")==0){ //收到询问温湿度数据
DHT11_Read_Data(&temp,&humi);//读取温湿度数据
THfeedback(temp,humi); //发送温湿度数据
}
}
if(strcmp(tp, "ctrl")==0){ //收到控制类型数据
if(strcmp(command, "on")==0){
ControlLED1(1); //开灯
}
if(strcmp(command, "off")==0){
ControlLED1(0); //关灯
}
}
}
cJSON_Delete(json); //解析JSON数据很占内存,及时删除json
}
}
USART_RX_STA3=0;
for(i=0;i<USART_REC_LEN3;i++){ //使用完数据,清除掉,防止干扰下次接收到的数据
USART_RX_BUF3[i]=0;
}
}
return 1;
}
u8 THfeedback(u8 temperature,u8 humidity){
u8 t[100]; //这里拼接之后的字符串存放必须是分配了内存空间的变量,直接写成*t这样的指针没有足够的内存。
u8 h[100];
sprintf((char*)t,"{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"data\",\"which\":\"temperature\",\"content\":%d}}",temperature); //这里在把字符数组转成指针就可以了,不然运行到这里就直接卡住了
sprintf((char*)h,"{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"data\",\"which\":\"humidity\",\"content\":%d}}",humidity);
Usart_SendString( USART3, (char*)t); //通过串口三发送拼接好的字符串
delay_ms(100); //延时一段时间再发送,否则只能发送最后一条数据
Usart_SendString( USART3, (char*)h);
return 1;
}
void STfeedback(){
Usart_SendString( USART3, "{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"feedback\",\"which\":\"stm32\",\"content\":\"ok\"}}");
}
u8 ControlLED1(u8 state){
LED1=state; //LED灯执行相应的操作
if(state==1){
LCD_ShowString(30,110,200,16,16,"LED1=ON");
Usart_SendString( USART3, "{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"feedback\",\"which\":\"led1\",\"content\":\"on\"}}");
}
if(state==0){
LCD_ShowString(30,110,200,16,16,"LED1=OF");
Usart_SendString( USART3, "{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"feedback\",\"which\":\"led1\",\"content\":\"off\"}}");
}
return 1;
}
data.h
#ifndef __DATA_H
#define __DATA_H
#define USART_REC_LEN3 200 //定义最大接收字节数 200
#include "sys.h"
extern u8 USART_RX_BUF3[USART_REC_LEN3]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA3; //接收状态标记
u8 ProcessData(void);
u8 THfeedback(u8 temperature,u8 humidity);
void STfeedback(void);
u8 ControlLED1(u8 state);
#endif
- 主程序设计
这里要考虑到两种情况,当stm32 启动时有可能微信小程序没有打开;当微信小程序打开了,但stm32有可能不在线。所以在程序中需要在初始化时,向微信小程序发送一条在线消息,如果微信小程序上线的时候也会询问STM32是否在线,STM32接收到询问数据,再回应就可以了。
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "usart3.h"
#include "lcd.h"
#include "wifi.h"
#include "cJSON.h"
#include "dht11.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "data.h"
void display(){
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"temperature:");
LCD_ShowString(30,70,200,16,16,"humidity:");
}
int main(void)
{
int j=0;
u8 oldtemp,oldhumi;
u8 temperature;
u8 humidity;
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
USART3_Config(115200); //串口三初始化位115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
LCD_Init();
while(DHT11_Init()) //DHT11初始化
{
LCD_ShowString(30,130,200,16,16,"DHT11 Error");
delay_ms(200);
LCD_Fill(30,130,239,130+16,WHITE);
delay_ms(200);
}
Usart_SendString( USART3, "{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"feedback\",\"which\":\"stm32\",\"content\":\"ok\"}}"); //发送在线应答
display();
while(1){
ProcessData();
if(j==250){ //每个一定的时间读取一次温湿度
DHT11_Read_Data(&temperature,&humidity);
if((temperature!=oldtemp)||(humidity!=oldhumi)){ //温湿度发生改变时再发送
THfeedback(temperature,humidity); //返回温湿度数据
LCD_ShowNum(130,50,temperature,2,16);
LCD_ShowNum(100,70,humidity,2,16);
oldtemp=temperature;
oldhumi=humidity;
}
j=0;
}
delay_ms(10);
j++;
}
}
这样STM32端的代码就写好了。
个人能力有限,有什么错误的地方欢迎指正,有问题也可以提,可以一起探讨