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



    前言

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

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


    芯片引脚图

    首先放个芯片原理图,方便查看引脚
    芯片原理图

    文件结构图

    下文引用头文件都在此路径下的文件夹内bearpi-hm_nano/ base / iot_hardware
    在这里插入图片描述
    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基础案例简介

    在这里插入图片描述

    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
            }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    GPIO中断

    接口名功能描述
    GpioRegisterIsrFunc设置GPIO引脚中断功能
    GpioUnregisterIsrFunc取消GPIO引脚中断功能
    GpioSetIsrMask屏蔽GPIO引脚中断功能
    GpioSetIsrMode设置GPIO引脚中断触发模式

    GPIO中断案例简介

    在这里插入图片描述

    通过按键控制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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    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;
            }    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    二、ADC采样

    ADC的原理在前言的链接里总结的还行,可以去看看,就是模拟量进行采样,转换成数字量。

    API函数

    AdcRead():根据输入参数从指定的ADC通道读取一段采样数据
    unsigned int AdcRead (WifiIotAdcChannelIndex channel, unsigned short * data, WifiIotAdcEquModelSel equModel, WifiIotAdcCurBais curBais, unsigned short rstCnt )

    参数说明
    channelADC通道
    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。

    在这里插入图片描述
    软件函数设计
    该函数通过使用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 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    示例代码编译烧录代码后,按下开发板的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芯片。
    在这里插入图片描述
    软件函数设计
    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);
    
    • 1
    • 2
    • 3
    • 4

    向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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、UART读写

    API

    UartInit()
    unsigned int UartInit (WifiIotUartIdx id, const WifiIotUartAttribute * param, const WifiIotUartExtraAttr * extraAttr )

    参数说明
    idUART端口号
    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 )

    参数说明
    idUART端口号.
    data表示指向要读写数据的起始地址的指针
    dataLen表示数据的长度

    UART案例简介

    本案例将用 BearPi-HM_Nano 开发板 E53 接口的 UART 作为测试,如原理图所示第 18 和 19 脚分别为 TXD 和 RXD ,连接了主控芯片的 GPIO_6 和 GPIO_5 ,所以在编写软件的时候需要将 GPIO_6 和 GPIO_5 分别复用为 TXD 和 RXD 。
    在这里插入图片描述
    软件函数设计
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通过 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);
    
    • 1
    • 2
    • 3

    总结

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

  • 相关阅读:
    Java 入门练习(31 - 35)
    java从键盘输入Scanner
    Python+Selenium简单安装配置
    基于遗传算法的微电网经济运行优化matlab程序
    Cadence virtuoso drc lvs pex 无法输入
    基于图像识别的迁移学习之一
    qt 汉字输出 中文输出 显示乱码 qDebug() 乱码 解决
    SSMP整合案例第七步 前后端业务异常消息统一处理
    安全保护制度
    java毕业生设计阳光社区新冠瘦苗接种系统计算机源码+系统+mysql+调试部署+lw
  • 原文地址:https://blog.csdn.net/kouqi627/article/details/126009438