1

OpenHarmony智能开发套件[驱动开发篇(下)

 10 months ago
source link: https://www.51cto.com/article/756202.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

OpenHarmony智能开发套件[驱动开发篇(下)

作者:stackor 2023-05-30 14:58:05
本章将介绍如何IO控制温湿度传感器,可燃气体传感器,RGB灯,人体红外传感器,光敏电阻,Oled显示屏。
166911d13819670bb47592a6eed40b9d7b090b.png

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

前面介绍了OpenHarmony智能开发套件驱动开发篇·上,下面我们接着介绍驱动开发,本章将介绍如何IO控制温湿度传感器,可燃气体传感器,RGB灯,人体红外传感器,光敏电阻,Oled显示屏。

环境监测板

环境检测板上一共有三个模块,AHT20数字温湿度传感器,蜂鸣器,MQ-2可燃气体传感器。蜂鸣器的使用在上一篇已经提及过,为了方便学习,本次只介绍温湿度传感器,可燃气体传感器的IO控制,蜂鸣器的结合使用可以放在以后的综合案例中去说。

温湿度传感器

案例:每隔1s,获取一次温湿度,打印在终端

  1. 新建样例目录
    applications/sample/wifi-iot/app/aht20
  2. 新建源文件和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是我们比较常用的。

  1. 从传感器中读取数据。
static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)

参数解释:

  • buffer:存储读取数据的缓冲区的指针。
  • buffLen:缓冲区的长度。
  • 返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于从传感器中读取数据。它使用 IoTI2cRead 函数从指定的地址读取数据到缓冲区中。

  1. 向传感器中写入数据。
static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)

参数解释:

  • buffer:存储要写入传感器的数据的缓冲区的指针。
  • buffLen:缓冲区的长度。

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

实现过程:该函数用于向传感器写入数据。它使用 IoTI2cWrite 函数将数据从缓冲区写入指定的地址。

  1. 获取传感器状态
static uint32_t AHT20_StatusCommand(void)

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于发送获取状态命令给传感器。它构造一个包含命令的缓冲区,然后使用 AHT20_Write 函数发送该命令。

  1. 软复位传感器。
static uint32_t AHT20_ResetCommand(void)

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于发送软复位命令给传感器。它构造一个包含命令的缓冲区,然后使用 AHT20_Write 函数发送该命令。

  1. 初始化传感器。
static uint32_t AHT20_CalibrateCommand(void)

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于发送初始化校准命令给传感器。它构造一个包含命令和参数的缓冲区,然后使用 AHT20_Write 函数发送该命令。

  1. 校准传感器。
uint32_t AHT20_Calibrate(void)

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于校准传感器。它首先发送获取状态命令,然后读取状态字并检查校准使能位。如果校准使能位不为1或传感器处于忙状态,它会发送软复位命令并等待一段时间后再发送初始化校准命令。

  1. 发送命令,传感器开始测量。
uint32_t AHT20_StartMeasure(void)

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于发送触发测量命令给传感器,以开始测量过程。它构造一个包含命令和参数的缓冲区,然后使用 AHT20_Write 函数发送该命令。

  1. 获取传感器的测量结果。
uint32_t AHT20_GetMeasureResult(float* temp, float* humi)

参数解释:

  • temp:用于存储温度值的指针。
  • humi:用于存储湿度值的指针。

返回值:一个 uint32_t 类型的整数,表示执行操作的结果。

该函数用于接收测量结果并将其转换为标准值。它首先从传感器读取状态命令的结果,然后根据状态字判断传感器的忙闲状态。如果传感器忙碌,函数会等待一段时间后再次读取状态命令的结果。如果传感器一直忙碌,函数返回失败。如果传感器空闲,函数会从缓冲区中提取湿度和温度的原始值,并将其转换为标准值,然后存储在指定的变量中。最后,函数返回成功或失败的结果。

  1. 编写源文件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);
  1. 编写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/"
    ]
}
  1. 编译,烧录,串口调试,观察控制台上的输出。
OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区

那么到这里,温湿度传感器最简单的一个案例就介绍到这里。

