ESP8266 —— 高效的串口接收模板

本代碼是在ESP8266_RTOS_SDK_V1.5.0基礎上修改的,ESP8266_RTOS_SDK_V1.5.0在哪兒能下載,請在我博客裏尋找下載鏈接~


#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "driver/uart.h"

#include "user_smartconfig.h"
#include "user_config.h"
//*********************************************************
//martin add

#define RX_BUFF_SIZE    0x100
#define TX_BUFF_SIZE    100

uint8 UartRxBuffer1[RX_BUFF_SIZE];
u8 RxCounter1 = 0;
u8 Uart1_Rx_Sta = 0;

LOCAL STATUS uart_tx_one_char(uint8 uart, uint8 TxChar) {
	while (true) {
		uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart))
				& (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);

		if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) {
			break;
		}
	}

	WRITE_PERI_REG(UART_FIFO(uart), TxChar);
	return OK;
}

void ICACHE_FLASH_ATTR uart0_putchar(char c) {
	uart_tx_one_char(UART0, c);
}

void ICACHE_FLASH_ATTR uart1_putchar(char c) {
	uart_tx_one_char(UART1, c);
}

LOCAL void uart1_write_char(char c) {
	if (c == '\n') {
		uart_tx_one_char(UART1, '\r');
		uart_tx_one_char(UART1, '\n');
	} else if (c == '\r') {
	} else {
		uart_tx_one_char(UART1, c);
	}
}

LOCAL void uart0_write_char(char c) {
	if (c == '\n') {
		uart_tx_one_char(UART0, '\r');
		uart_tx_one_char(UART0, '\n');
	} else if (c == '\r') {
	} else {
		uart_tx_one_char(UART0, c);
	}
}

//=================================================================

void UART_SetWordLength(UART_Port uart_no, UART_WordLength len) {
	SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_BIT_NUM, len, UART_BIT_NUM_S);
}

void UART_SetStopBits(UART_Port uart_no, UART_StopBits bit_num) {
	SET_PERI_REG_BITS(UART_CONF0(uart_no), UART_STOP_BIT_NUM, bit_num,
			UART_STOP_BIT_NUM_S);
}

void UART_SetLineInverse(UART_Port uart_no, UART_LineLevelInverse inverse_mask) {
	CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_LINE_INV_MASK);
	SET_PERI_REG_MASK(UART_CONF0(uart_no), inverse_mask);
}

void UART_SetParity(UART_Port uart_no, UART_ParityMode Parity_mode) {
	CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_PARITY | UART_PARITY_EN);

	if (Parity_mode == USART_Parity_None) {
	} else {
		SET_PERI_REG_MASK(UART_CONF0(uart_no), Parity_mode | UART_PARITY_EN);
	}
}

void UART_SetBaudrate(UART_Port uart_no, uint32 baud_rate) {
	uart_div_modify(uart_no, UART_CLK_FREQ / baud_rate);
}

//only when USART_HardwareFlowControl_RTS is set , will the rx_thresh value be set.
void UART_SetFlowCtrl(UART_Port uart_no, UART_HwFlowCtrl flow_ctrl,
		uint8 rx_thresh) {
	if (flow_ctrl & USART_HardwareFlowControl_RTS) {
		PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS);
		SET_PERI_REG_BITS(UART_CONF1(uart_no), UART_RX_FLOW_THRHD, rx_thresh,
				UART_RX_FLOW_THRHD_S);
		SET_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
	} else {
		CLEAR_PERI_REG_MASK(UART_CONF1(uart_no), UART_RX_FLOW_EN);
	}

	if (flow_ctrl & USART_HardwareFlowControl_CTS) {
		PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_UART0_CTS);
		SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
	} else {
		CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_TX_FLOW_EN);
	}
}

void UART_WaitTxFifoEmpty(UART_Port uart_no) //do not use if tx flow control enabled
{
	while (READ_PERI_REG(UART_STATUS(uart_no))
			& (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S))
		;
}

void UART_ResetFifo(UART_Port uart_no) {
	SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
	CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST);
}

void UART_ClearIntrStatus(UART_Port uart_no, uint32 clr_mask) {
	WRITE_PERI_REG(UART_INT_CLR(uart_no), clr_mask);
}

void UART_SetIntrEna(UART_Port uart_no, uint32 ena_mask) {
	SET_PERI_REG_MASK(UART_INT_ENA(uart_no), ena_mask);
}

void UART_intr_handler_register(void *fn, void *arg) {
	_xt_isr_attach(ETS_UART_INUM, fn, arg);
}

