华为云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
        }
}

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);

}

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 )

参数说明
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 */
}

示例代码编译烧录代码后,按下开发板的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);

向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 )

参数说明
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;
}

通过 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);

总结

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值