协处理器串口程序移植过程
(1)通过sensorcontroller软件配置好串口初始化程序
(2)将生成的IAR project代码复制到simple_peripheral工程相应文件夹下
(1) 将.c和.h文件添加当工程中的GY_SerialPort/UART中,并添加编译路径
(2) 改写sc_uart.c文件,这个文件由main_tirtos.c根据开发者自身需求改写而成,这里,包含了串口初始化函数,串口RX接收回调函数,串口打印函数,以及串口任务往app层的回调任务。sc_uart.h则包含了这些函数的借口,保留给app.c使用。
#include "scif.h"
#include "sc_uart.h"
#define BV(n) (1 << (n))
// Display error message if the SCIF driverhas been generated with incorrect operating system setting
#ifndef SCIF_OSAL_TIRTOS_H
#error "SCIF driver has incorrect operating system configurationfor this example. Please change to 'TI-RTOS' in the Sensor Controller Studioproject panel and re-generate the driver."
#endif
// Display error message if the SCIF driverhas been generated with incorrect target chip package
#ifndefSCIF_TARGET_CHIP_PACKAGE_QFN48_7X7_RGZ
#error "SCIF driver has incorrect target chip package configurationfor this example. Please change to 'QFN48 7x7 RGZ' in the Sensor ControllerStudio project panel and re-generate the driver."
#endif
/*********************************************************************
*LOCAL PARAMETER
*/
GY_UartRxBufCallbackGY_UartReviceDataCallback;
/*********************************************************************
*@fn GY_UartTask_RegisterPacketReceivedCallback
*
*@brief 注册串口接收回调任务(将串口接收的数据传给app任务去处理)
*
*@param callback -> 串口接收数据回调(包括数据buf及len)
*
*@return None.
*/
voidGY_UartTask_SC_RegisterPacketReceivedCallback(GY_UartRxBufCallback callback)
{
GY_UartReviceDataCallback = callback;
}
void scCtrlReadyCallback(void) {
}
/*********************************************************************
*@fn scTaskAlertCallback
*
*@brief sensor controller任务进程警报回调,在这里等同于串口RX的接收回调
* 我们可以从这里拿到UART RX接收到的数据
*
*@param none
*
*@return None.
*/
void scTaskAlertCallback(void) {
// Clear the ALERT interrupt source
scifClearAlertIntSource();
// Echo all characters currently in the RX FIFO
//获取串口接收的数据长度
int rxFifoCount = scifUartGetRxFifoCount();
//获取串口RX接收的数据
uint8_trxbuf[200] = {0};
for(int i=0; i
{
rxbuf[i] = scifUartRxGetChar();
}
GY_UartReviceDataCallback(rxbuf, rxFifoCount); //给app任务一个串口读回调
// Clear the events that triggered this
scifUartClearEvents();
// Acknowledge the alert event
scifAckAlertEvents();
}
/*********************************************************************
*@fn GY_UartTask_SC_Init
*
*@brief sensor controller串口进程任务初始化
* 这个初始化函数是由sensor controller studio生成main函数改写
*
*@param None
*
*@return None.
*/
void ScUARTInit (void)
{
// Initialize the Sensor Controller
scifOsalInit();
scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
scifInit(&scifDriverSetup);
// Start the UART emulator
scifExecuteTasksOnceNbl(BV(SCIF_UART_EMULATOR_TASK_ID));
// Enable baud rate generation
scifUartSetBaudRate(115200);
// Enable RX (10 idle bit periods required before enabling start bitdetection)
scifUartSetRxFifoThr(SCIF_UART_RX_FIFO_MAX_COUNT / 2);
scifUartSetRxTimeout(10 * 2);
scifUartSetRxEnableReqIdleCount(10 * 2);
scifUartRxEnable(1);
// Enable events (half full RX FIFO or 10 bit period timeout
scifUartSetEventMask(BV_SCIF_UART_ALERT_RX_FIFO_ABOVE_THR |BV_SCIF_UART_ALERT_RX_BYTE_TIMEOUT);
}
比较一下,改写后与改写前的区别
void scTaskAlertCallback(void) {
// Wake up the OS task
//唤醒任务进程,这边接收到串口数据会起作用
Semaphore_post(Semaphore_handle(&semScTaskAlert));
} // scTaskAlertCallback
void taskFxn(UArg a0, UArg a1) {
// Initialize the Sensor Controller
//初始化SensorController驱动,注意着四个都需要
scifOsalInit();
scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
scifInit(&scifDriverSetup);
// Start the UART emulator
//开始串口模拟进程,相当于打开串口功能
scifExecuteTasksOnceNbl(BV(SCIF_UART_EMULATOR_TASK_ID));
// Enable baud rate generation
//设置串口波特率
scifUartSetBaudRate(57600);
// Enable RX (10 idle bit periods required before enabling start bitdetection)
//使能RX接收
scifUartSetRxFifoThr(SCIF_UART_RX_FIFO_MAX_COUNT / 2);
scifUartSetRxTimeout(10* 2);
scifUartSetRxEnableReqIdleCount(10 * 2);
scifUartRxEnable(1);
// Enable events (half full RX FIFO or 10 bit period timeout
//启动时间(半完整RX FIFI或10位周期超时)
scifUartSetEventMask(BV_SCIF_UART_ALERT_RX_FIFO_ABOVE_THR |BV_SCIF_UART_ALERT_RX_BYTE_TIMEOUT);
// Main loop
while (1) {
// Wait for an ALERT callback
//串口中断回调阻塞
Semaphore_pend(Semaphore_handle(&semScTaskAlert),BIOS_WAIT_FOREVER);
// Clear the ALERT interrupt source
//清除中断标志
scifClearAlertIntSource();
// Echo all characters currently in the RX FIFO
//串口TX打印串口RX接收到的数据
int rxFifoCount = scifUartGetRxFifoCount();
while (rxFifoCount--) {
scifUartTxPutChar((char) scifUartRxGetChar());
}
// Clear the events that triggered this
//清除串口事件
scifUartClearEvents();
// Acknowledge the alert event
//确认中断事件
scifAckAlertEvents();
}
} // taskFxn
可以看出来,改写前的taskFxn任务函数中的初始化过程即为改写后的ScUARTInit()串口进程任务初始化函数。改写钱的while(1)循环中的代码就是scTaskAlertCallback任务进程警报回调函数,只不过是多了一个给app任务串口读回调函数。
scTaskAlertCallback接收到串口数据会起作用。
(3) 改写simple_peripheral.c文件,实现获取串口数据的回调,实现与手机端通信的接口。
首先就是添加sc_uart.h的头文件。
声明变量:
static Queue_Struct uartRxMsg;
static Queue_Handle uartRxQueue;
然后在SimpleBLEPeripheral_init初始化函数中增加sensorcontroller串口的初始化
uartRxQueue =Util_constructQueue(&uartRxMsg);//如果这条语句不加,手机能扫描到蓝牙,但是连接不上
//初始化sensorcontroller 串口
ScUARTInit();
//上电后发送串口测试信息
ScUARTWrite("This my uart test!\r\n",sizeof("This my uarttest!\r\n"));
GY_UartTask_SC_RegisterPacketReceivedCallback(TransUartReceiveDataCallback);
//打开LCD显示
dispHandle = Display_open(Display_Type_LCD,NULL);
其中GY_UartTask_SC_RegisterPacketReceivedCallback是sc_uart.c中的串口接收回调函数,将串口接收的数据传给app任务去处理。TransUartReceiveDataCallback的定义如下
串口数据回调,作用是从app 下获取串口端接收的数据。
static voidTransUartReceiveDataCallback(uint8_t *buf, uint16_t len)
{
uint8_t *pMsg;
//Create dynamic pointer to message.
if((pMsg = ICall_malloc(200)))
{
pMsg[0] = len;
memcpy(pMsg+1, buf, len);
// Enqueue the message.
Util_enqueueMsg(uartRxQueue,sem, (uint8*)pMsg);
}
}
接下来就要修改任务函数SimpleBLEPeripheral_taskFxn,增加串口接收数据队列处理
//串口接收回调函数队列中的RX消息不为空
while(!Queue_empty(uartRxQueue))
{
uint8_t *pMsg = (uint8_t*)Util_dequeueMsg(uartRxQueue);
if(pMsg)
{
Simple_Peripheral_NotiData(pMsg+1,pMsg[0]);
//将串口数据发送手机端
ICall_free(pMsg);
}
}
接收到手机数据通过串口及LCD打印出来
static void SimpleBLEPeripheral_processCharValueChangeEvt(uint8_tparamID)
{
#ifndefFEATURE_OAD_ONCHIP
uint8_t newValue;
switch(paramID)
{
case SIMPLEPROFILE_CHAR1:
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);
Display_print1(dispHandle, 4, 0,"Char 1: %d", (uint16_t)newValue);
Display_print1(dispUHandle,0,0,"Char1: %d" , (uint16_t)newValue);
ScUARTWrite(&newValue,1);
break;
case SIMPLEPROFILE_CHAR3:
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);
Display_print1(dispHandle, 4, 0,"Char 3: %d", (uint16_t)newValue);
Display_print1(dispUHandle,0,0,"Char3: %d" , (uint16_t)newValue);
break;
default:
// should not reach here!
break;
}
#endif//!FEATURE_OAD_ONCHIP
}
将串口RX接收到的数据发送给手机端
voidSimleBLEPeripheral_NotiData(uint8_t *buf,uint16_t len)
{
uint8_t notiValue[21]={0};
notiValue[0]=len;
memcpy(notfiValue+1,buf,len);
SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR4, sizeof(uint8_t),
¬fiValue);
}
以上移植好以后,编译通过烧录app程序,实现现象:串口只能发送一个字节的数据,手机也只能发送一个自己的数据
那么如果想要发送任意字节的数据包,该如何改写呢?
首先,我们选择app工程的Options选项/C/C++Compiler,如图
定义一个PROFILE_Multibyte,相当定义了宏定义#definePROFILE_Multibyte 1,下面开始改写代码
(1)simple_peripheral.c文件中
static voidSimpleBLEPeripheral_processCharValueChangeEvt(uint8_t paramID)
{
#ifndefFEATURE_OAD_ONCHIP
#ifdef PROFILE_Multibyte
uint8_t newValue[21];//定义CC2640蓝牙接收手机发送数据,最大20,还有一个为长度
#else
uint8_t newValue;//默认情况下值接收一个字节数据
#endif
switch(paramID)
{
case SIMPLEPROFILE_CHAR1:
#ifdef PROFILE_Multibyte
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, newValue);//获取CHAR1的数据
ScUARTWrite(newValue+1,newValue[0]);//将手机接收到的数据通过串口打印出来
//GY_UartTask_Write(newValue+1,newValue[0]);
#else
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR1, &newValue);//默认情况下只接收一个字节
ScUARTWrite(&newValue,1);
#endif
Display_print0(dispHandle, 4, 0,"Char 1:");
Display_print1(dispHandle, 5, 0,"%s", newValue+1);
break;
case SIMPLEPROFILE_CHAR3:
SimpleProfile_GetParameter(SIMPLEPROFILE_CHAR3, &newValue);
//Display_print1(dispHandle, 4, 0,"Char 3: %d", (uint16_t)newValue);
break;
default:
// should not reach here!
break;
}
#endif//!FEATURE_OAD_ONCHIP
}
(2)simple_gatt_profile.h文件中
#ifdefPROFILE_Multibyte
#definesimpleProfileChar4_len 20
#defineSIMPLEPROFILE_CHAR1_LEN 21//定义CHAR1一次可接收手机的数据包长度
staticuint8 char4ValueLen = 20; //定义CHAR4一次可接收串口的数据包长度
#endif
(1) simple_gatt_profile.c文件中
// Characteristic 1 Value
#ifdef PROFILE_Multibyte
static uint8simpleProfileChar1[SIMPLEPROFILE_CHAR1_LEN] = {0};//定义CHAR1接收缓存数组
#else
static uint8 simpleProfileChar1 = 0;//默认情况下一个字节
#endif
// Characteristic 4 Value
#ifdef PROFILE_Multibyte
static uint8 simpleProfileChar4[simpleProfileChar4_len]= {0};//定义CHAR4接收数组
#else
static uint8 simpleProfileChar4 = 0;
#endif
// Characteristic Value 1
{
{ ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
#ifdef PROFILE_Multibyte
simpleProfileChar1//数组地址
#else
&simpleProfileChar1 //char一个字节
#endif
},
// Characteristic Value 4
{
{ ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
0,
0,
#ifdef PROFILE_Multibyte
simpleProfileChar4
#else
&simpleProfileChar4
#endif
},
#ifdef PROFILE_Multibyte
if ( len == SIMPLEPROFILE_CHAR5_LEN ) //这里的len长度可以自己定义,但在调用该函数的时候对应的形参len要一致
{
memcpy( simpleProfileChar1, value, SIMPLEPROFILE_CHAR1_LEN );
}
#else
if ( len == sizeof ( uint8 ) )
{
simpleProfileChar1 = *((uint8*)value);
}
#endif
#ifdef PROFILE_Multibyte
uint8 *pBuf = value;
memset(simpleProfileChar4, 0, simpleProfileChar4_len);
VOID memcpy( simpleProfileChar4, pBuf+1, pBuf[0] );//第一个字节是长度
// See if Notification has been enabled
GATTServApp_ProcessCharCfg( simpleProfileChar4Config,simpleProfileChar4, FALSE,
simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
INVALID_TASK_ID,simpleProfile_ReadAttrCB );
#else
simpleProfileChar4 = *((uint8*)value);
// See if Notification has been enabled
GATTServApp_ProcessCharCfg( simpleProfileChar4Config,&simpleProfileChar4, FALSE,
simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
INVALID_TASK_ID, simpleProfile_ReadAttrCB );
#endif
case SIMPLEPROFILE_CHAR1:
#ifdef PROFILE_Multibyte
memcpy( value, simpleProfileChar1, SIMPLEPROFILE_CHAR1_LEN ); //simpleProfileChar1 是数组名
#else
*((uint8*)value) = simpleProfileChar1;
#endif
break;
case SIMPLEPROFILE_CHAR4:
#ifdef PROFILE_Multibyte
memcpy( value, simpleProfileChar4, simpleProfileChar4_len );
#else
*((uint8*)value) = simpleProfileChar4;
#endif
break;
#ifdef PROFILE_Multibyte
*pLen = char4ValueLen;
memcpy( pValue, pAttr->pValue, char4ValueLen );
#else
*pLen = 1;
pValue[0] = *pAttr->pValue;
#endif
最后重新编译,烧录。
实验现象:
手机用蓝牙调试助手在CHAR1发送20字节以内的数据包可以在水墨屏上显示,且串口会打印出来。在CHAR4可以接收到串口发送的数据。