678|0

73

帖子

2

资源

一粒金砂(中级)

【安信可NB-IoT开发板EC-01F-Kit测评】05.基于STM32+EC-01F Socket通信 [复制链接]

本帖最后由 李百仪 于 2021-12-22 21:11 编辑

1.通过PC串口助手发送指令形式大概了解EC-01F建立Socket通信所需的必要条件和步骤,剩下就是码起来……

2.AT指令通信基于串口收发,用到串口收发少不了串口超时+FIFO机制。串口接收存放到FIFO,每接收一个字节设置超时10ms,10ms无下一字节,认为一帧数据结束,设置数据帧接收完成标志。待主循环轮询到该标志位,从FIFO读取数据并解析。

FIFO接收流程图.png

3.AT指令发送后往往需要等待应答,这里使用轮询+状态机方式实现非阻塞。

以初始化NB为例使用两个状态机,A状态机:NB初始化状态,B状态机:AT指令状态.

A状态机(NB初始化):查询初始化状态需要发送的指令->发送指令->等待应答结果->根据结果切换到下一个状态

B状态机(处理AT指令):开始->发送->查询串口接收完成标志位->解析数据->返回结果

 

B状态机实现:

/*******************************************************************************
* 函 数 名      : NB_AT_CMD
* 函数功能  : 发送AT指令?
* 输    入         : 
参数1:cmd AT指令
参数2:timeout 单次发送的超时时间
参数3:res 要判断的返回结果
参数4:count 尝试次数
* 输    出         : ATCMD_REVOK 发送且收到回复  ATCMD_TIMEOUT 超时
*******************************************************************************/
ATCMD_StatusTypeDef NB_AT_CMD(U8* cmd,U16 timeout,const char* res, U8 count)
{
    static ATCMD_StatusTypeDef atcmd_status = ATCMD_START;
    static U8 cnt = 1;
    U16 temp;
    
    switch(atcmd_status)
    {
    case ATCMD_START:
        cnt = count;
        atcmd_status = ATCMD_SEND;
        break;
    case ATCMD_SEND:
        atcmd_status = ATCMD_WAIT_REV;
        AT_cmd_tick  = 0;
        memset(EC01RxCache, 0, sizeof(EC01RxCache));
        EC01_handle.rcv_size = 0;
		printf("\r\n AT->%s", cmd);
        USART_SendDataByIT(cmd, strlen((const char*)cmd));
        break;
    case ATCMD_WAIT_REV:
        if(AT_cmd_tick < timeout)
        {
            if(NB_Hand((char*)res,&temp,0))//
            {
                atcmd_status = ATCMD_REVOK;
            }
        }
        else
        {
            if(cnt > 0)//再次发送
            {
                atcmd_status = ATCMD_SEND;
            }
            else
            {
                atcmd_status = ATCMD_TIMEOUT;
            }
            cnt--;
        }
        break;
    case ATCMD_REVOK:
    case ATCMD_TIMEOUT:
        atcmd_status = ATCMD_START;
    default:
        break;
    }
    return atcmd_status;
}
/*******************************************************************************
* 函 数 名      : NB_Hand
* 函数功能  : 判断串口接收缓存中是否包含substr,
* 输    入         : substr:比较字符串指针,index:字符串比较完成结束位置指针,start_index:串口接收缓存起始位置
* 输    出         : 包含返回1  不包含返回0
*******************************************************************************/
U8 NB_Hand(char* substr,U16 *index,U16 start_index)
{
	U8 flag = 0;
	
	if(EC01_handle.rcv_size != 0)
	{
		if(!NB_strcmp(( char*)EC01RxCache, ( char*)substr, start_index,  EC01_handle.rcv_size))
		{
			flag =  1;
		}
		else
		{
			flag = 0;
		}
	}
	
	return flag;
	
}
/*******************************************************************************
* 函 数 名      : NB_strcmp
* 函数功能  : 判断str1中是否包含str2
* 输    入         : 待比较字符串指针,起始位置,长度
* 输    出         : 包含返回1  不包含返回0
*******************************************************************************/
U8 NB_strcmp(char *str1,  char *str2, U16 start_index, U16 Size)
{
	U16 i, flag = 1;
	char *p;
	for(i = start_index; i < Size; i++)
	{
		if(str1 == 0)
		{
			break;
		}
		if(str1 == *str2)
		{
			flag = 0;
			p    = str2;
			while(*p)
			{
				if(str1 == *p)
				{
					*p++;
					i++;
				}
				else
				{
					flag = 1;
					break;
				}
			}
			if(flag == 0)
			{
				break;
			}
		}
	}
	return flag;
}

