ESP8266学习之NONOS MQTT DEMO 增加串口处理程序

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lys_xm/article/details/82495262

项目背景

一个温控器项目,可以本地控制空调,也可微信远程控制。其中,远程控制为:微信扫码进入控制页面,该页面实现对空调状态的实时显示和控制功能。页面也服务器之间采用websocket协议通信,空调与服务器通过ESP8266进行无线通信,采用MQTT协议,实现实时双向通信。因为ESP8266与空调控制器之间采用串口uart通信,所以需要给官方提供的mqtt demo里增加串口处理程序。

串口介绍

ESP8266有两个串口,UART0和UART1。他们各有一个128Bytes的硬件FIFO,读写FIFO都在同一个地址操作。UART0一般用于通信,UART1只有TX功能,一般用于打印日志。但是默认情况下,os_print()函数使用的是UART0,可在uart_init中进行修改

另外,模块刚上电时会打印一串乱码。这是因为这期间的ESP8266的串口波特率(115200)是跟外部晶振相关的,程序默认晶振为40M。所以如果你使用的外部晶振是26M,则应该调整串口工具波特率为26*(115200/40)=74880 。

增加串口处理程序

下图是官方下载的demo结构,红框里的文件夹driver_lib是官方提供的各种驱动程序,我们使用的串口程序也在里面

 

打开driver_lib文件夹后,README.md就是它的使用方法

# driver_lib
## method 1
Generate libdriver.a in SDK/lib, in driver_lib folder, run:
 
    ./make_lib.sh driver

## method 2
* STEP 1: 
    
    Copy driver folder to your project sub-folder, such as app folder. Unused drivers can be removed in your project.

* STEP 2: 

    Modify Makefile in app folder.

    1). Search SUBDIRS, add driver as subdir, such as:

        SUBDIRS = user driver

    2). Search COMPONENTS_eagle.app.v6, add libdriver.a, such as:

        COMPONENTS_eagle.app.v6 = user/libuser.a driver/libdriver.a

我们采用方法2: 1)复制driver文件夹到自己的工程子文件夹里   2)修改app的makefile文件

上图红框内容为makefile增加内容

这样,就添加成功了。另外,uart.h和uart_register.h可能也需要从driver_lib文件夹里复制过来,不然有些宏可能会没有定义。

 

串口工作流程

1. 接收数据:模块串口接收到数据时,会先填充到FIFO里。每当FIFO接收到的数据时,都会产生中断,中断处理程序为uart0_rx_intr_handler(uart_init -> uart_config->ETS_UART_INTR_ATTACH(uart0_rx_intr_handler,  &(UartDev.rcv_buff))进行注册)。在中断处理程序中,判断接收的数据长度或者接收时间是否超过阈值。如果超过,则给接收任务(uart_init 里进行注册)发送信号量:system_os_post(uart_recvTaskPrio, 0, 0)。uart_recvTask接收到信号量后,就开始进行处理:

这里,宏UART_BUFF_EN非常重要,如果该宏值为0,则执行#else后面的程序,直接打印出来。如果我们需要处理,则需修改UART_BUFF_EN的值为1,进入Uart_rx_buff_enq()。在Uart_rx_buff_enq函数里主要的功能是把接收到的数据保存到pRxBuffer里。然后我们就可以对pRxBuffer进行解析来处理接收的内容了。(pRxBuffer是个环形缓存)

因为个人觉得Uart_rx_buff_enq这个函数写得非常优雅,所以特地放上来和学习一下,增加了注释:

//enqueue data from uart fifo to rx buffer
void Uart_rx_buff_enq(void)
{
    uint8 fifo_len = 0, buf_idx = 0,loop;
    ETSParam par = 0;
    uint8 fifo_data;
    uint8* tail = (pRxBuffer->pUartBuff + pRxBuffer->UartBuffSize);
    fifo_len = (READ_PERI_REG(UART_STATUS(UART0))>>UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT;
    
    //如果pRxBuffer的剩余空间不够,则只取pRxBuffer->Space
    if(fifo_len > pRxBuffer->Space) {
        buf_idx = pRxBuffer->Space;
    }else{
        buf_idx = fifo_len;
    }
    
    loop = buf_idx;
    while (loop--) {
        *(pRxBuffer->pInPos++) = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF;
        if (pRxBuffer->pInPos == tail) {
                pRxBuffer->pInPos = pRxBuffer->pUartBuff;
        }            
    }
    
    fifo_len -= buf_idx;
    //这里是当 fifo_len > pRxBuffer->Space, 释放fifo里没有被接收的数据
    //如果fifo_len < pRxBuffer->Space,则fifo_len -= buf_idx == 0,则不进行下面的循环
    while (fifo_len--) {
        fifo_data = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; // discard data
    }
    
    pRxBuffer->Space -= buf_idx ;
    par = buf_idx;

    //这里给自己的任务发送信号量,进行串口接收后续处理
    if(system_os_post(1, 1, 0) != TRUE) {
        //os_printf("post fail!!!\n\r");
    }

    //中断信号清除和重新使能
    WRITE_PERI_REG(UART_INT_CLR(UART0), UART_RXFIFO_FULL_INT_CLR |     
    UART_RXFIFO_TOUT_INT_CLR);
    uart_rx_intr_enable(UART0);
}

2. 发送数据:这里跟接收数据一样分析,省略。。。

 

 

 

 

 

 

 

 

展开阅读全文

没有更多推荐了,返回首页