蓝牙4.0 BLE协议栈中的串口应用,就像是开发板和电脑之间的一座桥梁,承载着数据交互的重要任务。下面我们将通过生动的比喻,结合代码解读、原理说明以及时序图和流程图,深入理解这部分内容。
串口:数据交互的信使
串口作为开发板和电脑交互的工具,就如同古代传递书信的信使。初始化串口的过程,就像是为信使规划好传递信件的路线和方式,设置波特率如同确定信使的行进速度,中断设置则像是为信使安排的紧急联络机制。而向发送缓冲区发送数据或从接收缓冲区读取数据,就好比将信件放入邮筒或者从邮筒中取出信件。
蓝牙4.0 BLE协议栈:信使的调度中心
在蓝牙4.0 BLE协议栈中,串口的使用有了独特的方式,就如同信使加入了一个专业的调度中心。协议栈提供的三个关键函数HalUARTOpen()、HalUARTRead()、HalUARTWrite(),分别承担着打开通道、读取信件内容、发送信件的职责。
串口收发实验:信使的工作演练
以SimpleBLEPeripheral示例工程为基础的串口收发实验,就像是信使的一场工作演练。
- 代码解读:
- 在“SimpleBLEPeripheral.c”文件中添加的代码,首先定义了一个数组
uartbuf
用于存储接收到的数据,就像准备了一个专门的信件收纳袋。rxCb
函数作为回调函数,当有数据接收事件发生时,就会被调用,类似于信使收到新信件时的响应机制。
#include "hal_uart.h" unsigned char uartbuf[152] ; static void rxCb(uint8 port,uint8 event) { HalUARTRead(0, uartbuf,19) ;//从串口读取19个数据存到uartbuf数组,如同从邮筒取出信件放入收纳袋 if(osal_memcmp(uartbuf,"BLE_stack_uart_test",19))//判断接收的数据是否是指定字符串 { HalUARTWrite(0, uartbuf,19) ;//将接收到的数据再发送出去,如同将信件原封不动地转发 osal_memset( uartbuf,0,19);//清空数组,为下一次接收做准备,如同清空收纳袋 } }
- 在
SimpleBLEPeripheral_Init()
函数中添加的代码,用于配置串口参数并打开串口。halUARTCfg_t
结构体就像是调度中心的任务配置表,包含了串口初始化所需的各种参数,如是否已配置、波特率、流控等。
halUARTCfg_t uartConfig; uartConfig.configured = TRUE; uartConfig.baudRate = HAL_UART_BR_115200; uartConfig.flowControl = FALSE; uartConfig.callBackFunc = rxCb ; HalUARTOpen (0, &uartConfig);//根据配置表打开串口通道,如同为信使开启工作路径
- 在“SimpleBLEPeripheral.c”文件中添加的代码,首先定义了一个数组
- 回调函数揭秘:回调函数
rxCb
就像是信使的一个特殊任务指令。当特定的事件(如数据接收)发生时,系统会通过函数指针调用这个回调函数,就好比调度中心在特定情况下向信使下达特殊任务。定义和使用回调函数的过程如下:- 定义回调函数
rxCb
,编写数据接收和处理的逻辑。 - 在初始化时,将
rxCb
函数的指针传递给uartConfig
的callBackFunc
成员,完成回调函数的注册,就像将任务指令交给调度中心备案。 - 当数据接收事件发生,系统通过
callBackFunc
调用rxCb
函数,执行相应操作。
- 定义回调函数
实例测试:信使工作的检验
将程序编译下载到CC2540开发板并进行实例测试,就像是对信使工作的一次实际检验。当发现接收栏没有显示数据时,就如同信使在传递信件过程中出现了问题。经过排查发现,是因为蓝牙4.0 BLE协议栈的条件编译,没有正确开启UART功能,就好比没有为信使打开正确的工作通道。通过在IAR开发环境中定义HAL_UART=TRUE
宏,就像是为信使打通了道路,从而使数据能够正常收发。
串口工作原理剖析:信使的工作机制
- 串口初始化:
HalUARTOpen()
函数就像是调度中心的总开关,根据不同的条件(如是否使用DMA、ISR等)调用不同的初始化函数,如HalUARTOpenDMA()
。在HalUARTOpenDMA()
函数中,对串口波特率的初始化就像是为信使设定行进速度,根据halUARTCfg_t
结构体中baudRate
的值,参考CC2540数据手册中的对应值,使用switch-case
语句进行设置。同时,对DMA接收缓冲区的初始化,就像是为接收信件准备好仓库。static void HalUARTOpenDMA(halUARTCfg_t *config) { dmaCfg.uartCB = config->callBackFunc; if (config->baudRate == HAL_UART_BR_57600 || config->baudRate == HAL_UART_BR_115200) { UxBAUD = 216; } else { UxBAUD = 59; } switch (config->baudRate) { case HAL_UART_BR_9600: UxGCR = 8; dmaCfg.txTick = 35; break; //其他波特率设置情况类似 } dmaCfg.rxBuf[0] = *(volatile uint8 *)DMA_UDBUF; HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_RX); HAL_DMA_ARM_IRQ(HAL_DMA_CH_RX); HAL_DMA_ARM_CH(HAL_DMA_CH_RX); osal_memset(dmaCfg.rxBuf, (DMA_PAD ^ 0xFF),HAL_UART_DMA_RX_MAX*2); }
- 数据接收与发送:在数据接收时,数据首先存放在DMA接收缓冲区,
HalUARTRead()
函数实际上调用HalUARTReadDMA()
函数从DMA缓冲区读取数据,就像是从仓库中取出信件进行处理。发送数据时,HalUARTWrite()
函数调用HalUARTWriteDMA()
函数将数据写入DMA发送缓冲区,然后DMA自动将数据通过串口发送给PC机,就像是将信件放入邮车进行发送。
时序图和流程图展示
- 串口收发时序图