hi3861 OpenHarmony SH1106 OLED 模块

SH1106OLED模块功能简单,价格便宜。I2C接口通信。

OpenHarmony系统自带I2C通信函数,只要调用就可以了。再使用I2C协议前,先打开 device/hisilicon/hispark_pegasus/sdk_liteos/build/config/usr_config.mk看看I2C设置是否是被注释掉,如果显示是 # CONFIG_I2C_SUPPORT is not set,就修改成CONFIG_I2C_SUPPORT=y。

在程序中设置端口,频率,并启动I2C初始化,如果不报错就初始化成功。

#define SDA_IO_NAME     HI_IO_NAME_GPIO_13
#define SDA_IO_FUNC     HI_IO_FUNC_GPIO_13_I2C0_SDA

#define SCL_IO_NAME     HI_IO_NAME_GPIO_14
#define SCL_IO_FUNC     HI_IO_FUNC_GPIO_14_I2C0_SCL

#define I2C_IDX         HI_I2C_IDX_0
#define I2C_BAUDRATE    400000

// I2C初始
hi_void I2C_Init(hi_void)
{
    hi_io_set_func(SDA_IO_NAME, SDA_IO_FUNC);
    hi_io_set_func(SCL_IO_NAME, SCL_IO_FUNC);
    if(hi_i2c_init(I2C_IDX, I2C_BAUDRATE) != 0)
    {
        printf(" [ I2C Init ] Failed! \n");
    }
}

I2C写操作,harmony自带I2C操作函数,只要执行就可以,非常简单。

// 写入 1条 指令, addr = 地址, data = 数据
static hi_void SH1106_I2C_Write(hi_u8 addr, hi_u8 data)
{
    hi_u8 data_send_buf[2] = {addr, data};
    hi_i2c_data sh1106_i2c_data = {0};
    sh1106_i2c_data.send_buf = data_send_buf;
    sh1106_i2c_data.send_len = 2;
    if(hi_i2c_write(SH1106_I2C_IDX, SH1106_ADDR, &sh1106_i2c_data) != 0)
    {
        printf(" [SH1106 I2C Write] Failed! \n");
    }
}

SH1106的初始化,复制样例里的设置就行,一般实际使用中没什么需要再设置的了。

// SH1106 初始化
hi_void SH1106_Init(hi_void)
{
    SH1106_I2C_Write(W_CMD, 0xAE);
    SH1106_I2C_Write(W_CMD, 0x02);
    SH1106_I2C_Write(W_CMD, 0x10);
    SH1106_I2C_Write(W_CMD, 0x40);
    SH1106_I2C_Write(W_CMD, 0xB0);
    SH1106_I2C_Write(W_CMD, 0x81);
    SH1106_I2C_Write(W_CMD, 0xCF);
    SH1106_I2C_Write(W_CMD, 0xA1);
    SH1106_I2C_Write(W_CMD, 0xC8);
    SH1106_I2C_Write(W_CMD, 0xA6);
    SH1106_I2C_Write(W_CMD, 0xA8);
    SH1106_I2C_Write(W_CMD, 0x3F);
    SH1106_I2C_Write(W_CMD, 0xAD);
    SH1106_I2C_Write(W_CMD, 0x8B);
    SH1106_I2C_Write(W_CMD, 0x33);
    SH1106_I2C_Write(W_CMD, 0xC8);
    SH1106_I2C_Write(W_CMD, 0xD3);
    SH1106_I2C_Write(W_CMD, 0x00);
    SH1106_I2C_Write(W_CMD, 0xD5);
    SH1106_I2C_Write(W_CMD, 0x80);
    SH1106_I2C_Write(W_CMD, 0xD9);
    SH1106_I2C_Write(W_CMD, 0xF1);
    SH1106_I2C_Write(W_CMD, 0xDA);
    SH1106_I2C_Write(W_CMD, 0x12);
    SH1106_I2C_Write(W_CMD, 0xDB);
    SH1106_I2C_Write(W_CMD, 0x40);
    SH1106_I2C_Write(W_CMD, 0xA4);
    SH1106_I2C_Write(W_CMD, 0xAF);
    hi_udelay(100000);
}

根据可能要使用的需求,做了几个功能函数。

// 清画布
hi_void Canvas_Clear(hi_void);

