鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发


目录

  • 前言
  • 芯片引脚图
  • 文件结构图
  • 一、GPIO
    • API接口
      • GPIO基础案例简介
    • GPIO中断
      • GPIO中断案例简介
    • PWM输出
      • PWM案例简介
  • 二、ADC采样
    • API函数
    • ADC案例简介
  • 三、I2C读写NFC芯片
    • API
    • I2C案例简介
  • 四、UART读写
    • API
    • UART案例简介
  • 总结

前言 之前学STM32时,学习过liteOS,对内核有过简单了解。 学了内核之后,这次学习一些驱动子系统,GPIO,I2C,串口,ADC数据采集等。主要了解封装后的接口函数及其如何调用。
相关概念有在stm32学习的时候总结过。
GPIO
ADC与DAC
I2C
串口
更多的可以去HAL库专栏看。本文主要总结鸿蒙的API接口

芯片引脚图 【鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发】首先放个芯片原理图,方便查看引脚
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

文件结构图 下文引用头文件都在此路径下的文件夹内bearpi-hm_nano/ base / iot_hardware
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

frameworks文件夹内为c源文件,是接口函数的实现文件;hals中为硬件抽象层函数定义头文件;我们主要引用interfaces/kits下的头文件,此文件夹提供了更方便的接口。
一、GPIO API接口 文件路径为base/iot_hardware/interfaces/kits/wifiiot_lite
在wifiiot_gpio.h中声明了GPIO函数,用于初始化GPIO。也声明了中断相关函数。
在wifiiot_gpio_ex.h中声明了GPIO扩展函数,用于设置GPIO的一些属性。
在wifiiot_pwm.h中声明了PWM相关接口函数。
接口名 功能描述
GpioInit 初始化GPIO
GpioDeinit 取消初始化GPIO
GpioSetDir 设置GPIO引脚方向
GpioGetDir 获取GPIO引脚方向
GpioSetOutputVal 设置GPIO引脚输出电平值
GpioGetOutputVal 获取GPIO引脚输出电平值
IoSetPull 设置GPIO引脚上拉
IoGetPull 获取GPIO引脚上拉
IoSetFunc 设置GPIO引脚功能
IoGetFunc 获取GPIO引脚功能
IoSetDriverStrength 设置GPIO驱动能力
IoGetDriverStrength 获取GPIO驱动能力
查找对应GPIO引脚
我们使用开发板做驱动的时候,都需要去看电路图找相应的引脚,在代码里进行相应的配置。
GPIO基础案例简介
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

