从点阵到OLED屏幕——动态扫描显示原理

在我们买电脑、手机或者电视时,厂家常常会宣传他们的产品用的是什么屏幕,分辨率达到2K或者4K,色彩有多鲜艳,刷新率有多高。

这些参数到底是什么意思?屏幕到底是如何显示出我们想要的文字、图片以及视频呢?本文将从LED点阵开始,讲解以上参数以及其工作原理。

首先,我们需要了解几个关于屏幕的重要参数:屏幕类型、分辨率、色彩分辨度、刷新率。

屏幕类型:关注过手机参数就知道,早些年的手机屏幕,大都是LCD或者TFT屏,现在的手机屏幕大都采用OLED、AMOLED,电脑还会采用IPS屏(TFT的升级版)。不同的屏幕类型反映的是不同的发光原理。

比如LCD屏幕显示原理就是在两块平行板之间填充液晶材料,通过电压来改变液晶材料内部分子的排列状况,以达到遮光和透光的目的来显示图象,加上滤光层后,就可实现显示彩色图象,总结来说就是遮光,所以LCD屏需要背光才能显示图像。

而OLED则是通过有机半导体材料和发光材料在电场驱动下,通过载流子注入和复合导致发光的,属于自发光类型,所以这种屏幕不需要背光就能显示图像。OLED或者AMOLED手机的息屏显示就是利用了该特性。

其他类型的屏幕基本都是这两种屏幕的分支。这里暂不展开介绍。

分辨率:分辨率反应的是屏幕像素组成。在显微镜下观察手机屏幕,或者凑近观察以前的老电视机屏幕,就会发现,屏幕里面均匀的排布着一个个彩色小点,这些小点就是像素点。

如果是黑白屏幕(例如墨水屏),我们可以把每个像素点看成一个白色小灯。每个像素点只有1或者0两种状态,分别代表着这个像素点是亮还是灭。

如果是彩色屏幕,一个像素点则由红绿蓝(RGB)三个彩色小灯组成。每个小灯又根据发光强度的不同分为很多等级(假设有n种),如此,三个小灯组合在一起,就有n*n*n种色彩了(任何颜色都可以用红绿蓝三种颜色按比例混合而成)。虽然有三个小灯,但它们是“绑”在一起的,互相配合才形成一个像素点。

分辨率反映的就是像素点的排列情况。我们通常所说的1080P、2K、4K分辨率其实是一个简称。比如1080P分辨率的屏幕(现在的中低端手机大都采用这种分辨率的屏幕),其像素排列规范为1920x1080(现在的全面屏手机分辨率一般为2340*1080),也就是整个屏幕共有1920列,1080行,总共2073600个像素点。2K像素排列标准为2048x1080,可以看到2K的像素点是要高于1080P的,所以说2K分辨率比1080P高,4K(UHDTV标准为3840x2160)则要更高。因为像素点越多,屏幕就能显示更多的东西,所以分辨率越高,屏幕画面看起来就越清晰。

色彩分辨度:色彩分辨度针对的是彩屏,黑白屏幕就没有色彩一说了,或者说分辨度为2(只有黑与白两种颜色)。前面讲到,彩色屏幕的一个像素点则由红绿蓝(RGB)三个彩色小灯组成,每个小灯又根据发光强度的不同分为很多状态。色彩分辨度就是取决于每个小灯的发光强弱能分为多少个等级。假设每个颜色的小灯都有256级(2^8)发光强度,三个灯组合就有256*256*256=16777216种颜色。因其色彩数为2^24,所以这种色彩标准就是24位真彩色,从颜色组成比例来看也称RGB888。这种色彩分辨度属于高标准的,大部分手机屏幕都达不到该标准,普通的手机屏幕大概只有1600万色,不过也能满足需求,只有在对色彩要求特别高(比如图像处理)才会用到24位真彩色屏幕。

除了24位真彩色,还有一种稍低的色彩分辨度标准:16位真彩。这种也是红绿蓝三色组成一个像素点,但是不像24位每个颜色的都有256级,红绿蓝三色的颜色分级分别为32(2^5)、64(2^6)、32(2^5),这种比例标准称为RGB565。其色彩只有65535种(2^16)。

所以,要想能显示24位真彩屏的所有颜色,一个像素点就需要24bit,即3Byte的数据,而16位真彩只需要16bit,即2Byte的数据。

