> 文档中心 > 华为云14天鸿蒙设备开发-Day5驱动子系统开发

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

目录

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

前言

之前学STM32时,学习过liteOS,对内核有过简单了解。

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


芯片引脚图

首先放个芯片原理图,方便查看引脚
华为云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_SDAIoSetFunc(WIFI_IOT_IO_NAME_GPIO_1, WIFI_IOT_IO_FUNC_GPIO_1_I2C1_SCL);   // GPIO_1复用为I2C1_SCLI2cInit(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);

总结

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