蓝牙和串口怎样共用主循环
串口能收到字节以后,为什么没有直接在中断里发送蓝牙?先看主循环每轮在做什么,再认识项目使用的事件处理方式。
1 · 循环每次都要回来
Main_Circulation 中的实际循环
while (1) {
TMOS_SystemProcess();
app_uart_process();
}第一项让厂商提供的事件系统处理当前可执行的工作,第二项处理自己的串口交接。两项都需要不断获得执行机会。如果在其中一项写一个永远不返回的等待,另一项就没有机会继续。
因此“我只是在等一个字节”也会影响无线连接。这里延续裸机中每次做一点、做完回来的思路;不是看到 Task 一词就应在回调里放 while(1)。
2 · 先约定处理函数,再提交一个待办事件
TMOS 是本工程蓝牙库使用的任务和事件调度接口。先把它理解为“登记处理函数,发生事情时标记一个事件,循环中再调用处理函数”。这与此前的函数指针回调能够连起来。
Peripheral_Init 中的两处调用 · 中间其他初始化省略
Peripheral_TaskID =
TMOS_ProcessEventRegister(Peripheral_ProcessEvent);
tmos_set_event(Peripheral_TaskID, SBP_START_DEVICE_EVT);登记后得到的编号表示这组事件交给谁处理;事件值表示具体要做哪件事。事件编号不携带收到的全部字节,那些字节仍保存在队列里。
3 · UART 中断如何把工作交出来
中断先保存数据并设置 uart_rx_flag。app_uart_process 检查标志,安排 UART_TO_BLE_SEND_EVT,再清标志。真正发送在 Peripheral_ProcessEvent 的对应分支执行。于是中断能尽快结束,主循环也能继续处理库的工作。
app_uart_process 内部的片段 · 外围保留项目原有临界区
tmos_start_task(Peripheral_TaskID, UART_TO_BLE_SEND_EVT, 2);
uart_rx_flag = false;最后一个数字是库计时单位,不应直接写成“2 毫秒”。需要换算时查询当前版本接口说明;教学上先掌握它表示稍后安排事件。保护标志的短临界区由项目代码处理,不把这一段孤立复制出去替换函数。
4 · 一次事件处理完,怎样表达还剩什么
Peripheral_ProcessEvent 用 events & 某事件值判断这一位是否存在,处理后返回剩余事件。按位与用于检查,按位异或在已经确认该位存在时清除该位。返回值不代表业务成功或失败,而是交回仍待处理的事件集合。
事件位处理示意 · MY_EVENT 是讲解用名称,未加入生产工程
if (events & MY_EVENT) {
/* 完成本次有界工作,然后返回。 */
return events ^ MY_EVENT;
}如果蓝牙暂时不能接收新的发送请求,当前代码会安排之后再试。把“等资源”变成未来一次事件,能让本轮处理函数先返回。
5 · 与 FreeRTOS 的任务区别在哪里
| 问题 | 本工程 TMOS 应用处理 | 主线 FreeRTOS 任务 |
|---|---|---|
| 入口通常怎样写 | 处理一次事件并返回 | 各自循环,可阻塞等待 |
| 业务执行会不会因普通等待自动交接 | 不能据此假定;长时间停留会阻碍循环 | 按内核调度规则切换 |
| 怎样延后工作 | 再次安排事件 | 任务延时、通知或同步对象 |
沿 事件处理源码 找出 UART_TO_BLE_SEND_EVT 的登记、触发和处理位置。画出“中断保存 → 标志 → 主循环安排 → 事件发送”的顺序,再进入下一篇的蓝牙服务。