刷新率:刷新率即刷新屏幕的速率,其单位为帧或者Hz。屏幕显示本来是一帧一帧静态的画面,将它们连续刷新就得到了动态画面,在1秒钟内,屏幕刷新了几次静态的画面就表示其刷新率为多少。普通的手机电脑屏幕刷新率一般只有60帧,稍微好点的手机屏幕已经适配90帧,甚至更高的120帧。电竞屏已经可以达到144Hz、240Hz了。刷新率高最直观的感受就是画面更流畅了。

接下来,将详细讲解屏幕的刷新原理(动态扫描)

在我前面的文章中有讲到过数码管的动态扫描,其实原理相同。只是屏幕稍复杂些。

我们先从8*8的LED点阵显示ASCII码字符讲起(要能清晰显示所有ASCII字符所需的最小像素为8*6),下面就是我们单片机学习时会见到的LED点阵。

这种点阵在生活中也是很常见的,像银行、酒店门口的滚动显示的广告牌就是这种小点阵拼接而成的。

 通过点亮特定位置的LED,就得到了我们想要显示的字符图案。

8x8LED点阵其实就是一块最简单的屏幕的。其参数为:分辨率8x8,色彩分辨度2,刷新率取决于驱动程序,它的每个像素点就是一个小LED灯。

每个LED灯有两个引脚,这里假设采用共阴接法,将所有LED的阴极接在一起并接地,如果想要能单独点亮所有LED灯,用最简单的实现方法是给每个LED的阳极都用一个端口来控制,只要对应的端口给阳极加电压,就能点亮LED灯了。那这个LED点阵就需要8x8=64个引脚才能单独控制所有LED。

如果用单片机来控制,单片机的IO口很可能不够用。如果点阵再大些,比如10*10的,那就需要100个了,根本就无法实现了,更别说分辨率更高的屏幕了。

这时候就需要用到动态扫描了。

何为动态扫描?那是不是也有静态的?

上面说到的显示方式有个特点,假如我要显示的字符或者图案是不变的,那我的控制端口的状态也是不变的,或者说是静态的,这种显示方式就是静态显示。刚才已经计算过,随着像素的增加,需要的IO口也增加,显然无法满足高分辨率屏幕的刷新。

所以不得以使用动态扫描,我们先来了解动态扫描的实现原理。

下图是实现动态扫描的接线图。

 同一行的LED共阳极并引出到左边,共8个引脚;同一列的LED共阴极并引出到上面,共8个引脚。总共16个引脚,可以看到,64个LED采用动态扫描后只要16个端口就能控制。

那到底是如何控制的呢?

这里我们使用STM32单片机控制该点阵,PA1-PA8按顺序连着第1行-第8行引出的线,PB1-PB8按顺序连着第一列-第8列引出线。

动态扫描分为行扫描与列扫描,这里以列扫描为例。列扫描即从左往右或者从右往左扫描(习惯左到右)。

假设我们要显示ASCII中的  "H",那么应该点亮的LED应当如下图所示。

按照列扫描的逻辑,即把上面的字样按列分为8部分,每部分正好是每列要扫描的图案。

从LED点亮的条件来看,扫描哪一列,对应的PB口就要置低电平,其他PB口置高电平。PA口则按照该列的图案将需要点亮的LED灯阳极置高电平,不需要点亮的置低电平。

如果将需要点亮的LED用1表示,不需要点亮的用0表示,这样就得到了“H”字符编码:

0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,        // H

(C语言中无法直接定义Bool型变量,所以将每一列的8个LED作为一个Byte,上面为低位,下面为高位,例如第2列,从上到下二进制表示为1111 1110,转换成十六机制即0x7F)

现在我们进行字符“H”动态扫描慢动作分解:

1.扫描第1列

PB:PB1置0,其他置1(0xFE)

PA:第一列没有LED需要点亮,所以全部置0(0x00)

短暂延时(1ms)

 2.扫描第2列

PB:PB2置0,其他置1(0xFD)

PA:第2列中PA1-PA7需要点亮,所以PA1-PA7置1,PA8置0(0x7F)

 短暂延时(1ms)

3.扫描第3列

PB:PB3置0,其他置1(0xFB)

PA:第3列中只有PA4需要点亮,所以PA4置1,其他置0(0x08)

 短暂延时(1ms)

4. 扫描第4列

PB:PB4置0,其他置1(0xF7)

