美文网首页物联网loT从业者物联网相关技术研究
ESP8266学习笔记(9)——UART接口使用

ESP8266学习笔记(9)——UART接口使用

作者: Leung_ManWah | 来源:发表于2019-02-16 17:55 被阅读1次

    一、简介

    ESP8266 有两个UART。UART0有TX、RX作为系统的打印信息输出接口数据收发口,而UART1只有TX,作为打印信息输出接口(调试用)。

    二、UART0接收

    2.1 相关函数

    /driver/uart.c中,

    2.1.1 uart0_rx_intr_handler

    用于UART0中断处理,用户可在该函数内添加对接收到数据包的处理。

    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;//UartDev.buff_uart_no;
        uint8 fifo_len = 0;
        uint8 buf_idx = 0;
        uint8 temp,cnt;
        //RcvMsgBuff *pRxBuff = (RcvMsgBuff *)para;
    
        /* 注意: */
        // 不要在中断处理函数中调用带有 "ICACHE_FLASH_ATTR" 宏的函数,否则将引起异常。
        /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
        /*IF NOT , POST AN EVENT AND PROCESS IN SYSTEM TASK */
    
        // 接收帧错误中断
        if(UART_FRM_ERR_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_FRM_ERR_INT_ST))
        {
            WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_FRM_ERR_INT_CLR);    // 清除中断寄存器的 帧错误位
        }
        // 接收满中断 FULL
        else if(UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST))
        {
            uart_rx_intr_disable(UART0);                                    // 1. 接收中断禁用,用于不再接受数据,因为现在处于处理数据中
            WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR);  // 2.清除中断寄存器的 接收 FULL 位
            system_os_post(uart_recvTaskPrio, 0, 0);                        // 3.向任务函数发送消息
        }
        // 接收超时中断 TOUT
        else if(UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST))
        {
            uart_rx_intr_disable(UART0);                                    // 1. 接收中断禁用,用于不再接受数据,因为现在处于处理数据中
            WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_TOUT_INT_CLR);  // 2.清除中断寄存器的 接收超时中断位
            system_os_post(uart_recvTaskPrio, 0, 0);                        // 3.向任务函数发送消息
        }
        // 发送 FIFO 空中断
        else if(UART_TXFIFO_EMPTY_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_TXFIFO_EMPTY_INT_ST))
        {
            /* to output uart data from uart buffer directly in empty interrupt handler*/
            /*instead of processing in system event, in order not to wait for current task/function to quit */
            /*ATTENTION:*/
            /*IN NON-OS VERSION SDK, DO NOT USE "ICACHE_FLASH_ATTR" FUNCTIONS IN THE WHOLE HANDLER PROCESS*/
            /*ALL THE FUNCTIONS CALLED IN INTERRUPT HANDLER MUST BE DECLARED IN RAM */
            CLEAR_PERI_REG_MASK(UART_INT_ENA(UART0), UART_TXFIFO_EMPTY_INT_ENA);// 清楚中断标志
            //system_os_post(uart_recvTaskPrio, 1, 0);
            WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_TXFIFO_EMPTY_INT_CLR);  // 清除中断寄存器的 发送 FIFO 空中断位
        }
        // 接收溢出中断
        else if(UART_RXFIFO_OVF_INT_ST  == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_OVF_INT_ST))
        {
            WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_OVF_INT_CLR); // 清除中断寄存器的 接收溢出中断位
        }
    }
    

    2.1.2 uart_recvTask

    上述uart0_rx_intr_handler函数中,在满中断和超时中断时,system_os_post发送了一个信号,于是进入uart_recvTask函数。

    LOCAL void ICACHE_FLASH_ATTR
    uart_recvTask(os_event_t *events)
    {
        if(events->sig == 0)
        {
            // 1.从先进先出通道 FIFO 读取接收到的数据长度
            uint8 fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
    
            uint8 d_tmp = 0;
            uint8 idx = 0;
            // 2.定义一个临时接收的数据区
            uint8 uartRxBuffer[256] = {0};
    
            // 3. 赋值给临时数组
            for(idx = 0; idx < fifo_len; idx++) 
            {
                d_tmp = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;   // 根据数据长度一个一个读取数据
                uartRxBuffer[idx] = d_tmp;                        // 赋值
            }
                  
            // 4.做你自己的事情,uartRxBuffer[]数组就是接收到的数据
            {
                ...
                ...
            }
    
            // 清除中断寄存器的 满中断位 或 超时中断位
            WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);  
            // 5.UART0接收中断使能
            uart_rx_intr_enable(UART0);
        }
        else if(events->sig == 1)
        {
        }
    }
    

    2.2 使用流程

    ①串口初始化
    uart_init(115200, 115200); // 设置串口0和串口1的波特率
    ②串口中断处理
    uart0_rx_intr_handler(void *para); // UART0 中断处理函数,在此用作中断触发类型的判断
    主要修改下面这个函数
    uart_recvTask(os_event_t *events) // UART0 中断处理函数,在此用作中断接收数据处理

    三、UART0发送

    3.1 相关函数

    3.2 使用流程

    ①串口初始化
    uart_init(115200, 115200); // 设置串口0和串口1的波特率
    ②串口发送数据
    uart0_tx_buffer(void *buf, uint16 len); // UART0 发送数据函数

    四、UART1发送

    4.1 相关函数

    /driver/uart.c中,

    4.1.1 UART_SetPrintPort

    用于设置打印调试信息的串口

    void ICACHE_FLASH_ATTR
    UART_SetPrintPort(uint8 uart_no)
    {
        if(uart_no==1){
            os_install_putc1(uart1_write_char);
        }else{
            /*option 1: do not wait if uart fifo is full,drop current character*/
            os_install_putc1(uart0_write_char_no_wait);
        /*option 2: wait for a while if uart fifo is full*/
        os_install_putc1(uart0_write_char);
        }
    }
    

    4.1.2 uart1_sendStr_no_wait

    用于串口1输出一串字符

    void uart1_sendStr_no_wait(const char *str)
    {
        while(*str){
            uart_tx_one_char_no_wait(UART1, *str++);
        }
    }
    

    3.2 使用流程

    ①串口初始化
    uart_init(115200, 115200); // 设置串口0和串口1的波特率
    ②设置调试串口
    UART_SetPrintPort(UART1); // 使用串口1打印调试信息
    ③打印调试信息
    os_printf()uart1_sendStr_no_wait()


    • 由 Leung 写于 2019 年 2 月 16 日

    • 参考:Esp8266 进阶之路25【高级篇】深聊下esp8266的串口 Uart 通讯中断编程
        ESP8266 Non-OS SDK API参考[zj6w]
        ESP8266 技术参考[zj5o]

    相关文章

      网友评论

        本文标题:ESP8266学习笔记(9)——UART接口使用

        本文链接:https://www.haomeiwen.com/subject/adobeqtx.html