> 文章列表 > STM32+EC20实现4G无线通信

STM32+EC20实现4G无线通信

STM32+EC20实现4G无线通信

EC20是一款集成度非常高的4G无线通信模块,支持多种常见通信频段,能满足几乎所有的M2M(MachinetoMachine)应用需求。模块支持TCP/UDP/FTP等一众网络协议,内置多星座高精度定位GNSS接收机,快速提供准确的经纬度信息,UART接口提供AT命令控制和数据传输。

物联网很多的网关设备因需要会安装在有线网络不易布到线的地方,而有些网关则需要跟着运输工具一起移动,那么就需要产品实现与上位机服务器进行无线通信,而4G的无线通信模块就提供了一种非常便利的实现。本例使用了FreeRTOS作为实时操作系统,嵌入式代码运行在FreeRTOS之上,使用提供系统调用完成了多任务编程。

目录

概念说明

实现原理

嵌入式程序

顶层结构

任务与串口初始化

EC20任务

传感器任务 


概念说明

  • 电平转换:在我们设计的电路中,不同芯片的引脚使用的电压不同,比如常见的1.8V、3.3V、5V等,在两种不同电压芯片引脚之间进行通讯时候,我们需要使得两边的电平都符合自身的需求且能够进行正常的通讯,这就叫电平转换。我们STM32与4G模块连接的控制与通信的引脚就需要做电平转化才能正常通信。
  • AT指令:在物联网中,AT(Attention)命令集可用于控制和调测设备、通信模块入网等。AT 指令以"AT"开始,以"\\r "或者"\\r\\n" 结尾,参数之间使用" ," 隔开,字符串参数使用双引号 "" 包裹,整形参数不适用双引号。
  • FreeRTOS:FreeRTOS是面向微控制器和小型微处理器的实时操作系统 (RTOS),本例在STM32的平台上使用了FreeRTOS作为实时操作系统,以更合理、更有效地利用CPU的资源,简化应用软件的设计,缩短系统开发时间,提供多任务编程环境,并且更好地保证系统的实时性和可靠性。
  • 4G模块:4G模块通常是插针到电路板或将贴片式模块焊到电路板上,并插入相应的SIM卡,通过4G蜂窝网络进行联网。

  • 物联网sim卡:物联网(IoT)的发展及其独特的需求推动了物联网SIM卡的发展,IoT SIM卡是传统SIM卡的变体,旨在存储用户信息并将手机连接到对应运营商的蜂窝网络。
  • APN:接入点名称(APN)用户的模块通过哪种接入方式来访问什么样的网络。一个典型的APN包含的参数有名称、MCC、MNC、接入点、类型。

实现原理

嵌入式程序运行在STM32芯片之上,通过UART与4G模块进行通信,控制协议为AT指令格式。STM32与4G模块之间还有两个引脚:

  • 开/关模块引脚:引脚拉高保持300ms后拉低开机,拉高保持800ms后拉低关机
  • 复位引脚:引脚拉高500ms后拉低复位

下图为实现原理的示意图:


嵌入式程序

顶层结构

本例基于STM32平台,完整工程代码已上传。工程一共涉及三个串口,功能分别如下:

  1. 连接4G模块完成无线数据收发
  2. 负责与传感器等数据采集模块连接
  3. 产品参数配置串口

代码的顶层结构由任务和消息队列与中断构成。程序开始初始化消息队列与串口控制器和相关GPIO之后,注册串口接收函数。接收函数在串口接收中断处调用,将信息发送到消息队列中。最后启动三个任务,来处理三个串口接收队列中的信息。完整的数据流图如下:


任务与串口初始化

下面是除了串口的初始化工作,已增加了中文注释帮助理解,主要包括任务的初始化和启动:

#define START_TASK_PRIO		1			//任务优先级
#define START_STK_SIZE 		64  		//任务堆栈大小
TaskHandle_t StartTask_Handler;			//任务句柄
void start_task(void *pvParameters);	//开始任务声明#define EC20_TASK_PRIO		10			
#define EC20_STK_SIZE 		128  			
TaskHandle_t ec20_task_handler;			
void ec20_task(void *pvParameters);		#define STM32_TASK_PRIO		11			
#define STM32_STK_SIZE 		128  			
TaskHandle_t stm32_task_handler;		
void stm32_task(void *pvParameters);	#define IDLE_TASK_PRIO		8			
#define IDLE_STK_SIZE 		128  	
TaskHandle_t idle_task_handler;			
void idle_task(void *pvParameters);		#define SET_TASK_PRIO		9		
#define SET_STK_SIZE 		128  		
TaskHandle_t set_task_handler;			
void set_task(void *pvParameters);		
int main(void)
{Flash_EnableReadProtection();//开Flash读保护NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4//创建开始任务xTaskCreate((TaskFunction_t )start_task,           (const char*    )"start_task",          (uint16_t       )START_STK_SIZE,        (void*          )NULL,                  (UBaseType_t    )START_TASK_PRIO,       (TaskHandle_t*  )&StartTask_Handler);       vTaskStartScheduler();       
}/
@GPIO初始化
/
void gpio_init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_ResetBits(GPIOB, GPIO_InitStructure.GPIO_Pin);		
}
/
@启动任务函数
/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           //进入临界区gpio_init();	//GPIO初始化delay_init();	//延时函数初始化global_init();	//全局变量初始化msg_init();		//消息队列初始化uart3_init(global.baud);//串口3初始化uart1_init(115200);//串口1初始化uart2_init(global.baud);//串口2初始化//创建ec20任务xTaskCreate((TaskFunction_t )ec20_task,     	(const char*    )"ec20_task",   	(uint16_t       )EC20_STK_SIZE, (void*          )NULL,				(UBaseType_t    )EC20_TASK_PRIO,	(TaskHandle_t*  )&ec20_task_handler);   //创建传感器任务xTaskCreate((TaskFunction_t )stm32_task,     	(const char*    )"stm32_task",   	(uint16_t       )STM32_STK_SIZE, (void*          )NULL,				(UBaseType_t    )STM32_TASK_PRIO,	(TaskHandle_t*  )&stm32_task_handler);//	//创建空闲任务
//				xTaskCreate((TaskFunction_t )idle_task,     	
//                (const char*    )"idle_task",   	
//                (uint16_t       )IDLE_STK_SIZE, 
//                (void*          )NULL,				
//                (UBaseType_t    )IDLE_TASK_PRIO,	
//                (TaskHandle_t*  )&idle_task_handler);   //创建参数设置任务xTaskCreate((TaskFunction_t )set_task,     	(const char*    )"set_task",   	(uint16_t       )SET_STK_SIZE, (void*          )NULL,				(UBaseType_t    )SET_TASK_PRIO,	(TaskHandle_t*  )&set_task_handler);   vTaskDelete(StartTask_Handler); //删除开始启动任务taskEXIT_CRITICAL();            //退出临界区
}

下面以串口1为例提供相关初始化以及发送和接收中断代码:

#include "global.h"
#include "usart1.h"
#include "msg.h"
#include "global.h"extern uint8_t callback_ec20_deault(MSG *rx);
static volatile MSG *tx;static COMMUCATION_RECV_CALLBACK callBack_recv = 0;
//串口接收中断数据处理函数
static COMMUCATION_RECV_CALLBACK default_callback = callback_ec20_deault;
//串口配置
static void uart1_config(u32 baud)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); //PA9 -> UART1_TXGPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	GPIO_Init(GPIOA, &GPIO_InitStructure);//PA10 -> UART1_RXGPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);//USART1 参数配置USART_DeInit(USART1);USART_InitStructure.USART_BaudRate = baud;						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_IDLE, ENABLE );	//¿ª¿ÕÏÐÖжÏUSART_ITConfig(USART1, USART_IT_ERR, ENABLE);	//¿ª´íÎóÖжÏUSART_ClearFlag(USART1, USART_FLAG_TC);USART_ClearFlag(USART1, USART_FLAG_RXNE);USART_ClearFlag(USART1, USART_FLAG_IDLE);USART_ClearFlag(USART1, USART_FLAG_ORE);USART_Cmd(USART1, ENABLE);  //NVIC ÅäÖÃNVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;			NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;	NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;			NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				NVIC_Init(&NVIC_InitStructure);								
}//dma接收配置 未用
static void dma_recv_config(void)
{	DMA_InitTypeDef DMA_InitStructure;				RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	DMA_DeInit(DMA1_Channel5); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART1->DR);	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)msg_recv_ec20[0].buf;	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;						DMA_InitStructure.DMA_BufferSize = global.bufferSize;						DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;			DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							DMA_InitStructure.DMA_Priority = DMA_Priority_High;						DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;							DMA_Init(DMA1_Channel5, &DMA_InitStructure);DMA_ClearFlag(DMA1_FLAG_GL4);       //Çå³ýDMA1ËùÓбêÖ¾USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);	DMA_Cmd(DMA1_Channel5, ENABLE);					}//dma发送配置 未用
static void dma_send_config(void)
{DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//DMA1 ʱÖÓDMA_DeInit(DMA1_Channel4);DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);DMA_InitStructure.DMA_MemoryBaseAddr = (u32)tx->buf;DMA_InitStructure.DMA_BufferSize = 0;							DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;				DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;			DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;					DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;			DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;					DMA_Init(DMA1_Channel4, &DMA_InitStructure);DMA_ClearFlag(DMA1_FLAG_GL4);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);DMA_Cmd(DMA1_Channel4, DISABLE);DMA_ClearFlag(DMA1_FLAG_GL4);DMA_ClearFlag(DMA1_FLAG_HT4);DMA_ClearFlag(DMA1_FLAG_TC4);DMA_ClearFlag(DMA1_FLAG_TE4);}
//串口1中断处理函数
void USART1_IRQHandler(void)
{uint32_t  sr;sr = sr;if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//·¢ËÍ¿Õ{USART_ClearITPendingBit(USART1, USART_IT_TXE);}if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)//·¢ËÍÍê³É{USART_ClearITPendingBit(USART1, USART_IT_TC);USART_ITConfig(USART1, USART_IT_TC, DISABLE);                                  }if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//ÊÕµ½{	 	USART_ClearITPendingBit(USART1, USART_IT_RXNE);//Çå½ÓÊÕÖжϱêÖ¾}if(USART_GetITStatus(USART1, USART_IT_ORE) != RESET){sr = USART_ReceiveData(USART1);USART_ClearITPendingBit(USART1, USART_IT_ORE);}if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//¿ÕÏÐ{sr = USART_ReceiveData(USART1);					DMA_Cmd(DMA1_Channel5, DISABLE);				USART_ClearITPendingBit(USART1, USART_IT_IDLE );msg_recv_ec20[global.cur_ec20_msg].state = 1;msg_recv_ec20[global.cur_ec20_msg].len = global.bufferSize - DMA_GetCurrDataCounter(DMA1_Channel5);	callBack_recv((MSG*)&msg_recv_ec20[global.cur_ec20_msg]);//启动回调函数函数处理中断内容callBack_recv = default_callback;DMA1_Channel5->CMAR = (u32)(ec20_rx()->buf);DMA1_Channel5->CNDTR = global.bufferSize;				DMA_Cmd(DMA1_Channel5, ENABLE);}if(USART_GetITStatus(USART1 ,USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//´íÎó{sr = USART_ReceiveData(USART1);USART_ClearITPendingBit(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE);}
}
//串口接收DMA中断
void DMA1_Channel5_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_IT_TC5) == SET)    {DMA_ClearITPendingBit(DMA1_IT_TC5);}if(DMA_GetITStatus(DMA1_IT_TE5) == SET){DMA_ClearITPendingBit(DMA1_IT_TE5);}DMA_ClearITPendingBit(DMA1_IT_TC5);DMA_ClearITPendingBit(DMA1_IT_TE5);DMA_Cmd(DMA1_Channel5, DISABLE);DMA1_Channel5->CNDTR = 100;DMA_Cmd(DMA1_Channel5, ENABLE);
}
//串口发送DMA中断
void DMA1_Channel4_IRQHandler(void)
{if(DMA_GetITStatus(DMA1_IT_TC4) == SET)    {DMA_ClearITPendingBit(DMA1_IT_TC4);}if(DMA_GetITStatus(DMA1_IT_TE4) == SET){DMA_ClearITPendingBit(DMA1_IT_TE4);}if(DMA_GetITStatus(DMA1_IT_GL4) == SET){DMA_ClearITPendingBit(DMA1_IT_GL4);}if(DMA_GetITStatus(DMA1_IT_HT4) == SET){DMA_ClearITPendingBit(DMA1_IT_HT4);}DMA_Cmd(DMA1_Channel4, DISABLE);
}//串口1初始化
void uart1_init(u32 baud)
{uart1_config(baud);dma_recv_config();dma_send_config();callBack_recv = default_callback;//配置串口中断回调函数
}//串口1发送函数
uint8_t uart1_send(uint8_t *pt_txbuf , uint32_t tx_len, COMMUCATION_RECV_CALLBACK callback)  
{	if(pt_txbuf == 0)return FALSE;if(callback != 0)callBack_recv = callback;	DMA_ClearFlag(DMA1_FLAG_TC4);DMA_ClearFlag(DMA1_FLAG_TE4);DMA_Cmd(DMA1_Channel4, DISABLE);	DMA1_Channel4->CMAR = (u32)(pt_txbuf);		DMA1_Channel4->CNDTR = tx_len;				DMA_Cmd(DMA1_Channel4, ENABLE);	return TRUE;
}

