第2部分,
- 实现proteus中 i2c 接口的 OLED12864 的驱动,后面将为其制作汉字字库!
- SSD1306是如何驱动OLED12864的?需要做哪些初始化工作?
- 由于OLED是显示缓存是列行式扫描,HZK16x16是逐行式扫描,需要将“逐行式”转化为列行式!
OLED12864 软件 i2c 驱动实现和HZK字库转化
Proteus中OLED12864(i2c)使用的是 SSD1306 驱动芯片!我们可以从网上下载 SSD1306 的datasheet,进一步地学习研究!
1 i2c时序图
1.1 SSD1306的 i2c 器件地址
1.1.1 测试OLED12864的i2c器件地址
1.2 i2c的起始与终止信号
1.3 i2c的应答信号
1.4 i2c的传输数据位
2 i2c底层实现
2.1 延时函数
static void i2c_delay(){
// 24MHz, 12T, delay 1.5us
_nop_();
_nop_();
}
2.2 起始信号
void i2c_start(void){
I2C_SDA = 1;
I2C_SCL = 1;
I2C_SDA = 0; // Falling edge
i2c_delay(); // 1us
I2C_SCL = 0; // Releasing the clock
}
2.2 终止信号
void i2c_stop(void){
I2C_SDA = 0;
I2C_SCL = 1;
i2c_delay(); // 1us
I2C_SDA = 1; // Rising edge
i2c_delay(); // 1us
I2C_SCL = 0; // Releasing the clock
}
2.3 发送数据字节
void i2c_send_byte(uint8_t dat){
uint8_t tmp = 0x80;
I2C_SCL = 0;
for(tmp = 0x80; tmp; tmp >>= 1){
if(dat & tmp){
I2C_SDA = 1;
}else{
I2C_SDA = 0;
}
I2C_SCL = 1;
i2c_delay(); // 1us
I2C_SCL = 0;
}
}
2.4 发送器接收应答信号
bit i2c_recv_ack(void){
bit ack = 0;
I2C_SDA = 1;
I2C_SCL = 1;
ack = !I2C_SDA;
i2c_delay();
I2C_SCL = 0; // Releasing the clock
return ack;
}
3 OLED12864 驱动实现
3.1 数据手册阅读
3.1.1 SSD1306 硬件框图
3.1.2 SSD1306 的 GDDRAM 结构
图形显示数据RAM,Graphic Display Data RAM (GDDRAM)
3.1.3 向OLED12864写入数据
控制字:用来识别发送的数据是“命令”还是“数据”!
3.2 代码实现
3.2.1 器件寻址
bit oled12864_addressing(uint8_t dev_addr){
bit ack = 0;
i2c_start();
i2c_send_byte((dev_addr << 1) | 0x00);
ack = i2c_recv_ack();
i2c_stop();
return ack;
}
3.2.2 向OLED写入命令或数据
// mode = 1 dat mode = 0 command
static bit oled_write(uint8_t dev_addr, uint8_t dat, bit mode){
;
i2c_start();
i2c_send_byte((dev_addr << 1) | 0x00);
if(!i2c_recv_ack()){
return 0;
}
if(mode){
i2c_send_byte(0x40);
}else{
i2c_send_byte(0x00);
}
if(!i2c_recv_ack()){
return 0;
}
i2c_send_byte(dat);
if(!i2c_recv_ack()){
return 0;
}
i2c_stop();
return 1;
}
3.2.2.1 写命令
static bit oled_write_cmd(uint8_t cmd){
return oled_write(OLED12864_I2C_ADDR, cmd, 0);
}
3.2.2.2 写数据
static bit oled_write_dat(uint8_t dat){
return oled_write(OLED12864_I2C_ADDR, dat, 1);
}
3.2.3 OLED显示开关
3.2.3.1 打开显示
void oled_on(void){
oled_write_cmd(0xAF); // display on
}
3.2.3.2 关闭显示
void oled_off(void){
oled_write_cmd(0xAE); // display off
}
3.2.4 初始化OLED
void oled_init(void){
oled_off();
/**** (1) OLED12864 or OLED12832 ****/
#if (RESOLUTION == 12864) // 0.96"
/** Set Multiplex Ratio(1 to 64) (Resolution Col * Row)
Setting Row from 16MUX(0x10) to 64MUX(0x3F)**/
oled_write_cmd(0xA8);
oled_write_cmd(0x3F); // 0x00|X[5:0] 64MUX
/**Set COM Pins Hardware Configuration
- X[4]=0b, Sequential COM pin configuration
- X[4]=1b(RESET), Alternative COM pin configuration
- X[5]=0b(RESET), Disable COM Left/Right remap
- X[5]=1b, Enable COM Left/Right remap **/
oled_write_cmd(0xDA);
oled_write_cmd(0x12); // 0x02|X[5]|X[4]
#elif (RESOLUTION == 12832) // 0.91"
/** Set Multiplex Ratio(1 to 64) (Resolution Col * Row)
Setting Row from 16MUX(0x10) to 64MUX(0x3F)**/
oled_write_cmd(0xA8);
oled_write_cmd(0x1F); // 0x00|X[5:0] 16MUX
/**Set COM Pins Hardware Configuration
- X[4]=0b, Sequential COM pin configuration
- X[4]=1b(RESET), Alternative COM pin configuration
- X[5]=0b(RESET), Disable COM Left/Right remap
- X[5]=1b, Enable COM Left/Right remap **/
oled_write_cmd(0xDA);
oled_write_cmd(0x02); // 0x02|X[5]|X[4]
#endif
/**** (2) Charge Pump Command Table ****/
oled_write_cmd(0x8D); // Charge Pump Setting
oled_write_cmd(0x10); // 0x10 dsiabled, 0x14 enabled
/**** (3) Fundamental Command ****/
oled_write_cmd(0xA5); // Entire display ON
oled_write_cmd(0xA4); // Display outputs according to the GDDRAM contents
oled_write_cmd(0xA6); // 0xA6 Normal display(default, 1 - 'ON'); 0xA7 Inverse display(0 - 'ON')
/** Contrast Control
The chip has 256 contrast steps from 00h to FFh.
The segment output current increases as the contrast step value increases. **/
oled_write_cmd(0x81);
oled_write_cmd(0x7F); // 0x7F
/**** (4) Addressing Setting Command Table ****/
/**Set Memory Addressing Mode
- X[1:0] = 00b, Horizontal Addressing Mode
- X[1:0] = 01b, Vertical Addressing Mode
- X[1:0] = 10b, Page Addressing Mode (RESET)
- X[1:0] = 11b, Invalid **/
oled_write_cmd(0x20);
oled_write_cmd(0x00); // 0x00|X[1:0] Vertical
/**** (5) Hardware Configuration (Panel resolution & layout related) Command Table ****/
/**Set Segment Re-map
- 0xA0 column address 0 is mapped to SEG0 (RESET)
- 0xA1 column address 127 is mapped to SEG0 **/
oled_write_cmd(0xA1);
/**Set COM Re-map
- 0xC0 normal mode (RESET) Scan from COM0 to COM[N-1]
- 0xC8 remapped mode. Scan from COM[N-1] to COM0 **/
oled_write_cmd(0xC8); // 0xC0|X[3], remapped mode
// Set Display Start Line. 0x40 ~ 0x7F(RESET = 0x40)
oled_write_cmd(0x40); // 0x40|X[5:0], from row 0 to 63
/**Set Display Offset
Set vertical shift by COM from 0~63(0x00~0z3F) **/
oled_write_cmd(0xD3);
oled_write_cmd(0x00); // Set vertical shift by COM from 0x00~0x3F(RESET=0x00)
/**Set Display Clock Divide Ratio/Oscillator Frequency
- X[7:4] : Set the Oscillator Frequency, Oscillator Frequency increases with the value of X[7:4] and vice versa.