电子DIY小家 发表于 2024-3-8 10:02:28

STC8H4K64TLCD驱动段码LCD屏教程(一)点亮段码LCD屏

STC8H4K64TLCD驱动段码LCD屏教程(一)点亮段码LCD屏STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键
STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键 - 触摸按键/80mA大电流LED数码管自动刷新显示/段码LCD/RTC实时时钟/低功耗 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)




    新版段码屏已到货,本系列文章均以这个板子围绕展开,有需要的可以自己打板测试,或者通过这个链接购买成品跟着测试:https://item.taobao.com/item.htm ... 97.7.40763d46EWIlaN

一、原理分析
   首先对于一个程序员来说,拿到一个段码屏要先看他的段码表和点亮效果图(每一个图标里的序号和第二个段码表里的序号对应)



    第一张图能看到他整个的显示内容,第二张图就是他的段码和位码,这里需要重点注意STC的com是四线的,屏也需要是最大是四com的,整体来说其实和数码管的操作原理类似,就是com和seg的一系列操作,但是区别的是数码管只输出高低电平,但是段码的输出不单单是高低电平,这里需要插入下他的原理介绍




    当然上述的这些不需要完全掌握,只需要知道他的意思就是说虽然同是com和seg,但是我们不能像数码管那样直接高低电平去点(虽然能点亮,但是很容易坏),当然,由于单片机内部有LCD的驱动器,我们也不需要自己搭电路去控制了,能省下不少的成本


    这里只需要考虑这里段码屏的com接单片机的com脚,如上图手册描述的一样,段码屏的seg接单片机的seg(可以随意接,不需要考虑顺序什么的,只是要方便写程序就行),由于这个原理图特别大不好截图,原理图请从qq群文件自行下载。
    这里段码屏还一个非常重要的参数,就是电压。这个屏的电压是3.3V,所以注意单片机的供电电压不能小于这个屏幕的驱动电压。



二、手册分析
    首先先对这个内部的LCD的驱动模块进行初始化;开始查阅手册


    1.从首页的介绍可以知道,目前stc能带段码屏的只有这个型号,其次他最大驱动4*40的段码屏,基本上绝大多数场合是完全够用了的。


由此我们可以编写如下代码
LCDCFG2 = 0x0f;                        // SEG0~3切换到P7.7~7.4



    2.功能脚切换,这里我们用的引脚是P7.7~7.4,所以这个寄存器的低4位全都选1




    3.时钟配置,可以看到这里有四种模式选择,第一种内部高速IRC在省电模式会停震导致无法刷新,所以实际做产品的话不建议用这个,但是我们测试的时候可以用!!第二种模式不让用,跳过!第三种模式在省电模式下依然可以使用,且用外部晶振可以省去1.5ua的内部低速时钟的功耗,推荐使用这个(这个模式下一章细讲)!


    4.电压配置,这里单片机VCC是5v,屏的电压是3.3v,所以VLCDSEL可以直接设置为0,即5*0.65 = 3.25V。


由此可以得出,这个寄存器的代码可以这样写
LCDCFG= 0x00 + 0;      // 0x00:选择CPU时钟为LCD时钟, 0x80: 选择外部32K晶振做时钟. VLCD电压选择0~7对应0.65+VLCD*0.05.

    5.这里还有一个比较重要的概念,刷新率,基本上在60hz的时候人眼就已经基本无法看出屏闪了,所以这里刷新率可以给他配置为60hz,这里我们选择手册说的24Mhz的情况下考虑的话,60hz所需要的参数都已经给出了,我们就按这个操作即可,我们就可以编写如下代码
DBLNTH   = 2;                // 设置LCD显示时的死区时间长度, 取值0~7.
      COMLNTHH      = 0x01;                // COM时间长度设置 高字节COMLEN,一共20bit.
      COMLNTHM      = 0x86;                // COM时间长度设置 中字节COMLEN      LCD刷新率 = LCD时钟频率 / ((DBLEN+COMLEN+1) *2 * COM数)
      COMLNTHL      = 0x9d;                // COM时间长度设置 低字节COMLEN      LCD刷新率 = 32768/((2+65+1)*2*4) = 60Hz
      BLINKFRPS = 60;                // 闪烁率配置寄存器, LCD闪烁率 = LCD刷新率 / BLINKRATE Hz



