梅科尔工作室-#14天鸿蒙设备开发实战#驱动子系统开发笔记 原创 精华
@toc
HarmonyOS驱动子系统开发
操作GPIO
参考:
GPIO API介绍
GPIO(General-purpose input/output)意思为通用输入/输出端口,通用型之输入输出的简称,用于电信号在电路中的输入输出,以方便控制电路部件。通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
wifiiot_gpio.h接口简介
这个.h中包含声明GPIO接口函数,这些功能用于初始化GPIO。
接口名 | 功能描述 |
---|---|
Gpiolnit | 初始化GPIO |
GpioDeinit | 取消初始化GPIO |
GpioSetDir | 设置GPIO引脚方向 |
GpioGetDir | 获取GPIO引脚方向 |
GpioSetOutputVal | 设置GPIO引脚输出电平值 |
GpioGetOutputVal | 获取GPIO引脚输出电平值 |
源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_gpio.h
路径下,可以从案例目录下的BUILD.gn文件中查找
-
GpioInit()
unsigned int GpioInit (void )
描述: 初始化GPIO外设
-
IoSetFunc()
unsigned int IoSetFunc (WifiIotIoName id, unsigned char val )
描述: 设置GPIO引脚复用功能
参数:
名字 描述 id 表示GPIO引脚号. val 表示GPIO复用功能 -
GpioSetDir()
unsigned int GpioSetDir (WifiIotGpioIdx id, WifiIotGpioDir dir )
描述: 设置GPIO输出方向
参数:
名字 描述 id 表示GPIO引脚号 dir 表示GPIO输出方向
wifiiot_gpio_ex.h接口简介
这个.h中包含声明扩展的GPIO接口函数,这些功能用于设置GPIO拉力和驱动器强度。
接口名 | 功能描述 |
---|---|
loSetPull | 设置GPIO引脚上拉 |
loGetPull | 获取GPIO引脚上拉 |
loSetFunc | 设置GPIO引脚功能 |
loGetFunc | 获取GPIO引脚功能 |
IOSetDriverStrength | 设置GPIO驱动能力 |
lOGetDriverStrength | 获取GPIO驱动能力 |
查看LED对应的GPIO引脚
LED对应的GPIO引脚是GPIO2,通过控制GPIO2输出的的电平信号来实现LED灯的闪烁。
-
高电平时点亮LED灯。
-
低电平时熄灭LED灯。
操作GPIO点亮LED
源码在applications\BearPi\BearPi-HM_Nano\sample\B1_basic_led_blink\led_example.c
路径下,以下添加了部分注释:
/*LED以1S的频率闪烁*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
static void LedTask(void)
{
//初始化GPIO
GpioInit();
//设置GPIO_2的复用功能为普通GPIO
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO); // 参数分别表示GPIO引脚号、GPIO复用功能
//设置GPIO_2为输出模式
GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT); // 参数分别表示GPIO引脚号、GPIO输出方向
while (1)
{
//设置GPIO_2输出高电平点亮LED灯
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1); // 参数分别表示GPIO引脚号、电平高低(1为高电平、0为低电平)
//延时1s
usleep(1000000);
//设置GPIO_2输出低电平熄灭LED灯
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 0);
//延时1s
usleep(1000000);
}
}
static void LedExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "LedTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 512;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL)
{
printf("Falied to create LedTask!\n");
}
}
APP_FEATURE_INIT(LedExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定led_example
,编译、烧录,按一下复位按键,可以看到开发板上的LED灯以1s的频率闪烁
GPIO扩展实验
源码:
/*读取GPIO的输出模式,读取GPIO的高低电平,*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
static void LedTask(void)
{
//初始化GPIO
GpioInit();
//设置GPIO_2的复用功能为普通GPIO
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO); // 参数分别表示GPIO引脚号、GPIO复用功能
//设置GPIO_2为输出模式
GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT); // 参数分别表示GPIO引脚号、GPIO输出方向
WifiIotGpioDir val = {0}; // 定义变量,存储GPIO输出方向指针的地址
GpioGetDir(WIFI_IOT_GPIO_IDX_2, &val); // 读取GPIO的输出模式,并赋值给val
printf("GPIO_2 Dir is %d\r\n", val); // 打印,0是输入(WIFI_IOT_GPIO_DIR_IN),1是输出(WIFI_IOT_GPIO_DIR_OUT)
WifiIotGpioValue OutputVal = {0}; // 定义变量,存储GPIO高低电平指针的地址
while (1)
{
//设置GPIO_2输出高电平点亮LED灯
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1); // 参数分别表示GPIO引脚号、电平高低(1为高电平、0为低电平)
GpioGetOutputVal(WIFI_IOT_GPIO_IDX_2, &OutputVal); // 读取GPIO的高低电平,并赋值给OutputVal
printf("GPIO_2 OutputVal is %d\r\n", OutputVal);
//延时1s
usleep(1000000);
//设置GPIO_2输出低电平熄灭LED灯
GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 0);
GpioGetOutputVal(WIFI_IOT_GPIO_IDX_2, &OutputVal); // 读取GPIO的高低电平,并赋值给OutputVal
printf("GPIO_2 OutputVal is %d\r\n", OutputVal);
//延时1s
usleep(1000000);
}
}
static void LedExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "LedTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 512;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL)
{
printf("Falied to create LedTask!\n");
}
}
APP_FEATURE_INIT(LedExampleEntry);
编译、烧录、打印日志
日志如下:
GPIO中断
GPIO中断API介绍
参考:
wifiiot_gpio.h接口简介
接口名 | 功能描述 |
---|---|
GpioRegisterlsrFunc | 设置GPIO引脚中断功能 |
GpioUnregisterlsrFunc | 取消GPIO引脚中断功能 |
GpioSetlsrMask | 屏蔽GPIO引脚中断功能 |
GpioSetlsrMode | 设置GPIO引脚中断触发模式 |
-
GpioRegisterIsrFunc()
unsigned int GpioRegisterIsrFunc (WifiIotGpioIdx id, WifiIotGpioIntType intType, WifiIotGpioIntPolarity intPolarity, GpioIsrCallbackFunc func, char * arg )
描述:启用GPIO引脚的中断功能。这个函数可以用来为GPIO pin设置中断类型、中断极性和中断回调。
参数:
名字 描述 id 表示GPIO引脚号 intType 表示中断类型,可设置为 WIFI_IOT_INT_TYPE_LEVEL
(电平触发)和WIFI_IOT_INT_TYPE_EDGE
(边沿触发),电平触发是指GPIO为高电平或低电平时触发,边沿触发是指GPIO电平跳变时触发,即高电平变为低电平(下降沿)或低电平变为高电平(上升沿)intPolarity 表示中断极性,可设置为 WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW
和WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH
,如果设置为WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW
,中断类型为电平触发时,表示低电平触发,中断类型为边沿触发时,表示下降沿触发;设置为WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH
则相反func 表示中断回调函数,中断期间执行的函数 arg 表示中断回调函数中使用的参数的指针,可以向中断回调函数传递参数
源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_gpio.h
路径下
查看按键对应的GPIO引脚
F1和F2按键对应的GPIO引脚是分别是GPIO11和GPIO12,通过检测GPIO的电平信号来判断按键的状态。
GPIO中断读取按键状态
源码在applications\BearPi\BearPi-HM_Nano\sample\B2_basic_button\button_example.c
路径下,以下添加了部分注释:
/*按一下F1,LED灯会被点亮,再按一下F2,LED灯会被熄灭*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
static void F1_Pressed(char *arg)
{
(void)arg;
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1); // 设置GPIO引脚为高电平
}
static void F2_Pressed(char *arg)
{
(void)arg;
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0); // 设置GPIO引脚为低电平
}
static void ButtonExampleEntry(void)
{
GpioInit(); // 初始化GPIO
//初始化LED灯
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT); // 设置GPIO_2为输出模式
//初始化F1按键,设置为下降沿触发中断
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO); // 设置GPIO_11的复用功能为普通GPIO
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_IN); // 设置GPIO_2为输入模式
IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP); // 设置GPIO引脚为上拉
GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL); // 边沿触发,设置GPIO引脚中断功能
// GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_LEVEL, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL); // 电平触发,设置GPIO引脚中断功能
//初始化F2按键,设置为下降沿触发中断
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_FUNC_GPIO_12_GPIO);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_GPIO_DIR_IN);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_PULL_UP);
GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2_Pressed, NULL);
}
APP_FEATURE_INIT(ButtonExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定button_example
,编译、烧录,按一下复位按键,按一下F1,LED灯会被点亮,再按一下F2,LED灯会被熄灭
GPIO中断扩展实验
源码
/*通过GpioSetIsrMode改变中断触发模式,通过GpioSetIsrMask屏蔽GPIO引脚中断功能,第一次按下F1、F2都能打印日志,第二次F1按键被按下时不会打印日志,松开之后才会打印出来,再按下F2不会打印出日志*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
static void F1_Pressed(char *arg)
{
(void)arg;
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1); // 设置GPIO引脚为高电平
printf("This is F1_Pressed\r\n");
GpioSetIsrMode(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH); // 设置GPIO引脚中断触发模式为上升沿
}
static void F2_Pressed(char *arg)
{
(void)arg;
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0); // 设置GPIO引脚为低电平
printf("This is F2_Pressed\r\n");
GpioSetIsrMask(WIFI_IOT_IO_NAME_GPIO_12, 1); // 屏蔽GPIO_12引脚中断功能(1为屏蔽,0为不屏蔽)
}
static void ButtonExampleEntry(void)
{
GpioInit(); // 初始化GPIO
//初始化LED灯
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT); // 设置GPIO_2为输出模式
//初始化F1按键,设置为下降沿触发中断
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO); // 设置GPIO_11的复用功能为普通GPIO
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_IN); // 设置GPIO_2为输入模式
IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP); // 设置GPIO引脚为上拉
GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL); // 边沿触发,设置GPIO引脚中断功能
// GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_LEVEL, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F1_Pressed, NULL); // 电平触发,设置GPIO引脚中断功能
//初始化F2按键,设置为下降沿触发中断
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_FUNC_GPIO_12_GPIO);
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_GPIO_DIR_IN);
IoSetPull(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_PULL_UP);
GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, F2_Pressed, NULL);
}
APP_FEATURE_INIT(ButtonExampleEntry);
编译、烧录、打印日志
日志如下:
PWM输出
参考:
PWM API介绍
wifiiot_pwm.h接口简介
这个wifiiot_pwm.h中包含声明PWM接口函数
接口名 | 功能描述 |
---|---|
PwmInit | 初始化PWM |
PwmDeinit | 取消初始化PWM |
PwmStart | 根据输入参数输出PWM |
PwmStop | 停止PWM输出 |
原代码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_pwm.h
路径下
-
PwmStart()
unsigned int PwmStart (WifiIotPwmPort port, unsigned short duty, unsigned short freq)
描述:
根据输入参数输出PWM信号。
参数:
名字 描述 port PWM端口号 duty 占空比 freq 分频倍数
查看LED对应的GPIO引脚
LED对应的GPIO引脚是GPIO2,通过控制GPIO2输出的的电平信号来实现LED灯的闪烁。
- 高电平时点亮LED灯。
- 低电平时熄灭LED灯。
输出PWM改变LED亮度
源码在applications\BearPi\BearPi-HM_Nano\sample\B3_basic_pwm_led\pwm_example.c
路径下,以下添加了部分注释:
/*LED由最暗变亮,变到最亮时,又变灰最暗,循环往复*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#define PWM_TASK_STACK_SIZE 512
#define PWM_TASK_PRIO 25
static void PWMTask(void)
{
unsigned int i;
//初始化GPIO
GpioInit();
//设置GPIO_2引脚复用功能为PWM
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_PWM2_OUT);
//设置GPIO_2引脚为输出模式
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);
//初始化PWM2端口
PwmInit(WIFI_IOT_PWM_PORT_PWM2);
while (1)
{
for (i = 0; i < 40000; i += 100)
{
//输出不同占空比的PWM波
PwmStart(WIFI_IOT_PWM_PORT_PWM2, i, 40000); // 参数分别表示PWM端口号、占空比、分频系数
usleep(10);
}
i = 0;
}
}
static void PWMExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "PWMTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 512;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)PWMTask, NULL, &attr) == NULL)
{
printf("Falied to create PWMTask!\n");
}
}
APP_FEATURE_INIT(PWMExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定pwm_example
,编译、烧录,按一下复位按键,可以看到LED呼吸的效果,由暗变亮再变到最暗,再重复这个过程
PWM扩展实验
源码:
/*PwmStop和PwmDeinit的使用,使用PwmStop时,可以看到LED灯变得很暗,但是还是在逐渐变亮再变到最暗,以此重复;使用PwmDeinit时,可以看到当LED灯由暗变亮再变暗经过5次后,LED灯保持常亮*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#define PWM_TASK_STACK_SIZE 512
#define PWM_TASK_PRIO 25
static void PWMTask(void)
{
unsigned int i;
//初始化GPIO
GpioInit();
//设置GPIO_2引脚复用功能为PWM
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_PWM2_OUT);
//设置GPIO_2引脚为输出模式
GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT);
//初始化PWM2端口
PwmInit(WIFI_IOT_PWM_PORT_PWM2);
uint8_t j = 0;
while (1)
{
for (i = 0; i < 40000; i += 100)
{
//输出不同占空比的PWM波
PwmStart(WIFI_IOT_PWM_PORT_PWM2, i, 40000); // 参数分别表示PWM端口号、占空比、分频系数
// PwmStop(WIFI_IOT_PWM_PORT_PWM2); // 停止PWM输出
usleep(10);
}
i = 0;
j++;
if (j == 5)
{
PwmDeinit(WIFI_IOT_PWM_PORT_PWM2); // 取消初始化PWM
}
}
}
static void PWMExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "PWMTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 512;
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)PWMTask, NULL, &attr) == NULL)
{
printf("Falied to create PWMTask!\n");
}
}
APP_FEATURE_INIT(PWMExampleEntry);
使用PwmStop时,将PwmDeinit有关语句注释掉,编译、烧录,按一下复位按键,可以看到LED灯在逐渐变亮再变到最暗,但LED灯整体变得很暗,以此重复
使用PwmDeinit时,将PwmStop有关语句注释掉,编译、烧录,按一下复位按键,可以看到当LED灯由暗变亮再变暗经过5次后,LED灯保持常亮,亮度不再变化
ADC采样
参考:
ADC API介绍
wifiiot_adc.h接口简介
这个wifiiot_adc.h中包含声明ADC接口函数
接口名 | 功能描述 |
---|---|
AdcRead | 根据输入参数从指定的ADC通道读取一段采样数据 |
源码在ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_adc.h
路径下
-
AdcRead()
unsigned int AdcRead (WifiIotAdcChannelIndex channel, unsigned short * data, WifiIotAdcEquModelSel equModel, WifiIotAdcCurBais curBais, unsigned short rstCnt )
描述:
根据输入参数从指定的ADC通道读取一段采样数据
参数:
名字 描述 channel 表示ADC通道 data 表示指向存储读取数据的地址的指针 equModel 表示平均算法的次数 curBais 表示模拟功率控制模式 rstCnt 表示从重置到转换开始的时间计数。一次计数等于334纳秒。值的范围必须从0到0xFF
查看ADC对应的GPIO引脚
本案例将使用板载用户按键F1来模拟GPIO口电压的变化。GPIO_11对应的是ADC Channel 5,所以需要编写软件去读取ADC Channel 5的电压。GPIO对应的哪个ADC通道需要从芯片手册查看。芯片手册参见附件。
ADC读取GPIO的电压值
源码在applications\BearPi\BearPi-HM_Nano\sample\B4_basic_adc\adc_example.c
路径下,以下添加了部分注释:
/*当没有按F1键的时候电压约为3.336V,按下F1键未松手的时候电压约为0.223V,松手后电压又变成约为3.336V*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_errno.h"
#include "wifiiot_adc.h"
#define ADC_TASK_STACK_SIZE 1024 * 8
#define ADC_TASK_PRIO 24
/***** 获取电压值函数 *****/
static float GetVoltage(void)
{
unsigned int ret;
unsigned short data;
ret = AdcRead(WIFI_IOT_ADC_CHANNEL_5, &data, WIFI_IOT_ADC_EQU_MODEL_8, WIFI_IOT_ADC_CUR_BAIS_DEFAULT, 0xff); // 参数分别表示ADC通道,由GPIO对应的ADC通道确定、存储读取数据的地址的指针、平均算法的次数、模拟功率控制模式,此处为默认模式、从重置到转换开始的时间计数
if (ret != WIFI_IOT_SUCCESS)
{
printf("ADC Read Fail\n");
}
return (float)data * 1.8 * 4 / 4096.0; // 计算出电压值并返回
}
static void ADCTask(void)
{
float voltage;
//上拉,让按键未按下时GPIO_11保持高电平状态
IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP);
while (1)
{
printf("=======================================\r\n");
printf("***************ADC_example*************\r\n");
printf("=======================================\r\n");
//获取电压值
voltage = GetVoltage();
printf("vlt:%.3fV\n", voltage);
//延时1s
usleep(1000000);
}
}
static void ADCExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "ADCTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = ADC_TASK_STACK_SIZE;
attr.priority = ADC_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)ADCTask, NULL, &attr) == NULL)
{
printf("[ADCExample] Falied to create ADCTask!\n");
}
}
APP_FEATURE_INIT(ADCExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定adc_example
,编译、烧录,打印日志
日志结果如下:
当没有按F1键的时候电压约为3.336V,按下F1键未松手的时候电压约为0.223V,松手后电压又变成约为3.336V
I2C总线
参考:
(I2C可以读作“I方C”)
I2C API介绍
wifiiot_i2c.h接口简介
wifiiot_i2c.h中包含声明I2C接口函数
接口名 | 功能描述 |
---|---|
l2clnit | 初始化I2C |
I2cDeinit | 取消l2C初始化 |
l2cWrite | 将数据写入到I2C设备 |
l2cRead | 从I12C设备读取数据 |
源码见ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_i2c.h
I2cInit()
unsigned int I2cInit (WifiIotI2cIdx id, unsigned int baudrate )
描述:
用指定的频率初始化I2C设备
参数:
名字 | 描述 |
---|---|
id | I2C设备ID |
baudrate | I2C频率,一般设置为400000或者100000 |
I2cWrite()
unsigned int I2cWrite (WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData * i2cData )
描述:
将数据写入I2C设备
参数:
名字 | 描述 |
---|---|
id | I2C设备ID |
deviceAddr | I2C设备地址 |
i2cData | 表示写入的数据 |
I2cRead()
unsigned int I2cRead (WifiIotI2cIdx id, unsigned short deviceAddr, const WifiIotI2cData * i2cData )
描述:
从I2C设备读取数据。读取的数据将保存到i2cData指定的地址
参数:
名字 | 描述 |
---|---|
id | I2C设备ID |
deviceAddr | I2C设备地址 |
i2cData | 表示要读取的数据指向的指针 |
wifiiot_i2c_ex.h接口简介
wifiiot_i2c_ex.h中包含声明扩展I2C接口函数
接口名 | 功能描述 |
---|---|
l2cWriteread | 向I2C设备发送数据并接受数据响应 |
l2cSetBaudrate | 设置I2C频率 |
源码见ohos_bundles\@ohos\iot_controller\interfaces\kits\wifiiot_lite\wifiiot_i2c_ex.h
I2cSetBaudrate()
unsigned int I2cSetBaudrate (WifiIotI2cIdx id, unsigned int baudrate )
描述:
为I2C设备设置频率,一般用于代码运行过程中,修改I2C频率
参数:
名字 | 描述 |
---|---|
id | I2C设备ID |
baudrate | I2C频率 |
查看NFC的I2C对应的GPIO引脚
NFC芯片的I2C对应的GPIO引脚是分别是GPIO0和GPIO1,所以需要编写软件使用GPIO_0和GPIO_1产生I2C信号去控制NFC芯片。
I2C读写NFC芯片
源码在applications\BearPi\BearPi-HM_Nano\sample\B5_basic_i2c_nfc\i2c_example.c
路径下,以下添加了部分注释:
/*使用具有NFC功能的手机去触碰开发板NFC天线,可以看到手机读出写入的数据*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_errno.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_i2c.h"
#include "wifiiot_i2c_ex.h"
#include "nfc.h"
#define I2C_TASK_STACK_SIZE 1024 * 8
#define I2C_TASK_PRIO 25
#define TEXT "Welcome to BearPi-HM_Nano!"
#define WEB "harmonyos.com"
static void I2CTask(void)
{
uint8_t ret;
GpioInit(); // 初始化GPIO
//GPIO_0复用为I2C1_SDA
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA);
//GPIO_1复用为I2C1_SCL
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL);
//baudrate: 400kbps
I2cInit(WIFI_IOT_I2C_IDX_1, 400000);
I2cSetBaudrate(WIFI_IOT_I2C_IDX_1, 400000); // 为I2C设备设置频率,一般用于代码运行过程中,修改I2C频率
printf("I2C Test Start\n");
ret = storeText(NDEFFirstPos, (uint8_t *)TEXT); // 写入文本文件到第一个位置,参数分别表示写的位置(可以是NDEFFirstPos、NDEFMiddlePos、NDEFLastPos三个位置,所以要保证I2C写入三个以内的数据)、写入的内容,写入成功则返回1
if (ret != 1)
{
printf("NFC Write Data Falied :%d ", ret);
}
ret = storeUrihttp(NDEFLastPos, (uint8_t *)WEB); // 写入http网址到最后一个位置,参数分别表示写的位置、写入的内容,写入成功则返回1。如果要在手机触碰I2C芯片的时候,手机自动打开网页,则要将http网址写入到第一个位置
if (ret != 1)
{
printf("NFC Write Data Falied :%d ", ret);
}
while (1)
{
printf("=======================================\r\n");
printf("***********I2C_NFC_example**********\r\n");
printf("=======================================\r\n");
printf("Please use the mobile phone with NFC function close to the development board!\r\n");
usleep(1000000);
}
}
static void I2CExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "I2CTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = I2C_TASK_STACK_SIZE;
attr.priority = I2C_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)I2CTask, NULL, &attr) == NULL)
{
printf("Falied to create I2CTask!\n");
}
}
APP_FEATURE_INIT(I2CExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定i2c_example
,编译、烧录,烧录到开发板上后按一下开发板复位按键,之后将具有NFC功能的手机去触碰开发板NFC天线,可以看到手机已经读出了写入的数据
如何查看手机是否具有NFC功能,可参考如何查看手机有没有NFC功能_百度知道 (baidu.com),
UART读写
参考:
- HarmomyOS驱动子系统开发—UART_哔哩哔哩_bilibili
- 通用异步收发器_百度百科 (baidu.com)
- UART串口协议详解 - 知乎 (zhihu.com)
- (38条消息) UART详解_sternlycore的博客-CSDN博客_uart
UART API介绍
通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,通常称作UART),是一种串行、异步、全双工的通信协议,在嵌入式领域应用的非常广泛。
wifiiot_uart.h接口简介
wifiiot_uart.h中包含声明UART接口函数
源码在base\iot_hardware\interfaces\kits\wifiiot_lite\wifiiot_uart.h
路径下
接口名 | 功能描述 |
---|---|
Uartlnit | 初始化UART |
UartDeinit | 取消UART初始化 |
UartRead | 从UART读取数据 |
UartWrite | 将数据写入UART |
UartSetFlowCtrl | 设置UART流控制 |
UartInit()
unsigned int UartInit (WifiIotUartIdx id, const WifiIotUartAttribute * param, const WifiIotUartExtraAttr * extraAttr)
描述:
配置一个UART设备。
参数:
名字 | 描述 |
---|---|
id | UART端口号 |
param | 表示基本UART属性 |
extraAttr | 表示扩展UART属性 |
UartWrite()
int UartWrite (WifiIotUartIdx id, const unsigned char * data, unsigned int dataLen)
描述:
将数据写入UART设备,也就是通过UART来发送数据
参数:
名字 | 描述 |
---|---|
id | UART端口号 |
data | 表示指向要写入数据的起始地址的指针 |
dataLen | 表示读取数据的长度 |
UartRead()
int UartRead (WifiIotUartIdx id, unsigned char * data, unsigned int dataLen)
描述:
从UART设备读取数据。
参数:
名字 | 描述 |
---|---|
id | UART端口号 |
data | 表示指向要读取数据的起始地址的指针 |
dataLen | 表示读取数据的长度 |
查看UART1对应的GPIO引脚
UART1对应的GPIO引脚是分别是GPIO5和GPIO6,将使用GPIO5和GPIO6进行UART数据的收发。
UART读写数据
源码在applications\BearPi\BearPi-HM_Nano\sample\B6_basic_uart\uart_example.c
路径下,以下添加了部分注释:
/*UART读出写入的数据*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_errno.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "wifiiot_adc.h"
#include "wifiiot_uart.h"
#define UART_TASK_STACK_SIZE 1024 * 8
#define UART_TASK_PRIO 25
#define UART_BUFF_SIZE 1000
static const char *data = "Hello, BearPi!\r\n";
static void UART_Task(void)
{
uint8_t uart_buff[UART_BUFF_SIZE] = {0};
uint8_t *uart_buff_ptr = uart_buff;
uint32_t ret;
// 基本UART属性
WifiIotUartAttribute uart_attr = {
//baud_rate: 9600
.baudRate = 9600, // 波特率,这个波特率要和接到UART端口上的设备波特率匹配
//data_bits: 8bits
.dataBits = 8, // 数据位
.stopBits = 1, // 停止位
.parity = 0, // 奇偶校验位
};
//Initialize uart driver
ret = UartInit(WIFI_IOT_UART_IDX_1, &uart_attr, NULL); // 参数分别表示UART的端口号、UART基本的属性、UART扩展属性
if (ret != WIFI_IOT_SUCCESS)
{
printf("Failed to init uart! Err code = %d\n", ret);
return;
}
printf("UART Test Start\n");
while (1)
{
printf("=======================================\r\n");
printf("*************UART_example**************\r\n");
printf("=======================================\r\n");
//通过串口1发送数据
UartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)data, strlen(data)); // 参数分别表示UART的端口号、要写入数据的起始地址的指针、数据的长度
//通过串口1接收数据。将开发板上的UART1_RXD和UART1_TXD短接,可以实现自发自收的功能
UartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);// 参数分别表示UART的端口号、要接收数据的起始地址的指针、能够读取的最大数据长度
printf("Uart1 read data:%s", uart_buff_ptr);
usleep(1000000);
}
}
static void UART_ExampleEntry(void)
{
// 创建一个任务
osThreadAttr_t attr;
attr.name = "UART_Task";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = UART_TASK_STACK_SIZE;
attr.priority = UART_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)UART_Task, NULL, &attr) == NULL)
{
printf("[ADCExample] Falied to create UART_Task!\n");
}
}
APP_FEATURE_INIT(UART_ExampleEntry);
修改applications\BearPi\BearPi-HM_Nano\sample
路径下的BUILD.gn文件,指定uart_example
,编译、烧录,烧录到开发板上后将开发板上的UART1_RXD和UART1_TXD短接,以实现自发自收的功能,能够看到效果,之后按一下开发板复位按键,打印日志
日志结果如下:
本章学习中的案例源码及BearPi_HM Nano 芯片手册见附件。
感悟
驱动子系统开发的学习相较于内核开发部分的学习要轻松许多,但是本部分的I2C总线部分,中间讲解NFC驱动的部分还是有些不理解,属于勉强能够接受,因为本人还未系统的学习过关于物联网、通讯等相关的理论知识,博客中解释不到位的地方或者是错误还请各位大佬指正,以后的学习中我有更深的理解我也会再进行补充。
推荐两个专栏,可以帮助你深入学习子系统:
开鸿OpenHarmony学院
https://ost.51cto.com/column/73
鸿蒙内核源码分析
https://ost.51cto.com/column/34
楼主既然没有系统学过物联网、通讯等相关的理论知识,那这些总结都是通过网上学习的吗?
多谢多谢
是的,网上资料挺全的
干的漂亮哦哥!