A状态机实现: 


U8 NB_Config(void)
{
    static ATCMD_StatusTypeDef res;
	
    switch(NB.CON)
    {
    	case 0x00:
	        res = NB_AT_CMD((U8*)"ATE0\r\n", 2000, "OK", 3);
	        if(res == ATCMD_REVOK)
	        {
	        	if(NB_parseDefaultMsg(&EC01RxCache[0], EC01_handle.rcv_size)&0x08)
				{
					uprintf("\r\n NB.RegStatus %d", NB.RegStatus);
				}
	            NB.CON = 1;
	            uprintf("\r\n ATE0 OK");
	        }
	        else if(res == ATCMD_TIMEOUT)
	        {
	            NB.CON = 0;
	            uprintf("\r\n ATE0_TIMEOUT");
	            return 1;
	        }
       break;
       
       case 0x01:
	        res = NB_AT_CMD("AT+CSCON=0\r\n", 2000, "OK", 1);//信号连接状态 关闭连接状态主动通知
	        if(res == ATCMD_REVOK)
	        {
				uprintf("\r\n CSCON OK");
	            NB.CON = 2;
	            if(NB_parseDefaultMsg(&EC01RxCache[0], EC01_handle.rcv_size)&0x08)
				{
					uprintf("\r\n NB.RegStatus %d", NB.RegStatus);
				}
	        }
	        else if(res == ATCMD_TIMEOUT)
	        {
				uprintf("\r\n CSCON_TIMEOUT");
	            NB.CON = 1;
	            return 1;
	        }
	    break;
	    
        case 0x02:
	        res = NB_AT_CMD((U8*)"AT+CEREG=1\r\n", 2000, "OK", 3);//设置网络注册状态上报信息
	        //设置成功后,当网络注册状态信息有变化,会主动上报给用户终端,如:
			 if(res == ATCMD_REVOK)
	        {
				NB.CON = 3;
	            uprintf("\r\n CEREG OK");
	            if(NB_parseDefaultMsg(&EC01RxCache[0], EC01_handle.rcv_size)&0x08)
				{
					uprintf("\r\n NB.RegStatus %d", NB.RegStatus);
				}
	        }
	        else if(res == ATCMD_TIMEOUT)
	        {
	            NB.CON = 2;
	            uprintf("\r\n CEREG_TIMEOUT");
	            return 1;
	        }
        break;
        case 0x03:
        break;
        default:
        break;
    }
}

中断处理:

/*串口超时*/
void UartTimeout(uart_process_t *up)
{
	if(up->rcv_timeout != 0)
	{
		up->rcv_timeout = up->rcv_timeout - 1;
		if(up->rcv_timeout == 0)
		{
			up->rcv_status = SET;
		}
	}
}

void TIM3_IRQHandler(void)
{
	static U16 uiCount = 0;

	if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		
		uiCount++;
		
		if(uiCount%1 == 0)	 {TimeSlice[0] = SET;}	//5ms

		if(uiCount%2 == 0)  {TimeSlice[1] = SET;}	//10ms

		if(uiCount%4 == 0)  {TimeSlice[2] = SET;}	//20ms
		
		if(uiCount%20 == 0) {TimeSlice[3] = SET;}	//100ms

		if(uiCount%40 == 0)  {TimeSlice[4] = SET;}	//200ms

		if(uiCount%200 == 0) {TimeSlice[5] = SET; uiCount = 0;}//1S

		NB_Tick();

		UartTimeout(&EC01_handle);
	}
}