LedTask()为LED灯测试主任务,该任务先调用 GpioInit()初始化GPIO,因为LED灯的控制引脚接在GPIO_2上,所以通过调用IoSetFunc()和GpioSetDir()将GPIO_2设置为普通GPIO的输出模式。最后在死循环里面间隔 1s 输出GPIO_2的高低电平,实现LED灯闪烁的现象
static void LedTask(void) { GpioInit(); //初始化GPIO IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO); //设置GPIO_2的复用功能为普通GPIO GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT); //设置GPIO_2为输出模式while (1) { GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1); //设置GPIO_2输出高电平点亮LED灯 usleep(1000000); //延时1s GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0); //设置GPIO_2输出低电平熄灭LED灯 usleep(1000000); //延时1s } }

GPIO中断
接口名 功能描述
GpioRegisterIsrFunc 设置GPIO引脚中断功能
GpioUnregisterIsrFunc 取消GPIO引脚中断功能
GpioSetIsrMask 屏蔽GPIO引脚中断功能
GpioSetIsrMode 设置GPIO引脚中断触发模式
GPIO中断案例简介
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

通过按键控制LED灯亮灭。这里以按键F1为例,按键F1的检测引脚与主控芯片的GPIO_11连接,首先通过调用IoSetFunc()和GpioSetDir()将GPIO_11设置为普通GPIO的输入模式。从前面原理图可知,当按键按下时,GPIO_11会被下拉到地,所以这里要使用IoSetPull()将GPIO_11引脚设置为上拉即高电平,这样才能产生电平的跳变。最后通过GpioRegisterIsrFunc()将中断类型设置为边沿触发,且为下降沿触发,当按键被按下时,GPIO_11会从高电平转为低电平,产生一个下降,这个时候就会触发中断并回调F1_Pressed函数。在F1_Pressed函数中实现点亮LED灯操作。
static void F1_Pressed(char *arg) { (void) arg; GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 1); } static void F2_Pressed(char *arg) { (void) arg; GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_2, 0); } static void ButtonExampleEntry(void) { GpioInit(); /*****初始化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); /*****初始化F1按键,设置为下降沿触发中断*****/ IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO); GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_IN); IoSetPull(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_PULL_UP); GpioRegisterIsrFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW,F1_Pressed, NULL); /*****初始化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); }

PWM输出
接口名 功能描述
PwmInit 初始化PWM
PwmDeinit 取消初始化PWM
PwmStart 根据输入参数输出PWM
PwmStop 停止PWM输出
PWM案例简介
本案例将使用板载的LED来验证GPIO的PWM功能,在BearPi-HM_Nano开发板上LED的连接电路图如基础部分所示,LED的控制引脚与主控芯片的GPIO_2连接,所以需要编写软件去控制GPIO_2输出PWM波实现呼吸灯的效果。高电平时点亮,低电平时熄灭。
PWMTask()为PWM测试主任务,该任务先调用 GpioInit()初始化GPIO,因为LED灯的控制引脚接在GPIO_2上,所以通过调用IoSetFunc()将GPIO_2复用为PWM功能,并通过PwmInit()初始化PWM2端口,最后在死循环里面间隔10us输出不同占空比的PWM波,实现呼吸灯的效果。
static void PWMTask(void) { unsigned int i; GpioInit(); //初始化GPIO IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_PWM2_OUT); //设置GPIO_2引脚复用功能为PWM GpioSetDir(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_GPIO_DIR_OUT); //设置GPIO_2引脚为输出模式 PwmInit(WIFI_IOT_PWM_PORT_PWM2); //初始化PWM2端口while (1) { for (i = 0; i < 40000; i += 100) { PwmStart(WIFI_IOT_PWM_PORT_PWM2, i, 40000); //输出不同占空比的PWM波 usleep(10); } i = 0; } }

二、ADC采样 ADC的原理在前言的链接里总结的还行,可以去看看,就是模拟量进行采样,转换成数字量。
API函数 AdcRead():根据输入参数从指定的ADC通道读取一段采样数据
unsigned int AdcRead (WifiIotAdcChannelIndex channel, unsigned short * data, WifiIotAdcEquModelSel equModel, WifiIotAdcCurBais curBais, unsigned short rstCnt )
参数 说明
channel ADC通道
data 用于存放读取数据的地址指针
equModel 表示平均算法的次数
curBais 表示模拟功率控制模式
rstCnt 指示从重置到转换开始的时间计数
ADC案例简介 本案例将使用板载用户按键F1来模拟GPIO口电压的变化。通过查看芯片手册可知GPIO_11对应的是 ADC Channel 5 ,所以需要编写软件去读取ADC Channel 5的电压,程序设计时先将GPIO_11上拉,使GPIO_11的电压一直处于高电平,当按键按下时GPIO_11接地,此时GPIO_11的电压变为 0 V。
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

软件函数设计
该函数通过使用AdcRead()函数来读取 ADC_CHANNEL_5 的数值存储在data中, WIFI_IOT_ADC_EQU_MODEL_8 表示8次平均算法模式,WIFI_IOT_ADC_CUR_BAIS_DEFAULT 表示默认的自动识别模式,最后通过 data * 1.8 * 4 / 4096.0 计算出实际的电压值。
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); if (ret != WIFI_IOT_SUCCESS) { printf("ADC Read Fail\n"); } return (float)data * 1.8 * 4 / 4096.0; /* data * 1.8 * 4 / 4096.0: Convert code into voltage */ }

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,当F1按键未按下时采集到的电压为3.3V左右,当按键按下时,电压变为0.2V左右。
三、I2C读写NFC芯片 API
接口名 功能描述
I2cInit 初始化I2C
I2cDeinit 取消初始化I2C
I2cWrite 将数据写入到I2C设备
I2cRead 从设备读数据
I2cWriteread 复合通信,向设备发送数据并接受数据响应
I2cSetBaudrate 设置I2C频率
I2C案例简介 NFC芯片使用的是I2C协议,I2C_SCL与GPIO_0相连接,I2C_SDA与GPIO_1相连接,所以需要编写软件使用GPIO_0和GPIO_1产生I2C信号去控制NFC芯片。
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

