天天看點

第十一章 ESP32的兩個UART實驗

  • 關注嘉友創科技公衆号
    第十一章 ESP32的兩個UART實驗
  • 源碼位址:​​https://github.com/HX-IoT/ESP32-Developer-Guide​​
  • ESP32開發指南QQ群:824870185,内有pdf版,排版整潔。

學習目的及目标

序列槽通信的原理

學習ESP32 的UART功能的配置

掌握UART收發測試程式

序列槽通訊協定簡介

序列槽通訊(Serial Communication)是一種裝置間非常常用的串行通訊方式,因為它簡單便捷,大部分電子裝置都支援該通訊方式,電子工程師在調試裝置時也經常使用該通訊方式輸出調試資訊,ESP32自有一個序列槽用于程式下載下傳和log列印,就是這個道理。

在計算機科學裡,大部分複雜的問題都可以通過分層來簡化。如晶片被分為核心層和片上外設;對于通訊協定,我們也以分層的方式來了解,最基本的是把它分為實體層和協定層。實體層規定通訊系統中具有機械、電子功能部分的特性,確定原始資料在實體媒體的傳輸。協定層主要規定通訊邏輯,統一收發雙方的資料打包、解包标準。簡單來說實體層規定我們用嘴巴還是用肢體來交流,協定層則規定我們用中文還是英文來交流。

實體層

序列槽通訊的實體層有很多标準及變種,我們主要講解 RS-232标準 ,RS-232标準主要規定了信号的用途、通訊接口以及信号的電平标準。使用 RS-232标準的序列槽裝置間常見的通訊結構如下。

第十一章 ESP32的兩個UART實驗

在上面的通訊方式中,兩個通訊裝置的“DB9 接口”之間通過序列槽信号線建立起連接配接,序列槽信号線中使用“RS-232 标準”傳輸資料信号。由于 RS-232電平标準的信号不能直接被控制器直接識别,是以這些信号會經過一個“電平轉換晶片”轉換成控制器能識别的“TTL校準”的電平信号,才能實作通訊。

協定層

序列槽通訊的資料包由發送裝置通過自身的 TXD 接口傳輸到接收裝置的 RXD 接口。在序列槽通訊的協定層中,規定了資料包的内容,它由啟始位、主體資料、校驗位以及停止位組成,通訊雙方的資料包格式要約定一緻才能正常收發資料,其組成如下:

第十一章 ESP32的兩個UART實驗

波特率

本章中主要講解的是序列槽異步通訊,異步通訊中由于沒有時鐘信号(如前面講解的 DB9接口中是沒有時鐘信号的),是以兩個通訊裝置之間需要約定好波特率,即每個碼元的長度,以便對信号進行解碼,上圖中用虛線分開的每一格就是代表一個碼元。常見的波特率為4800、9600、115200等。

通訊的起始和停止信号

序列槽通訊的一個資料包從起始信号開始,直到停止信号結束。資料包的起始信号由一個邏輯 0的資料位表示,而資料包的停止信号可由 0.5、1、1.5或 2 個邏輯 1 的資料位表示,隻要雙方約定一緻即可。

有效資料

在資料包的起始位之後緊接着的就是要傳輸的主體資料内容,也稱為有效資料,有效資料的長度常被約定為 5、6、7或 8位長。

資料校驗

在有效資料之後,有一個可選的資料校驗位。由于資料通信相對更容易受到外部幹擾導緻傳輸資料出現偏差,可以在傳輸過程加上校驗位來解決這個問題。校驗方法有奇校驗(odd)、偶校驗(even)、0校驗(space)、1校驗(mark)以及無校驗(noparity)。在無校驗的情況下,資料包中不包含校驗位。

硬體設計及原理

本實驗闆使用了ESP32的UART1和UART2,下表是我們的程式IO的映射。

UART1 功能 映射ESP32的引腳
TXD 發送 IO5
RXD 接收 IO4
UART2
IO12
IO13

若您使用的實驗闆 UART的連接配接方式或引腳不一樣,隻需根據我們的工程修改引腳即可,程式的控制原理相同。

軟體設計

代碼邏輯

第十一章 ESP32的兩個UART實驗

ESP32的UART接口介紹

UART配置函數:uart_param_config();

函數原型

esp_err_t uart_param_config

(

uart_port_t uart_num,

const uart_config_t *uart_config

)

函數功能 UART配置函數
參數

[in] uart_num:序列槽号,取值

UART_NUM_0 = 0x0, /*序列槽0,下載下傳程式端口*/

UART_NUM_1 = 0x1, /*序列槽1*/

UART_NUM_2 = 0x2,/*序列槽2*/

[in] uart_config:序列槽參數配置

typedef struct {

int baud_rate; /*波特率*/

uart_word_length_t data_bits; /*資料位*/

uart_parity_t parity; /*校驗模式*/

uart_stop_bits_t stop_bits; /*停止位*/

uart_hw_flowcontrol_t flow_ctrl; /*硬體流控使能位*/

} uart_config_t;

傳回值

ESP_OK:成功

ESP_ERR_INVALID_ARG : 參數錯誤

UART的IO映射設定函數:uart_set_pin();

esp_err_t uart_set_pin

int tx_io_num,

int rx_io_num,

int rts_io_num,

int cts_io_num

UART的IO映射函數

[in] tx_io_num:發送引腳

[in] rx_io_num:接收引腳

[in] rts_io_num:rts流控引腳

[in] cts_io_num:cts流控引腳

UART功能安裝使能函數:uart_driver_install();

esp_err_t uart_driver_install

