物联网学习之旅:微信小程序控制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;	//接收完成了 
				}
			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"

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

  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 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端的代码就写好了。

个人能力有限,有什么错误的地方欢迎指正,有问题也可以提,可以一起探讨

上一篇:STM32 串口 空闲中断使用


下一篇:(转载)STM32F103的串口2和串口3初始化