// 画线
hi_void Draw_Line(hi_s32 x1, hi_s32 y1, hi_s32 x2, hi_s32 y2);

// 画圆
hi_void Draw_Circle(hi_s32 cx, hi_s32 cy, hi_s32 cr);

// 画布 转入 缓存
hi_void Canv_Import_Buff(hi_void);



// 输入字符
hi_void Input_Char_6x12(hi_u8 cx, hi_u8 cy, hi_u8 ch);

// 输入字符串
hi_void Input_String_6x12(hi_u8 sx, hi_u8 sy, hi_u8 *str, hi_u8 len);



// 输入汉字
hi_void Input_CHINESE_12x12(hi_u8 cx, hi_u8 cy, hi_u8 *cn);



// 显示 1个 字符
hi_u8 Show_Char_4x8(hi_u8 x, hi_u8 y, hi_u8 c);

// 显示字符串
hi_u8 Show_String_4x8(hi_u8 sx, hi_u8 sy, hi_u8 *str, hi_u8 sl);

输出ASCII字符需要先做字库,用的工具是PCtoLCD2002,字体用Terminal。

PCtoLCD2002设置,主要根据你的sh1106的初始化设置是怎么做的,取模走向试几下就确认方向了。sh1106显示输出是按页输出,列地址自增。所以8个像素高度的字符在1个页里连续显示速度是最快的。首先做一个高效的6x8的字库,做成4x8也是可以的但是字太小了,挨在一起根本看不清楚,所以用6x8。

显示6x12像素字符是使用最舒服的效果:

12字符会有跨页显示的问题,先设置一个显示像素数组,然后把字符点阵数组铺进去,做好跨行处理就行了。

// 输入字符
hi_void Input_Char_6x12(hi_u8 cx, hi_u8 cy, hi_u8 ch)
{
    hi_u8  n = ch - 32;

    hi_u8 l1 = 0x00;
    hi_u8 l2 = 0x00;
    hi_u8 l3 = 0x00;

    hi_u8 ny = cy / 8;
    hi_u8 ly = cy % 8;

    for(hi_u8 i=0; i<6; i++)
    {
        l1 = 0x00;
        l2 = 0x00;
        l3 = 0x00;

        l1 |= char_6x12[n][i] << ly;
        l2 |= char_6x12[n][i] >> (8-ly);
        l2 |= char_6x12[n][i+6] << ly;
        l3 |= char_6x12[n][i+6] >> (8-ly);

        buffer[ny][cx+i] |= l1;
        buffer[ny+1][cx+i] |= l2;
        buffer[ny+2][cx+i] |= l3;
    }
}

可以满足任意位置输入字符,但是要考虑不要越出边界。

编辑汉字字符点阵数组显示也就变的很简单。

画线基本是不会用到的功能,但是偶尔线条能更好反应数据信息。

Bresenham画法真是个天才的妙想,我复制了画线画圆法,基本就够一般使用了。

Bresenham画法代码实现非常简单,效率很高。

// 画线  线两端 A点 B点 坐标, 可以任意A点B点 x: 0-127 y: 0-63
hi_void Draw_Line(hi_s32 x1, hi_s32 y1, hi_s32 x2, hi_s32 y2)
{
    hi_s32 w = abs(x2 - x1);
    hi_s32 h = abs(y2 - y1);

    hi_bool b = 0;

    if(h > w)
    {
        b = 1;
        Swap(&x1, &y1);
        Swap(&x2, &y2);
        Swap(&w, &h);
    }

    hi_s32 ix = 1;

    if (x1 > x2)
    {
        ix = -1;
    }

    hi_s32 iy = 1;

    if (y1 > y2)
    {
        iy = -1;
    }

    hi_s32 x = x1, y = y1;
    hi_s32 d = h * 2 - w;
    hi_s32 m = h * 2;
    hi_s32 n = (h - w) * 2;

    while (x != x2)
    {
        if (d < 0)
        {
            d += m;
        } else {
            d += n;
            y += iy;
        }

        if (b)
        {
            canvas[x][y] = 1;
        } else {
            canvas[y][x] = 1;
        }

        x += ix;
    }
}

结合红外遥控器做了一个例子。

例子源码

链接:https://pan.baidu.com/s/1tI3ua-zvx9tGCxfcWqyKSg?pwd=i27v 
提取码:i27v 

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值