下面只介绍 EC20任务和传感器任务的实现,剩下一个任务的实现有兴趣的读者可以到我的资源里把工程代码下载下来进行研究,欢迎评论区留言讨论。

EC20任务

下面是EC20模块初始化,建立TCP连接以及接收数据处理整个状态机在一切结果正常的情况下的流程图:

 下面是任务状态机的实现,包括一些模块返回错误的流程跳转,代码中以增加中文注释帮忙理解:

 //AT指令const char chk_baud[] = {"AT+IPR?\\r\\n"};			//查询波特率const char set_baud[] = {"AT+IPR=115200\\r\\n"};		//设置波特率const char chk_signal[] = {"AT+CSQ\\r\\n"};			//查询信号强度const char close_cmd_echo[] = {"ATE0\\r\\n"};	    //关闭数据回显const char save_param[] = {"AT&W\\r\\n"};			//保存设置参数,应答超时300msconst char chk_iccid[] = {"AT+QCCID\\r\\n"};			//查询ccidconst char chk_pin[] = {"AT+CPIN?\\r\\n"};			//查询sim卡密码,5s超时const char chk_pin_back1[] = {"+CME ERROR: 10"};	//sim卡未插好const char chk_pin_back2[] = {"+CPIN: READY"};		//sim卡准备好const char chk_sim_reg[] = {"AT+CREG?\\r\\n"};		//查询sim卡是否注册const char chk_net_reg[] = {"AT+CGREG?\\r\\n"};		//查询net注册//运营商APNconst char set_link_ChinaMobile[] = {"AT+QICSGP=1,1,\\"CMNET\\",\\"\\",\\"\\",1\\r\\n"};//设置接入点(移动)APN,USERNAME,PASSWORDconst char set_link_UNICOM[] = {"AT+QICSGP=1,1,\\"UNINET\\",\\"\\",\\"\\",1\\r\\n"};//设置接入点(联通) APN,USERNAME,PASSWORDconst char set_link_p[] = {"AT+QICSGP=1,1,\\"CTLTE\\",\\"\\",\\"\\",1\\r\\n"};//设置接入点(电信) APN,USERNAME,PASSWORDconst char chk_link_point[] = {"AT+QICSGP=1\\r\\n"};	//查询接入点const char active_pdp_context[] = {"AT+QIACT=1\\r\\n"};//激活接入点150s超时const char chk_pdp_context[] = {"AT+QIACT?\\r\\n"};	//查询context,返回当前接入点信息(150s超时)const char deactive_pdp_context[] = {"AT+QIDEACT=1\\r\\n"};//关闭接入点40s超时
