欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

CC2640R2F开发之:UART串口收发&TI-RTOS任务创建(二)

程序员文章站 2022-03-11 20:42:41
对于蓝牙的数据传输来说UART串口起到至关重要的作用,本篇将介绍CC2640R2F的UART串口使用方法,结合TI-RTOS操作系统与RingBuf机制完成串口的连续收发。...

开发一款蓝牙应用,其实不仅仅是蓝牙,其他的程序也是如此,串口在整个项目中都会占据重要的地位,串口能完成人与芯片的交互。所以在开发项目中首先完成串口部分就显得很重要(当然如果只是开发一个流水灯那大可不必)。
CC2640R2F的串口使用还是很方便的,这得益于TI 的生态做的好,TI 将串口、ADC、SPI、I2C等底层硬件驱动做成库,直接供用户使用,减少了很多的繁琐的事,但是CC2640R2F的串口有一个明显的缺点就是不支持串口DMA,着对于高波特率有需求的项目可能会产生较大影响。
在硬件上来说CC2640R2F的引脚是可以任意映射的,你可以根据需要将它们映射到对应的位置。在软件上来说串口的操作都是基于一个handle句柄值来进行读、写、控制等操作的。
串口使用流程大致包扩这几个过程:1、初始化硬件;2、设置参数;3、获得串口handle;4、基于handle进行读、写、控制等操作。如果想要提升串口的性能,那么还需要使用队列或者RingBuf机制,本文基于TI-RTOS系统和RingBuf来演示。
先上图:
CC2640R2F开发之:UART串口收发&TI-RTOS任务创建(二)
说明:
1、初始化硬件:CC2640R2F的串口已经在SDK配置好了,如果不更改引脚映射建议保持默认。
2、设置参数:根据自己的需要设置波特率、数据位、停止位、校验位。本文是基于回调的方式处理串口数据,回调函数接收串口数据的好处是可以与TI-RTOS任务系统配合,更好的处理数据流。
3、在设置好参数之后,调用open函数获取一个串口handle,后续的串口操作就是基于这个handle进行。
4、读写操作,这是核心,尤其是当对数据的速率以及连续性有要求的时候,运用RingBuf机制和任务事件来处理就要稳定很多。(PS:尤其是当数据量过大、速率过快的时候,可能会导致协议栈处理不过来而丢包或者死机。原因:协议栈的缓存有一定的大小,当串口过来的数据量过打速率过快时协议栈缓存很快就满了,这个缓存大小大概就是:最大连接数 x (MAX_PDU_SIZE - 4),也就是4 x 251)。
代码部分:
1)、配置串口,主要就是两个回调函数的设置,CC2640R2F的串口有一个很好的功能叫部分返回,它会自动的判断超时,并读取串口数据。
定义串口参数,为什么把 UART_MAX_READ_SIZE 定义为251个字节呢?


#define UART_MAX_READ_SIZE       251

typedef struct
{
    size_t       size;
    uint8_t      buf[UART_MAX_READ_SIZE];
}recv_T;
/*uart */
static   UART_Handle uartHandle = NULL;
recv_T   uartRead;
bool     wtEnable;
/*ringbuff*/
static uint8_t RingBufferData[2000];
RingBuf_Object RinfBuferObj;
uint8_t writebuf[UART_MAX_READ_SIZE];
配置串口
/*init uart*/
static void ecoInitUart(void)
{
    // Initialize UART
    UART_Params uartParams;
    UART_init();

    // Open UART in callback mode for both read and write
    UART_Params_init(&uartParams);
    uartParams.writeDataMode  = UART_DATA_BINARY;
    uartParams.readDataMode   = UART_DATA_BINARY;
    uartParams.readReturnMode = UART_RETURN_FULL;
    uartParams.readMode       = UART_MODE_CALLBACK;
    uartParams.writeMode      = UART_MODE_CALLBACK;
    uartParams.readCallback   = uartReadCallback;
    uartParams.writeCallback  = uartWriteCallback;
    uartParams.readEcho       = UART_ECHO_OFF;
    uartParams.baudRate       = 115200;
    uartParams.stopBits       = UART_STOP_ONE;
    uartParams.parityType     = UART_PAR_NONE;
    uartParams.dataLength     = UART_LEN_8;
    //open Board_UART0 ,get handle
    uartHandle = UART_open(Board_UART0, &uartParams);

    if (uartHandle == NULL)
    {
      // UART_open() failed
      while (1);
    }

    // Enable partial return
    UART_control(uartHandle, UARTCC26XX_CMD_RETURN_PARTIAL_ENABLE, NULL);
    //start receive data from RX
    UART_read(uartHandle, uartRead.buf, sizeof(uartRead.buf));
}
/*set uart receive callback*/
static void uartReadCallback(UART_Handle handle, void *rxBuf, size_t size)
{
    uartRead.size = size;
    Event_post(ecoEventHd,ECO_UART_RECV_EVT);
}
/*set uart write callback*/
static void uartWriteCallback(UART_Handle handle, void *writeBuf, size_t size)
{
    if(wtEnable)
    {
        size_t size = RingBuf_getCount(&RinfBuferObj);
        if(size > 0)
        {
            Event_post(ecoEventHd,ECO_MOVE_DATA_EVT);
        }
        else
        {
            wtEnable = false;
        }
    }
}
/**/
void ecoWriteData(unsigned char *buf,unsigned short size)
{
    UART_write(uartHandle,buf,size);
}

