添加OLED模块
概要
分析完I2C总线设备,并且当前是使用软件I2C,那么我们可以自己移植OLED模块,加深理解。
一、OLED模块介绍
(1)大小为0.96寸,分辨率为 12864
(2)本屏所用的驱动 IC 为 SSD1306,其具有内部升压功能
(3)SSD1306 的每页包含了128 个字节,总共 8 页,这样刚好是 12864 的点阵大小
(4)根据数据手册以及硬件电路,可以知道I2C的地址为0x3c
二、修改Menuconfig
menuconfig是依赖Kconfig文件的,而开启I2C的开关定义在bsp/stm32/stm32l475-atk-pandora/board/Kconfig中。那么就在该文件里面加上:
if BSP_USING_I2C
menuconfig BSP_USING_I2C2
bool "Enable I2C2 BUS (OLED)"
default y
if BSP_USING_I2C2
comment "Notice: PB9 --> 25; PA8 --> 8"
config BSP_I2C2_SCL_PIN
int "i2c2 scl pin number"
range 1 176
default 25
config BSP_I2C2_SDA_PIN
int "I2C2 sda pin number"
range 1 176
default 8
endif
......
endif
其中,对于PB9和PA8的索引,可以在bsp/stm32/libraries/HAL_Drivers/drv_gpio.c文件中找到。
#ifdef RT_USING_PIN
static const struct pin_index pins[] =
{
#if defined(GPIOA)
......
__STM32_PIN(8 , A, 8 ),
......
#if defined(GPIOB)
......
__STM32_PIN(25, B, 9),
......
......
#endif /* defined(GPIOB) */
#endif /* defined(GPIOA) */
};
修改完成后,去确认menuconfig下
确认完毕后生成MDK工程。
scons --target=mdk5
三、编写代码(主要部分)
1、硬件初始化
根据前面分析,在配置完menuconfig后,会自动初始化所配置的引脚,并注册对应的I2C总线,这时候,我们如果将此时的固件编译并烧录到板子上,那么就会发现对应的I2C设备了。
2、编写drv_oled.c文件(主要函数)
(1)将该文件存放在对应的bsp的/board/ports目录下
(2)传输函数
static rt_err_t oled_send_byte(rt_uint8_t data, rt_uint8_t cmd)
{
int ret;
rt_uint8_t buf[2];
if(cmd)
{
buf[0] = 0x00; //cmd
buf[1] = data;
ret = rt_i2c_master_send(oled_dev, OLED_I2C_ADDR, 0, buf, 2);
}
else
{
buf[0] = 0x40;
buf[1] = data;
ret = rt_i2c_master_send(oled_dev, OLED_I2C_ADDR, 0, buf, 2);
}
if(2 == ret)
return -RT_ERROR;
return RT_EOK;
}
(3)OLED寄存器初始化
static void oled_init(void)
{
oled_send_byte(0xAE, 1); //display off
oled_send_byte(0x00, 1); //set low column address
oled_send_byte(0x10, 1); //set high column address
oled_send_byte(0x40, 1); //set start line address
oled_send_byte(0xB0, 1); //set page address
oled_send_byte(0x81, 1); //contract control
oled_send_byte(0xFF, 1); //128
oled_send_byte(0xA1, 1); //set segment remap
oled_send_byte(0xA6, 1); //normal / reverse
oled_send_byte(0xA8, 1); //set multiplex ratio(1 to 64)
oled_send_byte(0x3F, 1); //1/32 duty
oled_send_byte(0xC8, 1); //Com scan direction
oled_send_byte(0xD3, 1); //set display offset
oled_send_byte(0x00, 1);
oled_send_byte(0xD5, 1); //set osc division
oled_send_byte(0x80, 1);
oled_send_byte(0xD8, 1); //set area color mode off
oled_send_byte(0x05, 1);
oled_send_byte(0xD9, 1); //Set Pre-Charge Period
oled_send_byte(0xF1, 1);
oled_send_byte(0xDA, 1); //set com pin configuartion
oled_send_byte(0x12, 1);
oled_send_byte(0xDB, 1); //set Vcomh
oled_send_byte(0x30, 1);
oled_send_byte(0x8D, 1); //set charge pump enable
oled_send_byte(0x14, 1);
oled_send_byte(0xAF, 1); //turn on oled panel
}
static int oled_hw_init(void)
{
oled_dev = rt_i2c_bus_device_find("i2c2");
if (oled_dev == RT_NULL)
{
return RT_NULL;
}
oled_init();
return RT_EOK;
}
INIT_DEVICE_EXPORT(oled_hw_init);
(4)增加字符串输出功能
//OLED清屏
void oled_clear(void)
{
rt_uint8_t i, n;
for(i=0; i<8; i++)
{
oled_send_byte(0xb0 + i, 1); //设置页地址(0~7)
oled_send_byte(0x00, 1); //设置显示位置—列低地址
oled_send_byte(0x10, 1); //设置显示位置—列高地址
for(n=0; n<128; n++)
oled_send_byte(0, 0);
}
}
//OLED设置坐标
static void oled_set_pos(rt_uint32_t x, rt_uint32_t y)
{
rt_uint8_t temp = 0;
temp = 0xb0 + y;
oled_send_byte(temp, 1);
temp = ((x & 0xf0) >> 4) |0x10;
oled_send_byte(temp, 1);
temp = x & 0x0f;
oled_send_byte(temp, 1);
}
/*
OLED显示一个字符
x - 横坐标,范围在0-127
y - 纵坐标,范围在0-7
*/
static void oled_show_char(rt_uint8_t x, rt_uint8_t y, rt_uint8_t data)
{
rt_uint8_t c=0,i;
c = data - ' '; //得到偏移后的值
if(x > 127)
{
x = 0;
y = y + 2;
}
if(16 == oled_font_size)
{
oled_set_pos(x, y);
for(i=0; i<8; i++)
oled_send_byte(F8X16[c*16 + i], 0);
oled_set_pos(x, y+1);
for(i=0; i<8; i++)
oled_send_byte(F8X16[c*16 + i + 8], 0);
}
else
{
oled_set_pos(x, y);
for(i=0; i<6; i++)
oled_send_byte(F6x8[c][i], 0);
}
}
void oled_show_string(unsigned char x, unsigned char y, unsigned char *buf)
{
unsigned char i = 0;
while (buf[i] != '\0')
{
oled_show_char(x, y, buf[i]);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
i++;
}
}
3、添加字库文件 drv_oled_font.h
(1)将该文件存放在对应的bsp的/board/ports目录下
(2)
#ifndef _DRV_OLED_FORNT_H
#define _DRV_OLED_FORNT_H
/************************************6*8的点阵************************************/
const 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,</