物联网学习之旅:微信小程序控制STM32(三)--STM32代码编写

STM32代码编写

STM32端不需要写关于连接MQTT服务器的代码,连接的工作交给ESP8266来做,STM32只需要通过串口接收和发送数据,间接的与服务器交互。

  1. 串口三配置
    串口一已经与电脑连接了,为了避免干扰,使用其它串口与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;	//接收完成了 
							if((USART_RX_BUF3[0]=='1')&&(USART_RX_BUF3[1]=='1')){ //接收到Esp8266初始化完成的标志
								mqttState=1;  
							}
					} 
				}
				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

  1. 串口数据处理
    因为设备之间传输的数据是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"

extern u8 mqttState;

u8 ProcessData(){
	u8 i;
	u8 temp;
	u8 humi;
	cJSON *json;
	if(USART_RX_STA3&0x8000) //接收数据完毕且收到的消息与上次不同
	{
		if(strcmp((char *)USART_RX_BUF3, "On")==0){
			//mqttState=1;
		}
		if(USART_RX_BUF3[0]=='{'){
		json=cJSON_Parse((char *)USART_RX_BUF3);
		if (!json) {
			printf("Error before: [%s]\n",cJSON_GetErrorPtr());
			return 0;
		}
		else{
			cJSON *src=cJSON_GetObjectItem(json,"src");
			cJSON *des=cJSON_GetObjectItem(json,"des");	
			cJSON *msg=cJSON_GetObjectItem(json,"msg");	
			cJSON *content=cJSON_GetObjectItem(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);
		}
	}
	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(){
	if(mqttState==1){
		Usart_SendString( USART3, "{\"src\":\"stm32\",\"des\":\"wx\",\"msg\":{\"type\":\"feedback\",\"which\":\"stm32\",\"content\":\"ok\"}}");
	}
}

u8 ControlLED1(u8 state){
	LED1=state;
	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;
}

u8 EspOnline(){
	if(mqttState==0){
		return 0;
	}else{
		return 1;
	}

}

char* getTime(){	
	Usart_SendString( USART3, "TIME");
	delay_ms(200);
	if(USART_RX_BUF3[0]=='t'){
		return (char *)USART_RX_BUF3;
	}
	else{
	return "error";
	}
}


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);
u8 EspOnline(void);
char* getTime(void);
	
#endif


  1. 主程序设计
    这里要考虑到两种情况,当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 i=0;
	int j=0;
	u8 oldtemp,oldhumi;
	u8 temperature;
	u8 humidity;
	delay_init();	    	 //延时函数初始化	  
	NVIC_Configuration(); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为9600	
	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);
	}	
	display();
	while(EspOnline()==0){		//等待ESP8266初始化完成
		delay_ms(1000);
		Usart_SendString( USART3, "A\r\n"); //发送询问ESP8266是否初始化完成
		delay_ms(1000);
		Usart_SendString( USART3, "T\r\n");	//发送当前时间询问	
		LCD_ShowString(30,130,200,16,16,"ESP8266 unline");	//显示ESP8266未初始化完成
		if(USART_RX_STA3&0x8000) 
		{
			printf("DATA1:%s\r\n",(char*)USART_RX_BUF3);
			USART_RX_STA3=0;
			for(i=0;i<USART_REC_LEN3;i++){
				USART_RX_BUF3[i]=0;
			}
		}		
	}	
	LCD_ShowString(30,130,200,16,16,"ESP8266 online");	 	//显示ESP8266初始化完成
	STfeedback();  //发送在线应答 
	while(1){
		ProcessData();
		if(j==250){
				if(EspOnline()==0){
					Usart_SendString( USART3, "AT\r\n");
					LCD_ShowString(30,130,200,16,16,"ESP8266 unline");
				}else{
				LCD_ShowString(30,130,200,16,16,"ESP8266 online");
				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端的代码就写好了。


更新内容:
问题:在最开始做这个项目的时候,有一个问题没注意,后来调试之后,突然发现一个问题,当Esp8266和STM32同时上电之后,不会发送上线消息,然后微信小程序就不会检测到STM32是否上线,进而无法控制STM32。这是因为在上电后,stm32和esp8266各自执行自己的代码,没有联系,所以STM32初始化过程中发送在线信息时,ESP8266还没有连接上服务器,然后向串口发送在线信息时,ESP8266不会转发到主题上去。
解决方法:更改STM32程序,在STM32初始化时,向ESP8266串口发送询问数据,询问ESP8266是否连接上服务器。更新ESP8266固件,当串口接收到询问数据后,在串口返回初始化完毕的状态。
更改后的代码贴在上面。
ESP8266离线状态显示unline,在线状态显示online
在这里插入图片描述
个人能力有限,有什么错误的地方欢迎指正,有问题也可以提,可以一起探讨

回答: STM32微信小程序通信的过程如下:首先,STM32作为下位机,通过连接到MQTT服务器,定期上传温湿度和光照度数据。微信小程序通过订阅相应的主题来接收来自STM32的数据,并进行处理。在微信小程序中,可以设置LED开关和蜂鸣器开关来控制STM32。\[1\]在项目中,有一个问题是当ESP8266和STM32同时上电后,STM32发送的上线消息无法被微信小程序检测到,这是因为ESP8266还没有连接到服务器,无法转发STM32的在线信息。为了解决这个问题,可以更改STM32代码,在初始化时向ESP8266发送询问数据,以确定ESP8266是否连接到服务器。同时,需要更新ESP8266的固件,使其在接收到询问数据后返回初始化完毕的状态。\[2\]此外,如果需要在微信小程序中与STM32进行蓝牙通信,可以通过加载功能界面后自动连接到指定的蓝牙模块。为了测试STM32的蓝牙通信是否成功,可以下载一个Android环境的蓝牙调试助手软件进行测试。一旦蓝牙通信成功,就可以开始测试微信小程序STM32的通信。\[3\]希望以上信息对您有所帮助。 #### 引用[.reference_title] - *1* [stm32智能家居+微信小程序接收控制](https://blog.csdn.net/m0_57678852/article/details/129299523)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [物联网学习之旅微信小程序控制STM32)--STM32代码编写](https://blog.csdn.net/m0_46225622/article/details/105342771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [项目前期准备(1)——基于微信小程序STM32知识准备阶段](https://blog.csdn.net/weixin_41673576/article/details/88411742)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值