鸿蒙 LiteOS|NBV2.1 开发板二维码实验踩坑全记录
📝前言
基于NBV2.1 物联网主板 + 鸿蒙 LiteOS完成二维码实验。 一开始我以为这套代码可以直接识别纸质二维码,实际跑通之后才发现:原有工程只实现了字符串编码,LCD 屏幕绘制输出二维码,摄像头解码识别外部二维码只是预留框架,并没有实现。
本文完整记录整个实验:整体架构、核心代码、现象结果、实际踩坑问题、问题排查思路与创新拓展,适合刚接触 LiteOS 多任务嵌入式开发的同学参考。
⚠️开发环境: 硬件:NBV2.1 鸿蒙物联网开发板 OS:HarmonyOS‑LiteOS‑M 屏幕:SPI‑TFT 240*320 外设:DVP 摄像头接口、4 路按键、LED、BC35G NB‑IoT 模组
🏗整体系统架构
本实验采用 LiteOS 多任务设计,两个业务任务分工明确:
表格
| 任务 | 优先级 | 职责 |
|---|---|---|
| control_task | 0(高) | 硬件主控、LED 状态指示、串口、NB‑IoT 模组业务,预留摄像头解码业务 |
| view_task | 1(低) | LCD 屏幕绘图、按键扫描、二维码编码绘制输出 |
💡重要概念区分(很多同学这里搞混)
- 编码:
QR_CODE_Display():输入字符串 → LCD 屏幕画出二维码,供手机扫码读取(本实验已实现) - 解码:摄像头采集图像 → 算法解析纸质二维码得到文本(本工程只有框架,需要自己新增代码)
main函数只做硬件初始化、内核初始化、创建任务;LOS_Start()启动调度之后 main 死循环,所有业务逻辑全部交给任务执行,和裸机开发思维有很大区别。
🧩硬件简要原理
- 主控 STM32 运行 LiteOS 操作系统,负责任务调度、图像处理;
- SPI‑TFT 屏幕通过 PE9~PE14 引脚与 MCU 相连,完成二维码图形渲染;
- 4 路 GPIO 按键,上拉输入模式,软件消抖;
- LED1 作为系统运行指示灯,1s 闪烁一次判断任务是否正常调度;
- DVP 摄像头接口预留,用于后续拓展二维码解码识别;
- BC35G NB‑IoT 模组,可拓展将扫码数据上传云端。
💻核心代码片段
main.c 入口函数
int main(void)
{
UINT32 uwRet = LOS_OK;
HAL_Init(); //硬件底层初始化
sysclkinit(); //系统时钟配置
task_view_init(); //显示模块初始化
task_control_init(); //控制模块初始化
printf("\r\n 二维码识别实验 \r\n");
printf("----------------------------------\r\n");
printf("开始本实验:\r\n\r\n");
uwRet = LOS_KernelInit(); //LiteOS内核初始化
if (uwRet != LOS_OK)
{
return LOS_NOK;
}
uwRet = creat_view_task(); //创建显示任务
uwRet = creat_control_task(); //创建控制任务
LOS_Start(); //开启操作系统任务调度
while (1)
{
}
}
main 函数不执行业务,只做初始化与任务创建。
view_task.c 核心‑二维码绘制函数
void QR_CODE_Display(uint8_t *qrcode_data)
{
uint8_t i,j;
uint16_t x,y,p;
uint16_t old_point_color = POINT_COLOR;
uint16_t old_back_color = BACK_COLOR;
BACK_COLOR = WHITE;
POINT_COLOR = BLACK;
#define QR_CODE_SIZE 120
#define QR_CODE_X 45
#define QR_CODE_Y 65
EncodeData((char *)qrcode_data); //字符串编码生成二维码矩阵
if(m_nSymbleSize*2 > QR_CODE_SIZE)
{
return;
}
for(i=0;i<10;i++)
{
if((m_nSymbleSize*i*2) > QR_CODE_SIZE) break;
}
p=(i-1)*3;
x=QR_CODE_X;
y=QR_CODE_Y;
for(i=0;i<m_nSymbleSize;i++)
{
for(j=0;j<m_nSymbleSize;j++)
{
if(m_byModuleData[i][j]==0)
LCD_Fill(x+p*i,y+p*j,x+p*(i+1)-1,y+p*(j+1)-1,WHITE);
else
LCD_Fill(x+p*i,y+p*j,x+p*(i+1)-1,y+p*(j+1)-1,BLACK);
}
}
Gui_StrCenter(0, 240, BLACK, WHITE, "欢迎来到万物互联的智能世界", 16, 0);
BACK_COLOR=old_back_color;
POINT_COLOR=old_point_color;
}
逻辑:调用EncodeData()把字符串转为二维码矩阵,双重循环填充黑白方块,在屏幕指定位置渲染出二维码图案。
control_task.c 控制任务主循环
VOID control_task(VOID)
{
UINT32 uwRet = LOS_OK;
static uint32_t sys_time = 0;
printf("** LED灯初始化\r\n");
while(1)
{
ptl_Handle();
if(HAL_GetTick() - sys_time > 1000)
{
sys_time = HAL_GetTick();
led_toggle(LED1_PORT); //LED1每秒闪烁,判断任务存活
}
Get_Bc35g();
ptl_Heartbeat_Handle();
BC35G_Handle();
uwRet = LOS_TaskDelay(10);
if(uwRet != LOS_OK)
{
return;
}
}
}
这里目前只有 LED、NB‑IoT 业务,摄像头解码逻辑需要自行添加到此循环内。
📊实验现象 & 预期对比
✅预期目标:
- 操作系统、两个任务正常启动,串口打印日志;
- LCD 显示标题、二维码,手机扫码读取预置字符串;
- LED1 一秒闪烁一次;
- 识别外部纸质二维码。
📌实际现象:
- 串口完整输出启动日志,两个任务创建成功;
- LCD 屏幕显示标题,生成二维码,手机扫码可以读到
Hello world!陈菲菲; - LED1 周期闪烁;
- ❗无法识别纸质二维码,只有编码输出功能;
- 屏幕偶发局部乱码,二维码持续重绘存在轻微闪烁。
🔍偏差原因:
- 缺少摄像头采集与解码业务代码,只实现编码;
- view_task 每 10ms 无条件重绘二维码,没有做字符串变更判断,无效绘图多;
- 多任务共享全局缓冲区,没有互斥锁保护,读写竞争造成随机乱码。
⚡实验踩坑记录(真实遇到的问题)
坑 1:串口打印正常,LCD 黑屏无显示
现象:LED 闪烁、串口日志全部正常,屏幕完全黑屏。 排查:排除主控问题;查看屏幕初始化函数,背光引脚没有使能。 解决:初始化函数增加背光 IO 开启。
坑 2:任务创建失败,上电直接死机
现象:串口打印到 “开始本实验” 就卡死。 原因:修改代码时把任务堆栈0x1000误写成0x0100,堆栈空间不足,LiteOS 任务直接创建失败。
✨心得体会:RTOS 开发,堆栈过小死机经常没有报错打印,是高频踩坑点。
坑 3:二维码随机局部乱码,复现概率低
现象:大部分时间显示正常,偶尔方块错乱。 原因:多任务共用字符串缓冲区,没有互斥锁,一边写一边读,拿到残缺数据绘图。 解决:后续正式项目必须加上 LiteOS 互斥锁保护共享资源。
坑 4:混淆编码和解码,以为代码可以识别纸质二维码
很多初学者会把QR_CODE_Display()解码,实际它是编码输出函数,只是把文字画成二维码。识别外界二维码需要摄像头 + 解码算法,需要自己拓展开发。
坑 5:Key4 按键一直提示等待 NB 联网
现象:按键检测正常,但不会发送 AT 指令。 原因:实验环境没有接 NB 天线,模组没有联网,属于硬件环境限制,不是程序 bug。
💡创新拓展思路
基于现有硬件可以继续做功能升级:
- 扫码控制外设:识别特定内容二维码,控制 LED、蜂鸣器,实现无按键控制开发板;
- 光敏 + 自动补光:暗光自动打开补光 LED,提升复杂环境二维码识别成功率;
- Flash 本地存储扫码记录,按键翻看历史扫码日志;
- NB‑IoT 上云:识别结果上传华为 IoT 平台,实现端云联动;
- 低功耗改造:LiteOS 休眠唤醒,按键触发扫码,模拟电池供电便携式扫码终端。
📚学习总结
- LiteOS 中 main 函数和裸机 main 不一样,main 只管初始化,业务交给任务,
LOS_Start()之后 main 不再干活; - 任务优先级、任务堆栈是 RTOS 两大易错点,堆栈太小直接死机,高优先级任务不延时会抢占全部 CPU;
- 多任务共享数据一定要考虑资源竞争,偶发乱码 bug 调试难度远大于必现 bug,前期就要做好锁保护;
- 做实验一定要分清 “哪些功能已经实现,哪些只是预留框架”,不要被函数名字误导;
- 嵌入式调试优先看串口打印,通过日志定位初始化故障,不要只盯着屏幕现象。
本实验完整报告(实验目的、原理图、代码、结果、总结、创新拓展)可以直接用于课程作业。
更多推荐




所有评论(0)