赞
踩
从阿里物联网套件上下载ESP8266SDK,然后构建ESP8266开发环境;我个人还是喜欢Oracle VM Virtual Box 安装ESP8266_Lubuntu。然后设置一个共享文件夹,就可以在linux环境下编译然后在windows环境下下载了。
阿里云的这个SDK是RTOS版本的,它的OS是FreeRTOS,而我没有学过FreeRTOS;还好我学过uCosIII,我估计实时操作系统应该实现的机制都是差不多的吧。
从SDK的串口uart.c中可以看到,例程里面它用到了消息队列的方法,把串口中断服务函数中的数据传到任务里面去。
首先定义一个事件结构体:
结构里面的event成员就可以设置枚举中的事件,而para就把串口传来的字符串数据放进去。
typedef _os_event_t_ {
uint32 event;
uint8* para;
} os_event_;
并且枚举一些可供选择的事件名:
enum {
UART_EVENT_RX_CHAR,
UART_EVENT_RX_MAX
};
作为设置ESP8266 RTOS版本的串口中断配置,第一步当然是配置串口中断函数(记得改名字)
void
user_uart_init(void)
{
UART_WaitTxFifoEmpty(UART0);
UART_WaitTxFifoEmpty(UART1);
UART_ConfigTypeDef uart_config;
uart_config.baud_rate = BIT_RATE_9600;
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 = 100; // 设置100个字符就溢出
uart_intr.UART_RX_TimeOutIntrThresh = 10;
uart_intr.UART_TX_FifoEmptyIntrThresh = 20;
UART_IntrConfig(UART0, &uart_intr);
UART_SetPrintPort(UART0);
UART_intr_handler_register(user_uart0_rx_intr_handler, NULL); // 注册串口中断函数处理函数
ETS_UART_INTR_ENABLE();
// 中断设置完成以后就马上初始化队列和创建串口处理任务
xQueueUart = xQueueCreate(32, sizeof(os_event_t));
// xTaskCreate(user_uart_task, (uint8 const *)"uTask", 512, NULL, 5, &xUartTaskHandle);
}

第二步就需要定义中断服务函数即发送消息的地方:(名字要一致)
LOCAL void
user_uart0_rx_intr_handler(void *para)
{
os_evet_t e;
uint8 RcvChar;
uint8 uart_no = UART0;//UartDev.buff_uart_no;
uint8 fifo_len = 0;
uint8 buf_idx = 0;
uint8 fifo_tmp[128] = {0};
portBASE_TYPE xHigherPriorityTaskWoken;
uint32 uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
while (uart_intr_status != 0x0) {
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)) {
printf("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)) {
printf("tout\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++;
}*/
while (buf_idx < fifo_len) {
fifo_tmp[buf_idx] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; // 把串口fifo里面的数据循环取出来并放到字符数组里面去
buf_idx++;
}
fifo_tmp[buf_idx] = '\0';
WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);
e.event = UART_EVENT_RX_CHAR; // 设置好事件,便于任务查看
e.para = fifo_tmp; // 把串口接收到的数据放到结构体中去
// 使用带串口中断保护的消息队列发送函数,这个函数只能用于中断服务函数中,其他地方绝对不能使用!!
xQueueSendFromISR(xQueueUart, (void *)&e, &xHigherPriorityTaskWoken);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
} else if (UART_TXFIFO_EMPTY_INT_ST == (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST)) {
printf("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
}
uart_intr_status = READ_PERI_REG(UART_INT_ST(uart_no)) ;
}
}

然后在任务里面就不停的查询事件
LOCAL void
uart_task(void *pvParameters)
{
os_event_t e;
// 任务就不停的查看事件
for (;;) {
if (xQueueReceive(xQueueUart, (void *)&e, (portTickType)portMAX_DELAY)) {
switch (e.event) {
case UART_EVENT_RX_CHAR:
printf("%s", e.param);
break;
default:
break;
}
}
}
vTaskDelete(NULL);
}

总结:
这种方法真的是很好,当配置好串口中断,串口来数据之后就马上执行串口中断服务函数;在中断服务函数中设置事件,让任务进行处理。最后,要提醒的是:uart.c中那些例程是不能用的,需要重新在其他地方编写而且就算是偷懒,照抄也要把中断的配置函数(void uart_init_new(void))和中断服务函数(LOCAL void uart0_rx_intr_handler(void *para))的名字改变!!切记啊,不然你会发现你写的程序你已经失去了对它的控制!!!无穷的“tout”和“full”谁遇到谁知道!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。