0.96寸OLED(SSD1306)屏幕显示(二)——超长文字水平滚动

0.96寸OLED(SSD1306)屏幕显示

(一)基础功能介绍

(二)超长文字水平滚动

(三)屏幕垂直水平滚动

最近,我突发奇想去翻阅了一些我本科期间所做的一些小项目,发现都挺有意思的!当年做这些项目的时候可走了很多弯路,所以想着可以将它们上传到网络上,并通过我的讲解文章可以帮助你们少走一些弯路!

今天,我要分享的是一个0.96寸OLED(SSD1306)屏幕显示的学习笔记,因为我想要讲的详细一点,所以打算做成一个系列,手把手地教你学习和认识屏幕显示。由于我知识有限,如果出现一些错误,希望大家可以帮助我指出来,我们一起学习进步!!!


一、内置水平滚动方法

我们通过查询SSD1306的用户手册得知,芯片内部提供了水平滚动的方法,如下图所示:

图 1 水平滚动命令表
图 2 官方手册水平滚动例子

 官方手册里给出的命令表清晰明了,并不难理解,下面我会给出详细代码,但在此之前我想要强调两点:

1)一定要在滚动前关闭滚动;

2)需要在发送命令D[2:0]后,发送两个Dummy byte;

// 每个滚动步骤之间的时间间隔,以帧为单位,越大越慢
typedef enum
{ 
	FRAME_2 = 0x07,
	FRAME_3 = 0x04, 
	FRAME_4 = 0x05,
	FRAME_5 = 0x06,
	FRAME_6 = 0x00, 
	FRAME_32 = 0x01,	
	FRAME_64 = 0x02,
	FRAME_128 = 0x03, 	
}Roll_Frame;

/**
  * @brief  OLED_Inside_Hor_Sroll,内部设置水平滚动
  * @param  start_page,end_page :起始滚动页与终止滚动页(start_page:0~7, end_page:0~7);
  *			frame : 每个滚动步骤之间的时间间隔,以帧为单位,越大越慢(FRAME_2 ~ FRAME_128)
  *			dir : 1 向右水平滚动,0 向左水平滚动
  * @retval 无
  */
void OLED_Inside_Hor_Sroll(uint8_t start_page,uint8_t end_page,Roll_Frame frame,uint8_t dir)
{
	// 先必须关闭滚动
	OLED_Write_Cmd(0x2E);
	
	// 1是向右水平滚动,0是向左水平滚动
	OLED_Write_Cmd(dir ? 0x26 : 0x27);
	
	// 发送一个虚拟字节
	OLED_Write_Cmd(0x00);        

	OLED_Write_Cmd(start_page & 0x07);      //起始页 0
	OLED_Write_Cmd(frame & 0x07);           //滚动时间间隔
	OLED_Write_Cmd(end_page & 0x07);        //终止页 7
	
	// 发送两个虚拟字节
	OLED_Write_Cmd(0x00);
	OLED_Write_Cmd(0xFF);
	
	//开启滚动
	OLED_Write_Cmd(0x2F);
}


二、自定义水平滚动方法

通过上个文章,我们知道0.96寸OLED屏幕内部是靠SSD1306驱动芯片驱动,而GDDRAM大小为 128x64 位,一列最多显示8个16x16像素点的汉字,除了缩小字体的办法外,并不能在一行内显示更多的中文字符串。

而在内置水平滚动方法,从上节可以看到,只能使得8个字符串在有限的空间重复滚动,不能在一列滚动超过8个字符串;于是我便想到自己编写函数来实现,最终在我的努力下将这个功能呈现了出来,大家可以先看看效果如何!!!

图 3 长文字水平滚动(模式1)
图 4 长文字水平滚动(模式2)

严格来说,通过我写的长文字水平滚动方法,可以实现任意长度的文字显示,只需要更改程序中宏定义 LONG_CN_LEN 的值,以下是详细的代码:

// 宏定义最多显示的中文字符串长度(可以直接更改以显示更多字符串)
#define     LONG_CN_LEN          20


/***************************点阵字体取模方式:共阴——列行式——逆向输出*********/

