乐于分享
好东西不私藏

当AI遇上嵌入式:DuMate陪我搞定Hi3861,5个实验踩坑实录

当AI遇上嵌入式:DuMate陪我搞定Hi3861,5个实验踩坑实录
说实话,嵌入式开发这块硬骨头,我以前是真啃不动。
GPIO、PWM、I2C……这些名词听着就头大。更崩溃的是,网上教程要么太老,要么太散,要么就是"懂的人都懂,不懂的人更懵"。
直到这次,我开了个"外挂"——DuMate,我的AI助手。
结果呢?
5个实验,全部成功,1个失败。
失败原因:接错引脚线,底板冒烟,可能烧掉了,后续测试是否真烧了。
从LED快闪到PWM呼吸灯,从按键检测到触摸传感器,全程只用了不到一周。
遇到编译错误?DuMate帮我分析原因。
API选择困惑?DuMate帮我查阅文档。
代码实现有问题?DuMate帮我调试优化。
实验成功后?DuMate帮我记录经验。
这不是传统意义上的"学习",这是人机协同的"降维打击"。
这次我把完整过程记录下来,包括踩过的坑、用过的API、验证过的代码。如果你也在入门嵌入式,或者想看看AI怎么帮你"开挂",这篇文章能帮你省下不少时间。
这篇文章,就是我和DuMate一起完成的学习笔记
已关注
关注
重播 分享
我会分享5个成功实验和1个失败实验,以及在这个过程中踩过的坑、总结的经验。
先剧透一下重点
  • Hi3861的API选择有讲究,用错了编译都过不了
  • GPIO控制看似简单,但有个SDK拼写错误坑了我好久
  • PWM功能必须用底层API,封装层根本不能用
  • 触摸传感器不支持双边沿中断,只能轮询
  • ADC实验失败了,但失败也有价值
实验1:LED快闪——嵌入式界的"Hello World"
为什么从LED开始?
学编程的都知道,第一个程序永远是"Hello World"。在嵌入式开发里,LED闪烁就是我们的"Hello World"。
看似简单,但这里面涉及的知识点可不少:
  • GPIO初始化
  • GPIO方向设置(输入还是输出)
  • GPIO输出控制(高电平还是低电平)
  • 延时函数
硬件连接
普中Hi3861开发板上有一颗板载LED——D1,连接在GPIO 2上。
好消息:不需要任何接线,直接就能用!
代码实现
```c// 初始化GPIOhi_gpio_init();// 设置GPIO 2为输出模式hi_io_set_func(HI_IO_NAME_GPIO_2, HI_IO_FUNC_GPIO_2_GPIO);hi_gpio_set_dir(HI_GPIO_IDX_2, HI_GPIO_DIR_OUT);// 循环闪烁while(1) {hi_gpio_set_ouput_val(HI_GPIO_IDX_2, HI_GPIO_VALUE1);  // 点亮sleep(1);hi_gpio_set_ouput_val(HI_GPIO_IDX_2, HI_GPIO_VALUE0);  // 熄灭sleep(1);}```
踩过的坑
坑1:函数名拼写错误
我一开始写的是 `hi_gpio_set_output_val()`,结果编译报错。
看了半天头文件才发现,SDK本身的函数名就是错的——应该是 `ouput` 而不是 `output`
坑2:宏定义选择
Hi3861有两套宏定义:
-`IOT_IO_NAME_GPIO_*`(封装层)
-`HI_IO_NAME_GPIO_*`(底层)
我一开始用的是封装层的宏,结果各种问题。后来发现,底层API更可靠。
实验结果
串口输出:
```LED Blink - PuZhong Hi3861D1=GPIO2[1] D1 ON[1] D1 OFF[2] D1 ON[2] D1 OFF```
LED真的在闪烁!那一刻,感觉整个世界都亮了(虽然只是一颗小LED)。
学到了什么
1.API选择原则:优先使用底层SDK API(`hi_*` 系列)
2.GPIO初始化流程:初始化 → 设置功能 → 设置方向 → 控制输出
3.注意细节:SDK可能有拼写错误,遇到问题多看头文件
实验2:按键检测——让开发板"听"你的话
LED会闪了,接下来能不能让开发板"听"我的话?
按键检测就是最好的入门实验。
两种检测方式
按键检测有两种方式:
方式1:中断
  • 按键按下时触发回调函数
  • 实时响应,不占用CPU
  • 需要配置回调函数
