Hi3861开发板使用与第六届全国大学生嵌入式竞赛海思赛道
参考资料
海思技术论坛注册:https://developer.hisilicon.com/forum/all
嵌入式物联网学习资料总入口:https://developer.hisilicon.com/postDetail?tid=0206112614830760003
海思技术论坛https://developer.hisilicon.com/forum/all
2023海思嵌入式大赛学习文档仓库Gitee:https://gitee.com/HiSpark/HiSpark_NICU2023
HUAWEI_Cloud与Android Studio开发联动:https://blog.csdn.net/weixin_43351158/article/details/124476656
工程结构分析
工程目录
1 | . |
hello_world.c文件代码结构
1 |
|
SYS_RUN定义在ohos_init.h文件中,是HarmonyOS启动恢复模块接口启动业务。
用于将业务构建成静态库的BUILD.gn文件代码结构
路径:./applications/sample/wifi-iot/app/my_first_app/BUILD.gn(与下面的模块编译build.gn不一样,请格外注意)
1 | //目标业务 |
指定需参与构建的特性模块的BUILD.gn文件代码结构
路径:./applications/sample/wifi-iot/app/BUILD.gn
1 | import("//build/lite/config/component/lite_component.gni") |
my_first_app是相对路径,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn。
myapp是目标,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn中的static_library(“myapp”)。
Hi3861其他代码结构
Hi3861平台配置文件
hi3861平台配置文件位于:vendor\hisilicon\hispark_pegasus\config.json
1 | { |
hi3861用的是liteos-m内核,但是目前hi3681的liteos-m被芯片rom化了,固化在芯片内部了。所以在harmonyOS代码是找不到hi3861的内核部分。
Hi3861启动流程
第一个入口函数
路径:.\src\device\hisilicon\hispark_pegasus\sdk_liteos\app\wifiiot_app\app_main.c
1 | hi_void app_main(hi_void) |
最后一行调用OHOS_Main()代码:
路径:.\src\device\hisilicon\hispark_pegasus\sdk_liteos\app\wifiiot_app\src
1 | void OHOS_Main() |
OHOS_SystemInit函数进行鸿蒙系统的初始化。
路径:D:\DevEcoProjects\first_test\src\base\startup\bootstrap_lite\services\source\system_init.c
1 | void OHOS_SystemInit(void) |
主要是初始化了一些相关模块、系统,包括有bsp、device(设备)。其中最终的是MODULE_INIT(run);负责调用所有run段的代码:前面application中使用SYS_RUN()宏设置的函数名。
一、GPIO的使用
API说明
1. IoTGpioInit()
作用:初始化指定的IO口
示例:
1 | // LED3的GPIO初始化 GPIO initialization of LED3 |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_gpio.h, 说明如下
1 | /** |
2. IoSetFunc()
作用:配置指定IO的复用功能
示例:
1 | // 设置GPIO9的管脚复用关系为GPIO Set the pin reuse relationship of GPIO9 to GPIO |
依赖库:src\applications\sample\wifi-iot\app\led_demo\hal_iot_gpio_ex.c
说明如下:
1 | unsigned int IoSetFunc(unsigned int id, unsigned char val) |
3. IoTGpioSetDir()
作用:设置指定IO的管脚方向
示例:
1 | // GPIO方向设置为输出 GPIO direction set to output |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_gpio.h, 说明如下
1 | /** |
4. IoTGpioSetOutputVal()
作用:设置指定IO的输出电平
示例:
1 | /* 设置GPIO09输出低电平 |
二、GPIO使用进阶
API说明
1. IoSetPull()
作用:设置指定IO的上下拉电阻
示例:
1 | /* |
依赖库:src\applications\sample\wifi-iot\app\led_demo\hal_iot_gpio_ex.c
对第二个参数说明如下:
1 | /** No pull */ |
2. IoTGpioRegisterIsrFunc()
作用:设置指定GPIO的中断功能
示例:
1 | /* |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_gpio.h,
第二个参数IotGpioIntType intType
说明如下
1 | /** Level-sensitive interrupt */ |
第三个参数IotGpioIntPolarity intPolarity
说明如下:
1 | /** Interrupt at a low level or falling edge */ |
第四个参数GpioIsrCallbackFunc func
,为自己编写的中断触发时的回调函数名,第五个参数char *arg
为中断回调函数中使用的参数的指针。
IoTGpioGetInputVal()
作用:读取指定GPIO的电平
示例:
1 | /* |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_gpio.h, IOT_GPIO_VALUE1为高电平,IOT_GPIO_VALUE0为低电平。
I2C总线开发
1. I2C总线开发基础
I2C通信中,主机通过时钟线SCL发送时钟信号,通过数据线SDA发送数据(包括从机地址、指令、数据包等),在发送完一帧数据后,需要等待从机的响应,才能继续发送下一帧数据,因此I2C属于同步通信。
2. 单I2C轮询
(1)IoTI2cInit()
作用:以指定的波特率初始化I2C设备。
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_i2c.h
(2)IoTI2cDeinit()
作用:关闭/去初始化指定的I2C设备。
定义:
1 | unsigned int IoTI2cDeinit(unsigned int id); |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_i2c.h
(3)IoTI2cWrite()
作用:向指定的I2C设备写入数据。
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_i2c.h
(4)IoTI2cRead()
作用:从指定的I2C设备读取数据。
注:未找到相应的示例,猜测该函数可能在驱动层面使用
定义:
1 | unsigned int IoTI2cRead(unsigned int id, unsigned short deviceAddr, |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_i2c.h
(5)IoTI2cSetBaudrate()
作用:设置指定I2C设备的波特率。
定义:
1 | unsigned int IoTI2cSetBaudrate(unsigned int id, unsigned int baudrate); |
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_i2c.h
3. I2C中断触发
示例:
1 | 195 void I2CBusExampleEntry(void) |
软件烧录成功后,按一下开发板的RESET按键复位开发板,可以在OLED屏幕上面看到陀螺仪方向角实时数据以及电池电量数据,当手机靠近小车的NFC模块时,NFC会拉起手机的淘宝应用,且可以通过S1、S2、S3功能按键来控制三个交通灯的亮灭,说明我们使用I2C总线,实现同时轮询多个设备的实验成功。
PWM接口开发
1. IoTPwmInit()
作用:初始化指定PWM端口
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_pwm.h
返回值:
IOT_SUCCESS:初始化成功
IOT_FAILURE:初始化失败
2. IoTPwmStart()
作用:启动PWM信号输出
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_pwm.h
3. IoTPwmStop()
作用:停止PWM信号输出
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_pwm.h
IoTPwmDeinit()
作用:释放/去初始化指定PWM端口
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_pwm.h
GPIO模拟PWM信号
Sg92r舵机原理
Sg92舵机的控制需要产生一个20ms的脉冲信号,以0.5ms到2.5ms的高电平来控制舵机的角度;高电平持续时间对应角度如下表所示。
高电平持续时间 | 角度 |
---|---|
0.5ms | 0° |
1.0ms | 45° |
1.5ms | 90° |
2.0ms | 135° |
2.5ms | 180° |
代码核心
1 | 30 void SetAngle(unsigned int duty) |
ADC开发
1.AdcRead()
作用:根据输入参数从指定的ADC通道读取一段采样数据
示例:
1 | ret = AdcRead(idx, &data, IOT_ADC_EQU_MODEL_4, IOT_ADC_CUR_BAIS_DEFAULT, 0xff); |
依赖库:src\applications\sample\wifi-iot\app\lth1550_demo\iot_adc.h
UART开发
1. IoTUartInit()
作用:初始化指定UART端口
示例:
1 |
|
依赖库:src\base\iot_hardware\peripheral\interfaces\kits\iot_uart.h
三、定时器使用——以频率测量为例
主要函数
1. osTimerId_t periodic_tid = osTimerNew(cb_timeout_periodic, osTimerPeriodic, NULL, NULL);
作用:创建一个新的定时器,命名为periodic_tid,其变量名称为osTimerId_t。
参数说明:
- cb_timeout_periodic:回调函数;
- osTimerPeriodic:定时器类型;
- NULL:(第一个)回调函数参数;
- NULL:(第二个)定时器属性
periodic_tid常用于确保定时器已创建成功,如下所示:
1 | if (periodic_tid == NULL) |
2. osTimerStart(periodic_tid, 100);
说明:
创建一个100个时钟周期调用一次回调函数cb_timeout_periodic的定时器
参数说明:
- periodic_tid:定时器ID;
- 100:定时器周期,单位为时钟周期,即100个时钟周期调用一次回调函数
3. void cb_timeout_periodic(void)
说明:定时器回调函数,无输入参数,无返回值。
频率测量原理
定时器每记过1个中断执行周期,期间开启上升沿输入捕获记录从低到高电平的变化个数num。由定时器中断执行周期/num可得到一个上升沿所占用的时钟周期,取倒数即可得到频率。
问题来了,Hi3861的系统时钟我找不到接口(骂骂咧咧.gif)
四、对华为云板端互联代码的分析:app_demo_iot.c
1. static void DemoMsgRcvCallBack(int qos, char *topic, char *payload)
代码结构:
1 | static void DemoMsgRcvCallBack(int qos, char *topic, char *payload) |
1 | static void TrafficLightMsgRcvCallBack(char *payload) |
解析:
- 该函数为回调函数,需要传入三个参数:qos、topic、payload,分别为服务质量、消息主题、消息内容(负载)。
- 调用TrafficLightMsgRcvCallBack函数处理消息内容。
- tmp = strstr(topic, CN_COMMAND_INDEX);用于在topic里查找 CN_COMMAND_INDEX 宏定义的字符串。如果找到了,说明这是一个来自平台的命令。
如果是,那么将计算请求ID的位置并将其存储在 requesID 变量。 - IoTCmdResp resp;用于创建一个 IoTCmdResp 类型的结构体 resp 并设置其字段。其中,requestID 字段设置为之前计算出的请求ID,respName 字段设置为NULL,retCode 字段设置为0表示成功,paras 字段设置为NULL。
让我们看看IoTCmdResp里面的内容:
1 | typedef struct { |
2. traffic light:1.control module
代码结构:
1 | void IotPublishSample(void) |
IoTProfilePropertyReport代码:
1 | //根据给定的设备 ID 和有效负载报告 IoT 设备的配置文件属性。 |
解析:
line 4:用 memset_s 函数将 property 变量的内存清零
line 5:设置其类型为字符串类型,名为 “ControlModule”
if:判断g_lightstatus的值并根据情况设置property的value字段
line 12:使用 memset_s 函数将 service 变量的内存清
line 13-14:设置服务 ID 为 “TrafficLight”,并将其服务属性指向 property 变量。
line 15:调用 IoTProfilePropertyReport 函数,使用设备 ID 和服务信息来上报物联网设备的状态信息。
3.demo main task entry
代码结构:
1 | // /< this is the demo main task entry,here we will set the wifi/cjson/mqtt ready ,and |
IoTSetMsgCallback代码:
1 | int IoTSetMsgCallback(FnMsgCallBack msgCallback) |
运行示例程序的输出结果:
1 | traffic light:control module //执行IotPublishSample函数, |
华为云端操作
ref:https://gitee.com/HiSpark/HiSpark_NICU2023/blob/master/4.5 物联网应用开发.md#452华为云的智能交通灯上报
1.创建产与相关属性
点击左边任务栏的“产品”同时选择控制台地址为“北京四”,然后点击最右上角的“创建产品”(产品名称可自定义)。注意:创建产品时如果所属空间为NULL,请先实名注册。
创建成功后,点击查看详情,点击“自定义模型”创建用户自己的模型:
根据自己需要自己定义,如为模型添加服务:“TrafficLight”,服务类型:“TrafficLight”,服务描述:“交通灯”,点击确定;新增属性为属性名称:“ControlModule”,数据类型:“String”,访问权限:“可读,可写”,长度:“255”,点击确定;新增命令为命令名称:“ControlModule”,新增参数:“TrafficLight”,数据类型:“String”,长度:“255”。
命令下发是 平台向设备下发设备控制命令 ,需要设备及时将命令的执行结果返回给平台。如果设备没有回应,平台会认为命令执行超时.
而响应参数是指 设备在收到平台下发的命令后,返回给平台的执行结果。 这些响应参数可以携带设备执行操作成功或失败后的响应参数.
点击左边任务栏的“设备”,然后注册设备图,注册创建的产品,用户根据自己需要随意填写,填写完成后,可以看到设备状态显示为未注册。
配置完成,如下:
2.工程移植
将oc_demo里的关于设备响应的函数抹去,因为此次工程只需要设备上报的功能。上报函数如下:
1 |
|
3. 云设备的激活
利用https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/ 生成Clientld,Username,Password。
将下图地方设备ID复制到DeviceId,密钥复制到DeviceSecret,点击Generate即可。
本次工程生成后的结果:
ClientId:64a98f799415fc7a573be8f0_Temp_Humi_Gas_Detector_0_0_2023070818
Username:64a98f799415fc7a573be8f0_Temp_Humi_Gas_Detector
Password:d500d9f5e8b5ad551b4b90181d8f22f0166b8afa91540e8b4bd995648665e483
修改applications/sample/wifi-iot/app/oc_demo/目录下iot_config.h中,WiFi名称和WiFi密码,搜索字段CONFIG_AP_SSID:代表WiFi名称;CONFIG_AP_PWD:代表WiFi密码(板子需要连接的WiFi)。
1 | // /<CONFIG THE WIFI |
修改applications/sample/wifi-iot/app/oc_demo/目录下iot_config.h中搜索CONFIG_DEVICE_ID和CONFIG_DEVICE_PWD,CONFIG_CLIENTID这三个字段。CONFIG_DEVICE_ID和CONFIG_DEVICE_PWD,CONFIG_CLIENTID,三个字段配置参数见上:
1 | // /<Configure the iot platform |
在华为云如下界面点击总览,可以看到平台接入地址,点击进去之后可以看到设备接入MQTT字样如下图所示,复制“xxxxxxx.iot-mqtts.cn-north-4.myhuaweicloud.com”字段,将该字段写到./applications/sample/wifi-iot/app/oc_demo/iot_main.c中CN_IOT_SERVER字段中。具体修改如下图所示。
报错?
=======KERNEL PANIC=======
syserr info start
kernel_ver : Hi3861V100 R001C00SPC025,2020-09-03 18:10:00
Exception Information
PC Task Name : IOTDEMO
PC Task ID = 9
Cur Task ID = 9
Task Stack Size = 0x1000
Exception Type = 0x5
reg info
mepc = 0x3fb732
mstatus = 0x1880
mtval = 0x1e
mcause = 0x5
ccause = 0x7
ra = 0x4b0ab2
sp = 0xfc5a0
gp = 0x11a9c0
tp = 0x78b11c76
t0 = 0x4b0a9a
t1 = 0xf
t2 = 0x6d65545f
s0 = 0x11d000
s1 = 0x0
a0 = 0x1e
a1 = 0x0
a2 = 0x4
a3 = 0x1e
a4 = 0xd00a0dff
a5 = 0x11d000
a6 = 0xfed01
a7 = 0x35313439
s2 = 0x1e
s3 = 0xfc774
s4 = 0x11111111
s5 = 0x10101010
s6 = 0x9090909
s7 = 0x8080808
s8 = 0x7070707
s9 = 0x6060606
s10 = 0x5050505
s11 = 0x4040404
t3 = 0x39376638
t4 = 0x39613436
t5 = 0x1ce
t6 = 0x4c61b8
memory info
Pool Addr = 0xe9d80
Pool Size = 0x2e840
Fail Count = 0x0
Peek Size = 0x16ca4
Used Size = 0x15c48
task info
Name : IOTDEMO
ID = 9
Status = 0x14
Stack Index = 0x8
Stack Peak = 0xb84
Stack Size = 0x1000
SP = 0x11a860
Stack : 0xfb7e0 to 0xfc7e0
Real SP = 0xfc5a0
Stack Overflow = 0
track_info
current_item:0x1
item_cnt:10
Index TrackType TrackID CurTime Data1 Data2
0001 0065 0009 0x10fa 0xd99ec 0x3f5e78
0002 0065 0001 0x10f8 0x3f5e78 0xd99ec
0003 0016 0007 0x10f8 0xd99ec 0x0
0004 0065 0000 0x10f9 0xd99ec 0x3f5e78
0005 0065 0007 0x10f9 0x3f5e78 0x3f5e78
0006 0065 0001 0x10f9 0x3f5e78 0xd99ec
0007 0016 0034 0x10f9 0xd99ec 0x0
0008 0065 0007 0x10f9 0xd99ec 0x3f5e78
0009 0065 0001 0x10f9 0x3f5e78 0xd99ec
0010 0016 0007 0x10f9 0xd99ec 0x0
Call Stack
Call Stack 0 – 4b0da0 addr:fc66c
Call Stack 1 – 4b5108 addr:fc68c
Call Stack 2 – 4b514c addr:fc6ac
Call Stack 3 – 4b51a0 addr:fc6cc
Call Stack 4 – 4b5224 addr:fc6ec
Call Stack 5 – 4b525c addr:fc70c
Call Stack 6 – 4b52e0 addr:fc73c
Call Stack 7 – 4b4882 addr:fc76c
Call Stack 8 – 4b49d0 addr:fc7ac
Call Stack 9 – 3f78c0 addr:fc7cc
Call Stack 10 – 3f5e24 addr:fc7dc
Call Stack end
🤔内核被我写爆了???
经过多方排查,发现property.value只能传进字符串,不能识别的格式,会导致内核崩溃。(虽然工程编译没有问题,其背后原因不得而知,可能需要请教海思的工程师)
修复之后:
作品设想
1. 作品功能
A.基础设施智能化建设解决方案
将小区分为社区门口、单元门、电梯间、入户门、停车场、公共区域、设备间7 个重点区域,对门禁、道闸、对讲、梯控、视频监控、周界防范、信息发布、停车管理、设备检测等进行基础设施智能化开发与建设,为智慧社区整体方案提供支撑,基础设施见图:
最终敲定功能:
小区设备综合管控:供电监测、水暖系统、排水系统、通风系统的设备情况实时监测
人脸、车牌识别:
电梯设备状态监控:
与市气象站数据整合,小区植被喷淋系统
主要工作:Hi3861开发板学习、各种传感器选型、解决方案敲定等。
B.物业综合服务平台
该平台用于:完成人员管理、养老服务、卫生服务、信息发布、收缴费管理、报事报修、车辆管理、便民服务等功能开发;为物业提供社区基础数据、日常业务管理工具,通过数据共享和应用聚合向政府提供社区管理通道、向居民提供社区服务。平台服务与应用见图4:
主要工作:华为云服务的学习与配置,物业综合服务平台的开发。
项目故事
物业<->USER/业主<->政府/社区 双向的故事 双向的沟通交流,贴近居民生活,提高居民生活质量。
海思CAMP
项目管理方法
传感器选型
电能监控模块
艾锐达IM1253B交直流电压电流功率电量测量电能采集电测计量模块
ref:https://item.taobao.com/item.htm?spm=a21n57.1.0.0.7b90523cKNbIy1&id=571489221834&ns=1&abbucket=0#detail
流量计模块
系统时钟拿不到就是寄,不用了((╯‵□′)╯︵┻━┻)