溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何使用MCU中的串口模組交互

發(fā)布時(shí)間:2021-12-29 10:22:26 來源:億速云 閱讀:260 作者:iii 欄目:互聯(lián)網(wǎng)科技

本篇內(nèi)容主要講解“如何使用MCU中的串口模組交互”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“如何使用MCU中的串口模組交互”吧!

1. AT客戶端框架

什么是AT客戶端

在使用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)如下:

如何使用MCU中的串口模組交互

為什么需要AT客戶端框架

首先來看上圖中的三個(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ù),提取有效信息

2. 剖析串口驅(qū)動(dòng)框架實(shí)現(xiàn)

串口驅(qū)動(dòng)直接使用LiteOS提供的驅(qū)動(dòng)框架實(shí)現(xiàn),由于其特殊性,最底層的驅(qū)動(dòng)框架實(shí)現(xiàn)文件放在了工程目錄中,調(diào)用HAL庫提供的API實(shí)現(xiàn):

如何使用MCU中的串口模組交互

uart_at.c文件中,主要完成了兩個(gè)功能:

  • 串口初始化

  • 實(shí)現(xiàn)串口驅(qū)動(dòng)框架的讀寫,并注冊串口設(shè)備到系統(tǒng)中

2.1. 串口初始化

串口初始化函數(shù)的調(diào)用架構(gòu)如圖:

如何使用MCU中的串口模組交互

其中默認(rèn)初始化的是LPUART1,如果將其它串口作為AT指令的串口,修改這兩行代碼即可:

如何使用MCU中的串口模組交互

2.2. ring_buffer

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路徑下:

如何使用MCU中的串口模組交互

ring_buffer在串口初始化函數(shù)中被調(diào)用初始化:

如何使用MCU中的串口模組交互

緩沖區(qū)大小在宏定義中聲明:

如何使用MCU中的串口模組交互

初始化之后,向LiteOS注冊的中斷服務(wù)函數(shù)只需要調(diào)用ring_buffer_write向緩沖區(qū)不停的寫入接收到的數(shù)據(jù),即可保證串口數(shù)據(jù)被完整的接收。

2.3. 串口驅(qū)動(dòng)框架實(shí)現(xiàn)

串口驅(qū)動(dòng)框架中,因?yàn)橐呀?jīng)有了初始化函數(shù),所以只需要實(shí)現(xiàn)read函數(shù)和write函數(shù)即可,實(shí)現(xiàn)的函數(shù)架構(gòu)如下:

如何使用MCU中的串口模組交互

因?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ì)講解。

3. 剖析AT客戶端框架

AT客戶端框架的實(shí)現(xiàn)源碼在SDK的IoT_LINK_1.0.0\iot_link\at文件夾下:

如何使用MCU中的串口模組交互

AT框架的架構(gòu)如下:

如何使用MCU中的串口模組交互

如圖,因?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與模組交互。

4. AT客戶端框架的使用

AT框架使能及配置

經(jīng)過上面的講解,完整的AT框架其實(shí)包括設(shè)備驅(qū)動(dòng)框架和AT框架實(shí)現(xiàn)兩部分,所以首先需要在配置文件中使能驅(qū)動(dòng)框架和AT框架

打開之前新建的HelloWorld工程(如果沒有可以參考之前的教程新建一個(gè)HelloWorld工程),在.sdkconfig中進(jìn)行配置,如圖:

如何使用MCU中的串口模組交互

使能之后,不僅驅(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)框架的初始化:

如何使用MCU中的串口模組交互

其次是串口硬件和AT框架的初始化:

如何使用MCU中的串口模組交互

在自動(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è)置如圖:

如何使用MCU中的串口模組交互

發(fā)送AT命令

發(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

如何使用MCU中的串口模組交互

然后在文件中編輯以下內(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é)果:

如何使用MCU中的串口模組交互

獲取AT指令返回結(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中的串口模組交互

到此,相信大家對“如何使用MCU中的串口模組交互”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(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)容。

mcu
AI