PA:第4列中只有PA4需要点亮,所以PA4置1,其他置0(0x08)

 短暂延时(1ms) 

5.扫描第5列

PB:PB5置0,其他置1(0xEF)

PA:第5列中只有PA4需要点亮,所以PA4置1,其他置0(0x08)

 短暂延时(1ms)

6. 扫描第6列

PB:PB6置0,其他置1(0xDF)

PA:第6列中PA1-PA7需要点亮,所以PA1-PA7置1,PA8置0(0x7F)

 短暂延时(1ms) 

(由于显示ASCII字符只要6列就足够,所有后面两列就可以不用扫描了)

第6列扫描完成之后,经过1ms延时后立马又回到第一列扫描。并一直循环上述过程。

由于扫描速度很快,利用人眼的视觉暂留效应,最终得到的效果是六张扫描图的叠加即“H”的字样。关于视觉暂留效应可看我关于数码管的文章,里面有详细介绍。

在显示“H”的字符过程中,16个端口的高低电平都发生了变化,所以我们称该显示方式为动态扫描。

如果要显示其他字符,则按照字模取出对应的编码即可。

这里我将所有ASCII字符进行编码并放在一个127*6的数组中,如下:

unsigned char Dictionary_ASCII8x6[127][6]=
{
	0,0,0,0,0,0,//0	
	0,0,0,0,0,0,//1	
	0,0,0,0,0,0,//2	
	0,0,0,0,0,0,//3	
	0,0,0,0,0,0,//4	
	0,0,0,0,0,0,//5	
	0,0,0,0,0,0,//6	
	0,0,0,0,0,0,//7	
	0,0,0,0,0,0,//8	
	0,0,0,0,0,0,//9	
	0,0,0,0,0,0,//10	
	0,0,0,0,0,0,//11	
	0,0,0,0,0,0,//12	
	0,0,0,0,0,0,//13	
	0,0,0,0,0,0,//14	
	0,0,0,0,0,0,//15	
	0,0,0,0,0,0,//16	
	0,0,0,0,0,0,//17	
	0,0,0,0,0,0,//18	
	0,0,0,0,0,0,//19	
	0,0,0,0,0,0,//20	
	0,0,0,0,0,0,//21	
	0,0,0,0,0,0,//22	
	0,0,0,0,0,0,//23	
	0,0,0,0,0,0,//24	
	0,0,0,0,0,0,//25	
	0,0,0,0,0,0,//26	
	0,0,0,0,0,0,//27	
	0,0,0,0,0,0,//28	
    0,0,0,0,0,0,//29	
	0,0,0,0,0,0,//30	
	0,0,0,0,0,0,//31   //0-31为回车、换行等特殊功能

	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//32	空格
	0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,//33 !	
	0x00, 0x00, 0x07, 0x00, 0x07, 0x00,//34 "	
	0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,//35 #	
	0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,//36 $	
	0x00, 0x23, 0x13, 0x08, 0x64, 0x62,//37 %	
	0x00, 0x36, 0x49, 0x55, 0x22, 0x50,//38 &	
	0x00, 0x00, 0x05, 0x03, 0x00, 0x00,//39 '	
	0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,//40 (	
	0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,//41 )	
	0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,//42 *	
	0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,//43 +	
	0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,//44 ,	
	0x00, 0x08, 0x08, 0x08, 0x08, 0x08,//45 -	
	0x00, 0x00, 0x60, 0x60, 0x00, 0x00,//46 .	
	0x00, 0x20, 0x10, 0x08, 0x04, 0x02,//47 /	
	0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,//48 0
	0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,//49 1	
	0x00, 0x42, 0x61, 0x51, 0x49, 0x46,//50 2	
	0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,//51 3	
	0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,//52 4	
	0x00, 0x27, 0x45, 0x45, 0x45, 0x39,//53 5	
	0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,//54 6	
	0x00, 0x01, 0x71, 0x09, 0x05, 0x03,//55 7	
	0x00, 0x36, 0x49, 0x49, 0x49, 0x36,//56 8	
	0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,//57 9	
	0x00, 0x00, 0x36, 0x36, 0x00, 0x00,//58 :	
	0x00, 0x00, 0x56, 0x36, 0x00, 0x00,//59 ;	
	0x00, 0x08, 0x14, 0x22, 0x41, 0x00,//60 <	
	0x00, 0x14, 0x14, 0x14, 0x14, 0x14,//61 =	
	0x00, 0x00, 0x41, 0x22, 0x14, 0x08,//62 >	
	0x00, 0x02, 0x01, 0x51, 0x09, 0x06,//63 ?	
	0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,//64 @	
	0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,//65 A	
	0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,//66 B	
	0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,//67 C	
	0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,//68 D	
	0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,//69 E	
	0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,//70 F	
	0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,//71 G	
	0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,//72 H	
	0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,//73 I	
	0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,//74 J	
	0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,//75 K	
	0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,//76 L	
	0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,//77 M	
	0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,//78 N	
	0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,//79 O	
	0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,//80 P	
	0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,//81 Q	
	0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,//82 R	
	0x00, 0x46, 0x49, 0x49, 0x49, 0x31,//83 S	
	0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,//84 T	
	0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,//85 U	
	0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,//86 V	
	0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,//87 W	
	0x00, 0x63, 0x14, 0x08, 0x14, 0x63,//88 X	
	0x00, 0x07, 0x08, 0x70, 0x08, 0x07,//89 Y	
	0x00, 0x61, 0x51, 0x49, 0x45, 0x43,//90 Z	
	0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,//91 [	
	0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,/*92 \	*/
	0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,//93 ]	
	0x00, 0x04, 0x02, 0x01, 0x02, 0x04,//94 ^	
	0x00, 0x40, 0x40, 0x40, 0x40, 0x40,//95 _	
	0x00, 0x00, 0x01, 0x02, 0x04, 0x00,//96 '	
	0x00, 0x20, 0x54, 0x54, 0x54, 0x78,//97 a	
	0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,//98 b	
	0x00, 0x38, 0x44, 0x44, 0x44, 0x20,//99 c	
	0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,//100 d	
	0x00, 0x38, 0x54, 0x54, 0x54, 0x18,//101 e	
	0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,//102 f	
	0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,//103 g	
	0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,//104 h	
	0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,//105 i	
	0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,//106 j	
	0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,//107 k	
	0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,//108 l	
	0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,//109 m	
	0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,//110 n	
	0x00, 0x38, 0x44, 0x44, 0x44, 0x38,//111 o	
	0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,//112 p	
	0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,//113 q	
	0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,//114 r	
	0x00, 0x48, 0x54, 0x54, 0x54, 0x20,//115 s	
	0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,//116 t	
	0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,//117 u	
	0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,//118 v	
	0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,//119 w	
	0x00, 0x44, 0x28, 0x10, 0x28, 0x44,//120 x	
	0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,//121 y	
	0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,//122 z	
	0x00,	0x08,	0x77,	0x41,	0x00,	0x00,//123	{
	0x00,	0x08,	0x7F,	0x00,	0x00,	0x00,//124	|
	0x00,	0x41,	0x77,	0x08,	0x00,	0x00,//125	}
	0x00,	0x08,	0x04,	0x08,	0x10,	0x08 //126	~
};

