Chapter 11 Two UART Experiments for ESP32

Learning goals and objectives

The principle of serial communication

Learn the configuration of the UART function of the ESP32

Master the UART transceiver test program

 

Introduction to Serial Communication Protocol

Serial Communication is a very common serial communication method between devices. Because it is simple and convenient, most electronic devices support this communication method. Electronic engineers often use this communication method to output debugging information when debugging equipment. ESP32 has its own serial port for program download and log printing, which is the reason.

In computer science, most complex problems can be simplified by layering. For example, the chip is divided into the kernel layer and the on-chip peripherals; for the communication protocol, we also understand it in a layered way, the most basic is to divide it into the physical layer and the protocol layer. The physical layer specifies the characteristics of the mechanical and electronic functional parts of the communication system to ensure the transmission of the original data in the physical medium. The protocol layer mainly specifies the communication logic, and unifies the data packaging and unpacking standards of the sender and receiver. Simply put, the physical layer specifies whether we communicate with our mouths or our bodies, and the protocol layer specifies whether we communicate with Chinese or English.

physical layer

The physical layer of serial communication has many standards and variants. We mainly explain the RS-232 standard. The RS-232 standard mainly specifies the purpose of the signal, the communication interface and the level standard of the signal. The common communication structure between serial devices using the RS-232 standard is as follows.

In the above communication method, the "DB9 interface" of the two communication devices is connected through the serial port signal line, and the "RS-232 standard" is used to transmit the data signal in the serial port signal line. Since the signals of the RS-232 level standard cannot be directly recognized by the controller, these signals will be converted into "TTL calibrated" level signals that can be recognized by the controller through a "level conversion chip" to realize communication.

Protocol layer

The data packets of serial communication are transmitted from the sending device to the RXD interface of the receiving device through its own TXD interface. In the protocol layer of serial communication, the content of the data packet is specified. It consists of start bit, main data, check bit and stop bit. The data packet format of both parties must be agreed to be consistent in order to send and receive data normally. The composition is as follows:

baud rate

This chapter mainly explains the serial asynchronous communication. Since there is no clock signal in asynchronous communication (for example, there is no clock signal in the DB9 interface explained earlier), the baud rate needs to be agreed between the two communication devices, that is, each code In order to decode the signal, each cell separated by a dotted line in the above figure represents a symbol. Common baud rates are 4800, 9600, 115200, etc.

Communication start and stop signals

A data packet of serial communication starts from the start signal and ends with the stop signal. The start signal of the data packet is represented by a data bit of logic 0, and the stop signal of the data packet can be represented by 0.5, 1, 1.5 or 2 data bits of logic 1, as long as the two parties agree.

valid data

Immediately after the start bit of the data packet is the content of the main body data to be transmitted, also known as valid data. The length of the valid data is often agreed to be 5, 6, 7 or 8 bits long.

Data validation

After the valid data, there is an optional data check digit. Since data communication is relatively more susceptible to external interference, resulting in deviation of transmitted data, a check digit can be added to the transmission process to solve this problem. The check methods include odd check (odd), even check (even), 0 check (space), 1 check (mark) and no check (noparity). In the absence of parity, the packet does not contain a parity digit.

Hardware Design and Principle

This experimental board uses UART1 and UART2 of ESP32. The following table is the mapping of our program IO.

UART1

Features

Map the pins of the ESP32

TXD

send

IO5

RXD

take over

IO4

UART2

Features

Map the pins of the ESP32

TXD

send

IO12

RXD

take over

IO13

If the connection method or pins of the UART of the experimental board you are using are different, you only need to modify the pins according to our project, and the control principle of the program is the same.

software design

code logic

Introduction to UART interface of ESP32

UART configuration function: uart_param_config();

function prototype

esp_err_t uart_param_config

(

uart_port_t uart_num,

const uart_config_t *uart_config

)

function

UART configuration function

parameter

[in] uart_num: serial port number, value

UART_NUM_0 = 0x0, /*Serial port 0, download program port*/

UART_NUM_1 = 0x1, /*Serial port 1*/

UART_NUM_2 = 0x2,/*serial port 2*/

[in] uart_config: serial port parameter configuration

 

typedef struct {undefined

int baud_rate; /*Baud rate*/

uart_word_length_t data_bits; /*Data bits*/

uart_parity_t parity; /*Check mode*/

uart_stop_bits_t stop_bits; /*stop bits*/

uart_hw_flowcontrol_t flow_ctrl; /*hardware flow control enable bit*/

} uart_config_t;

return value

ESP_OK: success

ESP_ERR_INVALID_ARG : parameter error

UART's IO mapping setting function: uart_set_pin();

function prototype

esp_err_t uart_set_pin

(

uart_port_t uart_num,

int tx_io_num

int rx_io_num

int rts_io_num

int cts_io_num

)

function

UART's IO mapping function

parameter

