您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“如何使用MCU中的串口模組交互”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何使用MCU中的串口模組交互”吧!
在使用AT指令的時(shí)候,直接發(fā)送AT指令的一端稱為客戶端(AT Client),接收AT指令并返回響應(yīng)的一端稱為服務(wù)端(AT Server)。
ESP8266、M26、BC35-G這些通信模組都是接收我們發(fā)送的AT指令,所以稱為AT命令服務(wù)端,MCU 需要向模組主動(dòng)發(fā)送AT指令,稱為AT客戶端,它們之間的通信架構(gòu)如下:
首先來看上圖中的三個(gè)數(shù)據(jù)流:
發(fā)送AT指令:可以直接調(diào)用HAL庫提供的API發(fā)送,AT框架并無太大作用;
等待接收返回結(jié)果:可以直接調(diào)用HAL庫的API使用中斷方式接收;
接收服務(wù)端主動(dòng)發(fā)送的數(shù)據(jù):可以直接調(diào)用HAL庫的API使用中斷方式接收;
三條數(shù)據(jù)流都可以調(diào)用HAL庫的API直接實(shí)現(xiàn)呀,為什么要設(shè)計(jì)一層AT框架呢?
在直接調(diào)用HAL庫實(shí)現(xiàn)的時(shí)候,首先無法保證每次模組向 MCU 發(fā)送的數(shù)據(jù)都能完整的被接收,所以,我們需要設(shè)計(jì)一層串口驅(qū)動(dòng)以保證數(shù)據(jù)在任何時(shí)候都可以被完整的接收進(jìn)緩沖區(qū)。
其次,在接收數(shù)據(jù)之后,難點(diǎn)在于對數(shù)據(jù)的處理,判斷AT指令發(fā)送的數(shù)據(jù)是不是正常的返回結(jié)果,從返回結(jié)果中提取有效信息等等,這些如果每條指令接收之后,都去寫代碼依次判斷,代碼量陡增暫且不說,編程的難度也是直接上升,所以,我們需要基于串口驅(qū)動(dòng),在保證數(shù)據(jù)被完整接收的前提之上,再根據(jù)AT命令通信的特點(diǎn),設(shè)計(jì)一層AT框架,專門負(fù)責(zé)解析數(shù)據(jù),提取有效信息。
串口驅(qū)動(dòng)直接使用LiteOS提供的驅(qū)動(dòng)框架實(shí)現(xiàn),由于其特殊性,最底層的驅(qū)動(dòng)框架實(shí)現(xiàn)文件放在了工程目錄中,調(diào)用HAL庫提供的API實(shí)現(xiàn):
uart_at.c文件中,主要完成了兩個(gè)功能:
串口初始化
實(shí)現(xiàn)串口驅(qū)動(dòng)框架的讀寫,并注冊串口設(shè)備到系統(tǒng)中
串口初始化函數(shù)的調(diào)用架構(gòu)如圖:
其中默認(rèn)初始化的是LPUART1,如果將其它串口作為AT指令的串口,修改這兩行代碼即可:
ring_buffer
是專門實(shí)現(xiàn)的用戶存放接收數(shù)據(jù)的緩沖區(qū),用戶只需要調(diào)用read和write操作緩沖區(qū)即可,其實(shí)現(xiàn)文件在iot-link SDK的IoT_LINK_1.0.0\iot_link\link_misc
路徑下:
ring_buffer
在串口初始化函數(shù)中被調(diào)用初始化:
緩沖區(qū)大小在宏定義中聲明:
初始化之后,向LiteOS注冊的中斷服務(wù)函數(shù)只需要調(diào)用ring_buffer_write向緩沖區(qū)不停的寫入接收到的數(shù)據(jù),即可保證串口數(shù)據(jù)被完整的接收。
串口驅(qū)動(dòng)框架中,因?yàn)橐呀?jīng)有了初始化函數(shù),所以只需要實(shí)現(xiàn)read函數(shù)和write函數(shù)即可,實(shí)現(xiàn)的函數(shù)架構(gòu)如下:
因?yàn)閿?shù)據(jù)全部保存在了ring_buffer中,所以串口驅(qū)動(dòng)的read API實(shí)現(xiàn)用緩沖區(qū)提供的讀取函數(shù)實(shí)現(xiàn)即可。
實(shí)現(xiàn)read和write兩個(gè)函數(shù)之后,調(diào)用如下的宏定義,即可將設(shè)備和驅(qū)動(dòng)注冊到系統(tǒng)中:
OSDRIV_EXPORT(uart_at_driv,CONFIG_AT_DEVICENAME,(los_driv_op_t *)&s_at_op,NULL,O_RDWR);
CONFIG_AT_DEVICENAME
由用戶指定,不重復(fù)即可,在iot_link_config.h
文件中,稍后會(huì)講解。
AT客戶端框架的實(shí)現(xiàn)源碼在SDK的IoT_LINK_1.0.0\iot_link\at
文件夾下:
AT框架的架構(gòu)如下:
如圖,因?yàn)榇谠O(shè)備已經(jīng)注冊到了系統(tǒng)中,所以AT框架的底層發(fā)送和接收函數(shù)直接調(diào)用LiteOS設(shè)備驅(qū)動(dòng)框架提供的API實(shí)現(xiàn),除了上述圖中的這些,還涉及到大量的使用信號量、互斥鎖、字符串比較等函數(shù)進(jìn)行AT指令匹配處理,提取結(jié)果的代碼,這些不是理解AT框架的重點(diǎn),所以圖中未給出。
在實(shí)現(xiàn)了AT框架之后,最終留給用戶使用的接口只要三個(gè),即可完成AT指令的交互,非常簡潔:
at_init
:初始化AT框架,啟動(dòng)AT數(shù)據(jù)接收引擎(優(yōu)先級為10)
at_command
:發(fā)送AT指令并匹配指定的返回結(jié)果
at_oobregister
:監(jiān)控AT主動(dòng)上報(bào)的數(shù)據(jù)
接下來,我們以ESP8266模組入網(wǎng)為例,講述如何使用AT框架提供的簡潔API與模組交互。
經(jīng)過上面的講解,完整的AT框架其實(shí)包括設(shè)備驅(qū)動(dòng)框架和AT框架實(shí)現(xiàn)兩部分,所以首先需要在配置文件中使能驅(qū)動(dòng)框架和AT框架。
打開之前新建的HelloWorld工程(如果沒有可以參考之前的教程新建一個(gè)HelloWorld工程),在.sdkconfig
中進(jìn)行配置,如圖:
使能之后,不僅驅(qū)動(dòng)框架的源碼和AT框架的源碼會(huì)被加入工程,還會(huì)進(jìn)行自動(dòng)初始化。
打開SDK中下的IoT_LINK_1.0.0\iot_link
目錄中的link_main.c
文件,其中在link_main
函數(shù)即可看到:
首先是驅(qū)動(dòng)框架的初始化:
其次是串口硬件和AT框架的初始化:
在自動(dòng)初始化的時(shí)候,可以看到串口通信波特率由宏定義CONFIG_AT_BAUDRATE
指定,串口設(shè)備注冊到系統(tǒng)的名稱由宏定義CONFIG_AT_DEVICENAME
指定,那么,這兩個(gè)宏定義在哪里指定呢?
不用的模組波特率不同,設(shè)備名稱當(dāng)然也不盡相同,所以這兩個(gè)設(shè)置在工程目錄中的OS_CONFIG/iot_link_config.h
中,這里我們使用ESP8266模組實(shí)驗(yàn),設(shè)置如圖:
發(fā)送AT指令的API原型及參數(shù)說明如下:
/** * @brief:use this function to register a function that monitor the URC message * @param[in]:cmd, the command to send * @param[in]:cmdlen, the command length * @param[in]:index, the command index, if you don't need the response, set it to NULL; this must be a string * @param[in]:respbuf, if you need the response, you should supply the buffer * @param[in]:respbuflen,the respbuf length * @param[in]:timeout, the time you may wait for the response;and the unit is ms * * @return:0 success while -1 failed * */ int at_command(const void *cmd, size_t cmdlen,const char *index,\ void *respbuf,size_t respbuflen,uint32_t timeout);
接下來我們在Demo
文件夾之下創(chuàng)建一個(gè)文件夾at_test_demo
,用于存放實(shí)驗(yàn)文件,并在該文件夾之下新建本節(jié)所使用的實(shí)驗(yàn)文件at_esp8266_demo.c
:
然后在文件中編輯以下內(nèi)容:
#include <osal.h> #include <string.h> #include <at.h> #define SSID "FAST_88A6" #define PASSWD "18324701020" static bool_t esp8266_atcmd(const char *cmd,const char *index) { int ret = 0; ret = at_command((unsigned char *)cmd,strlen(cmd),index,NULL,0,5000); if(ret >= 0) { return true; } else { return false; } } static int at_esp8266_demo_entry() { char cmd[64]; int ret; /* 測試AT是否OK,超時(shí)時(shí)間5S */ memset(cmd,0,64); snprintf(cmd,64,"AT\r\n"); while(false == esp8266_atcmd(cmd, "OK")) { printf("AT Test fail, repeat.\r\n"); } printf("AT test ok.\r\n"); /* 關(guān)閉回顯 */ memset(cmd,0,64); snprintf(cmd,64,"ATE0\r\n"); ret = esp8266_atcmd(cmd, "OK"); if(ret == false) { printf("ATE0 test fail.\r\n"); } else { printf("ATE0 test ok.\r\n"); } /* 設(shè)置模式為AP+STA */ memset(cmd,0,64); snprintf(cmd,64,"AT+CWMODE=3\r\n"); ret = esp8266_atcmd(cmd, "OK"); if(ret == false) { printf("AT+CWMODE=3 test fail.\r\n"); } else { printf("AT+CWMODE=3 test ok.\r\n"); } /* 連接路由器 */ memset(cmd,0,64); snprintf(cmd,64,"AT+CWJAP=\"%s\",\"%s\"\r\n", SSID, PASSWD); while(false == esp8266_atcmd(cmd, "OK")) { printf("try to join AP:%s fail, repeat.\r\n", SSID); } printf("AT+CWMODE=3 test ok.\r\n"); return 0; } int standard_app_demo_main() { osal_task_create("at_esp8266_demo",at_esp8266_demo_entry,NULL,0x800,NULL,12); return 0; }
結(jié)果:
對于AT命令返回的結(jié)果,如果其中存放有效信息,我們可以在調(diào)用at_command時(shí)傳入一個(gè)緩沖區(qū),如下,發(fā)送查詢模組的ip地址,并從中提取出ip地址:
在連接路由器的代碼之后,添加如下代碼:
/* 獲取ip地址 */ const char cs_cmd[] = "AT+CIFSR\r\n"; char buffer[150]; char *str; uint8_t ip[4]; memset(buffer,0,150); ret = at_command(cs_cmd,strlen(cs_cmd),"OK", buffer, 150, 5000); if(ret < 0) { printf("AT+CIFSR test fail.\r\n"); } else { printf("AT+CIFSR test ok.\r\n"); /* 提取ip地址 */ str = strstr(buffer,"STAIP"); str = str + 7; sscanf(str,"%d.%d.%d.%d",&ip[0],&ip[1],&ip[2],&ip[3]); printf("ip: %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3] ); }
實(shí)驗(yàn)結(jié)果如圖:
到此,相信大家對“如何使用MCU中的串口模組交互”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。