void UART_SetPrintPort(UART_Port uart_no) {
	if (uart_no == 1) {
		os_install_putc1(uart1_write_char);
	} else {
		os_install_putc1(uart0_write_char);
	}
}

void UART_ParamConfig(UART_Port uart_no, UART_ConfigTypeDef *pUARTConfig) {
	if (uart_no == UART1) {
		PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK);
	} else {
		PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
		PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD);
		PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD);
	}

	UART_SetFlowCtrl(uart_no, pUARTConfig->flow_ctrl,
			pUARTConfig->UART_RxFlowThresh);
	UART_SetBaudrate(uart_no, pUARTConfig->baud_rate);

	WRITE_PERI_REG(UART_CONF0(uart_no),
			((pUARTConfig->parity == USART_Parity_None) ? 0x0 : (UART_PARITY_EN | pUARTConfig->parity)) | (pUARTConfig->stop_bits << UART_STOP_BIT_NUM_S) | (pUARTConfig->data_bits << UART_BIT_NUM_S) | ((pUARTConfig->flow_ctrl & USART_HardwareFlowControl_CTS) ? UART_TX_FLOW_EN : 0x0) | pUARTConfig->UART_InverseMask);

	UART_ResetFifo(uart_no);
}

void UART_IntrConfig(UART_Port uart_no, UART_IntrConfTypeDef *pUARTIntrConf) {

	uint32 reg_val = 0;
	UART_ClearIntrStatus(uart_no, UART_INTR_MASK);
	reg_val = READ_PERI_REG(UART_CONF1(uart_no))
			& ~((UART_RX_FLOW_THRHD << UART_RX_FLOW_THRHD_S) | UART_RX_FLOW_EN);

	reg_val |= (
			(pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_TOUT_INT_ENA) ?
					((((pUARTIntrConf->UART_RX_TimeOutIntrThresh)
							& UART_RX_TOUT_THRHD) << UART_RX_TOUT_THRHD_S)
							| UART_RX_TOUT_EN) :
					0);

	reg_val |= (
			(pUARTIntrConf->UART_IntrEnMask & UART_RXFIFO_FULL_INT_ENA) ?
					(((pUARTIntrConf->UART_RX_FifoFullIntrThresh)
							& UART_RXFIFO_FULL_THRHD)
							<< UART_RXFIFO_FULL_THRHD_S) :
					0);

	reg_val |= (
			(pUARTIntrConf->UART_IntrEnMask & UART_TXFIFO_EMPTY_INT_ENA) ?
					(((pUARTIntrConf->UART_TX_FifoEmptyIntrThresh)
							& UART_TXFIFO_EMPTY_THRHD)
							<< UART_TXFIFO_EMPTY_THRHD_S) :
					0);

	WRITE_PERI_REG(UART_CONF1(uart_no), reg_val);
	CLEAR_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_INTR_MASK);
	SET_PERI_REG_MASK(UART_INT_ENA(uart_no), pUARTIntrConf->UART_IntrEnMask);
}

