dm3730平台oled显示时钟——ssd1306驱动
来源:互联网 发布:淘宝网 商城 编辑:程序博客网 时间:2024/06/04 19:09
转载请注明出处:http://blog.csdn.net/bhj1119/article/details/73330863
最近在dm3730平台上增加了oled显示屏,用来显示时间。功能虽然简单,但在此过程中还是总结了一些知识和经验,拿出来分享一下,水平有限,欢迎指正。
一,oled驱动芯片
oled驱动芯片一般采用ssd1306,初始化命令如下,具体含义可以参考ssd1306芯片手册。
void ssd1306_init(void){gpio_set_value(65, 1);udelay(100);gpio_set_value(65, 0);mdelay(50);gpio_set_value(65, 1);ssd1306_write_byte(0xae, SSD1306_CMD);//--turn off oled panelssd1306_write_byte(0x00, SSD1306_CMD);//---set low column addressssd1306_write_byte(0x12, SSD1306_CMD);//---set high column addressssd1306_write_byte(0x40, SSD1306_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)ssd1306_write_byte(0xb0, SSD1306_CMD);ssd1306_write_byte(0x81, SSD1306_CMD);//--set contrast control registerssd1306_write_byte(0xff, SSD1306_CMD); // Set SEG Output Current Brightnessssd1306_write_byte(0xa1, SSD1306_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常ssd1306_write_byte(0xa6, SSD1306_CMD);//--set normal displayssd1306_write_byte(0xa8, SSD1306_CMD);//--set multiplex ratio(1 to 64)ssd1306_write_byte(0x2f, SSD1306_CMD);//--1/48 dutyssd1306_write_byte(0xc8, SSD1306_CMD);//Set COM/Row Scan Direction0xc0上下反置 0xc8正常ssd1306_write_byte(0xd3, SSD1306_CMD);//-set display offsetShift Mapping RAM Counter (0x00~0x3F)ssd1306_write_byte(0x00, SSD1306_CMD);//-not offsetssd1306_write_byte(0xd5, SSD1306_CMD);//--set display clock divide ratio/oscillator frequencyssd1306_write_byte(0x80, SSD1306_CMD);//--set divide ratio, Set Clock as 100 Frames/Secssd1306_write_byte(0xd9, SSD1306_CMD);//--set pre-charge periodssd1306_write_byte(0x21, SSD1306_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clockssd1306_write_byte(0xda, SSD1306_CMD);//--set com pins hardware configurationssd1306_write_byte(0x12, SSD1306_CMD);ssd1306_write_byte(0xdb, SSD1306_CMD);//--set vcomhssd1306_write_byte(0x40, SSD1306_CMD);//Set VCOM Deselect Level}
void ssd1306_display_on(void){ssd1306_write_byte(0x8D, SSD1306_CMD);ssd1306_write_byte(0x14, SSD1306_CMD);ssd1306_write_byte(0xAF, SSD1306_CMD);}
这里重点理解一下下面这段文字
B0~B7表示起始页地址
00~0f表示起始列地址的低4位
10~1f表示起始列地址的高4位
上文所述,页地址设为B2h,列地址低4位为03h,列地址高4位为10h,这就意味着开始列是PAGE2的SEG3,数据字节将写入到RAM的第三列。网上有人问:高四位的起始地址10h起什么作用呢?
既然低4位是00h~0fh,高4位是10h~1fh,那么一共有8位,可以表示2^8=256列(这么说,ssd1306最大支持256列)。
高位10h~1fh共16个数,低位00h~0fh也是16个数,那么 16*16=256,也就是说,高位将列分成16等份,低位再将每一小份再等分16份,这样一共是256份,也就是256列了。
还是不明白?直接上图:
这样列地址低4位为03h,列地址高4位为10h,就可以这样表示:绿框为列起始地址
如果列地址低4位为0eh,高4位为11h,就可以这样表示:绿框为列起始地址
那么,页地址又是什么概念呢?可以简单的理解为:一页有8行,128*64的屏有64/8=8页,64*48的屏有48/8=6页。
二,显示算法
int oled_post_word(u8 x, u8 y, u8 w, u8 h, const u8 *word, u8 r){if (y > (SSD1306_HEIGHT-1) || x + w > SSD1306_WIDTH) {return -1;}if (h < 8) {return -1;}u8 i, j, tmp, tmp1;u8 i0 = y/8;u8 i1 = (y + h - 1)/8;u8 y_8 = y%8;u8 y_8_8 = (8 - y_8);u8 h_8 = h%8;u8 h_y_8 = (h_8 + y_8);u8 h_y_8_8 = 8 - (h_8 + y_8);u8 h_8__8 = (8 - h_8);u8 h_8__h_y_8 = h_8 - (h+y)%8;if(y%8) {for(i = i0;i <= i1;++i) {for(j = 0;j < w;++j) {if(i == i0) { //第一行if(TRUE == r) {tmp = ~(word[w*(i-i0)+j]);//(*word++);//word[8*(i-i0)+j];} else {tmp = word[w*(i-i0)+j]; //*word++;}tmp <<= y_8;//y%8; //低位左移lcd_screen_data[SSD1306_WIDTH*i + x + j] &= 0xFF>>y_8_8;//(8-y%8); //取低位lcd_screen_data[SSD1306_WIDTH*i + x + j] |= tmp;}else if(i == i1 && h_y_8 <=8) { //(h%8 + y%8)最后一行if(TRUE == r) {tmp = ~(word[w*(i-i0-1)+j]);//(*word++);//word[8*(i-i0)+j];} else {tmp = word[w*(i-i0-1)+j]; //*word++;} //tmp &= 0xFF>>(8 - h%8); //取低有效位 tmp >>= y_8_8; //高位右移 if(TRUE == r) { tmp1 = ~(word[w*(i-i0)+j]);//(*word++);//word[8*(i-i0)+j]; } else { tmp1 = word[w*(i-i0)+j]; //*word++; } //tmp &= 0xFF>>(8 - h%8); //取低有效位 tmp1 <<= y_8;//y%8; //高位右移 tmp |= tmp1; tmp &= 0xFF>>h_y_8_8;//(8 - (h%8 + y%8)); lcd_screen_data[SSD1306_WIDTH*i + x + j] &= 0xFF<<h_y_8;//((h%8 + y%8)); //删除低位 lcd_screen_data[SSD1306_WIDTH*i + x + j] |= tmp; } else if(i == i1 && h_y_8 > 8) { //(h%8 + y%8)最后一行 if(TRUE == r) { tmp = ~(word[w*(i-i0-1)+j]);//(*word++);//word[8*(i-i0)+j]; } else { tmp = word[w*(i-i0-1)+j]; //*word++; } tmp &= 0xFF>>h_8__8;//(8 - h%8); //取低有效位 tmp >>= h_8__h_y_8;//h%8-(h+y)%8; //高位右移 lcd_screen_data[SSD1306_WIDTH*i + x + j] &= 0xFF<<(((h+y)%8)); //删除低位 lcd_screen_data[SSD1306_WIDTH*i + x + j] |= tmp; } else { //中间行 if(TRUE == r) { tmp = ~(word[w*(i-i0-1)+j]);//(*word++);//word[8*(i-i0)+j]; } else { tmp = word[w*(i-i0-1)+j]; //*word++; } //tmp &= 0xFF>>(8 - h%8); //取低有效位 tmp >>= y_8_8;//8-y%8; //高位右移 if(TRUE == r) { tmp1 = ~(word[w*(i-i0)+j]);//(*word++);//word[8*(i-i0)+j]; } else { tmp1 = word[w*(i-i0)+j]; //*word++; } //tmp &= 0xFF>>(8 - h%8); //取低有效位 tmp1 <<= y_8;//y%8; //高位右移 tmp |= tmp1; lcd_screen_data[SSD1306_WIDTH*i + x + j] = tmp; } } } } else { for(i = i0;i <= i1;++i) { for(j = 0;j < w;++j) { if(TRUE == r) { tmp = ~(word[w*(i-i0)+j]);//(*word++);//word[8*(i-i0)+j]; } else { tmp = word[w*(i-i0)+j]; //*word++; } if (i0 !=i1 && i == i1) { //最后一行 tmp &= 0xFF>>h_8__8;//(8 - h%8); //取低位 lcd_screen_data[SSD1306_WIDTH*i + x + j] &= 0xFF<<h_8;//(h%8); //删除低位 lcd_screen_data[SSD1306_WIDTH*i + x + j] |= tmp;} else { lcd_screen_data[SSD1306_WIDTH*i + x + j] = tmp;}}}}return 0;}先到这里,下一节介绍系统时钟的获取和刷新部分。
阅读全文
0 0
- dm3730平台oled显示时钟——ssd1306驱动
- dm3730平台oled显示时钟——ssd1306驱动
- dm3730平台oled显示时钟——系统时钟的获取和刷新
- SSD1306 OLED 驱动
- Arduino驱动SSD1306 OLED
- stm32 ssD1306 OLED驱动架构
- OpenWrt驱动OLED(SSD1306)过程记录
- Intel Edison arduino代码驱动OLED(SSD1306)
- OLED(128*64)SSD1306驱动学习总结
- 【单片机笔记】OLED控制器SSD1306及驱动代码
- 【Arduino】【MATLAB】用ssd1306 oled屏显示任意图片
- FPGA驱动OLED动态显示(Verilog代码)——OLED初始化
- FPGA驱动OLED动态显示(Verilog代码)——向OLED写数据(关键)
- 【巨窝】stm32c8t6 驱动ssd1306 oled IIC显示屏,HAL库,cubeMX配置。
- FPGA驱动OLED动态显示(Verilog代码)——Demo演示(链接)
- FPGA驱动OLED动态显示(Verilog代码)——工程文件之间关系
- FPGA驱动OLED动态显示(Verilog代码)——SPI写操作
- ESP8266基于microPython的OLED(SSD1306)驱动程序
- GET 和 POST 有什么区别?及为什么网上多数答案都是错的
- Java常用设计模式
- 现在的一卡通系统不能再一味地想着多发卡了
- windows 下 netsh 实现 端口映射(端口转发)
- 高级特性(20160811).md
- dm3730平台oled显示时钟——ssd1306驱动
- 在数据库中生成随机id
- Java的接口
- linux 设置网络开虚拟机自动连接
- 深度学习框架设计序列-mxnet NNVM计算图抽象机制
- codeforces 817D Imbalanced Array
- Kafka快速上手
- 函数式编程(20160812).md
- 深入理解DIP、IoC、DI以及IoC容器