当前位置: 移动技术网 > 网络运营>网络>协议 > CC2640R2F开发之:UART串口收发&TI-RTOS任务创建(二)

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

2020年08月12日  | 移动技术网网络运营  | 我要评论
对于蓝牙的数据传输来说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来演示。
先上图:
串口处理
说明:
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串口RX接收40K数据并通过TX打印出来

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网