295 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// OLED显示屏简化版驱动源文件
 | 
						||
 | 
						||
#include <stdio.h>      // 标准输入输出
 | 
						||
#include <stddef.h>     // 标准类型定义
 | 
						||
 | 
						||
#include "iot_gpio.h"  // OpenHarmony HAL:IoT硬件设备操作接口-GPIO
 | 
						||
#include "iot_i2c.h"   // OpenHarmony HAL:IoT硬件设备操作接口-I2C
 | 
						||
#include "iot_errno.h" // OpenHarmony HAL:IoT硬件设备操作接口-错误代码定义
 | 
						||
#include "hi_io.h"     // 海思 Pegasus SDK:IoT硬件设备操作接口-IO
 | 
						||
 | 
						||
// 字库头文件
 | 
						||
#include "oled_fonts.h"
 | 
						||
 | 
						||
// OLED显示屏简化版驱动接口文件
 | 
						||
#include "oled_ssd1306.h"
 | 
						||
 | 
						||
// 定义一个宏,用于计算数组的长度
 | 
						||
#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
 | 
						||
 | 
						||
// 定义一个宏,用于标识I2C0
 | 
						||
#define OLED_I2C_IDX 0
 | 
						||
 | 
						||
// 定义一个宏,用于标识I2C0的波特率(传输速率)
 | 
						||
#define OLED_I2C_BAUDRATE (400 * 1000) // 400KHz
 | 
						||
 | 
						||
// 定义一个宏,用于标识OLED的宽度
 | 
						||
#define OLED_WIDTH (128)
 | 
						||
 | 
						||
// 定义一个宏,用于标识SSD1306显示屏驱动芯片的设备地址
 | 
						||
#define OLED_I2C_ADDR 0x78
 | 
						||
 | 
						||
// 定义一个宏,用于标识写命令操作
 | 
						||
#define OLED_I2C_CMD 0x00  // 0000 0000       写命令
 | 
						||
 | 
						||
// 定义一个宏,用于标识写数据操作
 | 
						||
#define OLED_I2C_DATA 0x40 // 0100 0000(0x40) 写数据
 | 
						||
 | 
						||
// 定义一个宏,用于标识100ms的延时
 | 
						||
#define DELAY_100_MS (100 * 1000)
 | 
						||
 | 
						||
// 定义一个结构体,表示要发送或接收的数据
 | 
						||
typedef struct
 | 
						||
{
 | 
						||
    // 要发送的数据的指针
 | 
						||
    unsigned char *sendBuf;
 | 
						||
    // 要发送的数据长度
 | 
						||
    unsigned int sendLen;
 | 
						||
    // 要接收的数据的指针
 | 
						||
    unsigned char *receiveBuf;
 | 
						||
    // 要接收的数据长度
 | 
						||
    unsigned int receiveLen;
 | 
						||
} IotI2cData;
 | 
						||
 | 
						||
/// @brief  向OLED写一个字节
 | 
						||
/// @param  regAddr 写入命令还是数据 OLED_I2C_CMD / OLED_I2C_DATA
 | 
						||
/// @param  byte 写入的内容
 | 
						||
/// @retval 成功返回IOT_SUCCESS,失败返回IOT_FAILURE
 | 
						||
