本来想用现成的AT组件的,结果发现添加后,程序压缩后还比原来大了20k,可能是因为下图几个服务层都选中了,AT和SAL是自动选中,libc不选中会出现[makefile:87: rtthread.elf] 的报错。
程序太大了,单片机放不下了,只能自己写了一个简易的at下发程序,在之前串口不定长基础上,参考往期博客 rtthread串口接收不定长数据 (关于伪帧尾那有改动,因为返回值有'\n'时会误判断) 具体如下:
#define PASS_MODE 0 //透传模式
#define AT_MODE 1 //AT模式
struct rt_semaphore at_rx_sem2;
char at_rx_data[50];
enum {WiFi = 1, NBIOT, BLE, lora, Zigbee, MCU}; //五种通信方式
enum {atWiFi, atTCP, at_check}; //要处理的AT相关信息
struct wifi_nbiot //wifi_nbiot相关信息
{
char netmode;
uint8_t transmode;//目前传输方式 wifi/nbiot
bool atmode; //透传模式/at模式
uint8_t data_sta;
char WiFi_name[20];
char WiFi_pswd[20];
char ip[20];
char port[4];
char MAC[17];
};
struct wifi_nbiot mycfg_tcp;
/****通过AT指令配置相关设备*******/
/***********/
/*
at指令下发及检测是否成功
tx_data:下发的AT数据
tx_num: 循环下发次数
rx_wait: 循环下发回馈等待时间
return: 0-发送读取失败 1-发送读取成功
*/
uint8_t at_tx_sta(char *tx_data, uint8_t tx_num, uint16_t rx_wait)
{
uint8_t tx_len = strlen(tx_data);
memset(at_rx_data, 0, sizeof(at_rx_data));
memcpy(at_rx_data, tx_data, tx_len);
for(uint8_t i=0; i<tx_num; i++)
{
rt_device_write(serial2, 0, at_rx_data, tx_len);
rt_sem_control(&at_rx_sem2, RT_IPC_CMD_RESET, RT_NULL);
if(RT_EOK == rt_sem_take(&at_rx_sem2, rx_wait))//rx_wait ms内获得at反馈
{
return 1;
}
}
rt_kprintf("AT client send %s failed or return response error!", tx_data);
return 0;
}
/*
处理远端tcp配置指令 进入at模式---读取或者设置参数---进入透传模式
dev_typ:设备类型 wifi nbiot ble lora
dev_parm:设备参数 wifi相关 tcp相关 检测参数
注意:此函数因为涉及到阻塞信号,不适合放到对时间有要求的线程里面,比如串口接收到配置信息后要在另一个线程里面调用此函数,否则会造成阻塞
*/
void cfg_dev_at(uint8_t dev_typ, uint8_t dev_parm)
{
uint8_t check_flag = 0;
#define at_tx_delay 1000
if(dev_typ == WiFi)
{
mycfg_tcp.atmode = AT_MODE;
if(!at_tx_sta("+++", 6, at_tx_delay))//间隔at_tx_delayms 连发5次 +++ 进入at模式
{
mycfg_tcp.atmode = PASS_MODE;//进入失败
rt_device_write(serial2, 0, "into AT mode failed,please try again", sizeof("into AT mode failed,please try again"));
return;
}
if(dev_parm == atWiFi)
{
char set_wifi_head[100] = "at+wifi_conf=,wpa2_aes,\r\n";//at+wifi_conf=HI-LINK,wpa2_aes,12345678\r\n
Insert_String(set_wifi_head, mycfg_tcp.WiFi_name, 14, strlen(mycfg_tcp.WiFi_name));//插入wifi名字到数组中
Insert_String(set_wifi_head, mycfg_tcp.WiFi_pswd, 24+strlen(mycfg_tcp.WiFi_name), strlen(mycfg_tcp.WiFi_pswd));//插入wifi密码到数组中
at_tx_sta(set_wifi_head, 5, at_tx_delay);
}
else if(dev_parm == atTCP)
{
char set_tcp_ip[50] = "at+remoteip=\r\n", set_tcp_port[30] = "at+remoteport=\r\n";//at+remoteip=192.168.11.245\r\n\ at+remoteport=8080\r\n
Insert_String(set_tcp_ip, mycfg_tcp.ip, 13, strlen(mycfg_tcp.ip));//插入tcp ip到数组中
Insert_String(set_tcp_port, mycfg_tcp.port, 15, strlen(mycfg_tcp.port));//插入tcp port到数组中
at_tx_sta(set_tcp_ip, 5, at_tx_delay);
at_tx_sta(set_tcp_port, 5, at_tx_delay);
}
else if(dev_parm == at_check)
{
if(at_tx_sta("at+netmode=?\r\n", 5, at_tx_delay))//获取netmode成功
{
mycfg_tcp.netmode = at_rx_data[15];
if(at_tx_sta("at+Get_MAC=?\r\n", 5, at_tx_delay))
{
memcpy(mycfg_tcp.MAC, at_rx_data+15, sizeof(mycfg_tcp.MAC));
check_flag = 1;
}
}
rt_thread_mdelay(1000);
if(at_tx_sta("at+out_trans=0\r\n", 6, at_tx_delay))//进入透传 退出at模式
tx_cfg_hard_dev(serial2, check_flag);
else//退出失败就重启
{
rst_my_dev(WiFi);
}
}
if((dev_parm == atWiFi) || (dev_parm == atTCP))//提交网络设置
{
at_tx_sta("at+net_commit=1\r\n", 6, at_tx_delay);
at_tx_sta("at+reconn=1\r\n", 6, at_tx_delay);
at_tx_sta("at+out_trans=0\r\n", 6, at_tx_delay);
}
mycfg_tcp.atmode = PASS_MODE;
}
else if(dev_typ == NBIOT)
{
if(dev_parm == atWiFi)
{
}
else if(dev_parm == atTCP)
{
}
else if(dev_parm == at_check)
{
}
}
}
static int uart4_ZIGBEE(void)
{
·····
rt_sem_init(&at_rx_sem2, "at_rx_sem2", 0, RT_IPC_FLAG_FIFO);
·····
}
static uint8_t rv_flag = 1;
static char HLK_NB_get_char(void)
{
char ch;
while (rt_device_read(serial2, 0, &ch, 1) == 0)
{
rt_sem_control(&rx_sem2, RT_IPC_CMD_RESET, RT_NULL);
if(rv_flag)
rt_sem_take(&rx_sem2, RT_WAITING_FOREVER);
else if(-RT_ETIMEOUT == rt_sem_take(&rx_sem2, 100))//超时100ms未获得串口数据
{
rv_flag = 1; //收完一帧
// ch = '\t';
return;
}
}
rv_flag = 0; //正常获取一个字节
return ch;
}
/* 数据解析线程 */
static void ZIGBEE_data_parsing(void)
{
while (1)
{
rx_temp = uart_ZIGBEE_get_char();
if(!rv_flag)
{
data_buf[(rx_len++) % 50] = rx_temp;//防止数组越界 大小从30改为50 否则at回馈有可能会覆盖
}
else //开始处理一帧数据
{
rx_len = 0;
rt_kprintf("uart4 received data is %s\n", data_buf);
/* 帧数据处理 */
if(mycfg_tcp.atmode == AT_MODE)//AT模式时不进行反馈
{
if((strstr(data_buf, "+++")) || (strstr(data_buf, "at+net_commit=1")) )//没有反馈
rt_sem_release(&at_rx_sem2);//发送信号量
else if(!strncmp(data_buf, at_rx_data, strlen(at_rx_data)-2))//如果data_buf里面存在at_rx_data关键字(at模块端要开回显) 除去\r\n比较
{
if(rx_len_temp - strlen(at_rx_data) > 3)//一般参数多于3个
{
memcpy(at_rx_data, data_buf, rx_len_temp);
rt_sem_release(&at_rx_sem2);//发送信号量
}
}
memset(data_buf, 0, sizeof(data_buf));
continue;
}
······
memset(data_buf, 0, sizeof(data_buf));
}
}
}
/****发送硬件参数*******/
/*
serial:发送参数的串口号
check_flag:是否要发送
*/
void tx_cfg_hard_dev(rt_device_t serial, uint8_t check_flag)
{
if(check_flag)
{
char str[] = "The configuration of WiFi_name,pswd,tcp_ip,port,MAC,netmode,transmode:";
rt_device_write(serial, 0, str, sizeof(str));
rt_device_write(serial, 0, mycfg_tcp.WiFi_name, sizeof(mycfg_tcp.WiFi_name));
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
rt_device_write(serial, 0, mycfg_tcp.WiFi_pswd, sizeof(mycfg_tcp.WiFi_pswd));
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
rt_device_write(serial, 0, mycfg_tcp.ip, sizeof(mycfg_tcp.ip));
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
rt_device_write(serial, 0, mycfg_tcp.port, sizeof(mycfg_tcp.port));
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
rt_device_write(serial, 0, mycfg_tcp.MAC, sizeof(mycfg_tcp.MAC));
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
rt_device_write(serial, 0, &mycfg_tcp.netmode, 1);
rt_thread_mdelay(200);
rt_device_write(serial, 0, ",", 1);
if(mycfg_tcp.transmode == WiFi)
rt_device_write(serial, 0, "WiFi", sizeof("WiFi"));
else if(mycfg_tcp.transmode == NBIOT)
rt_device_write(serial, 0, "NB-IOT", sizeof("NB-IOT"));
}
else
{
char str[] = "check config of hardware failed, please try again";
rt_device_write(serial, 0, str, sizeof(str));
}
}
/****复位硬件设备*******/
//dev:要复位的设备
void rst_my_dev(uint8_t dev)
{
#define rst_delay 1000
if(dev == WiFi)
{
rt_pin_write(HLK_LDO_EN, 0);
rt_thread_mdelay(rst_delay);
rt_pin_write(HLK_LDO_EN, 1);
}
else if(dev == NBIOT)
{
rt_pin_write(NB_LDO_EN, 0);
rt_thread_mdelay(rst_delay);
rt_pin_write(NB_LDO_EN, 1);
}
else if(dev == BLE)
{
}
else if(dev == lora)
{
}
else if(dev == Zigbee)
{
}
else if(dev == MCU)
{
rt_pin_write(BLE_RST, 0);
rt_pin_write(NB_LDO_EN, 0);
rt_pin_write(HLK_LDO_EN, 0);
rt_thread_mdelay(rst_delay);
rt_hw_cpu_reset();
}
}
/**
* @brief 将指定长度的字符串插入到另一个字符串的指定位置
* @param oldstr 旧字符串; instr[] 插入的字符串;location 插入的位置; length 插入的数据长度
* @retval no
*/
void Insert_String(char *oldstr, char instr[], int location, uint8_t length)
{
int j, k;
char dat_tmp[100];
for(j=0; j<location-1; j++)//将位置前的数据存到dat_tmp
dat_tmp[j] = oldstr[j];
//将instr复制到dat_tmp后面
j--;
k = 0;
while(length --)
{
j++;
dat_tmp[j] = instr[k];
k++;
}
//将oldstr第location位后复制到dat_tmp尾部
k = location - 1;
while(oldstr[k] != '\0')
{
j++;
dat_tmp[j] = oldstr[k];
k++;
}
//给dat_tmp字符串添加结束符
j++;
dat_tmp[j] = '\0';
//将dat_tmp字符串复制给oldstr
for(k=0; k<=j; k++)
oldstr[k] = dat_tmp[k];
}
例:
void cfg_hard_dev(void)
{
at_tx_sta("+++", 5, 200);//间隔200ms 连发5次 +++ 进入透传模式
cfg_dev_at(WiFi, atTCP);//通过wifi设置tcp参数
cfg_dev_at(WiFi, at_check);//通过wifi获取硬件参数
}