LOCAL void uart0_rx_intr_handler(void *para) {
	/* uart0 and uart1 intr combine togther, when interrupt occur, see reg 0x3ff20020, bit2, bit0 represents
	 * uart1 and uart0 respectively
	 */
	uint8 RcvChar;
	uint8 uart_no = UART0;
	uint8 fifo_len = 0;
	uint8 buf_idx = 0;
	uint8 fifo_tmp[128] = { 0 };
	uint8 val;

	os_event_t e;
	portBASE_TYPE xHigherPriorityTaskWoken;

	uint32 uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no));

	while (uart_intr_status != 0x0) {

		//os_printf("\n\n*********** uart_intr_status=0x%x ***********\n",
		//		uart_intr_status);

		if (UART_FRM_ERR_INT_ST == (uart_intr_status & UART_FRM_ERR_INT_ST)) {
			//printf("FRM_ERR\r\n");
			WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);
		} else if (UART_RXFIFO_FULL_INT_ST
				== (uart_intr_status & UART_RXFIFO_FULL_INT_ST)) {
			//os_printf("\nuart_isr()->full\r\n");
			fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)
					& UART_RXFIFO_CNT;
			buf_idx = 0;

			while (buf_idx < fifo_len) {
				uart_tx_one_char(UART0, READ_PERI_REG(UART_FIFO(UART0)) & 0xFF);
				buf_idx++;
			}

			WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);
		} else if (UART_RXFIFO_TOUT_INT_ST
				== (uart_intr_status & UART_RXFIFO_TOUT_INT_ST)) {
			os_printf("uart_isr()->time out\n");
			fifo_len = (READ_PERI_REG(UART_STATUS(UART0)) >> UART_RXFIFO_CNT_S)
					& UART_RXFIFO_CNT;
			buf_idx = 0;

			while (buf_idx < fifo_len) {
				RcvChar = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
				UartRxBuffer1[buf_idx] = RcvChar;
				buf_idx++;
			}
			val = UartRxBuffer1[4] - '0';
			if (val <= 3) {
				val = UartRxBuffer1[5] - '0';
				if ((UartRxBuffer1[1] == 's') && (UartRxBuffer1[2] == 'm')
						&& (UartRxBuffer1[3] == 't'))
					smartconfig_start(smartconfig_done);
			}
			WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
		} else if (UART_TXFIFO_EMPTY_INT_ST
				== (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST)) {
			//os_printf("uart_isr()->empty\n\r");
			WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);
			CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);
		} else {
			//skip
		}
		RxCounter1 = fifo_len;
		if (RxCounter1 > 0) {
			Uart1_Rx_Sta = 1;

			// 2019年4月25日19:55:34:設置爲串口接收溢出時就將數據傳到隊列
			e.event = UART_EVENT_RX_CHAR;
			e.param = RxCounter1;
			e.pdata = UartRxBuffer1;
			xQueueSendFromISR(xQueueUart, (void * )&e,
					&xHigherPriorityTaskWoken); // 將數據發送到隊列一次只有一次字符
			portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
		}
	}
}

void uart_init_new(void) {
	UART_WaitTxFifoEmpty(UART0);
	UART_WaitTxFifoEmpty(UART1);
	UART_ConfigTypeDef uart_config;

	uart_config.baud_rate = BIT_RATE_74880;
	uart_config.data_bits = UART_WordLength_8b;
	uart_config.parity = USART_Parity_None;
	uart_config.stop_bits = USART_StopBits_1;
	uart_config.flow_ctrl = USART_HardwareFlowControl_None;
	uart_config.UART_RxFlowThresh = 120;
	uart_config.UART_InverseMask = UART_None_Inverse;
	UART_ParamConfig(UART0, &uart_config);

	UART_IntrConfTypeDef uart_intr;
	uart_intr.UART_IntrEnMask = UART_RXFIFO_TOUT_INT_ENA | UART_FRM_ERR_INT_ENA
			| UART_RXFIFO_FULL_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA;
	uart_intr.UART_RX_FifoFullIntrThresh = 120;
	uart_intr.UART_RX_TimeOutIntrThresh = 5;
	uart_intr.UART_TX_FifoEmptyIntrThresh = 20;
	UART_IntrConfig(UART0, &uart_intr);

	UART_SetPrintPort(UART0);
	UART_intr_handler_register(uart0_rx_intr_handler, NULL);
	ETS_UART_INTR_ENABLE();

}

以上代碼我主要修改的地方就是 uart0_rx_intr_handler() 函數,當接收到有效的一幀數據我就打包到串口解析任務裏去:

xQueueSendFromISR(xQueueUart, (void * )&e,&xHigherPriorityTaskWoken); 

當串口接收到一幀數據後,通知串口解析任務,我們來看看串口接收任務是怎麼寫的:


LOCAL ICACHE_FLASH_ATTR void uart_decode_task(void * pvParameters) {
	os_event_t e;
	xQueueUart = xQueueCreate(10, sizeof(os_event_t));
	for (;;) {
		if (xQueueReceive(xQueueUart, (void * )&e,
				(portTickType)portMAX_DELAY)) {
			switch (e.event) {
			case UART_EVENT_RX_CHAR:
				os_printf("uart_decode_task RecvLength=%d\n", e.param);
				e.pdata[e.param] = '\0';
				os_printf("Conten:%s\n", e.pdata);
                break;

			default:
				break;
			}
		}
	}

	vTaskDelete(NULL);
}
xQueueHandle xQueueUart;

void ICACHE_FLASH_ATTR
user_init(void) {

    /* 串口接收任務 */
    xTaskCreate(uart_decode_task, "uart_decode", 512, NULL,
            tskIDLE_PRIORITY + 3, NULL);

}

 os_event_t 類型定義我就直接截圖了:

總結: sdk裏提供的庫已經很厲害了,但是對於RTOS的SDK來說一直掃描是否有新的數據這個效率太低了,最高效的辦法就是用通知!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章