AT指令框架之自定义

AT指令处理框架-AT-DEVICE & ATFrame ATFrameAT指令介绍MCU发AT指令,通讯模块响应返回。 阅读详情

简言:

  • 使用NB或BLE或者AT指令交互的模组时,需要一个方便灵活的AT指令框架

  • 便于快速的实现功能,后期维护扩展功能

  • 思路

  • 使用状态机原理和二维数组存储指令数据

  • 按照指令集顺序执行命令

  • 分享的友情链接
    https://blog.youkuaiyun.com/weixin_42192405/article/details/115765164

(另有一种AT Command 指令处理框架,本文框架与AT Command各有优劣)
AT Command使用教程全网有很多了,后续会更新AT command示例。

代码示例:

  • AT状态机处理
#include "app_iot_at.h"

extern rt_mailbox_t iot_mb_at;
extern rt_mailbox_t iot_mb_ctl;
extern rt_uint8_t iot_read_buff[IOT_READ_BUFF_SIZE];
extern rt_uint8_t iot_read_len;
extern rt_uint8_t iot_send_buff[IOT_SEND_BUFF_SIZE];
extern iot_device_message_t  i_dev_mess;

extern rt_timer_t iot_timer_2;
//临时测试数据
//const uint8_t temp_70[] = {"AT+MCWSEND=41,00FF2401010023435965676000121C20010B00FF0000000000C800640000330100025EBAED06F1C857\r\n"};

/*
 * 清单号
 */
rt_uint8_t i_list_num =0;
/*
 * 重试
 */
rt_uint8_t i_list_retry =0;
/*
 * 清单选择
 */
iot_cmd_list_t *i_list_select = NULL;

/*
 * 当前变量
 */
iot_dev_state_t i_cur = {0,0,0,0,0,0};

/*
 * 特定清单
 */
/*
 * 连接中国电信初始化
 */
iot_cmd_list_t  iot_list_poweron_lwm2m[]=
{I_AT, I_AT, I_QSCLK, I_CGMI, I_CGSN, I_ATE, I_QBAND, I_CGPADDR, I_NNMI, I_NCFG, I_CSCON1, I_CSCON, I_CEREG, I_NCDPOPEN, I_CSQ, I_NMSTATUS,  I_FINISH};
/*
 *上传数据
 */
iot_cmd_list_t iot_list_updata_lwm2m[]=
{ I_CSQ, I_NMGS, I_FINISH};

/*
 * 信号强度
 */
iot_cmd_list_t iot_list_csq[]=
{ I_CSQ, I_CCLK, I_FINISH};

/*
 * 连接客户后台初始化
 */
iot_cmd_list_t  iot_list_poweron_tcpip[]=
{I_AT, I_QSCLK, I_QICLOSE,  I_CGMI, I_CGSN, I_ATE, I_QBAND, I_CSCON1, I_CSCON, I_CEREG, I_CGPADDR,
       I_CSQ, I_CCLK, I_QENG, I_FINISH};
/*
 * 上传数据
 */
iot_cmd_list_t iot_list_updata_tcpip[]=
{ I_QIOPEN, I_QICFG, I_QISEND, I_FINISH};

/*
 * 列表
 */
iot_dev_state_t iot_cmds[] =
{
	//指令=指令+应答+等待时间+重试次数+处理
	{I_AT_NULL, "NULL", "NULL", 0, 0, NULL},
	{I_AT, "AT\r\n", "OK", 1000, 3, i_default_deal},
	{I_QRST, "AT+QRST=1\r\n", "+IP", 15000, 3, i_default_deal},
	{I_QSCLK, "AT+QSCLK=0\r\n", "OK", 1000, 3, i_default_deal},
	{I_CGMI, "AT+CGMI\r\n", "OK", 1000, 3, i_default_deal},
	{I_CGSN, "AT+CGSN=1\r\n", "OK", 1000, 3, i_default_deal},
	{I_ATE, "ATE0\r\n", "OK", 1000, 3, i_default_deal},
	{I_QBAND, "AT+QBAND=0\r\n", "OK", 1000, 3, i_default_deal},
	{I_CGPADDR, "AT+CGPADDR?\r\n", "OK", 1000, 3, i_default_deal},
	{I_NNMI, "AT+NNMI=1\r\n", "OK", 1000, 3, i_default_deal},
	{I_NCFG, "AT+NCFG=0,300\r\n", "OK", 1000, 3, i_default_deal},
	{I_CSCON1, "AT+CSCON=1\r\n", "OK", 1000, 3, i_default_deal},
	{I_CSCON, "AT+CSCON?\r\n", "OK", 1000, 3, i_default_deal},
	{I_CEREG, "AT+CEREG?\r\n", "OK", 1000, 3, i_default_deal},
	{I_NCDPOPEN, "AT+NCDPOPEN=\"221.229.214.202\",5683\r\n", "+QLWEVTIND: 3", 5000, 3, i_default_deal},
	{I_CSQ, "AT+CSQ\r\n", "OK", 1000, 3, i_csq_deal},
	{I_NMSTATUS, "AT+NMSTATUS?\r\n", "REGISTERED_AND_OBSERVED", 1000, 3, i_default_deal},
	{I_NMGS, iot_send_buff, "OK", 5000, 3, i_default_deal},

	{I_QIOPEN, "AT+QIOPEN=0,0,\"TCP\",\"47.94.169.135\",7191\r\n", "+QIOPEN: 0,0", 5000, 3, i_default_deal},
	//{I_QIOPEN, "AT+QIOPEN=0,0,\"TCP\",\"36.137.226.30\",43588\r\n", "+QIOPEN: 0,0", 5000, 3, i_default_deal},
	{I_QICFG, "AT+QICFG=\"dataformat\",1,1\r\n", "OK", 5000, 3, i_default_deal},
	{I_QISEND, iot_send_buff, "OK", 5000, 3, i_default_deal},
	{I_QICLOSE, "AT+QICLOSE=0\r\n", "CLOSE OK", 30000, 3, i_default_deal},
	{I_CCLK, "AT+CCLK?\r\n", "+CCLK", 3000, 3, i_rtc_deal},
	{I_QENG, "AT+QENG=0\r\n", "OK", 3000, 3, i_qeng_deal},
};