三、代码编写
    1.初始化函数
void      LCD_config(void)
{
      u8      i;
      
      LCDCFG= 0x00 + 0;      // 0x00:选择CPU时钟为LCD时钟, 0x80: 选择外部32K晶振做时钟. VLCD电压选择0~7对应0.65+VLCD*0.05.
      DBLNTH   = 2;                // 设置LCD显示时的死区时间长度, 取值0~7.
      COMLNTHH      = 0x01;                // COM时间长度设置 高字节COMLEN,一共20bit.
      COMLNTHM      = 0x86;                // COM时间长度设置 中字节COMLEN      LCD刷新率 = LCD时钟频率 / ((DBLEN+COMLEN+1) *2 * COM数)
      COMLNTHL      = 0x9d;                // COM时间长度设置 低字节COMLEN      LCD刷新率 = 32768/((2+65+1)*2*4) = 60Hz
      BLINKFRPS = 60;                // 闪烁率配置寄存器, LCD闪烁率 = LCD刷新率 / BLINKRATE Hz
      
      COM_ON_A= 0x0f;                // COM使能寄存器
      SEG_ON_A = 0xff;                // SEG线使能寄存器1, SEG7~SEG0
      SEG_ON_B = 0xff;                // SEG线使能寄存器2, SEG15~SEG8
      SEG_ON_C = 0xff;                // SEG线使能寄存器3, SEG23~SEG16
      SEG_ON_D = 0xff;                // SEG线使能寄存器4, SEG31~SEG24
      SEG_ON_E = 0xff;                // SEG线使能寄存器5, SEG39~SEG32
      
      P5n_pure_input(0x03);      //P5.0 P5.1 设置为高阻输入      COM0 COM1
      P3n_pure_input(0x60);      //P3.5 P3.6 设置为高阻输入      COM2 COM3

      LCDCFG2 = 0x0f;                        // SEG0~3切换到P7.7~7.4
      P7n_pure_input(0xf0);      //P7.7~P7.4 设置为高阻输入      SEG0~SEG3 (对应P7.7~7.4)
      P4n_pure_input(0x80);      //P4.7      设置为高阻输入      SEG4
      P1n_pure_input(0x03);      //P1.1~P1.0 设置为高阻输入      SEG5 SEG6       (对应P1.1 P1.0)
      P0n_pure_input(0xe0);      //P0.7~P0.5 设置为高阻输入      SEG7 SEG8 SEG9(对应P0.7 P0.6 P0.5)
      P5n_pure_input(0x0C);      //P5.3 P5.2 设置为高阻输入      SEG10 SEG11   (对应P5.3 P5.2)
      P0n_pure_input(0x1f);      //P0.4~P0.0 设置为高阻输入      SEG12~SEG16(对应P0.4 ~ 0.0)
      P4n_pure_input(0x60);      //P4.6 P4.5 设置为高阻输入      SEG17 SEG18
      P2n_pure_input(0xff);      //P2.7~P2.0 设置为高阻输入      SEG19~SEG26(对应P2.7~2.0)
      P4n_pure_input(0x1e);      //P4.4~P4.1 设置为高阻输入      SEG27~SEG30(对应P4.4~4.1)
      P3n_pure_input(0x80);      //P3.7      设置为高阻输入      SEG31
      P7n_pure_input(0x0f);      //P7.3~P7.0 设置为高阻输入      SEG32~SEG35(对应P7.3~7.0)
      P6n_pure_input(0x0f);      //P6.0~P6.3 设置为高阻输入      SEG36~SEG39(对应P6.3~6.0)

      for(i=0; i<20; i++)      
                LCD_buff = 0x00;      //清除显示内容
      
      LoadToLcd();      //将显示内容导入显存

      LCDCR = (0<<1) + 1;      // LCD控制寄存器, 0:普通模式, 1:长暗模式, 2:长亮模式, 3:闪烁模式.+0:禁止LCD模块,+1:允许LCD模块.    可以看到最上面的几行是不是就是第二快内容分析的寄存器配置,这里就不在赘述了。
    紧接着就是com和seg的使能了,这里就是写1使能,写0关闭,因为这里4个com和40个seg都用上了,所以这里全都写1了。
    在下面就是将所有使用的com和seg口都设置为高阻输入模式
    在下面一个for语句将LCD_buff的数组清0,后面我们点亮和熄灭屏的操作都是靠这个数组来的
    在下面的LoadToLcd函数是将我们的LCD_buff里的内容全都写入到lcd的数据寄存器里去,即直接显示
    最后开启数码管为常亮显示,这个初始化就结束了。


    下面就到了大家最关心的,我怎么去点亮段码屏的指定的某一段了,首先我们来看下这个段码屏是怎么和单片机连接的:


这里帮大家整理好了一个表格,分为了三块显示,每块的第一行是段码屏的引脚号,第二三四五行使单片机的com对应的显示的图标号,最后一行就是连接的单片机的引脚,因为这个图是按照段码屏的序号排布的不太好看,我给他整理了下,按照单片机的seg号排布,排列玩之后如下:


可以看到这里还是三块,第一块16个seg口就是,从seg0-seg15,可以看到这里最上面多可一行16进制数,最下面一行多了个中文。这个怎么理解呢,以第一个为例,看到“从上到下为 0 5 10 15”这个文字所在的那八列,其中横着的COM0对应的那一行就是对应的LCD_buff数组对应的显示内容,横着的COM1对应的那一行就是对应的LCD_buff数组对应的显示内容,横着的COM2对应的那一行就是对应的LCD_buff数组对应的显示内容,横着的COM3对应的那一行就是对应的LCD_buff数组对应的显示内容,且写1点亮
例1:要想点亮“P2”所在的图标就是LCD_buff |= 0x08;



例2:要想点亮“-2”所在的图标就是LCD_buff |= 0x10;





例3:要想点亮“L1”所在的图标就是LCD_buff |= 0x02;




这样子是不是就能点亮单个的段了!!


    2.再来点亮一个数字"8"
   

    每个数字8的段码和数码管一样,都是A-G,这里对应码表,假设我需要点亮一个1,是不是就是点亮表中的这两个段


换成代码就是这样子
    LCD_buff |= 0x02;

    LCD_buff |= 0x02;

    当然每次点亮都这么写太麻烦了,这里换成函数的写法
void      LCD_load(u8 n, u8 dat)                //n为第几个数字,为1~5,dat为要显示的数字
{
      u8      i,k;

      if((n == 0) || (n >= 15))      
                return;      //合法值 1~5

      dat =t_display;

      switch( n )
      {
                case 1:
                case 2:
                case 3:
                        LCD_buff&= ~(1<<seg_pos);
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
               
                        if(dat & 0x01)                LCD_buff |= (1<<seg_pos);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff |= (2<<seg_pos);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (2<<seg_pos);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (1<<seg_pos);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (1<<seg_pos);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff |= (1<<seg_pos);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff |= (2<<seg_pos);      //T_SEG_DEFG;      //G               
                        break;
               
                case 4:
                        LCD_buff&= ~(1<<7);
                        LCD_buff&= ~(1<<7);
                        LCD_buff &= ~(1<<7);
                        LCD_buff &= ~(1<<7);
//                        LCD_buff&= ~(1<<0);
                        LCD_buff&= ~(1<<0);
                        LCD_buff &= ~(1<<0);
                        LCD_buff &= ~(1<<0);
               
                        if(dat & 0x01)                LCD_buff |= (1<<7);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff |= (1<<0);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (1<<0);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (1<<7);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (1<<7);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff |= (1<<7);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff |= (1<<0);      //T_SEG_DEFG;      //G                              
                        break;
               
                case 5:
                case 6:                        
                        LCD_buff&= ~(1<<seg_pos);
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
               
                        if(dat & 0x01)                LCD_buff |= (1<<seg_pos);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff |= (2<<seg_pos);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (2<<seg_pos);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (1<<seg_pos);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (1<<seg_pos);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff |= (1<<seg_pos);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff |= (2<<seg_pos);      //T_SEG_DEFG;      //G               
                        break;
               
                case 14:                        
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
                        LCD_buff &= ~(2<<seg_pos);
               
                        if(dat & 0x01)                LCD_buff   |= (2<<seg_pos);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff   |= (1<<seg_pos);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (1<<seg_pos);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff   |= (2<<seg_pos);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff   |= (1<<seg_pos);      //T_SEG_DEFG;      //G               
                        break;               
               
                case 13:      
                case 12:
                case 11:
                case 10:                        
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
                        LCD_buff &= ~(2<<seg_pos);
               
                        if(dat & 0x01)                LCD_buff   |= (2<<seg_pos);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff   |= (1<<seg_pos);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (1<<seg_pos);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff   |= (2<<seg_pos);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff   |= (1<<seg_pos);      //T_SEG_DEFG;      //G               
                        break;      
               
                case 9:      
                case 8:
                case 7:      
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff&= ~(3<<seg_pos);
                        LCD_buff &= ~(3<<seg_pos);
                        LCD_buff &= ~(2<<seg_pos);
               
                        if(dat & 0x01)                LCD_buff   |= (2<<seg_pos);      //T_SEG_ABC;                //A
                        if(dat & 0x02)                LCD_buff   |= (1<<seg_pos);      //T_SEG_ABC;                //B
                        if(dat & 0x04)                LCD_buff|= (1<<seg_pos);      //T_SEG_ABC;                //C
                        if(dat & 0x08)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //D
                        if(dat & 0x10)                LCD_buff|= (2<<seg_pos);      //T_SEG_DEFG;      //E
                        if(dat & 0x20)                LCD_buff   |= (2<<seg_pos);      //T_SEG_DEFG;      //F
                        if(dat & 0x40)                LCD_buff   |= (1<<seg_pos);      //T_SEG_DEFG;      //G               
                        break;      
               
                default:
                        break;
               
      }
}入口参数的n表示第几个数字8,dat表示当前要写入的数,写入的数据包含这些:


这个函数主要就是先把指定的第几个8所在的位置的数据先清空,


例如第一个数字8他会先清空这7个位,在判断当前要显示的内容,在分别写入这七个位即可点亮,后面的数码管一次类推。函数写个LCD_load(1,0);      就可以让第一个数字8显示0;


Anijin 发表于 2024-3-8 10:07:02

STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键

STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键 - 触摸按键/80mA大电流LED数码管自动刷新显示/段码LCD/RTC实时时钟/低功耗 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)


