|
之前寫過一篇關(guān)于esp32串口的文章:ESP32中斷方式操作串口,但是不夠詳細(xì),這篇進(jìn)行更加細(xì)節(jié)的描述。
因?yàn)槲疫@個(gè)代碼是基于micropython esp32進(jìn)行二次開發(fā)的,需要改造原有micropython對(duì)串口的配置。當(dāng)然這些代碼直接用ESP32-IDF開發(fā)也沒問題。
先看下Micropython對(duì)ESP32uart0的串口配置:
對(duì)應(yīng)文件為:/micropython/ports/esp32/uart.c
該文件初始化打開了串口接收中斷,但是沒有安裝串口驅(qū)動(dòng),所以不能在中斷服務(wù)函數(shù)中調(diào)用uart_write_bytes()。如果要要調(diào)用該發(fā)送函數(shù),必須在串口初始化的時(shí)候,執(zhí)行如下兩步:
uart_driver_install(UART_NUM_0, 256,0, 0, NULL, 0); uart_isr_free(UART_NUM_0);
//micropython對(duì)串口的初始化代碼如下
void uart_init(void) {
uart_isr_handle_t handle;
uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle);
uart_enable_rx_intr(UART_NUM_0);
}
該函數(shù)主要執(zhí)行兩個(gè)步驟:
- 串口中斷服務(wù)函數(shù)的注冊(cè)
- 串口接收中斷的使能,接收中斷使能函數(shù)里面打開了兩個(gè)中斷FIFO 接收滿和接收超時(shí)中斷
如上是我們解釋一下micropython對(duì)串口的配置,但不是重點(diǎn),重點(diǎn)還在于我們自己的初始化和中斷服務(wù)函數(shù)代碼:
完整的串口初始化配置
void uart_init(void) {
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(UART_NUM_0, &uart_config);
uart_set_pin(UART_NUM_0,UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_isr_handle_t handle;
uart_driver_install(UART_NUM_0, 256,0, 0, NULL, 0); //安裝驅(qū)動(dòng)程序,使用idf自帶中斷服務(wù)函數(shù)
uart_isr_free(UART_NUM_0); //釋放不使用idf自帶中斷服務(wù)函數(shù)
uart_isr_register(UART_NUM_0, uart_irq_handler, NULL, ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM, &handle); //重新注冊(cè)中斷服務(wù)函數(shù)
uart_enable_rx_intr(UART_NUM_0); //使能中斷接收
uart_set_rx_timeout(UART_NUM_0,10); //配置接收超時(shí)中斷時(shí)間,單位為按照當(dāng)前波特率傳輸1個(gè)bytes的時(shí)間
}
該初始化主要執(zhí)行以下幾個(gè)步驟:
- 串口參數(shù)的初始化配置
- 串口引腳配置
- 串口驅(qū)動(dòng)安裝,這個(gè)地方需要注意,執(zhí)行完uart_driver_install以后,默認(rèn)會(huì)使用ESP32-IDF自帶的串口中斷服務(wù)函數(shù),而這里我們不是用就需要下一步操作
- 釋放idf自帶串口中斷服務(wù)函數(shù)
- 重新注冊(cè)自定義串口中斷服務(wù)函數(shù)
- 使能串口接收中斷uart_enable_rx_intr,該函數(shù)會(huì)打開兩個(gè)中斷源:rxfifo接收滿中斷,rxfifo超時(shí)中斷(默認(rèn)超時(shí)時(shí)間為10個(gè)byte)
- 最后一步設(shè)置接收超時(shí)中斷時(shí)間可以省略,因?yàn)樵谏弦徊揭呀?jīng)默認(rèn)打開,并且idf默認(rèn)值為10個(gè)bytes時(shí)間。如果想修改超時(shí)中斷時(shí)間的話就調(diào)用該函數(shù)
完整的串口中斷服務(wù)函數(shù)
STATIC void IRAM_ATTR uart_irq_handler(void *arg) {
volatile uart_dev_t *uart = &UART0;
uint8_t recSize=0;
uart->int_clr.rxfifo_full = 1;
uart->int_clr.frm_err = 1;
if(uart->int_st.rxfifo_tout) //檢查是否產(chǎn)生超時(shí)中斷
{
uart->int_clr.rxfifo_tout = 1;
recSize=uart->status.rxfifo_cnt;
if(recSize!=0)
{
while(uart->status.rxfifo_cnt)
{
uart0RxBuf[uart0RxCount++]=uart->fifo.rw_byte;
}
if(uart0RxCount==uart0RxBuf[0]) //接收一幀數(shù)據(jù)長(zhǎng)度等于第一個(gè)byte指示的長(zhǎng)度,接收正確
{
port_infoToRecQueue(PORT_UART,uart0RxCount,uart0RxBuf);
uart0RxCount=0;
}
else if(uart0RxCount>uart0RxBuf[0]) //接收數(shù)據(jù)長(zhǎng)度大于第一個(gè)byte指示的長(zhǎng)度,接收出錯(cuò)
{
uart0RxCount=0;
}
}
}
}
初始化已經(jīng)打開了串口中斷,針對(duì)接收有兩個(gè)中斷源:rxfifo滿中斷 rx接收超時(shí)中斷。默認(rèn)rxfifo的深度為128byte,所以只要不連續(xù)發(fā)超過128個(gè)byte都不會(huì)觸發(fā)fifo滿中斷。當(dāng)發(fā)送完一幀數(shù)據(jù),只要后面空閑的時(shí)間超過設(shè)定的超時(shí)時(shí)間就會(huì)產(chǎn)生超時(shí)中斷。所以這里要弄清楚并不是每接收到一個(gè)byte就會(huì)產(chǎn)生一次串口中斷。 在實(shí)際測(cè)試中,給ESP32發(fā)送一幀數(shù)據(jù)會(huì)讓他觸發(fā)兩次rx超時(shí)中斷,詳述如下
關(guān)于esp32 串口接收超時(shí)中斷
IDF中設(shè)置默認(rèn)超時(shí)時(shí)間為,10代表以當(dāng)前波特率傳輸10bytes的時(shí)間
UART_TOUT_THRESH_DEFAULT (10)
每接收一幀連續(xù)的數(shù)據(jù)包,會(huì)觸發(fā)兩次超時(shí)中斷。
- 第一次觸發(fā)超時(shí)中斷,讀取rxfifo中已接收字節(jié)數(shù)和這一幀數(shù)據(jù)長(zhǎng)度相等。
- 第二次觸發(fā)超時(shí)中斷,讀取rxfilo已接收字節(jié)數(shù)為0
所以只要每一幀數(shù)據(jù)之間都有時(shí)間空隙,并且空隙時(shí)間長(zhǎng)于設(shè)定值,那么第一次觸發(fā)超時(shí)中斷時(shí)rxfifo中的數(shù)據(jù)就是一幀的數(shù)據(jù)。讀取UART0.status.rxfifo_cnt該寄存器里面的值就是這一幀的數(shù)據(jù)包長(zhǎng)度值
|