void USART2_IRQHandler(void)                
{
	u8 Res;

	if(USART_GetITStatus(USART2, USART_IT_TXE) == SET)//发送完成中断
    {
		if(SendIdx != SendLength)
		{
			USART_SendData(USART2, *(pDataByte + SendIdx) );
			SendIdx++;
		}
		else
		{
			SendLength = 0;
			SendIdx    = 0;
			USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
		}
    }
    
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收中断
	{
		Res = USART_ReceiveData(USART2);
		InQueue(&EC01Q,Res);
		EC01_handle.rcv_timeout = 2;
	}
} 

FIFO复制到待解析缓存:

U16 NB_CopyFIFOToParseBuf(U8 *uP)
{
	U16 rc = 0;
	
	if(EC01_handle.rcv_status == SET)//串口接收超时
	{
		for(rc = 0; rc < USART_BUFFER_SIZE; rc++)//取出所有数据到待读取缓存
		{
			if(IsEmpty(&EC01Q) == 0)//有数据
			{
				OutQueue(&EC01Q, &uP[rc]);
			}
			else
			{
				EC01_handle.rcv_status = RESET;
				break;
			}
		}
	}

	return rc;
}

void NB_Polling_Msg(void)
{
	EC01_handle.rcv_size = NB_CopyFIFOToParseBuf(EC01RxCache);
	
	if((EC01_handle.rcv_size != 0)
	&& (NB.CON == 0xFF))//初始化完成允许轮询消息,(未初始化完成轮询消息可能无意义)
	{
		if(NB_parseDefaultMsg(&EC01RxCache[0], EC01_handle.rcv_size))
		{
			
		}
	}	
}

 

程序调用:



void Task_RealTime(void)
{
 	NB_Polling_Msg();//轮询NB消息
	
 	NB_CycleCheck();//周期性查询NB状态:信号、注册状态、附着状态、Socket连接状态
	
 	NB_TCP_ReportProcess();//处理TCP任务
	
 	NB_Config();//NB初始化
}


void  Task_100ms(void)
{    
    if(NB.CON != 0xFF)//上电开始闪烁
	{
		LedFlash();
	}
}


void  Task_200ms(void)
{    
    if(NB.CON == 0xFF && NB.isConnect != 1)//NB初始化完成,Socket未建立
	{
		LedFlash();
	}
}

void Task_1000ms(void)
{
	static U8 Times = 0;

	
	if(NB.CON == 0xFF && NB.isConnect == 1)//NB初始化完成,Socket建立
	{
		LedFlash();
	}	

	if(Times%10 == 0)
	{
		if(NB.CON == 0xFF)
		{
			uprintf("\r\n NB.CON %d CSQ %d RegStatus %d attach %d  CGACT_state %d CycleCheckStatus %d ReportStatus %d",
			NB.CON, NB.csq, NB.RegStatus,  NB.attach, NB.CGACT_state, NB.CycleCheckStatus, NB.ReportStatus);
			uprintf(" MQTT isConnect %d state %d ret_code %d conn_result %d", NB.isConnect, NB.mqtt.state,
			NB.mqtt.ret_code, NB.mqtt.conn_result);
		}
	}
}

int main(void)
{
	RCC_Config();
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);
	InitQueue(&EC01Q);
	Tim3_Config(49,7199);//5ms
	Delay_init(72);
	USART1_Config(115200);
	USART2_Config(9600);
 	LED_Config();

	memset(&EC01_handle, 0, sizeof(uart_process_t));
	memset(EC01RxCache, 0, sizeof(EC01RxCache));
	memset(&NB, 0, sizeof(NBStatus));

	while (1)
	{
		Task_RealTime();
  		if(GetSysClkFlg(3) == SET) 		{Task_100ms();	}
  		if(GetSysClkFlg(4) == SET) 		{Task_200ms();	}
 		if(GetSysClkFlg(5) == SET)      {Task_1000ms();	}
	}
}

调试运行效果: 

http://training.eeworld.com.cn/video/32079

 

此帖出自RF/无线论坛
个人签名

intersil Techwell应用工程师


回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

最新文章 更多>>
    关闭
    站长推荐上一条 1/9 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表