鸿蒙OS2.0 设备开发之Hi3861-基础功能汇总 原创 精华
@toc
这是一篇讲解在鸿蒙2.0全量源码中开发Hi3861的常用功能汇总,可帮助我们快速配置GPIO 如,如何实现PWM、I2C、ADC等。
1.基本IO功能
1.1 输出
分两步,使能、配置输出值;
IoTGpioInit(GPIO_idx);
IoTGpioSetDir(GPIO_idx,1);//1-输出 0-输入
IoTGpioSetOutputVal(GPIO_idx,1); //0-低 1-高
需要注意的是,有些GPIO还需要设置复用功能,可能默认不是普通GPIO模式。
这时候就需要使用hi_io_set_func函数;以GPIO9为例,设为普通IO;
hi_io_set_func(BEEP_IO,HI_IO_FUNC_GPIO_9_GPIO_OUT);
1.2 输入
分三步,使能、配置输入方式(上下拉)、获取io电平;
IoTGpioInit(GPIO_idx);
IoTGpioSetDir(GPIO_idx,0);//1-输出 0-输入
hi_io_set_pull(GPIO_idx, HI_IO_PULL_UP); //==上拉输入
IoSetPull(GPIO_idx, HI_IO_PULL_UP); //自行封装在iot_gpio.h 2021.09.23
IoTGpioGetInputVal(GPIO_idx,1); //0-低 1-高
1.3 系统延时
系统延时函数比较多,具体区别看使用效果。常用的有
usleep(us); // delay us
osDelay(us);// delay us
hi_udelay(us);// delay_us int32
2.PWM输出
Hi3861共有6路PWM。++Hi3861-2.0版本PWM使用流程++: ++1.初始化io、2. io复用为pwm、3. 使能pwm通道、4. 开始输出pwm 、5.停止输出pwm++
//==初始化 GPIO9
IoTGpioInit(PWM0_TEST_GPIO);
//==初始化 GPIO9 的pwm复用功能
hi_io_set_func(PWM0_TEST_GPIO,HI_IO_FUNC_GPIO_9_PWM0_OUT);
//==初始化pwm通道0
IoTPwmInit(PWM0);
//==配置pwm0输出参数:占空比50%、频率160M/80000=2KHz
IoTPwmStart(PWM0,50,80000);
IoTPwmStop(PWM0); //以上pwm操作基于iot_pwm.h 封装的函数,实质是封装hi_pwm.h
hi_pwm_init(hi_pwm_port port);
hi_pwm_start(hi_pwm_port port, hi_u16 duty, hi_u16 freq);
hi_pwm_stop(hi_pwm_port port); //以上pwm操作基于hi_pwm.h 封装的函数
2.1 PWM常用API
iot_pwm.h 封装的函数中,与hi_pwm.h 封装的函数入口参数不同;
iot_pwm.h 中定义的IoTPwmStart();
unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq)
port:0-5 pwm通道号
duty:1-99 占空比,不可为0\100
freq:>160M/65535 = 2441 与pwm频率有关,不是直接设置
unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq)
{
unsigned short hiDuty;
unsigned short hiFreq;
hiFreq = (unsigned short)(CLK_160M / freq);
hiDuty = (duty * hiFreq) / DUTY_MAX;
return hi_pwm_start((hi_pwm_port)port, hiDuty, freq);
// 源码: return hi_pwm_start((hi_pwm_port)port, hiDuty, hiFreq);
//最后一个参数为分频系数,传入时不能先使用160M/freq 这样不对, 2021.09.26 自信修正
}
hi_pwm.h 中定义的hi_pwm_start();
按配置的参数输出PWM信号。PWM信号占空比=duty/freq。频率=时钟源频率/freq。
* @param port [IN] PWM端口号。
* @param duty [IN] PWM占空比计数值。取值范围为:[1, 65535]。默认值为750。CNend
* @param freq [IN] 分频倍数。取值范围为:[1, 65535]。默认值为1500。
hi_u32 hi_pwm_start(hi_pwm_port port, hi_u16 duty, hi_u16 freq);
可以看出,函数封装后可更方便的使用PWM,直接设置占空比(1-99)。但发现iot_pwm.h封装的IoTPwmStart()频率有错误,导致pwm不正常,原因是在IoTPwmStart()中,hiFreq已经是计算后的实际频率,不是分频系数。给hi_pwm_start()传入数据时,不应该传入hiFreq,应该还是最初的freq。我已修正该封装,顺利驱动了蜂鸣器。
pwm总结,无论使用IoTPwmStart()还是hi_pwm_start(),实际输出频率hiFreq:
hiFreq = (unsigned short)(CLK_160M / freq);
//注:hi_u32 hi_pwm_set_clock(hi_pwm_clk_source clk_type); //==设置时钟源,默认160M
pwm总结,使用IoTPwmStart(port,duty,freq)实际占空比hiDuty:
hiFreq = (unsigned short)(CLK_160M / freq);
hiDuty = (duty * hiFreq) / 100; //所占总周期的百分比
pwm总结,使用hi_pwm_start(port,duty,freq)实际占空比hiDuty:
hiDuty = (duty) / 65535;
2.2 如何控制舵机
hi3861-PWM其他信息
–理论频率 [1, 65.535]KHz
(CLK_160M / freq) < 0xFFFF(65535)
分频系数freq [2442,160M]
–实际频率不会很低,具体没测,没示波器,
数字舵机(T=20ms)无法控制。
++模拟低频pwm: 延时+io输出(0-1)模拟实现++ 控制精度要求不是很高可以这么做。期待官方出解决方案。
3.ADC实现
Hi3861共有7路ADC , 各通道见hi3861手册表6.2(截取如下) 一共8个ADC通道,ADC0–ADC7 但通道7为参考电压,不能adc转换。
3.1 ADC常用API
++Hi3861-2.0版本ADC使用流程:++1.初始化io、2. io为输入、3. 配置输入模式、4. 读取AD数据。
IoTGpioInit(pinID);
IoTGpioSetDir(pinID,IOT_GPIO_DIR_IN);
hi_io_set_func(pinID,HI_IO_FUNC_GPIO_pinID_GPIO);
//可选,上拉等:
//IoSetPull(pinID, HI_IO_PULL_UP);
hi_io_set_pull(pinID,HI_IO_PULL_UP);
hi_adc_read(HI_ADC_CHANNEL_0,&data,HI_ADC_EQU_MODEL_1,HI_ADC_CUR_BAIS_DEFAULT, 0);
3.2 ADC使用注意事项
Hi3861-2.0版本i2c hi_adc_read()参数解析
hi_u32 hi_adc_read(hi_adc_channel_index channel, hi_u16 *data,
hi_adc_equ_model_sel equ_model, hi_adc_cur_bais cur_bais, hi_u16 delay_cnt);
channel: 0-7,通道0-7
*data :采集的AD数据
equ_model:平均算法模式,将采集后的数据平均再使用,取1就是原始数据,不平均。
cur_bais: 模拟电源控制,一般设置为默认
delay_cnt:从配置采样到启动采样的延时时间计数,一次计数是334ns,其值需在0~0xFF0之间
获取数据是指针传值。
4. 驱动i2c
4.1 i2c API
++Hi3861-2.0版本i2c使用流程(两路i2c):1.初始化io、2. 复用io为i2c、3. 初始化对应i2c通道、4. 读取/发送数据。++
//==i2c1
IoTGpioInit(I2C1_SDA_IO13);
IoTGpioInit(I2C1_SCL_IO14); //初始化io接口
hi_io_set_func(I2C1_SDA_IO13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
hi_io_set_func(I2C1_SCL_IO14 , HI_IO_FUNC_GPIO_14_I2C0_SCL); //==GPIO 复用为I2C0
hi_i2c_init(OLED_I2C_IDX, OLED_I2C_BAUDRATE); //==使能i2c1设置传输速率 OLED_I2C_IDX值为1
hi_i2c_write((hi_i2c_idx)id, OLED_I2C_ADDR, &i2cData);
//==i2c0
IoTGpioInit(MPU_SDA_IO0);
IoTGpioInit(MPU_SCL_IO1);
hi_io_set_func(MPU_SDA_IO0, HI_IO_FUNC_GPIO_13_I2C0_SDA);
hi_io_set_func(MPU_SCL_IO1, HI_IO_FUNC_GPIO_14_I2C0_SCL);
hi_i2c_init(MPU_I2C_IDX, MPU_I2C_BAUDRATE); //==使能i2c1设置传输速率 OLED_I2C_IDX值为0
hi_i2c_write((hi_i2c_idx)id, ((MPU_ADDR<<1)|0), &i2cData); //==发送器件地址+写命令+目标寄存器reg + 写入的data
hi_i2c_read((hi_i2c_idx)id,((MPU_ADDR<<1)|1), &i2cData); //==发送器件地址+读命令+目标寄存器reg + 读取的data
4.2 i2c 使用提示
Hi3861-2.0版本i2c 一些重要定义:
读取、发送的数据是一个结构体;
数据均使用指针的形式传值;
定义的函数每次只能收、发8位数据;
i2c 函数的一些思考:
如果读取一个寄存器地址为16bit的器件怎么办?----截断,分两次发送;
对mpu6050发、收数据一次需要发送两个地址(设备地址、目标寄存器地址),如何实现?---把第二个地址当作数据发送。
小总结
- [x]
基本IO功能 - [x]
I2C相关API - [x]
PWM相关API - [x]
ADC相关API
常用的头文件
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h" //==系统依赖 包括usleep() osdelay()
#include "iot_gpio.h" //==IoTGpioInit()、IoTGpioSetDir()、IoTGpioSetOutPutVal()
#include "iot_pwm.h" //==IoTPwmStart()、IoTPwmInit()
#include "hi_io.h" //==hi_io_set_func()、hi_io_set_pull()
#include "hi_pwm.h" //==hi_pwm_start()
#include "hi_adc.h" //==hi_adc_read()
#include "hi_time.h" //==hi_udelay()
我写了开发记录PPT,需要的可以去我B站私信自提点我拿资料。
5.演示案例及其链接
学会使用以上API之后,就可以实现各种功能,比如在HiSpark Wi-Fi IOT智能家居套件中提供的各种拓展板(炫彩板、环境监测板、交通灯板),学习过程中做了一些演示视频,有兴趣可点击查看:
i2c通信–连接MPU6050:点我见演示视频
ADC、PWM控制LED、蜂鸣器、舵机、各种拓展板:点我见演示视频
6.其他功能(wifi入网、web编程)
鸿蒙OS的目标是万物互联,其实更有意思的是Hi3861支持鸿蒙OS-轻量化小型系统并且具备wifi入网能力,连接上网,就可以说做很多事儿。比如视频末尾使用手机控制舵机,想想还能做啥呢? 无钥匙开门、开关灯、控制家电、控制设备……
下一期讲讲wifi入网,实现无钥匙开宿舍门。
不错 学习!!
点赞,收藏,学习
一份好资料
求教大牛 , pwm怎么驱动舵机 ,hi_pwm_start这个函数中三个参数该怎么设置。比如我要驱动 180度舵机 ,分别0-45-90-135-180,其占空比分别为2.5-5-7.5-10-12.5。用到这个里面,三个参数怎么设置
你好,hi3861的pwm频率太高,舵机一般是1000/20 = 50Hz的pwm,所以想控制舵机只好用GPIO输出高低电平来模拟,结合延时函数就可以
多谢多谢,我之前已经用你说的这个方法解决了,只是角度精度不够