int rx_buffer_size,

int tx_buffer_size,

int queue_size,

QueueHandle_t* uart_queue,

int intr_alloc_flags

UART功能安裝使能函數

[in] uart_num:序列槽号

[in] rx_buffer_size:接收緩存大小

[in] tx_buffer_size:發送緩存大小

[in] queue_size:隊列大小

[in] uart_queue:序列槽隊列指針

[in] intr_alloc_flags:配置設定中斷标記

UART發送函數:uart_write_bytes();

int uart_write_bytes

const char* src,

size_t size

UART發送函數函數

[in] src:發送資料指針

[in]size:發送資料大小

(-1) :參數錯誤

(>=0):資料已放到發送緩存

UART讀取函數:uart_read_bytes();

int uart_read_bytes

uint8_t* buf,

uint32_t length,

TickType_t ticks_to_wait

UART讀取函數

[in] buf:接收資料指針

[in]length:接收資料最大大小

[in]ticks_to_wait:等待時間

更多更詳細接口請參考​​官方指南​​。

序列槽收發代碼編寫

加載序列槽相關的頭檔案、定義序列槽IO映射引腳、定義序列槽緩存等。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

#include <stdio.h>

#include "esp_system.h"

#include "esp_spi_flash.h"

#include "esp_wifi.h"

#include "esp_event_loop.h"

#include "esp_log.h"

#include "esp_err.h"

#include "nvs_flash.h"

#include "freertos/FreeRTOS.h"

#include "freertos/task.h"

#include "driver/ledc.h"

#include "driver/uart.h"

#include "driver/gpio.h"

#include "string.h"

//UART1

#define RX1_BUF_SIZE        (1024)

#define TX1_BUF_SIZE        (512)

#define TXD1_PIN            (GPIO_NUM_5)

#define RXD1_PIN            (GPIO_NUM_4)  

//UART2

#define RX2_BUF_SIZE        (1024)

#define TX2_BUF_SIZE        (512)

#define TXD2_PIN            (GPIO_NUM_12)

#define RXD2_PIN            (GPIO_NUM_13)

序列槽配置函數

28

void uart_init(void)

{

//序列槽配置結構體

uart_config_t uart1_config,uart2_config;

//序列槽參數配置->uart1

uart1_config.baud_rate = 115200; //波特率

uart1_config.data_bits = UART_DATA_8_BITS; //資料位

uart1_config.parity = UART_PARITY_DISABLE; //校驗位

uart1_config.stop_bits = UART_STOP_BITS_1; //停止位

uart1_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; //硬體流控

uart_param_config(UART_NUM_1, &uart1_config); //設定序列槽

//IO映射-> T:IO4  R:IO5

uart_set_pin(UART_NUM_1, TXD1_PIN, RXD1_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

//注冊序列槽服務即使能+設定緩存區大小

uart_driver_install(UART_NUM_1, RX1_BUF_SIZE * 2, TX1_BUF_SIZE * 2, 0, NULL, 0);

//序列槽參數配置->uart2

uart2_config.baud_rate = 115200; //波特率

uart2_config.data_bits = UART_DATA_8_BITS; //資料位

uart2_config.parity = UART_PARITY_DISABLE; //校驗位

uart2_config.stop_bits = UART_STOP_BITS_1; //停止位

uart2_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; //硬體流控

uart_param_config(UART_NUM_2, &uart2_config); //設定序列槽

//IO映射-> T:IO12  R:IO13

uart_set_pin(UART_NUM_2, TXD2_PIN, RXD2_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

uart_driver_install(UART_NUM_2, RX2_BUF_SIZE * 2, TX2_BUF_SIZE * 2, 0, NULL, 0);

}

主函數:序列槽初始化、建立兩個任務用于序列槽資料接收、測試序列槽發送資料等。

/*

 * 應用程式的函數入口

*/

void app_main()

{    

//序列槽初始化

uart_init();

//建立序列槽1接收任務

xTaskCreate(uart1_rx_task, "uart1_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);

//建立序列槽2接收任務

xTaskCreate(uart2_rx_task, "uart2_rx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);

//序列槽1資料發送測試

uart_write_bytes(UART_NUM_1, "uart1 test OK ", strlen("uart1 test OK "));

//序列槽2資料發送測試

uart_write_bytes(UART_NUM_2, "uart2 test OK ", strlen("uart2 test OK "));

兩個序列槽任務

* 序列槽1接收任務

void uart1_rx_task()

    uint8_t* data = (uint8_t*) malloc(RX1_BUF_SIZE+1);//配置設定記憶體,用于序列槽接收

    while (1) {

        //擷取序列槽1接收的資料

        const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX1_BUF_SIZE, 10 / portTICK_RATE_MS);

        if (rxBytes > 0) {

            data[rxBytes] = 0;//在序列槽接收的資料增加結束符

//将接收到的資料發出去

uart_write_bytes(UART_NUM_1, (char *)data, rxBytes);

        }

    }

    free(data);//釋放申請的記憶體

* 序列槽2接收任務:基本同上,省略

硬體連接配接

可按照IO映射表将序列槽1和序列槽2的IO接到USB轉序列槽電路上,每次可接一個。如下圖是序列槽1接線圖。

第十一章 ESP32的兩個UART實驗

效果展示

第十一章 ESP32的兩個UART實驗

UART總結

樂鑫已經把序列槽部分的API封裝的非常好,直接在任務重解析資料即可。

序列槽發送32位元組,50ms周期發送1小時無丢包

序列槽發送32位元組,1ms發送5分鐘無當機

序列槽部分初步測試完成