static uint32_t I2cWiteByte(uint8_t regAddr, uint8_t byte)
 | 
						||
{
 | 
						||
    // 定义字节流
 | 
						||
    uint8_t buffer[] = {regAddr, byte};
 | 
						||
    IotI2cData i2cData = {0};
 | 
						||
    i2cData.sendBuf = buffer;
 | 
						||
    i2cData.sendLen = sizeof(buffer) / sizeof(buffer[0]);
 | 
						||
 | 
						||
    // 发送字节流
 | 
						||
    return IoTI2cWrite(OLED_I2C_IDX, OLED_I2C_ADDR, i2cData.sendBuf, i2cData.sendLen);
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 向OLED写一个命令字节
 | 
						||
/// @param cmd 写入的命令字节
 | 
						||
/// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE
 | 
						||
static uint32_t WriteCmd(uint8_t cmd)
 | 
						||
{
 | 
						||
    return I2cWiteByte(OLED_I2C_CMD, cmd);
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 向OLED写一个数据字节
 | 
						||
/// @param cmd 写入的数据字节
 | 
						||
/// @return 成功返回IOT_SUCCESS,失败返回IOT_FAILURE
 | 
						||
uint32_t WriteData(uint8_t data)
 | 
						||
{
 | 
						||
    return I2cWiteByte(OLED_I2C_DATA, data);
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 初始化SSD1306显示屏驱动芯片
 | 
						||
uint32_t OledInit(void)
 | 
						||
{
 | 
						||
    // 构造初始化代码
 | 
						||
    static const uint8_t initCmds[] = {
 | 
						||
        0xAE, // 显示关闭
 | 
						||
        0x00, // 页寻址模式时,设置列地址的低4位为0000
 | 
						||
        0x10, // 页寻址模式时,设置列地址的高4位为0000
 | 
						||
        0x40, // 设置起始行地址为第0行
 | 
						||
        0xB0, // 页寻址模式时,设置页面起始地址为PAGE0
 | 
						||
        0x81, // 设置对比度
 | 
						||
        0xFF, // 对比度数值
 | 
						||
        0xA1, // set segment remap
 | 
						||
        0xA6, // 设置正常显示。0对应像素熄灭,1对应像素亮起
 | 
						||
        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, // 显示开启
 | 
						||
    };
 | 
						||
 | 
						||
    // 初始化GPIO-13
 | 
						||
    IoTGpioInit(HI_IO_NAME_GPIO_13);
 | 
						||
    // 设置GPIO-13引脚功能为I2C0_SDA
 | 
						||
    hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
 | 
						||
    // 初始化GPIO-14
 | 
						||
    IoTGpioInit(HI_IO_NAME_GPIO_14);
 | 
						||
    // 设置GPIO-14引脚功能为I2C0_SCL
 | 
						||
    hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
 | 
						||
 | 
						||
    // 用指定的波特速率初始化I2C0
 | 
						||
    IoTI2cInit(OLED_I2C_IDX, OLED_I2C_BAUDRATE);
 | 
						||
 | 
						||
    // 发送初始化代码,初始化SSD1306显示屏驱动芯片
 | 
						||
    for (size_t i = 0; i < ARRAY_SIZE(initCmds); i++)
 | 
						||
    {
 | 
						||
        // 发送一个命令字节
 | 
						||
        uint32_t status = WriteCmd(initCmds[i]);
 | 
						||
        if (status != IOT_SUCCESS)
 | 
						||
        {
 | 
						||
            return status;
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    // OLED初始化完成,返回成功
 | 
						||
    return IOT_SUCCESS;
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 设置显示位置
 | 
						||
/// @param x x坐标,1像素为单位
 | 
						||
/// @param y y坐标,8像素为单位。即页面起始地址
 | 
						||
/// @return 无
 | 
						||
void OledSetPosition(uint8_t x, uint8_t y)
 | 
						||
{
 | 
						||
    //设置页面起始地址
 | 
						||
    WriteCmd(0xb0 + y);
 | 
						||
 | 
						||
    // 列:0~127
 | 
						||
    // 第0列:0x00列,二进制00000000。低地址0000,即0x00。高地址0000(需要|0x10),0000|0x10=0x10。
 | 
						||
    // 第127列:0x7f列,二进制01111111。低地址1111,即0x0F。高地址0111(需要|0x10),0111|0x10=0x17。
 | 
						||
 | 
						||
    // 设置显示位置:列地址的低4位
 | 
						||
    // 直接取出列地址低4位作为命令代码的低4位,命令代码的高4位为0000
 | 
						||
    WriteCmd(x & 0x0f);
 | 
						||
 | 
						||
    // 设置显示位置:列地址的高4位
 | 
						||
    // 取出列地址高4位作为命令代码的低4位,命令代码的高4位必须为0001
 | 
						||
    // 实际编程时,列地址的高4位和0x10(二进制00010000)进行按位或即得到命令代码
 | 
						||
    WriteCmd(((x & 0xf0) >> 4) | 0x10);
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 全屏填充
 | 
						||
/// @param fillData 填充的数据,1字节
 | 
						||
/// @return 无
 | 
						||
void OledFillScreen(uint8_t fillData)
 | 
						||
{
 | 
						||
    // 相关变量,用于遍历page和列
 | 
						||
    uint8_t m = 0;
 | 
						||
    uint8_t n = 0;
 | 
						||
 | 
						||
    // 写入所有页的数据
 | 
						||
    for (m = 0; m < 8; m++)
 | 
						||
    {
 | 
						||
        //设置页地址:0~7
 | 
						||
        WriteCmd(0xb0 + m);
 | 
						||
 | 
						||
        // 设置显示位置为第0列
 | 
						||
        WriteCmd(0x00); //设置显示位置:列低地址(0000)
 | 
						||
        WriteCmd(0x10); //设置显示位置:列高地址(0000)
 | 
						||
 | 
						||
        // 写入128列数据
 | 
						||
        // 在一个页中,数据按列写入,一次一列,对应发送过来的1字节数据
 | 
						||
        for (n = 0; n < 128; n++)
 | 
						||
        {
 | 
						||
            // 写入一个字节数据
 | 
						||
            WriteData(fillData);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 清屏函数
 | 
						||
/// @return 无
 | 
						||
void OledClearScreen(void)
 | 
						||
{
 | 
						||
    OledFillScreen(0x00);  // 用0x00填充整个屏幕,实现清屏
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
/// @brief 显示一个字符
 | 
						||
/// @param x: x坐标,1像素为单位
 | 
						||
/// @param y: y坐标,8像素为单位
 | 
						||
/// @param ch: 要显示的字符
 | 
						||
/// @param font: 字库
 | 
						||
void OledShowChar(uint8_t x, uint8_t y, uint8_t ch, Font font)
 | 
						||
{
 | 
						||
    // 数组下标
 | 
						||
    uint8_t c = 0;
 | 
						||
 | 
						||
    // 循环控制
 | 
						||
    uint8_t i = 0;
 | 
						||
 | 
						||
    // 得到数组下标
 | 
						||
    // 空格的ASCII码32,在字库中的下标是0。字库中的字符-空格即相应的数组下标
 | 
						||
    c = ch - ' ';
 | 
						||
 | 
						||
    // 显示字符
 | 
						||
    if (font == FONT8x16) // 8*16的点阵,一个page放不下
 | 
						||
    {
 | 
						||
        // 显示字符的上半部分
 | 
						||
        // 设置显示位置
 | 
						||
        OledSetPosition(x, y);
 | 
						||
        // 逐个字节写入(16个数组元素的前8个)
 | 
						||
        for (i = 0; i < 8; i++)
 | 
						||
        {
 | 
						||
            WriteData(F8X16[c * 16 + i]);
 | 
						||
        }
 | 
						||
 | 
						||
        // 显示字符的下半部分
 | 
						||
        // 设置显示位置为下一个PAGE
 | 
						||
        OledSetPosition(x, y + 1);
 | 
						||
        // 逐个字节写入(16个数组元素的后8个)
 | 
						||
        for (i = 0; i < 8; i++)
 | 
						||
        {
 | 
						||
            WriteData(F8X16[c * 16 + 8 + i]);
 | 
						||
        }
 | 
						||
    }
 | 
						||
    else // 6*8的点阵,在一个page中
 | 
						||
    {
 | 
						||
        // 设置显示位置
 | 
						||
        OledSetPosition(x, y);
 | 
						||
        // 逐个字节写入(数组第二维的6个数组元素)
 | 
						||
        for (i = 0; i < 6; i++)
 | 
						||
        {
 | 
						||
            WriteData(F6x8[c][i]);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
/// @brief 显示一个字符串
 | 
						||
/// @param x: x坐标,1像素为单位
 | 
						||
/// @param y: y坐标,8像素为单位
 | 
						||
/// @param str: 要显示的字符串
 | 
						||
/// @param font: 字库
 | 
						||
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;
 | 
						||
 | 
						||
        // 如果下一个要显示的字符超出了OLED显示的范围,则换行
 | 
						||
        if (x > 120)
 | 
						||
        {
 | 
						||
            x = 0;
 | 
						||
            y += 2;
 | 
						||
        }
 | 
						||
 | 
						||
        // 下一个字符
 | 
						||
        j++;
 | 
						||
    }
 | 
						||
}
 |