方式2:轮询
  • 定时读取GPIO状态
  • 简单直接
  • 占用CPU,有延迟
我两种都试了,最后发现:Hi3861不支持双边沿中断
什么意思呢?就是不能同时检测"按下"和"松开"两个动作。只能选一个:
  • 下降沿触发(按下)
  • 上升沿触发(松开)
如果要同时检测两个动作,只能用轮询方式。
硬件连接
普中开发板的按键需要跳线:
```GPIO 11 ──杜邦线──> KEY1 ──── 板载按键 K1 ──── GNDGPIO 12 ──杜邦线──> KEY2 ──── 板载按键 K2 ──── GND```
注意:按键需要上拉电阻,默认高电平,按下为低电平。
代码实现
中断方式(只检测按下)
```c// 初始化按键(上拉电阻)hi_io_set_pull(KEY1, HI_IO_PULL_UP);hi_io_set_func(KEY1, HI_IO_FUNC_GPIO_11_GPIO);hi_gpio_set_dir(KEY1, HI_GPIO_DIR_IN);// 注册中断回调(下降沿触发)hi_gpio_register_isr_function(KEY1,HI_INT_TYPE_EDGE,HI_GPIO_EDGE_FALL_LEVEL_LOW,& key_callback,NULL);// 回调函数hi_void key_callback(hi_void * arg){    printf("[INT] KEY1 pressed!\r\n");}```
轮询方式(检测按下和松开)
```chi_gpio_value key1_val, key1_val_last;hi_gpio_get_input_val(KEY1&key1_val_last);while (1) {    hi_gpio_get_input_val(KEY1&key1_val);    if (key1_val != key1_val_last) {        if (key1_val == HI_GPIO_VALUE0) {            printf("KEY1 pressed!\r\n");        } else {            printf("KEY1 released!\r\n");        }        key1_val_last = key1_val;    }    usleep(50000);  // 50ms轮询}```
实验结果
串口输出:
```========================================  Key Detection - PuZhong Hi3861  KEY1=GPIO11, KEY2=GPIO12========================================[INT] KEY1 pressed![POLL] KEY1: PRESSED[POLL] KEY1: RELEASED[INT] KEY2 pressed![POLL] KEY2: PRESSED[POLL] KEY2: RELEASED```
学到了什么
1.中断 vs 轮询:各有优缺点,根据需求选择
2.Hi3861中断限制:不支持双边沿触发
3.上拉电阻的作用:默认高电平,按键按下变低电平
4.跳线连接:普中开发板的按键需要通过P1排针跳线
实验3:蜂鸣器控制——让开发板"唱"起来
LED会闪了,按键会检测了,接下来能不能让开发板发出声音?
蜂鸣器实验,走起!
有源 vs 无源蜂鸣器
蜂鸣器分两种:
有源蜂鸣器
  • 内部有振荡电路
  • 通电就响
  • 只能发单一频率
无源蜂鸣器
  • 内部无振荡电路
  • 需要外部提供方波信号
  • 可以发不同频率的声音
普中Hi3861开发板用的是无源蜂鸣器,需要我们用GPIO输出方波信号来驱动。
硬件连接
蜂鸣器需要跳线连接:
```GPIO 14 ──杜邦线──> BP ──── 蜂鸣器```
注意:蜂鸣器控制端BP在P1排针上,需要用杜邦线连接。
代码实现
```c// 初始化蜂鸣器控制引脚hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_GPIO);hi_gpio_set_dir(HI_GPIO_IDX_14, HI_GPIO_DIR_OUT);// 发出声音(方波信号)for (int i = 0; i < 1000; i++) {    hi_gpio_set_ouput_val(HI_GPIO_IDX_14, HI_GPIO_VALUE1);    usleep(500);  // 高电平500微秒    hi_gpio_set_ouput_val(HI_GPIO_IDX_14, HI_GPIO_VALUE0);    usleep(500);  // 低电平500微秒}```
频率计算
方波频率 = 1 / (高电平时间 + 低电平时间)
上面的代码:
  • 高电平:500微秒
  • 低电平:500微秒
  • 周期:1000微秒 = 1毫秒
  • 频率:1 / 0.001 = 1000Hz
所以蜂鸣器会发出1000Hz的声音。
实验结果
蜂鸣器真的响了!虽然声音有点刺耳,但那是成功的喜悦。
学到了什么
1.无源蜂鸣器原理:需要方波信号驱动
2.频率控制:通过调整延时时间改变音调
3.GPIO高速翻转:可以用GPIO产生方波信号
4.跳线连接:普中开发板的蜂鸣器需要跳线
实验4:PWM呼吸灯——让LED"呼吸"起来
蜂鸣器会响了,接下来能不能让LED像呼吸一样慢慢变亮、慢慢变暗?
这就需要用到PWM(脉冲宽度调制)技术了。
PWM原理
PWM通过改变占空比来控制平均电压:
-占空比高 → 平均电压高 → LED亮
-占空比低 → 平均电压低 → LED暗
通过连续改变占空比,就能实现呼吸灯效果。
踩过的大坑
坑:封装层API不可用
我一开始用的是封装层API:
```cIoTPwmInit(HI_PWM_PORT_PWM2);IoTPwmStart(HI_PWM_PORT_PWM2, 50, 40000);  // 占空比50%```
结果编译通过,但LED根本不亮!
查了半天资料,才发现:Hi3861的PWM封装层API根本不能用!
必须使用底层SDK API:
```chi_pwm_init(HI_PWM_PORT_PWM2);hi_pwm_start(HI_PWM_PORT_PWM2, 20000, 40000);  // 占空比50%```
硬件连接
LED D1连接在GPIO 2上,而GPIO 2可以复用为PWM2输出。
不需要额外接线,直接用板载LED即可。
代码实现
```c// 1. 设置GPIO 2为PWM2输出hi_io_set_func(HI_IO_NAME_GPIO_2, HI_IO_FUNC_GPIO_2_PWM2_OUT);// 2. 初始化PWMhi_pwm_init(HI_PWM_PORT_PWM2);// 3. 呼吸灯效果while (1) {    // 渐亮    for (int duty = 0; duty <= 40000; duty += 400) {        hi_pwm_start(HI_PWM_PORT_PWM2, duty, 40000);        usleep(10000);  // 10ms    }    // 渐暗    for (int duty = 40000; duty >= 0; duty -= 400) {        hi_pwm_start(HI_PWM_PORT_PWM2, duty, 40000);        usleep(10000);  // 10ms    }}```
参数说明
周期:40000(普中开发攻略推荐值)
占空比:0 ~ 40000(不是0 ~ 100百分比!)
步进:400(即1%)
实验结果
LED真的像呼吸一样,慢慢变亮、慢慢变暗,循环往复。
效果非常棒!
学到了什么
1.PWM原理:通过占空比控制平均电压
2.API选择:PWM必须用底层API,封装层不可用
3.GPIO复用:GPIO可以复用为PWM输出
4.参数范围:占空比是0~period,不是0~100
实验5:触摸传感器——让开发板"感知"你的触摸
前面都是板载元件,这次试试外接模块——触摸传感器。
触摸传感器原理
电容式触摸传感器的工作原理:
  1. 触摸时,人体电容改变传感器电容值
2. 传感器内部电路检测到变化
3. DO引脚输出高电平
4. 松开后,恢复低电平
硬件连接
触摸传感器模块有4个引脚:
```触摸传感器模块          开发板P1排针────────────────────────────────────VCC (电源正)      →    3V3(右排)GND (地)          →    GND(左排)DO  (数字输出)    →    GPIO 11(左排第6个)AO  (模拟输出)    →    不接```
注意:AO是模拟输出,本实验不使用。
踩过的坑
坑:不支持双边沿中断
我一开始想用中断方式检测"触摸"和"松开"两个动作:
```chi_gpio_register_isr_function(TOUCH_SENSOR,                               HI_INT_TYPE_EDGE,                               HI_GPIO_EDGE_BOTH,  // 双边沿触发                               &touch_callback,                               NULL);```
结果编译报错:`HI_GPIO_EDGE_BOTH` 未定义!
查了头文件才发现,Hi3861根本不支持双边沿触发。
解决方案:改用轮询方式
```chi_gpio_value val, val_last;hi_gpio_get_input_val(TOUCH_SENSOR, &val_last);while (1) {    hi_gpio_get_input_val(TOUCH_SENSOR, &val);    if (val != val_last) {        if (val == HI_GPIO_VALUE1) {            // 触摸检测到            hi_gpio_set_ouput_val(LED_D1, HI_GPIO_VALUE1);            printf("Touch detected! LED ON\r\n");        } else {            // 触摸释放            hi_gpio_set_ouput_val(LED_D1, HI_GPIO_VALUE0);            printf("Touch released! LED OFF\r\n");        }        val_last = val;    }    usleep(50000);  // 50ms轮询}```
下拉电阻的作用
触摸传感器默认输出低电平,但为了稳定,我加了下拉电阻:
```chi_io_set_pull(TOUCH_SENSOR, HI_IO_PULL_DOWN);```
这样确保未触摸时读取到稳定的低电平。
实验结果
串口输出:
```========================================  Touch Sensor Test - PuZhong Hi3861  Sensor DO -> GPIO 11  LED D1   -> GPIO 2========================================[INIT] Touch sensor initial state: RELEASED[POLL] Touch detected! LED ON[POLL] Touch released! LED OFF[POLL] Touch detected! LED ON[POLL] Touch released! LED OFF```
触摸传感器圆形金属区域,LED点亮;松开,LED熄灭。完美!
学到了什么
1.触摸传感器原理:电容式检测
2.Hi3861中断限制:不支持双边沿触发
3.轮询方式:可以检测状态变化
4.下拉电阻:稳定输入电平
5.外接模块:学会使用外接传感器模块
实验6:ADC电位器采集——失败的实验
前面5个实验都成功了,这次ADC实验却失败了。
但失败也有价值,记录下来避免大家踩同样的坑。
实验目标
开发板上有一个电位器,连接在ADC通道上。我想读取电位器的模拟值,然后转换为电压值。
代码实现
```c#include"hi_adc.h"hi_u16 adc_value;float voltage;// 读取ADC值hi_adc_read(HI_ADC_CHANNEL_5, &adc_value,             HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_AUTO, 0);// 转换为电压值voltage = hi_adc_convert_to_voltage(adc_value);printf("ADC Value: %d, Voltage: %.2fV\r\n", adc_value, voltage);```
遇到的问题
问题1:ADC通道不确定
普中开发板的电位器到底连接在哪个ADC通道?文档没说清楚。
我试了所有通道(ADC0~ADC5),读取的值都是固定的,不会随电位器旋转而变化。
问题2:参考电压不确定
ADC转换需要知道参考电压。Hi3861的参考电压是多少?
文档说是3.3V,但实际测量可能不同。
问题3:ADC API文档不完善
`hi_adc_read()` 的参数含义不清楚:-`HI_ADC_EQU_MODEL_4` 是什么意思?-`HI_ADC_CUR_BAIS_AUTO` 是什么意思?-`delay_cnt` 应该设为多少?
失败原因分析
1.硬件连接不确定:电位器可能没有正确连接到ADC通道
2.API理解不深入:对ADC API的参数理解不够
3.缺乏调试手段:没有示波器等工具验证信号
学到了什么
1.实验前要确认硬件连接:不要假设,要验证
2.API文档很重要:理解每个参数的含义
3.失败也是经验:记录下来,避免重复踩坑
4.需要更多调试工具:示波器、逻辑分析仪等
后续计划
  1. 用万用表测量电位器引脚,确认连接
