×

stm8l152--------lcd使用

zxjy辉 zxjy辉 发表于2022-09-22 17:22:52 浏览710 评论1

1人参与发表评论

挪威纳柔依峡湾风景.jpeg

利用stm8l152自带的lcd驱动,驱动一个14SEG,4个Com的段码屏

这次需要驱动的段码屏是联想体重秤的段码屏,由于这样的屏大多是定制的,所以需要自己在能够驱动在屏幕上显示一个任何的东西,即表示能够被驱动起来(不知道它对应的引脚是不是正确的(和自己想的))


  1. 段码屏

    可以显示汉字和图案,利用电场扭曲实现的,很像数码管。一般来说显示白色的字符的都是正显,也就是要在SEG引脚上施加一个正电,显示黑色字的一般是负显示。这决定了到时候送入寄存器的值是1还是0;

    1. 段码屏和数码管之间的区别

      功耗:段码屏的功耗很低,一般在uA级别,主要是背光消耗,一般是十几mA

      显示:段码屏是通过电场来实现液晶分子的扭曲,配合偏光片来实现显示作用,数码屏是通过灯珠来实现每一笔段的显示

  2. 段码屏的占空比duty

    单位时间内扫描一次端口的所占用的时间,或者或是选通一个COM口,例如有4个COM,那么一个COM对应的就是1/4,也就是对应的占空比duty=1/4;

  3. 段码屏的偏压比bias

    是LCD模拟电压输出的最小值和最大值的比值,以偏压比=1/3为例子,电压为3v的时候,最小的lcd电压是1v,也就意味着,当屏幕亮起来的时候(SEG=1),对应的电压是3v,灭掉的时候1V,保证了对比度的均匀,如果想提高对比度,那么就要将偏压比提高。

  4. 段码屏的占空比duty和偏压比bias一般的关系

    图片.png

  5. 驱动段码屏

    这个驱动和数码管在形式上也是一样的,段码屏有公共端COM和对应的段引脚SEG,但是,不能用直流电直接驱动段码屏,这样会导致段码屏的损毁,需要采用的是交流的信号,例如方波;对于正显的段码屏来说,如果说要显示SEG1上对应的字符,那么就要将SEG1=1;COM=0,对应的电压是3V和1V(此时的偏压比为1/3),在间隔一定的时间里(死区?),将数据进行翻转,也就是SEG=0,COM=1,对应的电压是1V和3V;也就是保证在一定的周期内SEG和COM的电压的维持一样的值(2V)。

  6. Stml152c6t6驱动段码屏

    这个芯片自带lcd驱动,有4个COM引脚和25个SEG引脚

    图片.png

    这样的话,外围电路就很简单了,不需要加上拉或则是下拉电阻,直接连上对应的引脚,就可以了

    图片.png

  7. 初始化代码

    官方给的库包里自带了一些demo,我们只要修改修改,就可以使用了

    1. ///stm8l152c6t6 LCD 初始化
      void LCD_CLASS_Init(){
           //  LCD_PageSelect(LCD_PageSelection_FirstPage);                     //如果有8个com,还要选页
         //开启所需要的时钟
        CLK_PeripheralClockConfig(CLK_Peripheral_RTC,ENABLE);                      //使能RTC时钟
        CLK_PeripheralClockConfig(CLK_Peripheral_LCD,ENABLE);                      //使能LCD时钟
        //使用内部时钟源
        CLK_RTCClockConfig(CLK_RTCCLKSource_LSI,CLK_RTCCLKDiv_1);                    //内部低速时钟源38kHz,高速时16MHz,1分频,RTC时钟38kHz
        //初始化lcd
        LCD_Init(LCD_Prescaler_1,LCD_Divider_31,LCD_Duty_1_4,LCD_Bias_1_3,LCD_VoltageSource_External);  //lcd预分频1,分频31,总分频32;38k/32=1.1k;1.1khz=1ms
                                                                                                           //1ms/(1/4)(duty)=4ms,也就是250Hz
        
        LCD->CR2 &= (uint8_t)(~LCD_CR2_HD);//PON调节对比度 打开高性能驱动               //有的屏需要打开这个,不然的话:该显示的可能没显示,不改显的却显示                     
        
        
        //标记LCD寄存器 决定什么seg使用:只使用0~13对应的SEG
        /* PM0 :seg 7 6 5 4 3 2 1 0;低位对应 0*/
        LCD_PortMaskConfig(LCD_PortMaskRegister_0,0xFF);
         /* PM1 :seg 15~8*/
        LCD_PortMaskConfig(LCD_PortMaskRegister_1,0x3F);
        LCD_PortMaskConfig(LCD_PortMaskRegister_2, 0x00); 
        LCD_PortMaskConfig(LCD_PortMaskRegister_3, 0x00);
        //设置LCD 对比度最大电压
       // LCD_ContrastConfig(LCD_Contrast_3V0);                          
         LCD_ContrastConfig(LCD_Contrast_Level_4);    
        //设置LCD 死区时间
        LCD_DeadTimeConfig(LCD_DeadTime_0);
        //设置LCD 脉冲持续时间
        LCD_PulseOnDurationConfig(LCD_PulseOnDuration_7);
        //使能LCD 外设
        LCD_Cmd(ENABLE);
        
      }


    2. 完成了这个初始话之后,基本上LCD驱动就可以使用了,之后就是对对应的COM和SEG的寄存器写入数据就可以了

      PM寄存器:(置一)决定什么SEG引脚作为LCD引脚,(置零)作为普通的IO口

      图片.png

      LCD对应RAM地址,往这个地址上写入数据,就可以“点亮”对应的段

      图片.png

      左边一列下来代表地址:地址从0x0C一直到0x19,在代码中,这些地址都是被宏定义了,对应的宏定义是:LCD_RAMRegister_0~LCD_RAMRegister_13

      右边一列下来代表所映射的SEG引脚以及对应的COM口,例如第一行:S0[7:0](COM0),这个就表示往这个地址0x0C上写入8位数据,改变的是公共端是COM0的SEG0~SEG7上的值,此时如果往这个地址写入数据:LCD->RAM[LCD_RAMRegister_0] = 0x01,那么也就是将 SEG0 置一了,其余置零,然后在段码屏上就会“点亮”SEG0的段。

  8. 写数据代码

    这个需要注意的是:段码屏上一个(要显示的数字)的地址往往是不连续的,也就是说:一个8段的数字,可能A在0x0C地址上的某一位,B在0x10上的某一位,这就导致了一个问题,那就是,你所规定的断码顺序和LCD_RAM所映射的地址是不一样的。

    图片.png图片.png

    就类似上两张图,自己规定的是如左图一样的顺序,HGFEDCBA(高位到低位),如果是数码管,那就直接往数据地址上写入一个8位的数据,就可以点亮对应的段,但是在段码屏上,不行,因为对应的SEG引脚是在不同的地址上的(如右图所示),例如图中的RAM_0地址上的8位对应的是4a 4f 3a 3f 2a 2f 1a 1f ,往这个地址写入数据,只能“点亮”这几个段,所以数据要做一个处理,一个拼接

    1. 首先是设定对应的 0 1 2 3 4 5 6 7 8 9 对应的“点亮”时的8位数据

      1. u8 Dmp[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //正显 :0 1 2 3 4 5 6 7 8 9
    2. 需要做的事情就是将对应的“1”提取出来,进行移位操作,移动RAM所对应的位地址,再写入对应的RAM地址

      如果要在右图上的“数码管”3上,显示一个 “0” ,对应的段码是 0x3F ,0011 1111 (HGFEDCBA段码)

      1. 先提取A,那就&0x01:如果A是1,结果是0x01,如果是0,那结果就是0x00,

      2. 接着将这个A移动到RAM地址3a的位置上,图中3a的位置是在RAM_0地址上的位6位置,提取的A的位置是在位0的位置


        RAM_0 :                     4a   4f   3a   3f    2a    2f    1a    1f

        自己规定的段码顺序 :H    G     F     E     D     C     B      A

        那就将提取出来的0x01,进行左移5位,然后再写入到RAM_0地址上,就可以显示3a这个段

      3. 对应的具体代码如下:

        LCD->RAM[LCD_RAMRegister_0] = (((Dmp[num]&0x01)<<5))

      4. 如果要显示多个8位“数码管”,那么要注意的是一些段码是公用一个地址的,如4a 和 3a 就是共用了RAM_0的地址,在显示的时候,要注意将数据进行拼接,否则就会将后一个要写入地址的数据(0x80)(显示4a)将前一个数据(0x20)(显示3a)给覆盖掉,所以要这么写

        LCD->RAM[LCD_RAMRegister_0] = (((Dmp[num3]&0x01)<<5))|(((Dmp[num4]&0x01)<<7));   //这样就不会覆盖

    3. 完整的显示“数码管3”和“数码管4”的代码

      1. void Write_Num( int num3,int num4 ){
            //通过地址定义可以知道,一共有7个地址,其中重复的地址是0(a3 f3)、4(b3 g3)、7(c3 e3),只有11(d3)没有重复
            /
            
            //RAM_0
            //取出数码管a段码对应的位,然后左移1位,这样就变成0010 0000,就和a3所定义的位置对应上了,再与a3相与,看看对应的位是0还是1;&a3,保证只会取出a3对应的值
            LCD->RAM[LCD_RAMRegister_0] = (((Dmp[num3]&0x01)<<5)&a3)|(((Dmp[num3]&0x20)>>1)&f3)|(((Dmp[num4]&0x01)<<7)&a4)|(((Dmp[num4]&0x20)<<1)&f4);  
            //LCD->RAM[LCD_RAMRegister_0] = ;  //取出f段对应的位,然后左移1位,这样就变成0001 0000 ,与f3 对应上
            //RAM_4                       
            LCD->RAM[LCD_RAMRegister_4] = ((Dmp[num3]&0x02)&b3)|(((Dmp[num3]&0x40)>>6)&g3)|(((Dmp[num4]&0x02)<<2)&b4)|(((Dmp[num4]&0x40)>>4)&g4);
            //LCD->RAM[LCD_RAMRegister_4] = b3|g3;
            //LCD->RAM[LCD_RAMRegister_4] = ((Dmp[num]&0x40)>>6)&g3;
            //RAM_7                       
            LCD->RAM[LCD_RAMRegister_7] = (((Dmp[num3]&0x04)<<3)&c3)|((Dmp[num3]&0x10)&e3)|(((Dmp[num4]&0x04)<<5)&c4)|(((Dmp[num4]&0x10)<<2)&e4);
            //LCD->RAM[LCD_RAMRegister_7] = (Dmp[num]&0x10)&e3;
            //RAM_11  由于要保留kg这个单位,加上0x20.对应kg单位
            LCD->RAM[LCD_RAMRegister_11] = ((Dmp[num3]&0x08)>>3)&d3|((Dmp[num4]&0x08)>>1)&d4|(0x20);
        }
      2. //#define a3 0x20   //这个在RAM_0地址上
        //#define b3 0x02   //这个在RAM_4地址上
        //#define c3 0x20   //这个在RAM_7地址上
        //#define d3 0x01   //这个在RAM_10地址上
        //#define e3 0x10   //这个在RAM_7地址上
        //#define f3 0x10   //这个在RAM_0地址上
        //#define g3 0x01   //这个在RAM_4地址上
        //
        ////规定 第4个数码管的段的对应的地址
        //#define a4 0x80   //这个在RAM_0地址上
        //#define b4 0x08   //这个在RAM_4地址上
        //#define c4 0x80   //这个在RAM_7地址上
        //#define d4 0x04   //这个在RAM_10地址上
        //#define e4 0x40   //这个在RAM_7地址上
        //#define f4 0x40   //这个在RAM_0地址上
        //#define g4 0x04   //这个在RAM_4地址上








#好好学习!

群贤毕至

访客
admin admin2025-04-24 11:30:30 · 回复 常用的lcd断码屏驱动芯片:HT1621 三线spi串口驱动