目录
前言
之前学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 )
参数 | 说明 |
---|---|
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。
软件函数设计
该函数通过使用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 )
参数 | 说明 |
---|---|
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 。
软件函数设计
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);
总结
课程教的很简单,就是怎么用,其中的原理还是需要学。