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蜂窝网络进行联网。

STM32+EC20实现4G无线通信

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

实现原理

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

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

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

STM32+EC20实现4G无线通信


嵌入式程序

顶层结构

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

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

STM32+EC20实现4G无线通信

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

STM32+EC20实现4G无线通信


任务与串口初始化

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

#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_TX
	GPIO_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_RX
	GPIO_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连接以及接收数据处理整个状态机在一切结果正常的情况下的流程图:

STM32+EC20实现4G无线通信

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

 //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"};			//保存设置参数,应答超时300ms
 const char chk_iccid[] = {"AT+QCCID\r\n"};			//查询ccid

 const 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注册
 
 //运营商APN
 const char set_link_ChinaMobile[] = {"AT+QICSGP=1,1,\"CMNET\",\"\",\"\",1\r\n"};//设置接入点(移动)APN,USERNAME,PASSWORD
 const char set_link_UNICOM[] = {"AT+QICSGP=1,1,\"UNINET\",\"\",\"\",1\r\n"};//设置接入点(联通) APN,USERNAME,PASSWORD
 const char set_link_p[] = {"AT+QICSGP=1,1,\"CTLTE\",\"\",\"\",1\r\n"};//设置接入点(电信) APN,USERNAME,PASSWORD
 
 const 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;
				}else
				if(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;
				}
				else
				if(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:	//设置接入点,APN
				rs = 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;//跳转创建TCP
					UPDATE_REBOOT_TIME;
					CLEAR_REBOOT_COUNT;
				}
				else
				if(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;
				}
				else
				if(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;
				}else
				if(rs == 3){//已经激活
					ec20.fsm = ST_CHK_TCP;//先查询是否建立了TCP连接,如没有则建立
				}else
				if(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;
				}
				else
				if(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:	//查询TCP
				rs = c4g_chk_tcp();
				if(rs == TRUE)//没有建立tcp,需要重新建立
				{
					ec20.fsm = ST_CREAT_TCP;//跳转创建tcp
					UPDATE_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;
					}
				}
				else
				if(rs == 4)//正在关闭TCP
				{
					ec20.fsm = ST_CLOSE_TCP;//跳转关闭TCP
					UPDATE_REBOOT_TIME;
				}
				else//超时无人应答
				{
					printf("chk tcp timeout\r\n\r\n");//查询TCP失败
					ec20.fsm = ST_REBOOT;//跳转重启
				}
			break;
				
			case ST_CLOSE_TCP:		//关闭TCP
				rs = c4g_close_tcp();
				if(rs == TRUE)//关闭TCP成功
				{
					ec20.fsm = ST_CREAT_TCP;//跳转创建TCP
					UPDATE_REBOOT_TIME;
					CLEAR_REBOOT_COUNT;
				}
				else
				if(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;//跳转重启
					}
					else
					if(global.socket_state == 0)
					{
						printf("transfer to close tcp\r\n\r\n");
						ec20.fsm = ST_CLOSE_TCP;//跳转关闭TCP
						UPDATE_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;//重新建立tcp
							printf("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;//重新建立TCP
			printf("global timeout\r\n\r\n");
		}
	}
}

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

©2023 Yang Li. All rights reserved.

欢迎关注 『十六宿舍』,大家喜欢的话,给个👍,更多关于嵌入式相关技术的内容持续更新中。文章来源地址https://www.toymoban.com/news/detail-438569.html

