1
AT指令簡介
AT命令作為主控芯片與通信模塊的協(xié)議接口,通常使用串口作為通信協(xié)議的傳輸,因此在通信模塊中硬件接口通常為串口,這樣簡化了主控設(shè)備的代碼開發(fā)。
AT指令通常由前綴、主體、結(jié)束符構(gòu)成,其中前綴為“AT”,主體由命令、參數(shù)以及數(shù)據(jù)組成;結(jié)束符一般為“ ”。
AT指令的發(fā)送內(nèi)容最多為1056個字符的長度(不包括“AT”,但包括最后的空字符即回車符號)
使用AT指令進(jìn)行設(shè)備的連接通信,AT client與AT server必須共同完成。
即:AT server 必須對接收的AT client的命令進(jìn)行判斷并發(fā)送響應(yīng)給到AT client;AT client 等待響應(yīng),并對響應(yīng)的數(shù)據(jù)進(jìn)行解析處理。
當(dāng)然AT server也可主動發(fā)送數(shù)據(jù)給AT client,AT client對接收的數(shù)據(jù)進(jìn)行解析處理。一般是需要用戶做出相應(yīng)操作的情況,例如:WiFi的斷開連接等。
因此,AT server發(fā)送的數(shù)據(jù)可以分為兩種,一種是響應(yīng)數(shù)據(jù),另一種則是主動發(fā)送的數(shù)據(jù)(URC)。
AT指令集是用于實(shí)現(xiàn)設(shè)備(AT client)與服務(wù)器(AT Server)之前的連接與通信的方式。

由上圖可以看出,AT Client和AT Server既是發(fā)送端也是接收端。
AT server需要接收AT Client的請求,對請求進(jìn)行響應(yīng),解析。將響應(yīng)和解析結(jié)果發(fā)送給AT client。
2
設(shè)計思路
通過串口助手發(fā)送AT指令給目標(biāo)mcu,目標(biāo)mcu對接收的數(shù)據(jù)進(jìn)行解析和超時判斷,并響應(yīng)解析結(jié)果,執(zhí)行對應(yīng)的響應(yīng)。
設(shè)計思路如圖所示:

3
具體實(shí)現(xiàn)
超時設(shè)計
通過滴答定時器進(jìn)行接收和發(fā)送的超時判斷。
/*Timeoutjudgment.*/
boolis_timeout(uint32_ttimeout)
{
returntick>timeout;
}
/*SysTickISRentry.*/
voidSysTick_Handler(void)
{
tick+=1;
}
解析器設(shè)計
判斷接收到正確的AT指令是否超時,若超時則返回超時并發(fā)送[AT] TIMEOUT給客戶端,清除計數(shù)值,同時清空將數(shù)據(jù)接收緩存區(qū)。
將目標(biāo)mcu接收的數(shù)據(jù)和發(fā)送的AT指令進(jìn)行比較,若匹配則返回匹配成功并發(fā)送“[AT] OK”給客戶端,若失敗則返回錯誤”[AT] ERROR“給客戶端。
uint32_tat_parse(char*cmdstr,uint32_ttimeout)
{
uint32_tret;
tick=0;
while(!(is_timeout(timeout)))
{
if(REC_STA)/*receiveacompletelinecommand.*/
{
REC_STA=false;
for(uint32_ti=0;i<strlen(cmdstr);i++)
{
tick=0;
if(rec_buff[i]==cmdstr[i])
{
ret=AT_RETURN_OK;
}
else
{
ret=AT_RETURN_ERROR;
}
}
memset(rec_buff,0,sizeof(rec_buff));/*clearreceiverbuffer.*/
returnret;
}
}
tick=0;
ret=AT_RETURN_TIMEOUT;
memset(rec_buff,0,sizeof(rec_buff));/*clearreceiverbuffer.*/
returnret;
}
AT 適配器配置
使用pokt-f0040的默認(rèn)debug接口,UART1(PB6,和PB7),使用接收中斷來接收串口助手發(fā)送的數(shù)據(jù),具體實(shí)現(xiàn)如下:
實(shí)例化AT適配器
/*initializetheatadaptter.*/
staticAT_Adapter_Typeat=
{
.write=uart_putchar,
.read=uart_getchar,
.rec_buf=rec_buff,
.buf_idx=0u
};
AT接口初始化 void app_at_port_init(void)
初始化UART需要配置:時鐘頻率、波特率、數(shù)據(jù)長度、停止位、傳輸模式及是否使用校驗(yàn)。
voidapp_at_port_init(void)
{
UART_Init_Typeuart_init;
/*Setupthexferengine.*/
uart_init.ClockFreqHz=BOARD_AT_UART_FREQ;/*48mhz,APB2.*/
uart_init.BaudRate=BOARD_AT_UART_BAUDRATE;
uart_init.WordLength=UART_WordLength_8b;
uart_init.StopBits=UART_StopBits_1;
uart_init.Parity=UART_Parity_None;
uart_init.XferMode=UART_XferMode_RxTx;
uart_init.HwFlowControl=UART_HwFlowControl_None;
UART_Init(BOARD_AT_UART_PORT,&uart_init);
/*EnableRXinterrupt.*/
UART_EnableInterrupts(BOARD_AT_UART_PORT,UART_INT_RX_DONE,true);
NVIC_EnableIRQ(BOARD_AT_UART_IRQn);
/*EnableUART.*/
UART_Enable(BOARD_AT_UART_PORT,true);
/*EnableUART.*/
UART_Enable(BOARD_AT_UART_PORT,true);
}
發(fā)送函數(shù) uart_putchar(uint8_t c)
/*sneddata.*/
voiduart_putchar(uint8_tc)
{
while(0u==(UART_STATUS_TX_EMPTY&UART_GetStatus(BOARD_AT_UART_PORT)))/*Waitingtxbufferempty.*/
{}
UART_PutData(BOARD_AT_UART_PORT,c);
}
接收函數(shù) uint8_t uart_getchar(void)
uint8_tuart_getchar(void)
{
while(0u==(UART_STATUS_RX_DONE&UART_GetStatus(BOARD_AT_UART_PORT)))/*Waitingrxbufferreceivesacompletebyteofdata.*/
{}
returnUART_GetStatus(BOARD_AT_UART_PORT);
}
發(fā)送字符串函數(shù) void uart_putbuffer(uint8_t *str)
/*sendstring.*/
voiduart_putbuffer(uint8_t*str)
{
while((*str)!='?')
{
uart_putchar(*str);
str++;
}
}
中斷處理函數(shù)
在中斷中進(jìn)行接收數(shù)據(jù)的處理,判斷是否接收到完整的一行命令.當(dāng)接收到回車換行符時,即表示接收到了一行完整的命令。
/*receiverhandler*/
voidapp_at_port_rx_isr_hook(void)
{
tick=0;
if((0u!=(UART_INT_RX_DONE&UART_GetEnabledInterrupts(BOARD_AT_UART_PORT)))
&&(0u!=(UART_INT_RX_DONE&UART_GetInterruptStatus(BOARD_AT_UART_PORT))))
{
rec_buff[at.buf_idx]=UART_GetData(BOARD_AT_UART_PORT);/*readdatatoclearrxinterruptbits.*/
uart_putchar(rec_buff[at.buf_idx]);
if((rec_buff[at.buf_idx]=='
')&&(rec_buff[at.buf_idx-1]=='
'))/*recievedone.*/
{
REC_STA=true;
at.buf_idx=0;
}
at.buf_idx=(at.buf_idx+1)%AT_CMD_LEN;
}
}
/*BOARD_AT_UART_IRQHandlerISRentry.*/
voidBOARD_AT_UART_IRQHandler(void)
{
app_at_port_rx_isr_hook();
}
main() 函數(shù)
main()函數(shù)結(jié)合上述操作,不斷執(zhí)行用戶自定義的任務(wù)task()
intmain(void)
{
BOARD_Init();
while(1)
{
task();
}
}
用戶自定義的任務(wù) task()
用戶設(shè)定接收完整的一行AT指令的時間,調(diào)用AT指令解析函數(shù),根據(jù)響應(yīng)結(jié)果執(zhí)行自定義任務(wù)。
當(dāng)接收的命令和發(fā)送命令匹配時,串口助手顯示[AT]READY。
當(dāng)匹配失敗時,串口助手顯示[AT]ERROR,小燈長亮。
當(dāng)指定時間內(nèi)(本實(shí)驗(yàn)設(shè)置為5s)沒有接收到完整的一行指令時,串口助手顯示[AT]TIMEOUT,小燈以1s間隔閃爍。
voidtask(void)
{
while(AT_Parse(&at,cmdlib[0],5000))
{}
AT_SendBuf(&at,"
[AT]READY
");
while(AT_Parse(&at,cmdlib[1],5000))
{}
GPIO_WriteBit(BOARD_LED0_GPIO_PORT,BOARD_LED0_GPIO_PIN,0u);
}
代碼中的“cmdlib”為用戶自定義的AT指令庫,本此實(shí)驗(yàn)中定義的AT指令庫為:
/*customATcommandset.*/
char*cmdlib[command_len]={"AT+RST","AT+LED=1"};
task任務(wù)解讀:
當(dāng)通過串口發(fā)送“AT+RST ”時,mcu響應(yīng)指令,并反饋響應(yīng)結(jié)果給串口助手,若接收正確指令則執(zhí)行預(yù)設(shè)任務(wù),發(fā)送[AT] READY給串口助手。
當(dāng)通過串口發(fā)送“AT+LED=1 ”時,mcu響應(yīng)指令,并反饋響應(yīng)結(jié)果給串口助手,若接收正確指令則執(zhí)行預(yù)設(shè)任務(wù),點(diǎn)亮小燈。
4
實(shí)驗(yàn)結(jié)果
5
測試環(huán)境
//
? KEIL 5.37為程序下載調(diào)試環(huán)境
? Tera Term作為串口數(shù)據(jù)的發(fā)送和顯示的客戶端
? 測試板為POKT-F0040
審核編輯:湯梓紅
-
串口
+關(guān)注
關(guān)注
14文章
1580瀏覽量
78338 -
AT指令
+關(guān)注
關(guān)注
1文章
41瀏覽量
12332 -
MM32
+關(guān)注
關(guān)注
1文章
107瀏覽量
968
原文標(biāo)題:靈動微課堂 (第227講) | 基于F0040串口實(shí)現(xiàn)AT指令解析
文章出處:【微信號:MindMotion-MMCU,微信公眾號:靈動MM32MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
RISC-V架構(gòu)簡介
時間戳的簡介與實(shí)現(xiàn)
單片機(jī)指令系統(tǒng)
嵌入式CPU指令Cache的設(shè)計與實(shí)現(xiàn)
歐盟環(huán)保指令簡介
DSP常用匯編語言指令簡介
DSP指令系統(tǒng)
MCS-51指令簡介
Thumb指令集之Thumb指令應(yīng)用

單片機(jī)的指令周期的簡介和內(nèi)核架構(gòu)詳細(xì)說明

51單片機(jī)指令系統(tǒng)的詳細(xì)資料簡介
基于FPGA的ROM的實(shí)現(xiàn)簡介

ESP8266官方AT指令的實(shí)現(xiàn)方法
匯編指令是什么 計算機(jī)語言匯編指令簡介

評論