可燃气体传感器

案例:每隔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;
  1. 新建样例目录
    applications/sample/wifi-iot/app/gas
  2. 新建源文件和gn文件
    applications/sample/wifi-iot/app/gas/gasTest.c
    applications/sample/wifi-iot/app/gas/BUILD.gn
  3. 编写源文件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
  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/"
    ]
}
  1. 编译,烧录,串口调试,观察控制台上的输出。
OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区

绝大多数可见光可用三色光(红、绿、蓝)的不同强度的混合来表示,即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的占空比,实现红绿蓝的混色效果。

  1. 新建样例目录
    applications/sample/wifi-iot/app/rgb
  2. 新建源文件和gn文件
    applications/sample/wifi-iot/app/rgb/rgb.c
    applications/sample/wifi-iot/app/rgb/BUILD.gn
  3. 编写源文件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);
  1. 编写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/"
    ]
}
  1. 编译,烧录,重启开发板,观察三色灯,注意灯光可能比较强。
OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区

人体红外传感器

和控制可燃气体传感器一样,我们仍然使用的是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的样子。

OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区
#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的样子。

OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区

Oled显示屏

最后我们讲讲如何Oled板,主要是如何点亮他,让他能代替终端为我们显示一些东西,下方的两个按钮暂且不介绍了。

案例:在Oled板上打印“Hello,World”

  1. 新建样例目录
    applications/sample/wifi-iot/app/oled
  2. 新建源文件和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比较常用。

  1. 写入数据字节。
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设备发送数据。

  1. 命令写入。
uint32_t WriteCmd(uint8_t cmd)

参数解释:

  • cmd:命令字节,要写入的命令字节。
  • 返回值类型为uint32_t,表示操作的结果。返回IOT_SUCCESS表示操作成功,否则返回定义在wifiiot_errno.h中的错误代码。

该函数用于向OLED设备写入命令字节。它调用了I2cWiteByte函数,将命令字节和OLED_I2C_CMD作为参数传递给I2cWiteByte函数进行发送。

  1. 数据写入。
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的初始化过程。

  1. 设置数据起始位置。
void OledSetPosition(uint8_t x, uint8_t y)

参数解释:

  • x:X轴位置,写入数据的起始列位置。
  • y:Y轴位置,写入数据的起始行位置。

返回值:无

该函数用于设置写入数据的起始位置。它调用WriteCmd函数向OLED设备发送命令字节,设置OLED设备的行和列地址。

  1. 填充屏幕。
void OledFillScreen(uint8_t fillData)

参数解释:

  • fillData:填充数据,要用于填充屏幕的数据字节。

返回值:无

该函数用于全屏填充屏幕。通过循环遍历所有行和列,调用WriteData函数向OLED设备发送填充数据字节。

  1. 输出字符。
void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font)

参数解释:

  • x:X轴位置,写入字符的起始列位置。
  • y:Y轴位置,写入字符的起始行位置。
  • ch:字符,要写入的字符。
  • font:字体,选择使用的字体。

返回值:无

该函数用于显示一个字符。根据所选字体,它调用WriteData函数向OLED设备发送对应字体的字形数据。

  1. 输出字符串。
void OledShowString(uint8_t x, uint8_t y, const char* str, Font font)

参数解释:

  • x:X轴位置,写入字符串的起始列位置。
  • y:Y轴位置,写入字符串的起始行位置。
  • str:字符串,要写入的字符串。
  • font:字体,选择使用的字体。

返回值:无

该函数用于显示一个字符串。它遍历字符串中的每个字符,调用OledShowChar函数逐个显示字符,并根据需要更新X和Y轴位置。

  1. 编写源文件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);
  1. 编写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",
    ]
}
  1. 编译,烧录,重启开发板,观察oled显示屏。
OpenHarmony智能开发套件[驱动开发篇·下]-开源基础软件社区

至此驱动模块就给大家介绍到这里,大家可以结合内核编程驱动编程自行开发一些小案例。后面也会给大家带来一些综合案例的演示。

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

责任编辑:jianghua 来源: 51CTO 开源基础软件社区

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK