OpenHarmony智能开发套件[驱动开发篇·下]
前言
前面介绍了OpenHarmony智能开发套件驱动开发篇·上,下面我们接着介绍驱动开发,本章将介绍如何IO控制温湿度传感器,可燃气体传感器,RGB灯,人体红外传感器,光敏电阻,Oled显示屏。
驱动开发
环境监测板
环境检测板上一共有三个模块,AHT20数字温湿度传感器,蜂鸣器,MQ-2可燃气体传感器。蜂鸣器的使用在上一篇已经提及过,为了方便学习,本次只介绍温湿度传感器,可燃气体传感器的IO控制,蜂鸣器的结合使用可以放在以后的综合案例中去说。
温湿度传感器
案例:每隔1s,获取一次温湿度,打印在终端
-
新建样例目录
applications/sample/wifi-iot/app/aht20
-
新建源文件和gn文件
applications/sample/wifi-iot/app/aht20/aht20Test.c
applications/sample/wifi-iot/app/aht20/BUILD.gn
-
补充文件
applications/sample/wifi-iot/app/aht20/aht20.c
applications/sample/wifi-iot/app/aht20/aht20.h
aht20.c
/*
* Copyright (C) 2021 HiHope Open Source Organization .
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
* limitations under the License.
*/
#include "aht20.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "iot_i2c.h"
#include "iot_errno.h"
#define AHT20_I2C_IDX 0
#define AHT20_STARTUP_TIME 20*1000 // 上电启动时间
#define AHT20_CALIBRATION_TIME 40*1000 // 初始化(校准)时间
#define AHT20_MEASURE_TIME 75*1000 // 测量时间
#define AHT20_DEVICE_ADDR 0x38
#define AHT20_READ_ADDR ((0x38<<1)|0x1)
#define AHT20_WRITE_ADDR ((0x38<<1)|0x0)
#define AHT20_CMD_CALIBRATION 0xBE // 初始化(校准)命令
#define AHT20_CMD_CALIBRATION_ARG0 0x08
#define AHT20_CMD_CALIBRATION_ARG1 0x00
/**
* 传感器在采集时需要时间,主机发出测量指令(0xAC)后,延时75毫秒以上再读取转换后的数据并判断返回的状态位是否正常。
* 若状态比特位[Bit7]为0代表数据可正常读取,为1时传感器为忙状态,主机需要等待数据处理完成。
**/
#define AHT20_CMD_TRIGGER 0xAC // 触发测量命令
#define AHT20_CMD_TRIGGER_ARG0 0x33
#define AHT20_CMD_TRIGGER_ARG1 0x00
// 用于在无需关闭和再次打开电源的情况下,重新启动传感器系统,软复位所需时间不超过20 毫秒
#define AHT20_CMD_RESET 0xBA // 软复位命令
#define AHT20_CMD_STATUS 0x71 // 获取状态命令
/**
* STATUS 命令回复:
* 1. 初始化后触发测量之前,STATUS 只回复 1B 状态值;
* 2. 触发测量之后,STATUS 回复6B: 1B 状态值 + 2B 湿度 + 4b湿度 + 4b温度 + 2B 温度
* RH = Srh / 2^20 * 100%
* T = St / 2^20 * 200 - 50
**/
#define AHT20_STATUS_BUSY_SHIFT 7 // bit[7] Busy indication
#define AHT20_STATUS_BUSY_MASK (0x1<<AHT20_STATUS_BUSY_SHIFT)
#define AHT20_STATUS_BUSY(status) ((status & AHT20_STATUS_BUSY_MASK) >> AHT20_STATUS_BUSY_SHIFT)
#define AHT20_STATUS_MODE_SHIFT 5 // bit[6:5] Mode Status
#define AHT20_STATUS_MODE_MASK (0x3<<AHT20_STATUS_MODE_SHIFT)
#define AHT20_STATUS_MODE(status) ((status & AHT20_STATUS_MODE_MASK) >> AHT20_STATUS_MODE_SHIFT)
// bit[4] Reserved
#define AHT20_STATUS_CALI_SHIFT 3 // bit[3] CAL Enable
#define AHT20_STATUS_CALI_MASK (0x1<<AHT20_STATUS_CALI_SHIFT)
#define AHT20_STATUS_CALI(status) ((status & AHT20_STATUS_CALI_MASK) >> AHT20_STATUS_CALI_SHIFT)
// bit[2:0] Reserved
#define AHT20_STATUS_RESPONSE_MAX 6
#define AHT20_RESLUTION (1<<20) // 2^20
#define AHT20_MAX_RETRY 10
// typedef struct {
// /** Pointer to the buffer storing data to send */
// unsigned char *sendBuf;
// /** Length of data to send */
// unsigned int sendLen;
// /** Pointer to the buffer for storing data to receive */
// unsigned char *receiveBuf;
// /** Length of data received */
// unsigned int receiveLen;
// } IotI2cData;
static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
{
// IotI2cData data = { 0 };
// data.receiveBuf = buffer;
// data.receiveLen = buffLen;
// uint32_t retval = I2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, data.receiveBuf );
// if (retval != IOT_SUCCESS) {
// printf("I2cRead() failed, %0X!\n", retval);
// return retval;
// }
// return IOT_SUCCESS;
uint32_t retval = IoTI2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, buffer, buffLen);
if (retval != IOT_SUCCESS) {
printf("I2cRead() failed, %0X!\n", retval);
return retval;
}
return IOT_SUCCESS;
}
static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
{
// IotI2cData data = { 0 };
// data.sendBuf = buffer;
// data.sendLen = buffLen;
// uint32_t retval = IoTI2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, &data);
// if (retval != IOT_SUCCESS) {
// printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
// return retval;
// }
// return IOT_SUCCESS;
uint32_t retval = IoTI2cWrite(AHT20_I2C_IDX, AHT20_READ_ADDR, buffer, buffLen);
if (retval != IOT_SUCCESS) {
printf("I2cRead() failed, %0X!\n", retval);
return retval;
}
return IOT_SUCCESS;
}
// 发送获取状态命令
static uint32_t AHT20_StatusCommand(void)
{
uint8_t statusCmd[] = { AHT20_CMD_STATUS };
return AHT20_Write(statusCmd, sizeof(statusCmd));
}
// 发送软复位命令
static uint32_t AHT20_ResetCommand(void)
{
uint8_t resetCmd[] = {AHT20_CMD_RESET};
return AHT20_Write(resetCmd, sizeof(resetCmd));
}
// 发送初始化校准命令
static uint32_t AHT20_CalibrateCommand(void)
{
uint8_t clibrateCmd[] = {AHT20_CMD_CALIBRATION, AHT20_CMD_CALIBRATION_ARG0, AHT20_CMD_CALIBRATION_ARG1};
return AHT20_Write(clibrateCmd, sizeof(clibrateCmd));
}
// 读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通过发送0x71可以获取一个字节的状态字),
// 如果不为1,要发送0xBE命令(初始化),此命令参数有两个字节, 第一个字节为0x08,第二个字节为0x00。
uint32_t AHT20_Calibrate(void)
{
uint32_t retval = 0;
uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { AHT20_CMD_STATUS };
memset(&buffer, 0x0, sizeof(buffer));
retval = AHT20_StatusCommand();
if (retval != IOT_SUCCESS) {
return retval;
}
retval = AHT20_Read(buffer, sizeof(buffer));
if (retval != IOT_SUCCESS) {
return retval;
}
if (AHT20_STATUS_BUSY(buffer[0]) || !AHT20_STATUS_CALI(buffer[0])) {
retval = AHT20_ResetCommand();
if (retval != IOT_SUCCESS) {
return retval;
}
usleep(AHT20_STARTUP_TIME);
retval = AHT20_CalibrateCommand();
usleep(AHT20_CALIBRATION_TIME);
return retval;
}
return IOT_SUCCESS;
}
// 发送 触发测量 命令,开始测量
uint32_t AHT20_StartMeasure(void)
{
uint8_t triggerCmd[] = {AHT20_CMD_TRIGGER, AHT20_CMD_TRIGGER_ARG0, AHT20_CMD_TRIGGER_ARG1};
return AHT20_Write(triggerCmd, sizeof(triggerCmd));
}
// 接收测量结果,拼接转换为标准值
uint32_t AHT20_GetMeasureResult(float* temp, float* humi)
{
uint32_t retval = 0, i = 0;
if (temp == NULL || humi == NULL) {
return IOT_FAILURE;
}
uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { 0 };
memset(&buffer, 0x0, sizeof(buffer));
retval = AHT20_Read(buffer, sizeof(buffer)); // recv status command result
if (retval != IOT_SUCCESS) {
return retval;
}
for (i = 0; AHT20_STATUS_BUSY(buffer[0]) && i < AHT20_MAX_RETRY; i++) {
// printf("AHT20 device busy, retry %d/%d!\r\n", i, AHT20_MAX_RETRY);
usleep(AHT20_MEASURE_TIME);
retval = AHT20_Read(buffer, sizeof(buffer)); // recv status command result
if (retval != IOT_SUCCESS) {
return retval;
}
}
if (i >= AHT20_MAX_RETRY) {
printf("AHT20 device always busy!\r\n");
return IOT_FAILURE;
}
uint32_t humiRaw = buffer[1];
humiRaw = (humiRaw << 8) | buffer[2];
humiRaw = (humiRaw << 4) | ((buffer[3] & 0xF0) >> 4);
*humi = humiRaw / (float)AHT20_RESLUTION * 100;
uint32_t tempRaw = buffer[3] & 0x0F;
tempRaw = (tempRaw << 8) | buffer[4];
tempRaw = (tempRaw << 8) | buffer[5];
*temp = tempRaw / (float)AHT20_RESLUTION * 200 - 50;
// printf("humi = %05X, %f, temp= %05X, %f\r\n", humiRaw, *humi, tempRaw, *temp);
return IOT_SUCCESS;
}
aht20.h
/*
* Copyright (C) 2021 HiHope Open Source Organization .
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
* limitations under the License.
*/
#ifndef AHT20_H
#define AHT20_H
#include <stdint.h>
uint32_t AHT20_Calibrate(void);
uint32_t AHT20_StartMeasure(void);
uint32_t AHT20_GetMeasureResult(float* temp, float* humi);
#endif // AHT20_H
这两个文件,相当于给我们提供了控制aht20数字温湿度传感器的API,通过网上各种温湿度传感器的学习也发现了,这两个文件是必备的,笔者也是直接从源码提供的demo中直接。贴出来了。下面也详细给大家介绍以下每一个函数怎么去使用。其中标号1至5是不需要我们手动去调用他的,6至8是我们比较常用的。
- 从传感器中读取数据
static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
参数解释:
buffer
:存储读取数据的缓冲区的指针。buffLen
:缓冲区的长度。
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于从传感器中读取数据。它使用 IoTI2cRead
函数从指定的地址读取数据到缓冲区中。
- 向传感器中写入数据
static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
参数解释:
buffer
:存储要写入传感器的数据的缓冲区的指针。buffLen
:缓冲区的长度。
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
实现过程:该函数用于向传感器写入数据。它使用 IoTI2cWrite
函数将数据从缓冲区写入指定的地址。
- 获取传感器状态
static uint32_t AHT20_StatusCommand(void)
参数:无
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于发送获取状态命令给传感器。它构造一个包含命令的缓冲区,然后使用 AHT20_Write
函数发送该命令。
- 软复位传感器
static uint32_t AHT20_ResetCommand(void)
参数:无
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于发送软复位命令给传感器。它构造一个包含命令的缓冲区,然后使用 AHT20_Write
函数发送该命令。
- 初始化传感器
static uint32_t AHT20_CalibrateCommand(void)
参数:无
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于发送初始化校准命令给传感器。它构造一个包含命令和参数的缓冲区,然后使用 AHT20_Write
函数发送该命令。
- 校准传感器
uint32_t AHT20_Calibrate(void)
参数:无
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于校准传感器。它首先发送获取状态命令,然后读取状态字并检查校准使能位。如果校准使能位不为1或传感器处于忙状态,它会发送软复位命令并等待一段时间后再发送初始化校准命令。
- 发送命令,传感器开始测量
uint32_t AHT20_StartMeasure(void)
参数:无
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于发送触发测量命令给传感器,以开始测量过程。它构造一个包含命令和参数的缓冲区,然后使用 AHT20_Write
函数发送该命令。
- 获取传感器的测量结果
uint32_t AHT20_GetMeasureResult(float* temp, float* humi)
参数解释:
temp
:用于存储温度值的指针。humi
:用于存储湿度值的指针。
返回值:一个 uint32_t
类型的整数,表示执行操作的结果。
该函数用于接收测量结果并将其转换为标准值。它首先从传感器读取状态命令的结果,然后根据状态字判断传感器的忙闲状态。如果传感器忙碌,函数会等待一段时间后再次读取状态命令的结果。如果传感器一直忙碌,函数返回失败。如果传感器空闲,函数会从缓冲区中提取湿度和温度的原始值,并将其转换为标准值,然后存储在指定的变量中。最后,函数返回成功或失败的结果。
- 编写源文件aht20Test.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_gpio.h"
#include "hi_io.h"
// I2C控制器
#include "hi_i2c.h"
// aht20温湿度传感器
#include "aht20.h"
// 一些宏定义 如 IOT_SUCCESS
#include "iot_errno.h"
// 样例主函数
static void ahtMain(void){
// 设置引脚的功能,
hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
// 以特定的波特率初始化I2C设备
hi_i2c_init(HI_I2C_IDX_0, 4000);
// 定义返回值
uint32_t retval = 0;
retval = AHT20_Calibrate();
while(retval != IOT_SUCCESS){
printf("传感器校准失败!\r\n");
osDelay(50);
}
while(1){
// 定义温湿度变量
float temp = 0.0, humi = 0.0;
// 命令传感器开始工作
retval = AHT20_StartMeasure();
if(retval != IOT_SUCCESS){
printf("传感器工作异常!\r\n");
}
// 读取传感器的测量值
retval = AHT20_GetMeasureResult(&temp, &humi);
if(retval != IOT_SUCCESS){
printf("传感器数值读取失败!\r\n");
} else {
printf("当前温度:%.2f 当前湿度:%.2f.\r\n", temp, humi);
}
// 每隔1s读取一次传感器数据
osDelay(100);
}
}
// 样例测试入口
static void aht20Test(void){
osThreadAttr_t attr = {"ahtMain", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)ahtMain, NULL, &attr);
}
APP_FEATURE_INIT(aht20Test);
- 编写BUILD.gn (app目录下的BUILD.gn文件记得也修改好,这里就不多演示了)
static_library("aht20"){
sources = [
"aht20.c",
"aht20Test.c",
]
include_dirs = [
"//commonlibrary/utils_lite/include/",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis",
"//base/iothardware/peripheral/interfaces/inner_api",
"//device/soc/hisilicon/hi3861v100/sdk_liteos/include/"
]
}
- 编译,烧录,串口调试,观察控制台上的输出
那么到这里,温湿度传感器最简单的一个案例就介绍到这里。
可燃气体传感器
案例:每隔1s,获取一次可燃气体传感器测量的电阻值,打印在终端
他会用到hi_adc.h
库下的hi_adc_read
这个接口,从单个ADC通道读取一个数据。
hi_u32 hi_adc_read(hi_adc_channel_index channel, hi_u16 *data, hi_adc_equ_model_sel equ_model,
hi_adc_cur_bais cur_bais, hi_u16 delay_cnt);
参数解释:
channel
:要读取的ADC通道,类型为hi_adc_channel_index
。data
:数据存储地址,类型为指向hi_u16
类型的指针。equ_model
:平均算法模式,类型为hi_adc_equ_model_sel
。cur_bais
:模拟电源控制,类型为hi_adc_cur_bais
。delay_cnt
:从配置采样到启动采样的延时时间计数,每次计数为334纳秒,取值范围为0~0xFF0。
返回值:
HI_ERR_SUCCESS
:成功。- 其他值:失败
其中 hi_adc_equ_model_sel
定义为如下的枚举类型
typedef enum {
HI_ADC_EQU_MODEL_1, /**< 0:The average value is not used.
CNcomment:1次平均,即不进行
平均 CNend */
HI_ADC_EQU_MODEL_2, /**< 1:2-time average algorithm mode.
CNcomment:2次平均算法模式 CNend */
HI_ADC_EQU_MODEL_4, /**< 2:4-time average algorithm mode.
CNcomment:4次平均算法模式 CNend */
HI_ADC_EQU_MODEL_8, /**< 3:8-time average algorithm mode.
CNcomment:8次平均算法模式 CNend */
HI_ADC_EQU_MODEL_BUTT,
} hi_adc_equ_model_sel;
hi_adc_cur_bais
typedef enum {
HI_ADC_CUR_BAIS_DEFAULT, /**< 0:Auto control.
CNcomment:自动识别模式 */
HI_ADC_CUR_BAIS_AUTO, /**< 1:Auto control.
CNcomment:自动识别模式 */
HI_ADC_CUR_BAIS_1P8V, /**< 2:Manual control, AVDD=1.8V.
CNcomment:手动控制,AVDD=1.8V */
HI_ADC_CUR_BAIS_3P3V, /**< 3:Manual control, AVDD=3.3V.
CNcomment:手动控制,AVDD=3.3V */
HI_ADC_CUR_BAIS_BUTT,
} hi_adc_cur_bais;
-
新建样例目录
applications/sample/wifi-iot/app/gas
-
新建源文件和gn文件
applications/sample/wifi-iot/app/gas/gasTest.c
applications/sample/wifi-iot/app/gas/BUILD.gn
-
编写源文件gasTest.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_gpio.h"
#include "hi_io.h"
// adc
#include "hi_adc.h"
// 一些宏定义 如 IOT_SUCCESS
#include "iot_errno.h"
#define GAS_SENSOR_CHAN_NAME 5
// 主函数
static void gasMain(void){
// 定义数据变量
float gasSensorResistance = 0.0f;
while(1){
unsigned short data = 0;
int retval;
retval = hi_adc_read(GAS_SENSOR_CHAN_NAME, &data, 2, 0, 0);
if (retval == IOT_SUCCESS) {
float Vx = data * 1.8 * 4 / 4096;
gasSensorResistance = 5 / Vx - 1;
printf("当前可燃气体传感器获取的电阻值为:%.2f\r\n", gasSensorResistance);
} else {
printf("\r\n hi_adc_read fail, retval=%d", retval);
}
osDelay(100);
}
}
// 样例测试入口
static void gasTest(void){
osThreadAttr_t attr = {"gasMain", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)gasMain, NULL, &attr);
}
APP_FEATURE_INIT(gasTest);
while循环中的部分是从源码提供的demo中贴过来的,涉及到一些电路问题,还没有研究这一块。
// Vcc ADC GND
// | ______ | ______ |
// +---| MG-2 |---+---| 1kom |---+
// ------ ------
// 查阅原理图,ADC 引脚位于 1K 电阻和燃气传感器之间,燃气传感器另一端接在 5V 电源正极上
// 串联电路电压和阻止成正比:
// Vx / 5 == 1kom / (1kom + Rx)
// => Rx + 1 == 5/Vx
// => Rx = 5/Vx - 1
- 编写BUILD.gn (app目录下的BUILD.gn文件记得也修改好,这里就不多演示了)
static_library("gas"){
sources = [
"gasTest.c",
]
include_dirs = [
"//commonlibrary/utils_lite/include/",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis",
"//base/iothardware/peripheral/interfaces/inner_api",
"//device/soc/hisilicon/hi3861v100/sdk_liteos/include/"
]
}
- 编译,烧录,串口调试,观察控制台上的输出
RGB板
三色灯
绝大多数可见光可用三色光(红、绿、蓝)的不同强度的混合来表示,即RGB颜色模型。
R/G/B取值范围:0~255。黑色(0,0,0),白色(255,255,255),红色(255,0,0)、绿色(0,255,0)、蓝色(0,0,255)。
可表示颜色数:256256256=16777216色
红色:28引脚,GPIO-10 / PWM1
绿色:29引脚,GPIO-11 / PWM2
蓝色:30引脚,GPIO-12 / PWM3
下面直接上案例吧,RGB的效果,实际上就是改变PWM的占空比,实现红绿蓝的混色效果。
-
新建样例目录
applications/sample/wifi-iot/app/rgb
-
新建源文件和gn文件
applications/sample/wifi-iot/app/rgb/rgb.c
applications/sample/wifi-iot/app/rgb/BUILD.gn
-
编写源文件rgb.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "hi_io.h"
#include "hi_pwm.h"
static void rgbDemo(){
IoTGpioInit(HI_IO_NAME_GPIO_10);
IoTGpioInit(HI_IO_NAME_GPIO_11);
IoTGpioInit(HI_IO_NAME_GPIO_12);
hi_io_set_func(HI_IO_NAME_GPIO_10, HI_IO_FUNC_GPIO_10_PWM1_OUT);
hi_io_set_func(HI_IO_NAME_GPIO_11, HI_IO_FUNC_GPIO_11_PWM2_OUT);
hi_io_set_func(HI_IO_NAME_GPIO_12, HI_IO_FUNC_GPIO_12_PWM3_OUT);
IoTGpioSetDir(HI_IO_NAME_GPIO_10, IOT_GPIO_DIR_OUT);
IoTGpioSetDir(HI_IO_NAME_GPIO_11, IOT_GPIO_DIR_OUT);
IoTGpioSetDir(HI_IO_NAME_GPIO_12, IOT_GPIO_DIR_OUT);
IoTPwmInit(HI_PWM_PORT_PWM1); // 红
IoTPwmInit(HI_PWM_PORT_PWM2); // 绿
IoTPwmInit(HI_PWM_PORT_PWM3); // 蓝
while(1){
for(int i = 1; i < 100; i++){
IoTPwmStart(HI_PWM_PORT_PWM1, 1, 4000);
IoTPwmStart(HI_PWM_PORT_PWM2, 100 - i, 4000);
IoTPwmStart(HI_PWM_PORT_PWM3, i, 4000);
usleep(20 * 1000);
IoTPwmStop(HI_PWM_PORT_PWM1);
IoTPwmStop(HI_PWM_PORT_PWM2);
IoTPwmStop(HI_PWM_PORT_PWM3);
}
for(int i = 1; i < 100; i++){
IoTPwmStart(HI_PWM_PORT_PWM1, i, 4000);
IoTPwmStart(HI_PWM_PORT_PWM2, 1, 4000);
IoTPwmStart(HI_PWM_PORT_PWM3, 100 - i, 4000);
usleep(20 * 1000);
IoTPwmStop(HI_PWM_PORT_PWM1);
IoTPwmStop(HI_PWM_PORT_PWM2);
IoTPwmStop(HI_PWM_PORT_PWM3);
}
for(int i = 1; i < 100; i++){
IoTPwmStart(HI_PWM_PORT_PWM1, 100 - i, 4000);
IoTPwmStart(HI_PWM_PORT_PWM2, i, 4000);
IoTPwmStart(HI_PWM_PORT_PWM3, 1, 4000);
usleep(20 * 1000);
IoTPwmStop(HI_PWM_PORT_PWM1);
IoTPwmStop(HI_PWM_PORT_PWM2);
IoTPwmStop(HI_PWM_PORT_PWM3);
}
}
}
static void rgbTest(void){
osThreadAttr_t attr = {"rgbDemo", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)rgbDemo, NULL, &attr);
}
APP_FEATURE_INIT(rgbTest);
- 编写BUILD.gn (app目录下的BUILD.gn文件记得也修改好,这里就不多演示了)
static_library("rgb"){
sources = [
"rgb.c"
]
include_dirs = [
"//commonlibrary/utils_lite/include/",
"//device/soc/hisilicon/hi3861v100/hi3861_adapter/kal/cmsis",
"//base/iothardware/peripheral/interfaces/inner_api",
"//device/soc/hisilicon/hi3861v100/sdk_liteos/include/"
]
}
- 编译,烧录,重启开发板,观察三色灯,注意灯光可能比较强。
人体红外传感器
和控制可燃气体传感器一样,我们仍然使用的是hi_adc_read的一个API,不同的是,我们在获取可燃气体传感器时,用的是5,而人体红外传感器的标号是3,光敏电阻其实也是一样的,他的标号是4。
这里就直接贴个主体代码给大家了,看过上面可燃气体传感器的,可以直接拷贝一份案例,在上面直接修改。
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_gpio.h"
#include "hi_io.h"
// adc
#include "hi_adc.h"
// 一些宏定义 如 IOT_SUCCESS
#include "iot_errno.h"
#define INFRARED_SENSOR_CHAN_NAME 3
// 主函数
static void infraredMain(void){
while(1){
unsigned short data = 0;
int retval;
retval = hi_adc_read(INFRARED_SENSOR_CHAN_NAME, &data, 2, 0, 0);
if (retval == IOT_SUCCESS) {
printf("人体红外传感器获取数据:data = %d\r\n", data);
if(data > 1800){
printf("检测到人体红外!\r\n");
}
} else {
printf("\r\n hi_adc_read fail, retval=%d", retval);
}
osDelay(100);
}
}
// 样例测试入口
static void infraredTest(void){
osThreadAttr_t attr = {"infraredMain", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)infraredMain, NULL, &attr);
}
APP_FEATURE_INIT(infraredTest);
串口调试效果如下:
在有红外是,值在1800的样子,没有红外时,值在120的样子
光敏电阻
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_gpio.h"
#include "hi_io.h"
// adc
#include "hi_adc.h"
// 一些宏定义 如 IOT_SUCCESS
#include "iot_errno.h"
#define SHINE_SENSOR_CHAN_NAME 4
// 主函数
static void shineMain(void){
while(1){
unsigned short data = 0;
int retval;
retval = hi_adc_read(SHINE_SENSOR_CHAN_NAME, &data, 2, 0, 0);
if (retval == IOT_SUCCESS) {
printf("光敏电阻传感器获取数据:data = %d\r\n", data);
} else {
printf("\r\n hi_adc_read fail, retval=%d", retval);
}
osDelay(100);
}
}
// 样例测试入口
static void shineTest(void){
osThreadAttr_t attr = {"shineMain", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)shineMain, NULL, &attr);
}
APP_FEATURE_INIT(shineTest);
串口调试效果如下:
在没有光时,值在1800的样子,有光时,值在120的样子
Oled显示屏
最后我们讲讲如何Oled板,主要是如何点亮他,让他能代替终端为我们显示一些东西,下方的两个按钮暂且不介绍了。
案例:在Oled板上打印“Hello,World”
-
新建样例目录
applications/sample/wifi-iot/app/oled
-
新建源文件和gn文件
applications/sample/wifi-iot/app/oled/oledTest.c
applications/sample/wifi-iot/app/oled/BUILD.gn
-
补充文件
applications/sample/wifi-iot/app/oled/oled_ssd1306.c
applications/sample/wifi-iot/app/oled/oled_ssd1306.h
applications/sample/wifi-iot/app/oled/oled_fonts.h
oled_ssd1306.c
/*
* Copyright (C) 2021 HiHope Open Source Organization .
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
* limitations under the License.
*/
#include <stddef.h>
#include <stdio.h>
#include "oled_ssd1306.h"
#include "iot_gpio.h"
#include "iot_i2c.h"
#include "iot_errno.h"
#include "oled_fonts.h"
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
#define OLED_I2C_IDX 0
#define OLED_WIDTH (128)
#define OLED_I2C_ADDR 0x78 // 默认地址为 0x78
#define OLED_I2C_CMD 0x00 // 0000 0000 写命令
#define OLED_I2C_DATA 0x40 // 0100 0000(0x40) 写数据
#define OLED_I2C_BAUDRATE (400*1000) // 400k
#define DELAY_100_MS (100*1000)
// unsigned int I2cSetBaudrate(WifiIotI2cIdx id, unsigned int baudrate);
typedef struct {
/** Pointer to the buffer storing data to send */
unsigned char *sendBuf;
/** Length of data to send */
unsigned int sendLen;
/** Pointer to the buffer for storing data to receive */
unsigned char *receiveBuf;
/** Length of data received */
unsigned int receiveLen;
} IotI2cData;
static uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte)
{
unsigned int id = OLED_I2C_IDX;
uint8_t buffer[] = {regAddr, byte};
IotI2cData i2cData = {0};
i2cData.sendBuf = buffer;
i2cData.sendLen = sizeof(buffer)/sizeof(buffer[0]);
return IoTI2cWrite(id, OLED_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen);
}
/**
* @brief Write a command byte to OLED device.
*
* @param cmd the commnad byte to be writen.
* @return Returns {@link IOT_SUCCESS} if the operation is successful;
* returns an error code defined in {@link wifiiot_errno.h} otherwise.
*/
static uint32_t WriteCmd(uint8_t cmd)
{
return I2cWiteByte(OLED_I2C_CMD, cmd);
}
/**
* @brief Write a data byte to OLED device.
*
* @param cmd the data byte to be writen.
* @return Returns {@link IOT_SUCCESS} if the operation is successful;
* returns an error code defined in {@link wifiiot_errno.h} otherwise.
*/
static uint32_t WriteData(uint8_t data)
{
return I2cWiteByte(OLED_I2C_DATA, data);
}
/**
* @brief ssd1306 OLED Initialize.
*/
uint32_t OledInit(void)
{
static const uint8_t initCmds[] = {
0xAE, // --display off
0x00, // ---set low column address
0x10, // ---set high column address
0x40, // --set start line address
0xB0, // --set page address
0x81, // contract control
0xFF, // --128
0xA1, // set segment remap
0xA6, // --normal / reverse
0xA8, // --set multiplex ratio(1 to 64)
0x3F, // --1/32 duty
0xC8, // Com scan direction
0xD3, // -set display offset
0x00, //
0xD5, // set osc division
0x80, //
0xD8, // set area color mode off
0x05, //
0xD9, // Set Pre-Charge Period
0xF1, //
0xDA, // set com pin configuartion
0x12, //
0xDB, // set Vcomh
0x30, //
0x8D, // set charge pump enable
0x14, //
0xAF, // --turn on oled panel
};
IoTGpioInit(13);
hi_io_set_func(13, 6);
IoTGpioInit(14);
hi_io_set_func(14, 6);
IoTI2cInit(0, OLED_I2C_BAUDRATE);
for (size_t i = 0; i < ARRAY_SIZE(initCmds); i++) {
uint32_t status = WriteCmd(initCmds[i]);
if (status != IOT_SUCCESS) {
return status;
}
}
return IOT_SUCCESS;
}
void OledSetPosition(uint8_t x, uint8_t y)
{
WriteCmd(0xb0 + y);
WriteCmd(((x & 0xf0) >> 4) | 0x10);
WriteCmd(x & 0x0f);
}
/*全屏填充*/
void OledFillScreen(uint8_t fillData)
{
uint8_t m = 0;
uint8_t n = 0;
for (m=0; m < 8; m++) {
WriteCmd(0xb0 + m);
WriteCmd(0x00);
WriteCmd(0x10);
for (n=0; n < 128; n++) {
WriteData(fillData);
}
}
}
/**
* @brief 8*16 typeface
* @param x: write positon start from x axis
* @param y: write positon start from y axis
* @param ch: write data
* @param font: selected font
*/
void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font)
{
uint8_t c = 0;
uint8_t i = 0;
c = ch - ' '; //得到偏移后的值
if (x > OLED_WIDTH - 1) {
x = 0;
y = y + 2;
}
if (font == FONT8x16) {
OledSetPosition(x, y);
for (i = 0; i < 8; i++){
WriteData(F8X16[c*16 + i]);
}
OledSetPosition(x, y+1);
for (i = 0; i < 8; i++) {
WriteData(F8X16[c*16 + i + 8]);
}
} else {
OledSetPosition(x, y);
for (i = 0; i < 6; i++) {
WriteData(F6x8[c][i]);
}
}
}
void OledShowString(uint8_t x, uint8_t y, const char* str, Font font)
{
uint8_t j = 0;
if (str == NULL) {
printf("param is NULL,Please check!!!\r\n");
return;
}
while (str[j]) {
OledShowChar(x, y, str[j], font);
x += 8;
if (x > 120) {
x = 0;
y += 2;
}
j++;
}
}
oled_ssd1306.h
/*
* Copyright (C) 2021 HiHope Open Source Organization .
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
* limitations under the License.
*/
#ifndef OLED_SSD1306_H
#define OLED_SSD1306_H
#include <stdint.h>
/**
* @brief ssd1306 OLED Initialize.
*/
uint32_t OledInit(void);
/**
* @brief Set cursor position
*
* @param x the horizontal posistion of cursor
* @param y the vertical position of cursor
* @return Returns {@link WIFI_IOT_SUCCESS} if the operation is successful;
* returns an error code defined in {@link wifiiot_errno.h} otherwise.
*/
void OledSetPosition(uint8_t x, uint8_t y);
void OledFillScreen(uint8_t fillData);
enum Font {
FONT6x8 = 1,
FONT8x16
};
typedef enum Font Font;
void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font);
void OledShowString(uint8_t x, uint8_t y, const char* str, Font font);
#endif // OLED_SSD1306_H
oled_fonts.h
/*
* Copyright (C) 2021 HiHope Open Source Organization .
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
*
* limitations under the License.
*/
#ifndef OLOED_FONTS_H
#define OLOED_FONTS_H
/************************************6*8的点阵************************************/
static unsigned char F6x8[][6] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp
{ 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 }, // !
{ 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // #
{ 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $
{ 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 }, // %
{ 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 }, // )
{ 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 }, // *
{ 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 }, // ,
{ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // <
{ 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 }, // >
{ 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E }, // @
{ 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C }, // A
{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F
{ 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G
{ 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M
{ 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W
{ 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y
{ 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [
{ 0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 }, // 55
{ 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ]
{ 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 }, // '
{ 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C }, // g
{ 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 }, // j
{ 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k
{ 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 }, // p
{ 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC }, // q
{ 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C }, // y
{ 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 }, // horiz lines
};
/****************************************8*16的点阵************************************/
static const unsigned char F8X16[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
#endif
具体介绍一下c文件中提供的一些API,其中标号1至3不需要我们手动调用,4至8比较常用。
- 写入数据字节
uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte)
参数解释:
regAddr
:寄存器地址,要写入的寄存器地址。byte
:字节值,要写入的数据字节。
返回值:
- 返回值类型为
uint32_t
,表示操作的结果。返回IOT_SUCCESS
表示操作成功,否则返回定义在wifiiot_errno.h
中的错误代码。
该函数封装了通过I2C总线向OLED设备写入一个字节数据的操作。它使用了一个结构体变量IotI2cData
,并将要写入的寄存器地址和字节值存储在一个缓冲区buffer
中。函数内部调用了IoTI2cWrite
函数,通过I2C总线向OLED设备发送数据。
- 命令写入
uint32_t WriteCmd(uint8_t cmd)
参数解释:
cmd
:命令字节,要写入的命令字节。
返回值:
- 返回值类型为
uint32_t
,表示操作的结果。返回IOT_SUCCESS
表示操作成功,否则返回定义在wifiiot_errno.h
中的错误代码。
该函数用于向OLED设备写入命令字节。它调用了I2cWiteByte
函数,将命令字节和OLED_I2C_CMD
作为参数传递给I2cWiteByte
函数进行发送。
- 数据写入
uint32_t WriteData(uint8_t data)
参数解释:
data
:数据字节,要写入的数据字节。
返回值:
- 返回值类型为
uint32_t
,表示操作的结果。返回IOT_SUCCESS
表示操作成功,否则返回定义在wifiiot_errno.h
中的错误代码。
该函数用于向OLED设备写入数据字节。它调用了I2cWiteByte
函数,将数据字节和OLED_I2C_DATA
作为参数传递给I2cWiteByte
函数进行发送。
- 初始化
uint32_t OledInit(void)
参数解释:无
返回值:
- 返回值类型为
uint32_t
,表示操作的结果。返回IOT_SUCCESS
表示操作成功,否则返回定义在wifiiot_errno.h
中的错误代码。
该函数用于初始化SSD1306 OLED显示屏。首先,它初始化GPIO引脚,并将其配置为I2C功能。然后调用IoTI2cInit
函数初始化I2C控制器。接下来,通过循环发送一系列的初始化命令字节到OLED设备,以完成OLED的初始化过程。
- 设置数据起始位置
void OledSetPosition(uint8_t x, uint8_t y)
参数解释:
x
:X轴位置,写入数据的起始列位置。y
:Y轴位置,写入数据的起始行位置。
返回值:无
该函数用于设置写入数据的起始位置。它调用WriteCmd
函数向OLED设备发送命令字节,设置OLED设备的行和列地址。
- 填充屏幕
void OledFillScreen(uint8_t fillData)
参数解释:
fillData
:填充数据,要用于填充屏幕的数据字节。
返回值:无
该函数用于全屏填充屏幕。通过循环遍历所有行和列,调用WriteData
函数向OLED设备发送填充数据字节。
- 输出字符
void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font)
参数解释:
x
:X轴位置,写入字符的起始列位置。y
:Y轴位置,写入字符的起始行位置。ch
:字符,要写入的字符。font
:字体,选择使用的字体。
返回值:无
该函数用于显示一个字符。根据所选字体,它调用WriteData
函数向OLED设备发送对应字体的字形数据。
- 输出字符串
void OledShowString(uint8_t x, uint8_t y, const char* str, Font font)
参数解释:
x
:X轴位置,写入字符串的起始列位置。y
:Y轴位置,写入字符串的起始行位置。str
:字符串,要写入的字符串。font
:字体,选择使用的字体。
返回值:无
该函数用于显示一个字符串。它遍历字符串中的每个字符,调用OledShowChar
函数逐个显示字符,并根据需要更新X和Y轴位置。
- 编写源文件oledTest.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "oled_ssd1306.h"
static void oledMain(void){
OledInit();
OledFillScreen(0);
OledShowString(0, 0, "Hello,World", 1);
}
static void oledTest(void){
osThreadAttr_t attr = {"oledMain", 0, NULL, 0, NULL, 1024, osPriorityNormal, 0, 0};
osThreadNew((osThreadFunc_t)oledMain, NULL, &attr);
}
APP_FEATURE_INIT(oledTest);
- 编写BUILD.gn (app目录下的BUILD.gn文件记得也修改好,这里就不多演示了)
static_library("oled") {
sources = [
"oled_ssd1306.c",
"oledTest.c",
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
"//base/iot_hardware/peripheral/interfaces/kits",
"//device/hisilicon/hispark_pegasus/sdk_liteos/include",
"//base/iothardware/peripheral/interfaces/inner_api",
]
}
- 编译,烧录,重启开发板,观察oled显示屏
结束语
至此驱动模块就给大家介绍到这里,大家可以结合内核编程驱动编程自行开发一些小案例。后面也会给大家带来一些综合案例的演示。如有地方说错了,请各位指正,感谢大家的支持!
本文作者:stackor