2. 查阅更多ADC相关文档
3. 尝试其他ADC通道
4. 如果还是不行,可能需要外接ADC模块
虽然失败了,但这个过程让我对ADC有了更深的理解。嵌入式开发就是这样,硬件、软件、文档,缺一不可。
经验总结——这些坑你别踩
做了这么多实验,踩了这么多坑,总结一下关键经验。
一、API选择原则
原则:优先使用底层SDK API
| 场景 | 推荐选择 | 原因 ||------|---------|------|GPIO控制 | `hi_gpio_*` | 底层API更可靠 |PWM控制 | `hi_pwm_*` | 封装层不可用 |GPIO复用 | `hi_io_set_func()` | Hi3861专用API |
封装层API的问题
-`IoTPwm*` 系列根本不能用
-`IoTGpio*` 系列部分可用,但行为不一致
  • 文档不完善,容易踩坑
底层API的优势
  • 直接操作硬件,行为可预测
  • 文档相对完善
  • 社区经验丰富
二、常见错误速查
| 错误写法 | 正确写法 | 说明 ||---------|---------|------|`hi_gpio_set_output_val` | `hi_gpio_set_ouput_val` | SDK拼写错误(`ouput`不是`output`) |`IoSetFunc` | `hi_io_set_func` | Hi3861使用`hi_io_*`系列 |`IOT_IO_NAME_GPIO_*` | `HI_IO_NAME_GPIO_*` | 使用`HI_IO_NAME_*`系列 |`HI_GPIO_EDGE_BOTH` | 不存在 | 不支持双边沿触发,改用轮询 |`IoTPwm*` | `hi_pwm_*` | PWM封装层不可用,使用底层API |
三、GPIO工作流程
```c// 1. 初始化hi_gpio_init();// 2. 设置功能hi_io_set_func(GPIO, HI_IO_FUNC_GPIO_X_GPIO);// 3. 设置方向hi_gpio_set_dir(GPIO, HI_GPIO_DIR_OUT);// 4. 控制输出hi_gpio_set_ouput_val(GPIO, HI_GPIO_VALUE1);  // 高电平hi_gpio_set_ouput_val(GPIO, HI_GPIO_VALUE0);  // 低电平```
输入模式(读取按键、传感器等)
```c// 1. 初始化hi_gpio_init();// 2. 设置功能hi_io_set_func(GPIO, HI_IO_FUNC_GPIO_X_GPIO);// 3. 设置上下拉hi_io_set_pull(GPIO, HI_IO_PULL_UP);    // 上拉(默认高电平)// 或hi_io_set_pull(GPIO, HI_IO_PULL_DOWN);  // 下拉(默认低电平)// 4. 设置方向hi_gpio_set_dir(GPIO, HI_GPIO_DIR_IN);// 5. 读取输入hi_gpio_value val;hi_gpio_get_input_val(GPIO, &val);```
四、中断 vs 轮询
| 方式 | 优点 | 缺点 | 适用场景 |
|------|------|------|---------|
| 中断 | 实时响应,不占用CPU | 需要配置回调函数 | 单边沿触发 |
| 轮询 | 简单直接 | 占用CPU,有延迟 | 双边沿检测 |
Hi3861中断限制
  • ✅ 支持上升沿触发
  • ✅ 支持下降沿触发
  • ✅ 支持高电平触发
  • ✅ 支持低电平触发
  • ❌ 不支持双边沿触发
