| 之前寫(xiě)過(guò)一篇關(guān)于esp32串口的文章:ESP32中斷方式操作串口,但是不夠詳細(xì),這篇進(jìn)行更加細(xì)節(jié)的描述。 因?yàn)槲疫@個(gè)代碼是基于micropython esp32進(jìn)行二次開(kāi)發(fā)的,需要改造原有micropython對(duì)串口的配置。當(dāng)然這些代碼直接用ESP32-IDF開(kāi)發(fā)也沒(méi)問(wèn)題。 先看下Micropython對(duì)ESP32uart0的串口配置:對(duì)應(yīng)文件為:/micropython/ports/esp32/uart.c  該文件初始化打開(kāi)了串口接收中斷,但是沒(méi)有安裝串口驅(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ù)里面打開(kāi)了兩個(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ì)打開(kāi)兩個(gè)中斷源:rxfifo接收滿中斷,rxfifo超時(shí)中斷(默認(rèn)超時(shí)時(shí)間為10個(gè)byte)最后一步設(shè)置接收超時(shí)中斷時(shí)間可以省略,因?yàn)樵谏弦徊揭呀?jīng)默認(rèn)打開(kāi),并且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)打開(kāi)了串口中斷,針對(duì)接收有兩個(gè)中斷源:rxfifo滿中斷  rx接收超時(shí)中斷。默認(rèn)rxfifo的深度為128byte,所以只要不連續(xù)發(fā)超過(guò)128個(gè)byte都不會(huì)觸發(fā)fifo滿中斷。當(dāng)發(fā)送完一幀數(shù)據(jù),只要后面空閑的時(shí)間超過(guò)設(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)度值 
 |