/*
 * 重置
 */
void i_cur_reset(void)
{
	i_cur.i_cur_cmd = I_AT_NULL;
	i_cur.i_send = NULL;
	i_cur.i_ack = NULL;
	i_cur.i_wait_time = 0;
	i_cur.i_try_cnt = 0;
	i_cur.i_recv_deal = NULL;

	i_list_num =0;
	i_list_retry =0;
	i_list_select = NULL;
}
/*
 * 默认处理
 */
uint8_t i_default_deal(char* data, uint8_t len)
{
	return 1;
}
/*
 * 信号强度
 */
uint8_t i_csq_deal(char* data, uint8_t len)
{
    uint8_t *data_p = data;
    uint8_t csq_value = 0;
    if(strstr(data_p, "+CSQ") != NULL)
    {
        LOG_OUT("%c\r\n", *(data_p+8));
        LOG_OUT("%c\r\n", *(data_p+9));

        csq_value = (*(data_p+8) - '0')*10 + (*(data_p+9) - '0');
        LOG_OUT("csq_value =%d\r\n", csq_value);


        i_dev_mess.csq = csq_value;
    }

    return 1;
}
/*
 * RTC处理
 */
uint8_t i_rtc_deal(char* data, uint8_t len)
{
    uint8_t *data_p = data;
    uint8_t temp =0;
    uint8_t year =0;
    uint8_t Month =0;
    uint8_t Date =0;

    uint8_t Hours =0;
    uint8_t Minutes =0;
    uint8_t Seconds =0;

    uint32_t timestamp = 0;

    if(strstr(data_p, "+CCLK") != NULL)
    {
        year = *(data_p+12) - '0';
        year = year*10 + (*(data_p+13) - '0');
        LOG_OUT("year=%d\r\n", year);
        year = dec_transition_hex_show(year);

        Month = *(data_p+15) - '0';
        Month = Month*10 + (*(data_p+16) - '0');
        LOG_OUT("Month=%d\r\n", Month);
        Month = dec_transition_hex_show(Month);

        Date = *(data_p+18) - '0';
        Date = Date*10 + (*(data_p+19) - '0');
        LOG_OUT("Date=%d\r\n", Date);
        Date = dec_transition_hex_show(Date);

        Hours = *(data_p+21) - '0';
        Hours = Hours*10 + (*(data_p+22) - '0');
        LOG_OUT("Hours=%d\r\n", Hours);
        Hours = dec_transition_hex_show(Hours);

        Minutes = *(data_p+24) - '0';
        Minutes = Minutes*10 + (*(data_p+25) - '0');
        LOG_OUT("Minutes=%d\r\n", Minutes);
        Minutes = dec_transition_hex_show(Minutes);


        Seconds = *(data_p+27) - '0';
        Seconds = Seconds*10 + (*(data_p+28) - '0');
        LOG_OUT("Seconds=%d\r\n", Seconds);
        Seconds = dec_transition_hex_show(Seconds);

        rtc_receive_calibration(Hours, Minutes, Seconds, year, Month, Date);
        app_rtc_data_read(&timestamp);

        i_dev_mess.collect_time[0] = (timestamp >>24) & 0xFF;
        i_dev_mess.collect_time[1] = (timestamp >>16) & 0xFF;
        i_dev_mess.collect_time[2] = (timestamp >>8) & 0xFF;
        i_dev_mess.collect_time[3] = (timestamp ) & 0xFF;
    }
    return 1;
}