const typFNT_GB16 cfont16[] = 
{
	"  ",0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/
	"我",0x20,0x24,0x24,0x24,0xFE,0x23,0x22,0x20,0x20,0xFF,0x20,0x22,0x2C,0xA0,0x20,0x00,0x00,0x08,0x48,0x84,0x7F,0x02,0x41,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00,/*"我",0*/
	"是",0x00,0x00,0x00,0x7F,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x7F,0x00,0x00,0x00,0x00,0x81,0x41,0x21,0x1D,0x21,0x41,0x81,0xFF,0x89,0x89,0x89,0x89,0x89,0x81,0x81,0x00,/*"是",1*/
	"羌",0x00,0x08,0x48,0x48,0x49,0x4E,0xC8,0x78,0x48,0x4C,0x4B,0x48,0x48,0x08,0x00,0x00,0x82,0x82,0x42,0x22,0x12,0x0E,0x03,0x02,0x7E,0x82,0x82,0x82,0x82,0x82,0xE2,0x00,/*"羌",3*/
	"族",0x10,0x10,0xF1,0x96,0x90,0x90,0x10,0x08,0xF7,0x44,0xC4,0x44,0x44,0x44,0x04,0x00,0x80,0x60,0x1F,0x40,0x80,0x7F,0x04,0x85,0x44,0x34,0x0F,0x34,0x44,0x84,0x84,0x00,/*"族",4*/
	"小",0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00,0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00,/*"小",5*/
	"煞",0x10,0x28,0x27,0x24,0x34,0x2C,0xE0,0x20,0x10,0x6C,0x8B,0x08,0x88,0x78,0x08,0x00,0x88,0x69,0x09,0x09,0x29,0xC9,0x0F,0x00,0x30,0xC8,0x05,0x02,0x25,0xC8,0x10,0x00,/*"煞",6*/
};


// 测定字符串长度
int my_strlen(uint8_t* str)
{
    int count = 0; //计数
    while(*str != '\0')
    {
        count++;
        str++;
    }
    return count;
}
 

/**
  * @brief  OLED_Show_LongRoll_CN显示长中文字符串并向左滚动(16x16字符串0.96寸最多显示8个)
  * @param  x : 中文字符串显示的起始位置x(0-20*16)
            y : 中文字符串显示的起始位置y(0-7)
            *str : 中文字符串的指针
            mode : 1 - 水平滚动模式1(滚动一圈后原位置开始继续滚动)
			       2 - 水平滚动模式2(滚动一圈后屏幕末尾位置开始继续滚动)
  * @retval 无
  */
void OLED_Show_LongRoll_CN(uint16_t x,uint8_t y,uint8_t *str,uint8_t mode)
{
	uint16_t CN_Last_Pixel = (my_strlen(str)/2)*16;
	/* 将数据直接放入长数组内(最大长度依据LONG_CN_LEN的值,默认为20) */
	// 字符串宽度是16
	uint8_t hsize=16;
	// 移动的像素点
	uint16_t move_pixel = 0;
	// 模式2的标志位
	uint8_t mode2_flag = 0;
	
	// 对长数组进行赋值
	y = y*8;
	while(*str!='\0')
	{
		if(hsize == 16)
		{
			GUI_ShowFont16(x,y,str,2);
		}
		else
		{
			return;
		}
		x+=hsize;
		str+=2;
	}

	// 死循环进行向左移动阅读
	while(1)
	{
		for(uint8_t i=0;i<8;i++)
		{
			// 起始点开始全部刷新
			OLED_Write_Cmd(0xb0+i);  //设置页地址(0~7)
			OLED_Write_Cmd(0x00);    //设置显示位置—列低地址
			OLED_Write_Cmd(0x10);    //设置显示位置—列高地址   
			for(uint16_t n=move_pixel;n<128 + move_pixel;n++)  //写一PAGE的GDDRAM数据
			{
				if(mode == 1 || mode2_flag == 0)
				{
					// 设置起始点坐标
					OLED_Write_Data(OLED_LONG_GRAM[n][i]);
				}
				else if(mode == 2)
				{
					if(n<128)
					{
						OLED_Write_Data(0x00);
					}
					else
					{
						// 设置起始点坐标
						OLED_Write_Data(OLED_LONG_GRAM[n-128][i]);
					}	
				}
			}
		}
		// 每次移动的像素点为1
		move_pixel++;
		// 这里变小可以更改移动速度
		SysTick_Delay_ms(30);
		
		// 字符串长度走完正好留一段空白(8个字符)
		if(move_pixel > CN_Last_Pixel)
		{
			move_pixel = 0;
			if(mode == 2)
			{
				mode2_flag = 1;
			}
		}
		
		// 模式2分为两个阶段才能重复显示,因此需要一个标志位
		if(mode2_flag == 1 && move_pixel > 128)
		{
			move_pixel = 0;
			mode2_flag = 0;
		}	
	}
}


总结

本系列所用单片机型号为STM32F103VE,后续我会把本节所涉及的工程及相关资料放在评论区,大家自取!请大家多多点赞、多多收藏、感谢支持!!!我会继续输出优质内容的!!!加油!加油!🌸🌸🌸

  • 29
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值