//const char creat_tcp[] = {"AT+QIOPEN=1,0,\\"TCP\\",\\"120.55.115.113\\",5008,0,2\\r\\n"};//创建TCP连接(150s超时)
//const char creat_tcp[] = {"AT+QIOPEN=1,0,\\"TCP\\",\\"120.26.204.86\\",8001,0,2\\r\\n"};//创建TCP连接(150s超时)const char creat_tcp_top[] = {"AT+QIOPEN=1,0,\\"TCP\\",\\""};
const char creat_tcp_tail[] = {"\\","};//创建TCP连接150s
const char creat_tcp_port[] = {",0,1\\r\\n"};//服务端口号+传输模式【推送,非透传】
const char creat_tcp_back1[] = {"CONNECT"};//创建TCP成功,透传模式的回应const char close_tcp[] = {"AT+QICLOSE=0\\r\\n"};		//关闭TCP连接(自己设置超时时间)
const char chk_tcp[] = {"AT+QISTATE=1,0\\r\\n"};		//查询TCP连接(指定connetcID)
const char chk_data_echo[] = {"AT+QISDE?\\r\\n"};		//查询数据回显
//const char close_data_echo[] = {"AT+QISDE=0\\r\\n"};	//关闭数据回显(透传模式不需要)
const char chk_err_code[] = {"AT+QIGETERROR\\r\\n"};	//查询最近的错误码const char exit_transpartent[] = {"+++"};		//退出透传模式
const char exit_transpartent2[] = {"++++++++\\r\\n"};		//命令模式下+++操作const char change_transparent_mode[] = {"AT+QISWTMD=1,2\\r\\n"};		//改为透传模式
const char enter_transparent_mode[] = {"ATO\\r\\n"};		//进入透传模式const char common_ack[] = {"OK"};	//通用回复"OK"const char chk_Operator[] = {"AT+COPS?\\r\\n"};//查是什么卡,移动联通电信
const char Operater1_ack[] = {"CHINA MOBILE"};//中国移动
const char Operater2_ack[] = {"CHN-UNICOM"};//中国联通
const char Operater3_ack[] = {"CHN-CT"};//中国电信
//	const char Operater1_ack[] = {"china mobile"};//中国移动
//	const char Operater2_ack[] = {"chn-unicom"};//中国联通
//	const char Operater3_ack[] = {"chn-ct"};//中国电信const char chk_signal_quality[] = {"AT+CSQ\\r\\n"};//查询信号强度
const char chk_signal_ack[] = {"+CQS"};//查询信号强度返回值const char remote_recv[] = {"+QIURC"};//服务器数据返回const char tcp_direct_ack[] = {"+QIOPEN:"};//tcp连接 direct push 模式返回值const char send_head[] = {"AT+QISEND=0,"};//通知ec20即将发送数据
const char send_head_ack[] = {">"};
const char sended_data_ack[] = {"SEND OK"};
const char query_sended[] = {"AT+QISEND=0,0\\r\\n"};//查询发送数据
const char query_sended_ack[] = {"+QISEND:"};
/
//EC20主任务
void ec20_task(void)
{u8 rs;ec20.fsm = ST_PWR_ON;//初始化状态机UPDATE_REBOOT_TIME;	//初始化重启计时CLEAR_REBOOT_COUNT;	//初始化重启计数while(1){switch(ec20.fsm){					case ST_PWR_ON:		//上电
//				c4g_power_off();c4g_power_on();ec20.fsm = ST_CLOSE_CMD_ECHO;//跳转关闭回显break;case ST_REBOOT:		//重启c4g_power_reset();ec20.fsm = ST_CLOSE_CMD_ECHO;//跳转关闭回显UPDATE_REBOOT_TIME;CLEAR_REBOOT_COUNT;global.reboot_time_count = xTaskGetTickCount();//更新全局数据发送时间间隔break;case ST_CLOSE_CMD_ECHO://关闭数据回显if(c4g_close_cmd_echo()){UPDATE_REBOOT_TIME;ec20.fsm = ST_CHK_SIM;}if(JUDGE_REBOOT_TIME(30))//超时则重启{ec20.fsm = ST_REBOOT;printf("EC20 reboot\\r\\n\\r\\n");}break;case ST_CHK_SIM:	//查看sim卡,物理卡rs = c4g_chk_sim();if(rs == TRUE){ec20.fsm = ST_CHK_SIGNAL;//跳转信号强度UPDATE_REBOOT_TIME;}elseif(rs == 2)//未插卡{printf("no sim\\r\\n");UPDATE_REBOOT_TIME;}else//重启{if(JUDGE_REBOOT_TIME(20))//查询时间超过20s{printf("check sim timeout\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;}}break;case ST_CHK_SIGNAL:	//查询信号强度rs = c4g_chk_signal();if(rs == TRUE){ec20.fsm = ST_CHK_SIM_REG;//跳转sim卡注册UPDATE_REBOOT_TIME;}else{if(JUDGE_REBOOT_TIME(20))//查询时间超过20s{printf("check signal timeout\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;}}break;case ST_CHK_SIM_REG:	//查询sim卡注册rs = c4g_sim_reg();if(rs == TRUE){ec20.fsm = ST_CHK_NET_REG;UPDATE_REBOOT_TIME;}else if(rs == 2){if(JUDGE_REBOOT_TIME(90))//查询时间超过90s{printf("check sim reg timeout\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;}}break;case ST_CHK_NET_REG:	//查询网络注册rs = c4g_net_reg();if(rs == TRUE){ec20.fsm = ST_CHK_OPERATER;//跳转查询运营商UPDATE_REBOOT_TIME;}elseif(rs == 2){if(JUDGE_REBOOT_TIME(60))//查询时间超过60s{printf("check net reg timeout\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;}}break;case ST_CHK_OPERATER:	//查询运营商rs = c4g_check_Operater();if(rs == TRUE){ec20.fsm = ST_SET_POINT;//跳转设置接入点UPDATE_REBOOT_TIME;}else{if(JUDGE_REBOOT_TIME(60))//查询时间超过60s{printf("Operater check err\\r\\n\\r\\n");//没查到运营商ec20.fsm = ST_REBOOT;}}break;case ST_SET_POINT:	//设置接入点,APNrs = c4g_set_point();if(rs == TRUE){ec20.fsm = ST_ACTIVE_POINT;//Ìø×ª->"¼¤»î½ÓÈëµã"UPDATE_REBOOT_TIME;}else{if(JUDGE_REBOOT_TIME(60))//²éѯʱ¼ä³¬¹ý60s{printf("set apn err\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;}}break;case ST_CHK_POINT:	//查询接入点break;case ST_ACTIVE_POINT:	//激活接入点rs = c4g_active_context();if(rs == TRUE){ec20.fsm = ST_CREAT_TCP;//跳转创建TCPUPDATE_REBOOT_TIME;CLEAR_REBOOT_COUNT;}elseif(rs == 2)//收到数据,但是数据错误{printf("active PDP Context err 1\\r\\n\\r\\n");ec20.fsm = ST_DEACTIVE_POINT;//跳转关闭接入点UPDATE_REBOOT_TIME;}else//超过150秒未收到回复{printf("active PDP Context err 2\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;//跳转到重启设备}break;case ST_DEACTIVE_POINT:	//关闭接入点rs = c4g_deactive_context();if(rs == TRUE){ec20.fsm = ST_CHK_SIM;//跳转查询sim卡CLEAR_REBOOT_COUNT;//清除重启计数UPDATE_REBOOT_TIME;}elseif(rs == 2)//有返回,但是返回数据错误{if(JUDGE_REBOOT_COUNT(3))//最多查4次,如果还是失败则重启设置{printf("link point err 1\\r\\n\\r\\n");//接入点设置失败ec20.fsm = ST_REBOOT;//跳转重启设备}}else//40秒超时无回答{printf("link point err 2\\r\\n\\r\\n");//接入点设置失败ec20.fsm = ST_REBOOT;//跳转重启设备}break;case ST_CHK_CONTEXT:	//查询接入点文本rs = c4g_chk_context();if(rs == TRUE){//查询成功,但是未激活ec20.fsm = ST_ACTIVE_POINT;UPDATE_REBOOT_TIME;}elseif(rs == 3){//已经激活ec20.fsm = ST_CHK_TCP;//先查询是否建立了TCP连接,如没有则建立}elseif(rs == 2){//错误信息printf("context err 1\\r\\n\\r\\n");//查询接入点文本错误}break;case ST_CREAT_TCP:	//创建TCP连接rs = c4g_creat_tcp();if(rs == TRUE){ec20.fsm = ST_COMMUCATION;//跳转通信global.socket_state = 1;//tcp连接成功CLEAR_REBOOT_COUNT;//清除重启计数UPDATE_REBOOT_TIME;}elseif(rs !=0 && rs != TRUE)//有返回,则返回数据错误{if(JUDGE_REBOOT_COUNT(5))//五次失败重启{char tmp[2];sprintf(tmp, "%u", rs);printf("creat tcp err:");printf((const char*)tmp);printf("\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;//跳转重启}}else//创建TCP超时,150s{printf("creat tcp timout\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;//跳转重启}break;case ST_CHK_TCP:	//查询TCPrs = c4g_chk_tcp();if(rs == TRUE)//没有建立tcp,需要重新建立{ec20.fsm = ST_CREAT_TCP;//跳转创建tcpUPDATE_REBOOT_TIME;CLEAR_REBOOT_COUNT;}else//if(rs == 3)//TCP连接已存在{if( xTaskGetTickCount() - global.reboot_time_count > global.reboot_time_set )//超过系统超时时间{global.reboot_time_count = xTaskGetTickCount();//更新时间ec20.fsm = ST_CLOSE_TCP;//跳转"关闭CTP"UPDATE_REBOOT_TIME;}else{ec20.fsm = ST_COMMUCATION;//跳转等待接收数据UPDATE_REBOOT_TIME;}}elseif(rs == 4)//正在关闭TCP{ec20.fsm = ST_CLOSE_TCP;//跳转关闭TCPUPDATE_REBOOT_TIME;}else//超时无人应答{printf("chk tcp timeout\\r\\n\\r\\n");//查询TCP失败ec20.fsm = ST_REBOOT;//跳转重启}break;case ST_CLOSE_TCP:		//关闭TCPrs = c4g_close_tcp();if(rs == TRUE)//关闭TCP成功{ec20.fsm = ST_CREAT_TCP;//跳转创建TCPUPDATE_REBOOT_TIME;CLEAR_REBOOT_COUNT;}elseif(rs == 2)//错误信息{if( JUDGE_REBOOT_COUNT(5) )//最多查5次{printf("close tcp err\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;//跳转重启}}else{printf("close tcp timeout\\r\\n\\r\\n");//关闭TCP超时ec20.fsm = ST_REBOOT;//Ì跳转重启}break;case ST_COMMUCATION://数据通信{MSG*cmsg;u8 err;err = getting_queue_ec20_remote((void*)&cmsg, 10*OS_TICKS_PER_SEC);//每10s查询一次if(err == pdTRUE)//收到远端数据{send_to_stm32(cmsg);//发送给传感器串口printf("send to user\\r\\n\\r\\n");}else{if(global.socket_state == 2){printf("direct reboot\\r\\n\\r\\n");ec20.fsm = ST_REBOOT;//跳转重启}elseif(global.socket_state == 0){printf("transfer to close tcp\\r\\n\\r\\n");ec20.fsm = ST_CLOSE_TCP;//跳转关闭TCPUPDATE_REBOOT_TIME;}}}break;case ST_CHK_DATA_ECHO:	//查询数据回显printf("idle \\r\\n\\r\\n");break;case ST_CLOSE_DATA_ECHO://关闭数据回显break;case ST_CHK_ERRCODE:	//查询最近的错误码break;}}
}

传感器任务 

下面是传感器任务的实现,将传感器通过串口的发过来的数据通过EC20模块发送出去:

void stm32_recv_task(void)
{uint8_t rs, err, resend = 0;MSG *cmsg;while(1){err = getting_queue_stm32((void*)&cmsg, global.reboot_time_set);//无限等待传感器队列消息if(err == pdTRUE){global.reboot_time_count = xTaskGetTickCount();if(global.socket_state != 1)//tcp未连接{msg_free(cmsg);//不处理,并释放队列空间printf("stm32 recv data no dealwith\\r\\n");}else{//1.将数据发送至ec20//2.查询数据是否发送成功,即tcp是有否回应。如果没有发送成功,此条数据重新丢进队列,关闭TCP,重新连接tcp,重新发送此数据rs = 0xff; resend = 0;do{rs = send_commucation_head(cmsg->len);}while(resend++ < 3 && rs != 1);if(rs == 1)//发送数据头,通知ec20即将发送数据{u8 i = 0;do{uart1_send(cmsg->buf, cmsg->len, 0);//发数据rs = sended_result();if(rs != 1)//发送失败(EC20本身发送失败,并不是发送远端失败){printf("ec20 send err\\r\\n\\r\\n");}else//发送成功{rs = query_sended_result(cmsg->len);//检查发送到remote是否成功if(rs == 0)//超时90s{rs = 111;global.socket_state = 2;//重启printf("sended no ack\\r\\n\\r\\n");}}}while(i++ < 3 && rs != 1);if(rs == 1)//发送remote成功{}else/发送失败{printf("send data err\\r\\n\\r\\n");if(rs != 111){global.socket_state = 0;//重新建立tcpprintf("sended data fail\\r\\n\\r\\n");}}}else//发送数据头,无'>'回复{printf("head is no ack\\r\\n\\r\\n");global.socket_state = 2;//重启}msg_free(cmsg);//释放消息,这里无论remote是否收到没有}}else//超过最长发送时间间隔{global.socket_state = 2;//重新建立TCPprintf("global timeout\\r\\n\\r\\n");}}
}

 十六宿舍 原创作品,转载必须标注原文链接。

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。