STM32F103C8T6+ESP-01S+MQTT server realizes data upload and reception (2)


Article directory
STM32F103C8T6+ESP-01S+MQTT server realizes data upload and reception (1)

foreword

Because the program needs to receive and recognize JSON data, the cJSON library needs to be introduced.
The use of cJSON requires heap memory space. The default heap space of STM32F103C8T6 is 0x00000200, which is not enough to meet the requirements of cJSON.
Therefore, line 44 in the startup_stm32f10x_md.s file needs to be modified. Change the heap memory to 0x00001000

After the modification is complete, it looks like this:

Modify the heap memory size

Serial port configuration

initialization

Conventional serial port initialization code, you need to pay attention at the endEnable receive interrupt and bus idle interrupt

Here simply receive two kinds of interrupts.
Each time the serial port receives a character, it will enter a receive interrupt.
When the serial port receives a complete character string, it will enter a bus idle interrupt.
For example: the device sends a string "lcheng" to the MCU.
It will enter the receiving interrupt 6 times, and when the last 'g' of the string is received, it will enter the bus idle interrupt 1 time

void usart_init(uint32_t bound)				//115200
{
    
    
        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_TX   PA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);   
        
        USART_InitStructure.USART_BaudRate = bound;
        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_Rx | USART_Mode_Tx;
        USART_Init(USART1, &USART_InitStructure);


        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);			//开启接收中断
		USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);			//开启空闲中断
				
        USART_Cmd(USART1, ENABLE);                   
}

printf output redirection

If you need to redirect to USART2, please replace all USART1 below with USART2

#include <stdio.h>							//重定向需要引入该头文件
int fputc(int ch,FILE *f)					
{
    
      
	USART_ClearFlag(USART1, USART_FLAG_TC);
    USART_SendData(USART1,(unsigned char)ch); 
    while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);  
    return ch;  
}

Serial port interrupt function

In the serial port receiving interrupt, store each character received with Rec_i into the global variable USART_ReceiveString.

uint16_t Rec_i;
void USART1_IRQHandler(void)
{
    
    
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   
    {
    
    
			USART_ReceiveString[Rec_i++]=USART_ReceiveData(USART1);				//将接收到的字符存入USART_ReceiveString中
    }
		if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){
    
    					//表示接收到了一个完整的字符串
			uint16_t clear;
			USART_ReceiveString[Rec_i]='\0';
			if(USART_ReceiveString[0]!='\0'){
    
    
				baseACK(USART_ReceiveString);				//处理AT指令基本回复  OK  ERROR FALT
				msg_handle(USART_ReceiveString);			//真正的数据处理
				clear_ReceiveString();						//清除串口的接收数据。
			}
			clear = USART1->SR;								//清除寄存器
			clear = USART1->DR;
		}
}
void clear_ReceiveString(){
    
    	
	USART_ReceiveString[0]='\0';
	Rec_i=0;
}

Process the data received by the serial port

baseAck()

This function is used to modify the corresponding response flag bit in the program for the basic response of 8266.

void baseACK(char USART_ReceiveString[]){
    
    
	if(checkOK(USART_ReceiveString,OK)){
    
    
		back_flag=SUCC;
	}else if(checkOK(USART_ReceiveString,ERROR)||checkOK(USART_ReceiveString,FAIL)){
    
    
		back_flag=FAULT;
	}else{
    
    
		clearBackFlag();
	}
	if (checkOK(USART_ReceiveString,WIFI_GOT_IP)||checkOK(USART_ReceiveString,WIFI_CONNECTED)){
    
    
			ATBack_KeyWords=WIFI_GOT;
		}
}

Get MQTT topic content get_mqttval()

This function is used to obtain the content of the topic subscribed by MQTT and needs to be used with info_type()

void get_mqttval(char USART_ReceiveString[],char *val){
    
    
	unsigned short int i,j,count=0;  //count为逗号数量
	for(i=0;USART_ReceiveString[i]!='\0';i++){
    
    
		if(USART_ReceiveString[i]==','&&count!=3){
    
    
			if(count<3){
    
    
				j=0;
				count+=1;
			}
		}else{
    
    
			if(count==3){
    
    
				val[j++]=USART_ReceiveString[i];
				if(USART_ReceiveString[i+1]=='\r'){
    
    
					val[j++]='\0';
				}
			}
		}
	}
}

msg_handle()

Perform corresponding processing according to the data received by the serial port

void msg_handle(char *USART_ReceiveString){
    
    

	if(info_type(USART_ReceiveString)){
    
    	//是mqtt订阅的话题题消息,就根据mqtt协议得到最终数据进行处理
		char val[300],*type,*msg;
		cJSON* val_json=NULL;
		get_mqttval(USART_ReceiveString,val);		//去掉MQTT协议壳得到原始数据(json字符串)
		val_json=cJSON_Parse(val);					//将json字符串转化成cJSON结构体数据
		if(val_json!=NULL){
    
    
			type=cJSON_GetObjectItem(val_json,"type")->valuestring;		//得到json中键为type的值
			msg=cJSON_GetObjectItem(val_json,"msg")->valuestring;       //得到json中键为msg的值
			if(!strcmp(type,"dj")){
    
    				//对键值进行判断
				if(!strcmp(msg,"ON")|| !strcmp(msg,"on")){
    
      
					//如果匹配进行相应处理
				}else{
    
    
					//其他处理........
				}
			}
			cJSON_Delete(val_json);				//JSON结构体使用完毕需要释放掉,不然会造成堆内存溢出导致程序卡死
		}
	}else{
    
    		//非MQTT话题消息
		/*非MQTT话题消息处理
		例如baseACK()函数可以放在此处性能会更好,
		但是为了代码可读性更好,选择放在了与msg_handle()同级的地方。*/
	}
}

Summarize

The reason why cJSON is not used when sending MQTT messages is because the ',' in the json data sent by MQTT needs to be escaped, and the ',' in the string constructed by cJSON is not escaped. This place is not harmonious. In addition, use cJSON to construct json characters Strings take up more heap memory than parsing json strings, so cJSON is not used, and we can continue to improve this place in the future. In addition, the introduction of cJSON will cause the generated hex file to be a bit larger. If there is no need to use JSON, you can choose not to introduce cJSON, which will save some flash capacity.

Guess you like

Origin blog.csdn.net/weixin_46144773/article/details/122813763