不错,受教了,教程很详细。

神农鼎 发表于 2024-3-8 10:19:17

冲哥 威武







电子DIY小家 发表于 2024-3-8 10:27:32

有疑问的可以下面留言,章节预告:

第二章,讲触摸
STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键

STC8H4K64TLCD驱动段码LCD屏教程(二)触摸按键 - 触摸按键/80mA大电流LED数码管自动刷新显示/段码LCD/RTC实时时钟/低功耗 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)

第三章,主要讲【外部32.768K晶振+RTC】,驱动屏


21cnxin 发表于 2024-3-8 10:35:12

{:5_332:}

NTC 发表于 2024-3-10 17:42:57

摆好小板凳等开讲{:smile:}

lzl1okOK 发表于 2024-3-12 00:39:17

以前用89c52驱动过位数少的,当时用的电阻分压做的,现在STC有专用芯片方便多了{:4_174:}

小涵子爸爸 发表于 2024-3-12 01:29:08

讲的真好

wellhope 发表于 2024-3-12 08:09:00

受教了,等下一节课!{:4_250:}

hdxs 发表于 2024-3-12 08:36:34

{:5_332:}
页: [1] 2 3 4
查看完整版本: STC8H4K64TLCD驱动段码LCD屏教程(一)点亮段码LCD屏