[in] uart_num: serial port number, value

[in] tx_io_num: send pin

[in] rx_io_num: Receive pin

[in] rts_io_num: rts flow control pin

[in] cts_io_num:cts flow control pin

return value

ESP_OK: success

ESP_ERR_INVALID_ARG : parameter error

UART function installation enable function: uart_driver_install();

function prototype

esp_err_t uart_driver_install

(

uart_port_t uart_num,

int rx_buffer_size,

int tx_buffer_size,

int queue_size,

QueueHandle_t* uart_queue,

int_alloc_flags

)

function

UART function installation enable function

parameter

[in] uart_num: serial port number

[in] rx_buffer_size: Receive buffer size

[in] tx_buffer_size: Send buffer size

[in] queue_size: queue size

[in] uart_queue: serial port queue pointer

[in] intr_alloc_flags: allocation interrupt flags

return value

ESP_OK: success

ESP_ERR_INVALID_ARG : parameter error

UART send function: uart_write_bytes();

function prototype

int uart_write_bytes

(

uart_port_t uart_num,

const char* src,

size_t size

)

function

UART send function

parameter

[in] uart_num: serial port number

[in] src: send data pointer

[in]size: send data size

return value

(-1) : parameter error

(>=0): The data has been placed in the send buffer

UART read function: uart_read_bytes();

function prototype

int uart_read_bytes

(

uart_port_t uart_num,

uint8_t* buf,

uint32_t length,

TickType_t ticks_to_wait

)

function

UART read function

parameter

[in] uart_num: serial port number

[in] buf: receive data pointer

[in]length: maximum size of received data

[in]ticks_to_wait: wait time

return value

(-1) : parameter error

(>=0): The data has been placed in the send buffer

For more detailed interfaces, please refer to the official guide .

Serial port transceiver code writing

Load serial port related header files, define serial port IO mapping pins, define serial port cache, etc.

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 <stdio.h>

#include "freertos / FreeRTOS.h"

#include "freertos/task.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)

 

Serial port configuration function

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

28

void uart_init(void)

{undefined

//Serial port configuration structure

uart_config_t uart1_config,uart2_config;

//Serial port parameter configuration->uart1

uart1_config.baud_rate = 115200; //Baud rate

uart1_config.data_bits = UART_DATA_8_BITS; //Data bits

uart1_config.parity = UART_PARITY_DISABLE; //check bit

uart1_config.stop_bits = UART_STOP_BITS_1; //stop bits

uart1_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; //hardware flow control

uart_param_config(UART_NUM_1, &uart1_config); //Set serial port

//IO mapping -> T:IO4 R:IO5

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

//Register the serial port service even if it is enabled + set the buffer size

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

 

//Serial parameter configuration->uart2

uart2_config.baud_rate = 115200; //Baud rate

uart2_config.data_bits = UART_DATA_8_BITS; //data bits

uart2_config.parity = UART_PARITY_DISABLE; //check bit

uart2_config.stop_bits = UART_STOP_BITS_1; //stop bits

uart2_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE; //hardware flow control

uart_param_config(UART_NUM_2, &uart2_config); //Set serial port

//IO mapping -> T:IO12 R:IO13

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

//Register the serial port service even if it is enabled + set the buffer size

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

}

 

Main function: serial port initialization, creating two tasks for serial port data reception, testing serial port sending data, etc.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

/*

 * Function entry of the application

*/

void app_main()

{    

// serial port initialization

uart_init();

//Create serial port 1 receive task

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

//Create serial port 2 receive task

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

//Serial port 1 data transmission test

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

//Serial port 2 data transmission test

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

}

 

Two serial port tasks

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/*

* Serial port 1 receive task

*/

void uart1_rx_task()

{undefined

    uint8_t* data = (uint8_t*) malloc(RX1_BUF_SIZE+1);//Allocate memory for serial port reception

    while (1) {undefined

        //Get the data received by serial port 1

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

        if (rxBytes > 0) {undefined

            data[rxBytes] = 0;//Add terminator to the data received at the serial port

//Send the received data

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

        }

    }

    free(data);//Release the requested memory

}

/*

* Serial port 2 receiving task: basically the same as above, omitted

*/

 

hardware connection

The IO of serial port 1 and serial port 2 can be connected to the USB to serial port circuit according to the IO mapping table, and one can be connected at a time. The following figure is the wiring diagram of serial port 1.

Show results

UART Summary

Espressif has encapsulated the API of the serial port very well, and you can directly reparse the data in the task.

The serial port sends 32 bytes, and the 50ms period sends 1 hour without packet loss

Serial port sends 32 bytes, 1ms send 5 minutes without crash

The preliminary test of the serial port part is completed

Source address: https://github.com/xiaolongba/wireless-tech

 

Click me -> more ESP32 development guide series catalog

Related: Chapter 11 Two UART Experiments for ESP32