CC2640R2F开发之:UART串口收发&TI-RTOS任务创建(二)
开发一款蓝牙应用,其实不仅仅是蓝牙,其他的程序也是如此,串口在整个项目中都会占据重要的地位,串口能完成人与芯片的交互。所以在开发项目中首先完成串口部分就显得很重要(当然如果只是开发一个流水灯那大可不必)。
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数据连传效果:
本文地址:https://blog.csdn.net/baidu_30759519/article/details/107784133