到了这里,关于STM32+EC20实现4G无线通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于I.MX6ULL的Linux C多线程物联网网关+STM32+Qt上位机+Linux C++多线程服务器(含web)的多种无线通信系统的智慧农场

    我国是农业大国,而非农业强国。近30年来农业高产量主要依靠农药化肥的大量投入,大部分化肥和水资源没有被有效利用而随地弃置,导致大量养分损失并造成环境污染。我国农业生产仍然以传统生产模式为主,传统耕种只能凭经验施肥灌溉,不仅浪费大量的人力物力,也

    2024年04月14日
    浏览(91)
  • ESP8266初次如何实现无线通信(基于电脑与ESP8266)

    本次软件是需要串口调试助手,网络调试助手,KEIL5                             下面图标依次排列 本次硬件是需要一个ESP8266模块,一个stm32f103c8t6芯片,一个USB转TTL模块 ESP8266是一个微小的且集成的国产WIFI模块,它有很多种型号,但是使用

    2023年04月20日
    浏览(33)
  • STM32F103 4G Cat.1模块EC200S使用

    EC200S-CN 是移远通信最近推出的 LTE Cat 1 无线通信模块,支持最大下行速率 10Mbps 和最大上行速率 5Mbps,具有超高的性价比;同时在封装上兼容移远通信多网络制式 LTE Standard EC2x(EC25、EC21、EC20 R2.0、EC20 R2.1)和 EC200T/EG25-G/EG21-G 模块以及 UMTS/HSPA+ UC20/UC200T 模块,实现了 3G 网络与

    2024年02月11日
    浏览(42)
  • MIMO-OFDM无线通信技术(Matlab代码实现)

        目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 本代码为MIMO-OFDM无线通信技术及MATLAB实现。分为十章,供大家学习。 主函数部分代码: [1]黄丘林. MIMO无线通信技术研究[D].西安电子科技大学,2007. 部分理论引用网络文献,若有侵权联系博主删除。

    2023年04月16日
    浏览(44)
  • 【物联网无线通信技术】LoRa从理论到实现(SX1268)

    文章先从LoRa的物联网通信技术前辈们讲起,慢慢引出了这种功耗又低,距离又远的无线通信技术,然后又似庖丁解牛一般,从物理层到链路层,详细的介绍了LoRa这种技术的组成,最后以一种实际的原理与嵌入式软件实现,让读者近距离接触到基于LoRa这种无线通信技术产品的

    2024年02月10日
    浏览(47)
  • 【物联网无线通信技术】UWB定位从理论到实现(DW1000)

    超宽带(UWB)是一种基于IEEE 802.15.4a和802.15.4z标准的无线电技术,可以非常精确地测量无线电信号的飞行时间,从而实现厘米级精度的距离/位置测量。UWB技术除了提供定位功能外,它本身是一种通信技术,其提供了一种安全的无线通信新方式,为新形式的安全交易打开了大门

    2024年02月14日
    浏览(40)
  • 无线通信安全作业4

    1.请分析WEP协议中IV的作用和由于IV引发的安全缺陷。 首先我们来看WEP协议中IV的作用。 WEP基于RC4算法,而RC4算法作为流密码加密算法,用RC4加密的数据丢失会导致加解密失步从而导致后面的数据丢失,WEP需要在每帧重新初始化密钥流,所以引入初始向量IⅣ。WEP使用IV和密钥级

    2024年02月03日
    浏览(85)
  • 商用无线通信:信道带宽

    GSM: 200 kHz WCDMA: 5 MHz cdma2000 1X: 1.25 MHz TD-SCDMA: 1.6 MHz LTE: 1.4 MHz /3 MHz /5 MHz /10 MHz / 15 MHz /20 MHz 5G(Rangel 频段):5 MHz/15 MHz/ 20 MHz/30 MHz/40 MHz/50 MHz/60 MHz/ 70 MHz/80 MHz/90 MHz/100 MHz 5G (Range2 Hif): 50 MHz/100 MHz/ 200 MHz/400 MHz Wi-Fi: 22 MHz/20 MHz/40 MHz/80 MHz/ 80 MHz +80 MHz /160 MHz ZigBee: 2 MHz NB-IoT: 200 kHz

    2024年04月17日
    浏览(47)
  • 熵 | 无线通信知识

    熵定义: H ( X ) = E [ − l o g 2 p ( x ) ] = − ∑ x ∈ X p ( x ) l o g 2 p ( x ) H(X)=E[-log_2p(x)]=-sum_{xin X}p(x)log_2p(x) H ( X ) = E [ − l o g 2 ​ p ( x )] = − x ∈ X ∑ ​ p ( x ) l o g 2 ​ p ( x ) note H(X)是X的平均香农信息内容 H(X)是每个符号的平均信息量 二元问题(抛硬币),H(X)取值为[H(X),H(X)+1] 为

    2024年02月09日
    浏览(53)
  • 无线通信发展历程分析

    摘要: 当前,移动、无线技术领域正处在一个高速发展的时期,各种创新移动、无线技术不断涌现并快速步入商用,移动、无线应用市场异常活跃,移动、无线技术自身也在快速演进中不断革新。无线通信未来的发展趋势表现为:从大范围公众移动通信来看,3G或超3G技术将是

    2024年02月05日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包