软件函数设计
I2C初始化的代码,首先用 IoSetFunc() 函数将GPIO_0复用为I2C1_SDA,GPIO_1复用为I2C1_SCL。然后调用I2cInit()函数初始化I2C1端口,最后使用 I2cSetBaudrate() 函数设置I2C1的频率为400kbps.
IoSetFunc(WIFI_IOT_IO_NAME_GPIO_0, WIFI_IOT_IO_FUNC_GPIO_0_I2C1_SDA); // GPIO_0复用为I2C1_SDA IoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL); // GPIO_1复用为I2C1_SCL I2cInit(WIFI_IOT_I2C_IDX_1, 400000); /* baudrate: 400kbps */ I2cSetBaudrate(WIFI_IOT_I2C_IDX_1, 400000);

向NFC芯片写入数据,但需要写入2个记录时,第2个记录的位置需要用NDEFLastPos来定义; 当需要写入3个记录时,第2个和第3个记录的位置分别需要用NDEFMiddlePos和NDEFLastPos来定义。
ret=storeText(NDEFFirstPos, (uint8_t *)TEXT); if(ret != 1) { printf("NFC Write Data Falied :%d ",ret); } ret=storeUrihttp(NDEFLastPos, (uint8_t *)WEB); if(ret != 1) { printf("NFC Write Data Falied :%d ",ret); }

四、UART读写 API UartInit()
unsigned int UartInit (WifiIotUartIdx id, const WifiIotUartAttribute * param, const WifiIotUartExtraAttr * extraAttr )
参数 说明
id UART端口号
param 表示基本UART属性
extraAttr 表示扩展UART属性
UartWrite()
int UartWrite (WifiIotUartIdx id, const unsigned char * data, unsigned int dataLen )
UartRead()
int UartRead (WifiIotUartIdx id, unsigned char * data, unsigned int dataLen )
参数 说明
id UART端口号.
data 表示指向要读写数据的起始地址的指针
dataLen 表示数据的长度
UART案例简介 本案例将用 BearPi-HM_Nano 开发板 E53 接口的 UART 作为测试,如原理图所示第 18 和 19 脚分别为 TXD 和 RXD ,连接了主控芯片的 GPIO_6 和 GPIO_5 ,所以在编写软件的时候需要将 GPIO_6 和 GPIO_5 分别复用为 TXD 和 RXD 。
鸿蒙设备开发|华为云14天鸿蒙设备开发-Day5驱动子系统开发
文章图片

软件函数设计
UART初始化的代码,首先要在 uart_attr 结构体这配置波特率、数据位、停止位、奇偶检验位,然后通过 UartInit() 函数对串口1进行配置。
WifiIotUartAttribute uart_attr = { .baudRate = 9600, /* baud_rate: 9600 */ .dataBits = 8,/* data_bits: 8bits */ .stopBits = 1, .parity = 0, }; /* Initialize uart driver */ ret = UartInit(WIFI_IOT_UART_IDX_1, &uart_attr, NULL); if (ret != WIFI_IOT_SUCCESS) { printf("Failed to init uart! Err code = %d\n", ret); return; }

通过 UartWrite() 函数在串口1发送一串数据,然后通过 UartRead() 函数将数据都回来,并通过 debug 串口打印出来。
UartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)data, strlen(data)); // 通过串口1发送数据 UartRead(WIFI_IOT_UART_IDX_1,uart_buff_ptr,UART_BUFF_SIZE); // 通过串口1接收数据 printf("%s",uart_buff_ptr);

总结 课程教的很简单,就是怎么用,其中的原理还是需要学。

    推荐阅读