这样我们就可以显示任意ASCII的字符了。

这里我封装了一个简单的Printf_ASCII()函数,调用该函数就能显示括号中的字符(注意字符要加英文双引号)

void Printf_ASCII(char Indexes)        //输出ASCII字符函数
{
	int X_axis[8]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};	
	int x;
	while(1)
    {
        for(x=0;x<6;x++)        //循环按列扫描
	    {
	    	GPIO_Write(GPIOB, X_axis[x]<<1);			//左移一位
		    GPIO_Write(GPIOA, Dictionary_ASCII8x6[Indexes][x]<<1);	// 在ASCII字符数组中寻码
		    Delay_ms(1);
		    GPIO_Write(GPIOA, 0);		//清码,防止串码
	    }
    }   
}

上面的列和行都有个左移一位的处理,是因为PA与PB都是从PA0、PB0开始的,而我是从PA1、PB1开始接线。GPIO_Write函数是对PA0-PA15、PB0-PB15这16位bit进行操作的,所以左移一位后刚好对齐PA1-PA8。如果是接的PA0-PA7,PB0-PB7,则不需要左移一位。

了解的点阵的扫描原理,OLED或者其他屏幕都是基于此,可以看成多个8*8点阵拼接而成,只是他们扫描的列与行更多而已。

下文我将以SSD1603驱动的0.96寸OLED屏幕为例讲解OLED的使用。

猜你喜欢

转载自blog.csdn.net/qq_55203246/article/details/124155818