dm3730平台oled显示时钟——ssd1306驱动

本文详细介绍了在DM3730平台上使用SSD1306芯片驱动OLED显示屏的方法,并深入解析了初始化命令的具体含义及画图函数的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载请注明出处:http://blog.youkuaiyun.com/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 panel
	ssd1306_write_byte(0x00, SSD1306_CMD);//---set low column address
	ssd1306_write_byte(0x12, SSD1306_CMD);//---set high column address
	ssd1306_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 register
	ssd1306_write_byte(0xff, SSD1306_CMD); // Set SEG Output Current Brightness
	ssd1306_write_byte(0xa1, SSD1306_CMD);//--Set SEG/Column Mapping 	0xa0左右反置 0xa1正常
	ssd1306_write_byte(0xa6, SSD1306_CMD);//--set normal display
	ssd1306_write_byte(0xa8, SSD1306_CMD);//--set multiplex ratio(1 to 64)
	ssd1306_write_byte(0x2f, SSD1306_CMD);//--1/48 duty
	ssd1306_write_byte(0xc8, SSD1306_CMD);//Set COM/Row Scan Direction	0xc0上下反置 0xc8正常
	ssd1306_write_byte(0xd3, SSD1306_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
	ssd1306_write_byte(0x00, SSD1306_CMD);//-not offset
	ssd1306_write_byte(0xd5, SSD1306_CMD);//--set display clock divide ratio/oscillator frequency
	ssd1306_write_byte(0x80, SSD1306_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
	ssd1306_write_byte(0xd9, SSD1306_CMD);//--set pre-charge period
	ssd1306_write_byte(0x21, SSD1306_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	ssd1306_write_byte(0xda, SSD1306_CMD);//--set com pins hardware configuration
	ssd1306_write_byte(0x12, SSD1306_CMD);
	ssd1306_write_byte(0xdb, SSD1306_CMD);//--set vcomh
	ssd1306_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位


那么,页地址又是什么概念呢?可以简单的理解为:一页有8行,128*64的屏有64/8=8页,64*48的屏有48/8=6页。
上文所述,页地址设为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,就可以这样表示:绿框为列起始地址
 二,画图函数
void 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;
	}
	
	if (h < 8) {
		return;
	}

	u8 i0 = y/8, i1 = (y + h - 1)/8;
	u8 i, j, tmp, tmp1;
	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>>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;                                           //高位右移
					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;
				}
			}
		
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值