//+QENG: 0,3688,11,264,"09018613",-84,-8,-77,6,8,"4B03",0,21,3
//-6, -66,
//6, 66,
/*
 * 参考信号强度等
 */
uint8_t i_qeng_deal(char* data, uint8_t len)
{
    uint8_t *data_p = data;
    uint8_t cnt =0;
    uint16_t pci = 0;
    uint16_t rsrp = 0;
    uint16_t snr = 0;

    for(uint8_t t=0; t<60; t++)
    {
        if( *(data_p+t) == ',')
        {
            cnt++;

            if(cnt == 3)
            {
                if(*(data_p+t+4) == ',')
                {
                    pci = (*(data_p+t+1)-'0')*100 + (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
                }
                else if(*(data_p+t+3) == ',')
                {
                    pci = (*(data_p+t+1)-'0')*10 + (*(data_p+t+2)-'0');
                }
                else if(*(data_p+t+2) == ',')
                {
                    pci = (*(data_p+t+1)-'0');
                }
                LOG_OUT("pci=%d\r\n", pci);

                i_dev_mess.pci[0] = pci >>8;
                i_dev_mess.pci[1] = pci &0xFF;
            }
            else if(cnt == 5)
            {
                if(*(data_p+t+1) == '-')
                {

                    if(*(data_p+t+5) == ',')
                    {
                        rsrp = (*(data_p+t+2)-'0')*100 + (*(data_p+t+3)-'0')*10 + (*(data_p+t+4)-'0');
                    }
                    else if(*(data_p+t+4) == ',')
                    {
                        rsrp = (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
                    }
                    else if(*(data_p+t+3) == ',')
                    {
                        rsrp = (*(data_p+t+2)-'0');
                    }

                    LOG_OUT("rsrp=%d\r\n", rsrp);
                    if(rsrp >= 141)
                    {
                        rsrp = 0;
                    }
                    else
                    {
                        rsrp = 141 - rsrp;
                    }

                    LOG_OUT("rsrp=%d\r\n", rsrp);

                    i_dev_mess.rsrp[0] = rsrp >>8;
                    i_dev_mess.rsrp[1] = rsrp &0XFF;
                }

            }
            else if(cnt == 8)
            {
                if(*(data_p+t+1) == '-')
                {
                    if(*(data_p+t+3) == ',')
                    {
                        snr = (*(data_p+t+2)-'0');
                    }
                    else if(*(data_p+t+4) == ',')
                    {
                        snr = (*(data_p+t+2)-'0')*10 + (*(data_p+t+3)-'0');
                    }
                    LOG_OUT("snr=%d\r\n", snr);
                    snr |= 0x8000;
                    LOG_OUT("snr=%x\r\n", snr);
                }
                else
                {
                    if(*(data_p+t+2) == ',')
                    {
                        snr =(*(data_p+t+1)-'0');
                    }
                    else if(*(data_p+t+3) == ',')
                    {
                        snr = (*(data_p+t+1)-'0')*10 + (*(data_p+t+2)-'0');
                    }
                    LOG_OUT("snr=%d\r\n", snr);
                }

                i_dev_mess.snr[0] = snr >>8;
                i_dev_mess.snr[1] = snr &0XFF;
            }
        }
    }


    return 1;
}


/*
 * 超时重发
 */
void iot_timeout_task_2(void *parameter)
{
	LOG_OUT("iot_timeout_task_2\r\n");
	rt_mb_send_wait(iot_mb_at, I_AT_TIMEOUT, 1000);
}
/*
 * AT线程任务
 * 操作系统使用线程邮箱等待事件触发
 * 裸机使用状态标志位等待事件触发
 * 避免延时,加快速度
 */
void iot_at_thread_task(void *parameter)
{
    rt_thread_mdelay(100);
	LOG_OUT("iot_at_thread_task OK\r\n");

	rt_uint32_t at_cmd = 0;
	rt_uint32_t at_ret = 0;
    while (1)
    {
    	at_ret = rt_mb_recv(iot_mb_at, &at_cmd, RT_WAITING_FOREVER);
    	if(at_ret == RT_EOK)
    	{
    		LOG_OUT("at_cmd=%d\r\n", at_cmd);

    		switch(at_cmd)
    		{
    		    //空闲
    			case I_AT_IDLE:
    			{
    				LOG_OUT("I_AT_IDLE\r\n");
    			}
    			break;
    			//发送
    			case I_AT_SEND:
    			{
    				LOG_OUT("I_AT_SEND=");
    				i_cur = iot_cmds[i_list_select[i_list_num]];
    				i_list_retry = 0;

    				if( i_list_select[i_list_num] != I_FINISH)
    				{
    					rt_device_write(app_iot_dev, RT_NULL, i_cur.i_send, strlen(i_cur.i_send));
    					rt_timer_control(iot_timer_2, RT_TIMER_CTRL_SET_TIME, &i_cur.i_wait_time);
    					rt_timer_start(iot_timer_2);
    					LOG_OUT("%s\r\n", i_cur.i_send);
    				}
    				else
    				{
    					LOG_OUT("I_FINISH\r\n");
    					rt_mb_send_wait(iot_mb_at, I_AT_FINISH, 1000);
    				}
    			}
    			break;
    			//等待
    			case I_AT_WAIT:
    			{
    				LOG_OUT("I_AT_WAIT:");
    				memset(iot_read_buff, 0x00, sizeof(iot_read_buff));
    				while( (iot_read_len = rt_device_read(app_iot_dev, RT_NULL, iot_read_buff, RT_NULL)) > 0)
    				{
    					LOG_OUT("iot_read_len=%d\r\n", iot_read_len);
    					LOG_OUT("I_AT_REC=");
    					for(uint8_t t=0; t<iot_read_len; t++)
    					{
    						LOG_OUT("%c",iot_read_buff[t]);
    					}
    					LOG_OUT("\r\n");
    					if(i_cur.i_send != NULL)
						{
							if(strstr(iot_read_buff, i_cur.i_ack) != NULL)
							{
								if(i_cur.i_recv_deal(iot_read_buff, iot_read_len) == 1)
								{
									LOG_OUT("iot ack ok\r\n");
									rt_timer_stop(iot_timer_2);
									i_list_num++;
									rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
								}
							}
		                    else if(i_cur.i_ack == NULL)
                            {
                                LOG_OUT("null ack ok\r\n");
                                rt_timer_stop(iot_timer_2);
                                i_list_num++;
                                rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
                            }
						}
    					else
    					{

    						LOG_OUT("URC:\r\n");

    						if(iot_ctl.i_module == I_LWM2M)
    						{
                                if(strstr(iot_read_buff, "+NNMI" ) != NULL)
                                {
                                    i_urc_deal(iot_read_buff, iot_read_len);
                                }
    						}
    						else
    						{
                                if(strstr(iot_read_buff, "+QIURC: \"recv\"" ) != NULL)
                                {
                                    i_urc_deal(iot_read_buff, iot_read_len);
                                }
                                else if( strstr(iot_read_buff, "+QIURC:\"closed\"" ) != NULL )
                                {
                                    LOG_OUT("+QIURC: closed deal\r\n");

                                    iot_ctl.i_send_cmd = I_CMD_UPDATA;
                                    rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
                                }
                            }
    					}
    				}
    			}
    			break;
    			//超时
    			case I_AT_TIMEOUT:
    			{
    				LOG_OUT("I_AT_TIMEOUT:");
    				LOG_OUT("retry:%d < %d\r\n", i_list_retry, i_cur.i_try_cnt);
    				if(i_list_retry++ < i_cur.i_try_cnt)
    				{
    					rt_device_write(app_iot_dev, RT_NULL, i_cur.i_send, strlen(i_cur.i_send));
    					rt_timer_control(iot_timer_2, RT_TIMER_CTRL_SET_TIME, &i_cur.i_wait_time);
    					rt_timer_start(iot_timer_2);
    					LOG_OUT("%s\r\n", i_cur.i_send);
    				}
    				else
    				{
    					rt_mb_send_wait(iot_mb_at, I_AT_FAIL, 1000);
    				}
    			}
    			break;
    			//完成
    			case I_AT_FINISH:
    			{
    				LOG_OUT("I_AT_FINISH\r\n");
    				i_cur_reset();
    				rt_mb_send_wait(iot_mb_ctl, I_EVT_RET_SUCC, 1000);
    			}
    			break;
    			//失败
    			case I_AT_FAIL:
    			{
    				LOG_OUT("I_AT_FAIL\r\n");
    				i_cur_reset();
    				rt_mb_send_wait(iot_mb_ctl, I_EVT_RET_FAIL, 1000);
    			}
    			break;
    		}
    	}
    }
}





  • 定义的状态变量
#ifndef __APP_IOT_AT_H
#define __APP_IOT_AT_H

#include "app_user.h"

//AT任务事件
typedef enum
{
	I_AT_IDLE 	 = 1 << 0,
	I_AT_SEND	 = 1 << 1,
	I_AT_WAIT	 = 1 << 2,
	I_AT_TIMEOUT = 1 << 3,
	I_AT_FINISH  = 1 << 4,
	I_AT_FAIL	 = 1 << 5,
}IOT_AT_EVENT_T;


/*
 * 针对某NB模组的AT指令
 */
typedef enum
{
	I_AT_NULL = 0,
	I_AT,
	I_QRST,
	I_QSCLK,
	I_CGMI,
	I_CGSN,
	I_ATE,
	I_QBAND,
	I_CGPADDR,
	I_NNMI,
	I_NCFG,
	I_CSCON1,
	I_CSCON,
	I_CEREG,
	I_NCDPOPEN,
	I_CSQ,
	I_NMSTATUS,
	I_NMGS,
	I_QIOPEN,
	I_QICFG,
	I_QISEND,
	I_QICLOSE,
	I_CCLK,
	I_QENG,

	I_FINISH

}iot_cmd_list_t;

/*
 * 控制
 */
typedef struct
{
	iot_cmd_list_t i_cur_cmd;//当前指令
	uint8_t*	i_send;//发送指令
	uint8_t*	i_ack;//应答数据
	int 		i_wait_time;//等待时间
	int			i_try_cnt;//重试次数
	uint8_t		(*i_recv_deal)(uint8_t* data, uint8_t len);//处理数据
}iot_dev_state_t;


uint8_t i_default_deal(char* data, uint8_t len);
uint8_t i_csq_deal(char* data, uint8_t len);
uint8_t i_rtc_deal(char* data, uint8_t len);
uint8_t i_qeng_deal(char* data, uint8_t len);


#endif

  • 控制AT执行流程的事件
    		    //空闲
    			case I_EVT_IDLE:
    			{
    				LOG_OUT("I_EVT_IDLE\r\n");
    			}
    			break;
    			//上电
    			case I_EVT_POWERON:
    			{
    				LOG_OUT("I_EVT_POWERON\r\n");
    				memset(iot_read_buff, 0x00, sizeof(iot_read_buff));
    				while( (iot_read_len = rt_device_read(app_iot_dev, RT_NULL, iot_read_buff, RT_NULL)) > 0)
    				{
    					LOG_OUT("iot_read_len=%d\r\n", iot_read_len);
    					for(uint8_t t=0; t<iot_read_len; t++)
    					{
    						LOG_OUT("%c",iot_read_buff[t]);
    					}
    					LOG_OUT("\r\n");
    					//IP入网
    					if((strstr(iot_read_buff, "+IP" ) != NULL))
    					{
    						LOG_OUT("readly iot_list_poweron\r\n");
    						iot_ctl.i_run_ste = I_WORK;
    						i_cur_reset();

    						if(iot_ctl.i_module == I_LWM2M)
    						{
    						 i_list_select = iot_list_poweron_lwm2m;
    						}
    						else
    						{
    						    i_list_select = iot_list_poweron_tcpip;
                            }
    						iot_ctl.i_send_cmd = I_CMD_POWER;
    						rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
    					}
    				}
    			}
    			break;
    			//返回成功
    			case I_EVT_RET_SUCC:
    			{
    				LOG_OUT("I_EVT_RET_SUCC\r\n");
    				LOG_OUT("send_cmd=%d\r\n", iot_ctl.i_send_cmd);
    				switch(iot_ctl.i_send_cmd)
    				{
    				    //上电事件
    					case I_CMD_POWER:
    					{

    					    LOG_OUT("I_CMD_POWER\r\n");
                            //上报标志
                            if(iot_ctl.i_up_flag == true)
                            {
                                iot_ctl.i_up_flag = false;

                                //上传数据
                                app_iot_up_data_update();

                                LOG_OUT("reday updata\r\n");
                                i_cur_reset();
                                if(iot_ctl.i_module == I_LWM2M)
                                {
                                    i_list_select = iot_list_updata_lwm2m;
                                }
                                else
                                {
                                    i_list_select = iot_list_updata_tcpip;
                                }

                                iot_ctl.i_send_cmd = I_CMD_UPDATA;
                                rt_mb_send_wait(iot_mb_at, I_AT_SEND, 1000);
                            }
                            else
                            {
                                LOG_OUT("bsp_iot_close\r\n");
                                bsp_iot_close();

                            }
    					}
    					break;
    					//结束事件
    					case I_CMD_UPDATA:
    					{
    						LOG_OUT("send data success\r\n");

                            LOG_OUT("bsp_iot_close\r\n");
                            bsp_iot_close();

    					}
    					break;
    				}
    			}
    			break;
    			//失败关闭
    			case I_EVT_RET_FAIL:
    			{
    				LOG_OUT("I_EVT_RET_FAIL\r\n");
    				LOG_OUT("send_cmd=%d\r\n", iot_ctl.i_send_cmd);

                    LOG_OUT("bsp_iot_close\r\n");
                    bsp_iot_close();
    			}
    			break;
  • 控制流程变量
#ifndef __APP_IOT_CTL_H
#define __APP_IOT_CTL_H

#include "app_user.h"



typedef enum
{
	I_POWERON = 0,
	I_WORK,
	I_SLEEP,
	I_ALARM
}IOT_RUN_STATE_T;

typedef enum
{
	I_CMD_POWER = 0,
	I_CMD_UPDATA ,

}IOT_SEND_CMD_T;

typedef enum
{
    I_LWM2M = 0,
    I_TCP_IP,
}I_MODULE_TYPE_T;


typedef struct
{
	IOT_RUN_STATE_T i_run_ste;
	IOT_SEND_CMD_T i_send_cmd;
	uint8_t    i_up_flag;
	uint8_t    i_module;


}iot_control_t;



//EVT任务事件
typedef enum
{
	I_EVT_IDLE       		= 1 << 0,//空闲
	I_EVT_POWERON 	 		= 1 << 1,//电源上电事件

	I_EVT_RET_SUCC   		= 1 << 2,//返回成功事件
	I_EVT_RET_FAIL   		= 1 << 3,//返回失败事件

	I_EVT_UPDATA_SUCC       = 1 << 4,//上传成功事件
	I_EVT_UPDATA_FAIL       = 1 << 5,//上传失败事件

	I_EVT_RTC_UPDATA        = 1 << 6,//RTC触发事件

	I_EVT_SENSOR_REC        = 1 << 7,//传感器反馈结果事件
	I_EVT_SENSOR_SEND       = 1 << 8,//传感器控制参数事件

}IOT_EVT_EVENT_T;



extern iot_control_t iot_ctl;
void iot_parameter_init(void);


#endif

ESP-AT自定义命令开发全指南:从注册、解析到量产交付 AT指令集是嵌入式设备与Wi-Fi/蓝牙模组通信的基础协议,其核心价值在于标准化、低耦合与跨平台兼容性。在实际物联网项目中,标准AT命令难以覆盖私有协议、传感器集成与云平台对接等定制需求,因此掌握可复用、可维护的自定义AT命令开发能力成为关键工程技能。本文围绕ESP-AT框架,系统阐述命令语义类型(测试/查询/设置/执行)、参数健壮解析机制、透传数据同步模型、UART与Wi-Fi分层性能优化、mfg_nvs出厂分区自动化生成,以及面向产线的单元测试与OTA升级闭环。内容严格适配ESP-IDF v4.4+与E 阅读详情

相关推荐

StreamCom:嵌入式流式命令接口统一框架

在嵌入式系统开发中,串口、USB、Wi-Fi、BLE等多模通信通道的异构性常导致AT指令或自定义协议重复解析,引发代码冗余与状态不一致。StreamCom作为轻量级流式通信语义桥接器,通过物理层抽象、协议层分帧(支持行尾/长度前缀)、应用层静态命令注册三大机制,实现‘一次定义、多通道复用’。其零动态内存分配、超低ROM/RAM占用(<3KB/<256B)及中断安全的状态机设计,特别适配STM32、ESP32等资源受限MCU平台,广泛应用于工业物联网网关、多模终端与FOTA安全升级场景。

weixin_42589700的博客 506

[单片机框架][AT指令框架][从机版] 高内聚 低耦合

注意:如果使用gcc或iar,则需要修改lds文件,添加atcmd段。没有使用DMA和中断,仅提供思路。

嵌入式单片机实验室 2984

平衡小车远程通信系统:ESP32双模协议与自定义帧设计

嵌入式无线通信是智能移动机器人实现人机协同的基础能力,其核心在于协议栈分层设计、实时性保障与低功耗多模适配。Wi-Fi提供高带宽稳定连接,适用于调试与数据回传;BLE则以毫秒级连接和超低功耗支撑日常遥控。ESP32凭借双核处理、Wi-Fi/BLE共存及原生RTOS支持,成为中低端嵌入式设备的理想通信枢纽。在资源受限的STM32+F4平台下,需通过AT指令状态机驱动、二进制自定义协议(含帧头/CRC16校验)、任务级资源隔离(如FreeRTOS多任务调度)与硬件加速(DMA/中断优化)协同保障控制指令<10m

weixin_35811662的博客 304

【AT 指令开发】软件框架与接口

本文主要用于记录纯MCU无OS下,AT 指令开发软件框架。

欢迎私信、留言交流 1961

告别点灯实验:用STM32F407+HC-05打造你的第一个智能硬件原型(附手机控制源码)

本文详细介绍了如何利用STM32F407微控制器和HC-05蓝牙模块构建智能硬件原型系统,实现手机APP远程控制LED等设备。内容涵盖硬件连接、蓝牙通信协议设计、STM32固件开发及手机端控制实现,为物联网应用开发提供实用指南。

weixin_42657024的博客 361

qt之基于自定义AT指令解析代码示例

【代码】qt之基于自定义AT指令解析代码示例。

我不是码农的博客~~~ 1626

ESP32蓝牙连接不止AT命令:对比Arduino框架与AT指令集,哪种更适合你的IoT项目?

本文深度对比了ESP32蓝牙连接的两种实现方案:Arduino框架与AT指令集。从技术架构、开发效率、系统性能到量产维护,详细分析了两者在IoT项目中的适用场景,帮助开发者根据项目需求选择最合适的蓝牙连接方案,特别适合需要蓝牙配对的物联网应用。

weixin_33725126的博客 658

c语言-自用的通用AT框架(修改了一些错误)

之前写NB、SIM、LORA模块程序的时候经常为AT指令头疼不已,用过百度来的AT框架,用过华为的AT框架,用过同事写的at框架。 百度出来的的五花八门,华为LiteOS的AT框架必须配合系统一起使用,同事写的看着最舒服,可是和其他程序耦合度太高了,一直想写一个自己的AT框架,写什么模块都能用的那种。 最近终于把这个玩意搞出来了。 具体效果与使用方法见我的博客。

ESP8266--学习笔记(八)-由AT固件源码分析一

怎么说呢,其实学习ESP8266的资料还是挺少的,但是可以找得到一些固件源码;而我们作为初学者,这些源码真的是不可多得的资料。当我想实现一些功能的时候,其实是可以用一系列的AT指令来完成的。于是我就想,既然AT指令可以做到,那么我可以参考AT指令的机制来写一个符合自己要求的固件啊!  于是乎通过AT固件启示,我完成了这样一个程序框架。 user_main.c my_wifi.c my_wifi.h

似水流年 3210

一个AT指令解析框架,mark一下

网上看到的一个at指令解析框架,已调试通过,感谢分享

AT_Test_stm32at_AT指令框架_stm32at_at_AT指令框架

STM32+通信模组的通用AT指令框架,简单修改即可移植。

ESP32 相关

ESP32 相关记录 Espressif Systems 芯片选型 编程指南 使用eclipse开发更简单 官方烧录工具 EspTouch APP(smartconfig)

hzlarm的博客 2565

IBM V3700更换控制器2(503错误)

正常的node1 ,机器代码版本:7.5.0.3, 机器代码构建:115.51.1509171734000。耐心等待后,刷新,看到node2,状态变成 节点状态:服务,错误:656,版本和node1一样了。新换的node2 ,机器代码版本:7.2.0.5, 机器代码构建:87.8.1404221000。耐心等待,刷新,node2,状态看到了,节点状态:活动,错误 724 1 1 0。拔出故障的控制,把内存和HBA卡,电池换到新的控制器。新的控制还是报错无法使用,节点状态:服务 错误:503。

klyshao的博客 4447

Android——RIL 机制源码分析

Android 电话系统框架介绍在Android系统中rild运行在AP上,AP上的应用通过rild发送AT指令给BP,BP接收到信息后又通过rild传送给AP。AP与BP之间有两种通信方式:1.Solicited Response:Ap向Bp发送请求,Bp给Ap发送回复,该类型的AT指令及其回调函数以数组的形式存放在Ril_commands.h文件中:    {数组中的索引号,请求回调函数,响应

LoongEmbedded的专栏 2554

ENVI 5.6保姆级教程:高分七号DLC影像从打开到融合的完整流程(附避坑指南)

本文详细介绍了ENVI 5.6处理高分七号DLC影像的完整流程,包括环境准备、数据解压、正射校正、图像融合等关键步骤。特别针对国产卫星数据处理的独特挑战,提供了实用的避坑指南和优化技巧,帮助用户高效完成光学影像的预处理和质量提升。

weixin_33269743的博客 382

Vmware 17保姆级教程:从零部署华为enspPro模拟器(附镜像下载+配置优化)

本文提供了一份详尽的Vmware 17部署华为eNSP Pro模拟器的保姆级教程。内容涵盖从镜像下载、虚拟机导入、网络配置到深度性能调优的全过程,并针对常见启动失败、设备卡顿等故障提供了实用的排查方案,旨在帮助网络工程师和华为认证备考者快速搭建稳定高效的实验环境。

arduino9maker的博客 636

高效实用的AT指令解析框架:助力物联网与嵌入式开发

高效实用的AT指令解析框架:助力物联网与嵌入式开发 【下载地址】AT指令解析框架简介 本仓库提供了一个高效且实用的AT指令解析框架,源于网络上的共享智慧。经过详细测试与调整,此框架已成功验证其功能性和稳定性,特在此分享给需要进行AT命令处理的开发者们。对于物联网、嵌入式开发以及与无线通信相关的项目而言,这将是一个非常有价...

gitblog_09722的博客 1400

window下迁移SVN仓库到新的windows服务器

window下迁移SVN仓库到新的windows服务器

Bertram的博客 4692

阿里云IoT设备建模与MQTT双向通信实战

物联网设备接入云平台的核心在于标准化建模与可靠消息路由。基于MQTT协议的发布/订阅机制,通过产品-设备两级抽象实现硬件能力解耦;物模型定义属性、服务与事件,支撑语义化数据交互;Topic类与云产品流转规则共同构建端云间安全、可扩展的消息通道。该架构广泛应用于智能家居、工业传感等场景,兼顾开发效率与生产可靠性。本文聚焦阿里云IoT平台,详解STM32+ESP8266+微信小程序协同下的设备建模、自定义Topic设计、规则引擎配置及AT指令级联调实践。

weixin_31163455的博客 610

群辉NAS映射为本地盘符

鼠标右击网络→映射网络驱动器→以上适合通过局域网操作,采用ZeroTier组网后,也可以按照以上步骤实现,这时使用 “虚拟局域网”的IP地址。

dgnankai的专栏 5775

SAP 合并报表(EC-CS)完整方法论 + 全业务操作步骤

SAP合并报表(EC-CS)方法论与操作指南摘要 SAP EC-CS模块提供完整的集团合并解决方案,其核心方法论基于会计准则和集团管控逻辑,通过6大维度构建标准化合并体系:组织架构标准化、数据采集标准化、外币换算规则化、内部交易自动化抵消、股权与商誉规范化、报表出具灵活化。 实施过程分为两个阶段: 上线前配置阶段(12个步骤):包括合并架构搭建、科目表配置、外币规则设定、抵消规则定义等基础工作 日常操作阶段(10个步骤):涵盖数据报送、外币换算、内部对账、自动抵消、调整分录等月结流程 系统优势包括: 支持多

金牌架构师 1365

实战指南,基于快马ai快速开发stm32农业物联网监测终端

它的原理是维护一个固定长度的数据队列,每次新的采样值进来,就挤掉最旧的那个值,然后计算队列里所有数据的平均值作为本次的有效输出。土壤湿度传感器我选用的是模拟输出型,它的输出信号电压与湿度成正比,因此使用STM32的ADC进行采集是最直接的方式。虽然我这个STM32项目最终是要烧录到硬件芯片里的,但平台这个功能让我联想到,如果我是做一个物联网设备的云端模拟测试界面,或者一个数据展示面板,那就能直接在这里部署成一个可访问的网页服务,快速分享给同事或客户看效果,省去了自己租服务器、配置环境的麻烦。

BlackironPanther23的博客 95

通用抓取————6D位姿估计

这意味着算法在没有物体的先验知识(如 CAD 模型)的情况下,依然能够通过神经网络捕捉物体的外观、形状和几何特征,生成相关的 6D 位姿估计。通过输入物体类别的描述,算法能够推断出该类别物体的位姿和尺度,无需特定物体的 CAD 模型。在这个坐标空间中,物体的位姿和尺度都是已知的,基于这个标准化表示,算法可以对输入图像中的物体进行 6D 位姿和尺寸的估计。○优势: ICP 是一种非常有效的位姿优化算法,特别适合精细调整物体的位姿,确保最终估计的位姿与真实物体的点云或模型高度一致。

具身机器人和通用AI 2380

智能家居背后的通信引擎:深入剖析51单片机+ESP8266+E4A的技术架构

本文深入剖析了基于51单片机、ESP8266 WiFi模块和E4A安卓开发框架的智能家居通信架构。该方案通过WIFI通信实现设备与手机APP的高效连接,提供了高性价比、低功耗的轻量级解决方案,适用于智能照明、环境监控等典型物联网应用场景。

f9g0h的博客 189

OWASP 2025版AI大模型攻击安全风险汇总(攻击方法种类)

提示词注入是大模型最基础、最常见的核心漏洞,攻击者通过构造直接或间接的恶意自然语言输入,篡改大模型原本的正常行为与输出结果。哪怕这类恶意内容对人类是隐藏、不可见的,只要模型能够正常解析读取,就会触发漏洞。它和大家常说的模型“越狱”相关,但并不等同:越狱是提示词注入的极端形式,会直接让模型彻底无视所有内置安全协议,完全脱离管控;而普通提示词注入,更多是针对性篡改模型行为、诱导执行特定操作。

墨痕诉清风的博客 517

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【免费下载】 自用的通用AT框架(C语言版):简化AT指令处理的利器

自用的通用AT框架(C语言版):简化AT指令处理的利器 【下载地址】自用的通用AT框架C语言版 在开发NB、SIM、LORA等模块的程序时,AT指令的处理常常让人头疼。为了解决这个问题,我参考了百度上的各种AT框架,也使用了华为的AT框架,甚至还用过同事写的框架。然而,这些框架要么五花八门,要么需要配合特定的系统使用,要...

gitblog_09765的博客 1745

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

上一篇: 管理多条模拟IIC总线方法
下一篇: STM32L0内部EEPROM
Long-Run
博客等级 码龄3年 4600粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值