解决方案:如需检测上升沿和下降沿,使用轮询方式。
五、PWM参数设置
周期:40000(普中开发攻略推荐值)
占空比:0 ~ 40000(不是0 ~ 100百分比!)
步进:400(即1%)
示例:```c// 50%占空比hi_pwm_start(HI_PWM_PORT_PWM2, 20000, 40000);// 25%占空比hi_pwm_start(HI_PWM_PORT_PWM2, 10000, 40000);// 100%占空比hi_pwm_start(HI_PWM_PORT_PWM2, 40000, 40000);```
六、开发流程建议
1.先看文档:理解硬件连接和API用法
2.参考示例:从现有Demo开始修改
3.逐步调试:不要一次写太多代码
4.记录问题:遇到问题及时记录,避免重复踩坑
5.更新文档:实验成功后更新API文档
七、调试技巧
1.串口打印:多用`printf()`输出调试信息
2.万用表测量:验证硬件连接和电平
3.示波器观察:验证信号波形(如果有条件)
4.分步验证:每个功能单独测试,确认正常后再组合
八、学习资源
1.官方文档:Hi3861 SDK文档
2.开发攻略:普中提供的开发指南
3.社区论坛:鸿蒙开发者社区
4.开源项目:GitHub上的Hi3861项目
最后一点建议:嵌入式开发需要耐心,遇到问题不要急,一步步排查。硬件、软件、文档,三方面都要检查。
回顾
这篇文章,我和DuMate一起完成了:
5个成功实验
  1. LED快闪——嵌入式界的"Hello World"
2. 按键检测——让开发板"听"你的话
3. 蜂鸣器控制——让开发板"唱"起来
4. PWM呼吸灯——让LED"呼吸"起来
5. 触摸传感器——让开发板"感知"你的触摸
1个失败实验
  • ADC电位器采集——失败的实验
关键经验
  • API选择原则
  • 常见错误速查
  • GPIO工作流程
  • 中断 vs 轮询
  • PWM参数设置
  • 开发流程建议
  • 调试技巧
感悟
嵌入式开发,真的不是写代码那么简单。
硬件层面
  • 要理解电路原理
  • 要知道引脚连接
  • 要会用测试工具
软件层面
  • 要理解API用法
  • 要注意参数范围
  • 要处理异常情况
文档层面
  • 要看官方文档
  • 要参考社区经验
  • 要记录自己的经验
三者缺一不可。
DuMate的贡献
这次学习之旅,DuMate给了我很大帮助:
技术支持
  • 帮我分析编译错误,快速定位问题
  • 帮我查阅API文档,避免踩坑
  • 帮我优化代码实现,提高效率
  • 帮我记录实验经验,建立知识库
知识管理
  • 自动维护API验证文档
  • 记录每次实验的成功和失败
  • 总结常见错误和解决方案
  • 建立项目知识库,方便查阅
效率提升
  • 以前查文档要半天,现在DuMate直接给出答案
  • 以前调试要试错多次,现在DuMate帮我分析原因
  • 以前记录要手动整理,现在DuMate自动生成文档
有了DuMate,学习效率至少提升了3倍!
接下来我打算:
1.继续学习I2C通信:驱动OLED屏幕、温湿度传感器等
2.尝试WiFi功能:连接网络,实现物联网应用
3.探索更多外设:超声波传感器、电机驱动等
4.做综合项目:智能家居、智能小车等
DuMate会继续陪我一起学习、一起成长。
写在最后
学习嵌入式开发,就像攀登一座山。
刚开始,看着山顶遥不可及。但只要一步一步往上爬,总会到达。
过程中会遇到困难,会踩坑,会失败。但这些都是成长的代价。
重要的是
  • 保持好奇心
  • 保持耐心
  • 保持记录
  • 保持分享
  • 有个好搭档(比如DuMate)
希望这篇文章对你有帮助。如果你也在用AI帮助你学习嵌入式开发,欢迎交流!
感谢阅读!我们下次见!