
利用stm8l152自带的lcd驱动,驱动一个14SEG,4个Com的段码屏
这次需要驱动的段码屏是联想体重秤的段码屏,由于这样的屏大多是定制的,所以需要自己在能够驱动在屏幕上显示一个任何的东西,即表示能够被驱动起来(不知道它对应的引脚是不是正确的(和自己想的))
- 段码屏- 可以显示汉字和图案,利用电场扭曲实现的,很像数码管。一般来说显示白色的字符的都是正显,也就是要在SEG引脚上施加一个正电,显示黑色字的一般是负显示。这决定了到时候送入寄存器的值是1还是0; 
- 段码屏和数码管之间的区别 - 功耗:段码屏的功耗很低,一般在uA级别,主要是背光消耗,一般是十几mA - 显示:段码屏是通过电场来实现液晶分子的扭曲,配合偏光片来实现显示作用,数码屏是通过灯珠来实现每一笔段的显示 
- 段码屏的占空比duty- 单位时间内扫描一次端口的所占用的时间,或者或是选通一个COM口,例如有4个COM,那么一个COM对应的就是1/4,也就是对应的占空比duty=1/4; 
- 段码屏的偏压比bias- 是LCD模拟电压输出的最小值和最大值的比值,以偏压比=1/3为例子,电压为3v的时候,最小的lcd电压是1v,也就意味着,当屏幕亮起来的时候(SEG=1),对应的电压是3v,灭掉的时候1V,保证了对比度的均匀,如果想提高对比度,那么就要将偏压比提高。 
- 段码屏的占空比duty和偏压比bias一般的关系 
- 驱动段码屏- 这个驱动和数码管在形式上也是一样的,段码屏有公共端COM和对应的段引脚SEG,但是,不能用直流电直接驱动段码屏,这样会导致段码屏的损毁,需要采用的是交流的信号,例如方波;对于正显的段码屏来说,如果说要显示SEG1上对应的字符,那么就要将SEG1=1;COM=0,对应的电压是3V和1V(此时的偏压比为1/3),在间隔一定的时间里(死区?),将数据进行翻转,也就是SEG=0,COM=1,对应的电压是1V和3V;也就是保证在一定的周期内SEG和COM的电压的维持一样的值(2V)。 
- Stml152c6t6驱动段码屏- 这个芯片自带lcd驱动,有4个COM引脚和25个SEG引脚  - 这样的话,外围电路就很简单了,不需要加上拉或则是下拉电阻,直接连上对应的引脚,就可以了  
- 初始化代码- 官方给的库包里自带了一些demo,我们只要修改修改,就可以使用了 
- ///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); }
- 完成了这个初始话之后,基本上LCD驱动就可以使用了,之后就是对对应的COM和SEG的寄存器写入数据就可以了 - PM寄存器:(置一)决定什么SEG引脚作为LCD引脚,(置零)作为普通的IO口  - LCD对应RAM地址,往这个地址上写入数据,就可以“点亮”对应的段  - 左边一列下来代表地址:地址从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段的数字,可能A在0x0C地址上的某一位,B在0x10上的某一位,这就导致了一个问题,那就是,你所规定的断码顺序和LCD_RAM所映射的地址是不一样的。   - 就类似上两张图,自己规定的是如左图一样的顺序,HGFEDCBA(高位到低位),如果是数码管,那就直接往数据地址上写入一个8位的数据,就可以点亮对应的段,但是在段码屏上,不行,因为对应的SEG引脚是在不同的地址上的(如右图所示),例如图中的RAM_0地址上的8位对应的是4a 4f 3a 3f 2a 2f 1a 1f ,往这个地址写入数据,只能“点亮”这几个段,所以数据要做一个处理,一个拼接 
- 首先是设定对应的 0 1 2 3 4 5 6 7 8 9 对应的“点亮”时的8位数据 
- u8 Dmp[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //正显 :0 1 2 3 4 5 6 7 8 9
- 需要做的事情就是将对应的“1”提取出来,进行移位操作,移动RAM所对应的位地址,再写入对应的RAM地址 - 如果要在右图上的“数码管”3上,显示一个 “0” ,对应的段码是 0x3F ,0011 1111 (HGFEDCBA段码) 
- 先提取A,那就&0x01:如果A是1,结果是0x01,如果是0,那结果就是0x00, 
- 接着将这个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这个段 
- 对应的具体代码如下: - LCD->RAM[LCD_RAMRegister_0] = (((Dmp[num]&0x01)<<5)) 
- 如果要显示多个8位“数码管”,那么要注意的是一些段码是公用一个地址的,如4a 和 3a 就是共用了RAM_0的地址,在显示的时候,要注意将数据进行拼接,否则就会将后一个要写入地址的数据(0x80)(显示4a)将前一个数据(0x20)(显示3a)给覆盖掉,所以要这么写 - LCD->RAM[LCD_RAMRegister_0] = (((Dmp[num3]&0x01)<<5))|(((Dmp[num4]&0x01)<<7)); //这样就不会覆盖 
- 完整的显示“数码管3”和“数码管4”的代码 
- 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); }
- //#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地址上 
 
        