2)、TI-RTOS任务创建。TI-RTOS任务的核心是事件,通过pend、wait、post就能处理一个任务中的不同事件。
首先创建任务参数:

    /*event cfg*/
#define ECO_UART_RECV_EVT        Event_Id_29
#define ECO_UART_WRITE_EVT       Event_Id_28
#define ECO_MOVE_DATA_EVT        Event_Id_27

#define ET_ALL_EVENTS            (ECO_UART_RECV_EVT    |\
                                  ECO_UART_WRITE_EVT   |\
                                  ECO_MOVE_DATA_EVT)

/*task cfg*/
#ifndef ET_TASK_STACK_SIZE
#define ET_TASK_STACK_SIZE       1024    //根据自己的需要更改任务堆栈大小
#endif
#ifndef ET_TASK_PRIORITY
#define ET_TASK_PRIORITY         2      //设置任务等级的时候需要注意不要和别的任务重复
#endif
/*event variables*/
Event_Struct ecoEvent;
static Event_Handle ecoEventHd;

/*task variables*/
uint8_t ecoTaskStack[ET_TASK_STACK_SIZE];
Task_Struct ecoTask;

初始化任务:

static void ecoTaskInit(void)
{
    /*event init*/
    Event_Params ecoEvtParam;
    Event_Params_init(&ecoEvtParam);
    Event_construct(&ecoEvent,&ecoEvtParam);
    ecoEventHd = Event_handle(&ecoEvent);

    ecoInitUart();

    RingBuf_construct(&RinfBuferObj,&RingBufferData[0],sizeof(RingBufferData));

}

创建任务函数:

static void ecoTaskFunc(UArg arg0, UArg arg1)
{
    ecoTaskInit();
    // Application main loop
    for(;;)
    {
        uint32_t events;
        events = Event_pend(ecoEventHd, Event_Id_NONE, ET_ALL_EVENTS,
                            ICALL_TIMEOUT_FOREVER);
        if(events & ECO_UART_RECV_EVT)
        {
            handleRecvEvt();
        }
        if(events & ECO_MOVE_DATA_EVT)
        {
            handleMoveEvt();
        }
    }
}

创建任务:

void ecoTaskCreat(void)
{
    Task_Params taskParams;
    // Configure task
    Task_Params_init(&taskParams);
    taskParams.stack = ecoTaskStack;
    taskParams.stackSize = ET_TASK_STACK_SIZE;
    taskParams.priority = ET_TASK_PRIORITY;

    Task_construct(&ecoTask, ecoTaskFunc, &taskParams, NULL);
}

处理事件:

static void handleRecvEvt(void)
{
    size_t i;
    for( i=0;i<uartRead.size;i++)
    {
        if(RingBuf_put(&RinfBuferObj,uartRead.buf[i]) < 0)
        {
            break;
        }
    }
    if(wtEnable == false)
    {
        wtEnable = true;
        Event_post(ecoEventHd,ECO_MOVE_DATA_EVT);
    }
    UART_read(uartHandle, uartRead.buf, sizeof(uartRead.buf));
}

static void handleMoveEvt(void)
{
    size_t size = RingBuf_getCount(&RinfBuferObj);
    size_t i;
    if(size > 0)
    {
        for(i=0;i<sizeof(writebuf);i++)
        {
            if(RingBuf_get(&RinfBuferObj,writebuf+i) < 0)
            {
                break;
            }
        }
        ecoWriteData(writebuf,i);
    }
}

由于本文并没有涉及到数据流向BLE的部分,所以就仅仅将串口RX接收到的数据通过串口TX再打印出来。
实测40K数据连传效果:
CC2640R2F开发之:UART串口收发&TI-RTOS任务创建(二)

本文地址:https://blog.csdn.net/baidu_30759519/article/details/107784133