深圳市展讯达科技有限公司 
SHENZHEN CANSEED TECHNOLOGY CO.,LTD.
怎样用单片机IO口直接驱动段码LCD液晶屏
2019-01-01

用IO口驱动段式LED(数码管)的方法相信大家比较清楚,但用IO口直接驱动段式LCD的方法相对复杂一些。在网上搜了一下单片机IO口驱动段式LCD的方法,大部分资料讲得不够清晰、具体,而且简单问题复杂化。现在根据LCD的显示原理,结合网上的相关资料,简单介绍一下怎样用单片机方式来驱动段码LCD液晶显示屏:


1、 LCD和LED的显示原理不一样:LED是加正向电压发光,而LCD必须交替加正、反向电压才会持续显示(可以做个实验,如果把恒定电压加到LCD的一段上,该段会显示一下,但马上不能显示,而且长时间加恒定电压,会加速LCD的老化和损坏)


2、常听说1/2bias,1/3bias LCD,是什么意思呢?对于1/2bias LCD,假如LCD的显示电压是3V,则1/2bias是1.5V,也就是说在±3V电压作用时,LCD有显示;±1.5V及以下的电压作用时没有显示


3、普通单片机IO口不能直接输出半高电平(1.5V),但可以用相等的上下拉电阻实现,当IO口设置为输入(高阻)时,由于上下拉电阻的分压作用,则产生一个半高电平(1.5V)


知道了以上3点后,动态驱动LCD就不是难事了,对于4*8段的LCD(4个COM,8个SEG,显示电压为3V,1/2bias),驱动方法如下:


1、  四个COM采用交替扫描的方式,每个COM在相邻两次扫描时又进行电压交变的方式。


2、  若扫描到某一个COM时,该COM输出3V(0V):


与该COM相连的SEG输出与COM相反,ΔV=±3V,则该相连点亮;

与该COM相连的SEG输出与COM相同,ΔV=0,则该相连点不亮。


3、其他没有扫描到的COM,单片机IO口为输入,从而产生1/2 bias(1.5V),不管SEG为何值,ΔV<±1.5V,故该点不亮。


例如用4*8段的LCD自制一个数字钟表,验证以上方法的可行性,现把制作过程罗列如下:


1、原理图


怎样用单片机IO口直接驱动段码LCD液晶屏

说明:由于管脚不够用,所以时钟芯片DS1302的RST和LCD的一个SEG是复用的,只要在这个SEG无效的时候去读取时间就可以了,另外,3PIN串口是ISP下载程序用的。


2、备料


怎样用单片机IO口直接驱动段码LCD液晶屏


3、 焊接


怎样用单片机IO口直接驱动段码LCD液晶屏


4、实验结果



怎样用单片机IO口直接驱动段码LCD液晶屏


5、不足之处


通过实验结果可以发现,不显示的SEG也有阴影


原因分析:纽扣电池电压3.7V,1/2bias是1.85V,大于1.5V,所以会出现阴影。


解决办法:选择工作电压小于3V的单片机和电压等于3V的电池(如2节干电池)




6、程序源代码 




/******************************************************************


段式LCD驱动实验             


外部晶体:12MHz                    


#include


#include




//管脚定义


sbit COM0=P3^5;


sbit COM1=P3^4;


sbit COM2=P3^3;


sbit COM3=P3^2;


sbit BI_4=P3^7;


sbit RTC_CLK=P3^0;


sbit RTC_IO=P3^1;


sbit RTC_RST=P3^7;   //复用




//P3口模式寄存器


sfr P3M1=0xb1;


sfr P3M0=0xb2;




//当前时间(BCD码):秒、分、时、日、月、星期、年


unsigned char ClockBuffer[8]={0x34,0x12,0x08,0x20,0x03,0x05,0x09};




//0~9的段码查询表


//位序 D7 D6 D5 D4 D3 D2 D1 D0


//段   A  B  C  D  E  F  G  DOT 


code unsigned char seg_code[10]={~0x03,~0x9f,~0x25,~0x0d,~0x99,~0x49,~0x41,~0x1f,~0x01,~0x09};




unsigned char ScanCoun=0;                  //动态扫描显示位数计数器


unsigned char DisplayBuf[4]={1,2,3,4};               //4位数字对应的显示暂存




//段码缓冲区


unsigned char SegBuf[4]={0x00,0x00,0x00,0x00};//COM1、COM2、COM3、COM4的段码


bit bi_4a=0; //COM0对应的4a


bit bi_4b=0; //COM1对应的4a


bit bi_4c=0; //COM2对应的4a




//延时


void dly(unsigned char x)


   {unsigned char i;


    for (i=0; i


    }




//ds1302写1字节


void rtc_wt_byte(unsigned char sent_buf)


         {unsigned char i;


          for (i=0; i<8; i++)


              {RTC_CLK=0;


               if (sent_buf&0x01) RTC_IO=1;


               else RTC_IO=0;


               RTC_CLK=1;


               dly(5);


               sent_buf=sent_buf>>1;


               }


              RTC_CLK=0;


              dly(5);


           }




//ds1302读1字节


unsigned char rtc_rd_byte(void)


          {unsigned char i,read_buf;


           RTC_IO=1;         //RTC_IO置1,保证为输入状态


           for (i=0; i<8; i++)


               {read_buf=read_buf>>1;


               RTC_CLK=0;


               dly(5);


                if (RTC_IO) read_buf=read_buf|0x80;


                else read_buf=read_buf&0x7f;


                RTC_CLK=1;


                dly(5);


               }


           RTC_CLK=0;


           dly(5);


           return read_buf;


          }




//ds1302写入时间


void rtc_wr_time(unsigned char *p_wt_time)


           {unsigned char i;


            unsigned char tmp1;


            dly(30);


            RTC_RST=1;


            rtc_wt_byte(0xbe);         //burst写入时间


            for (i=0; i<8; i++)


                  {tmp1=*p_wt_time++;


                   rtc_wt_byte(tmp1);


                   }


            RTC_CLK=0;


            RTC_RST=0;


           }




//ds1302读出时间


void rtc_rd_time(unsigned char *p_rd_time)


           {unsigned char i;


            unsigned char tmp1;


            dly(30);


            RTC_RST=1;


            rtc_wt_byte(0xbf);        //burst读取时间




            RTC_IO=1;


            for (i=0; i<8; i++)


                  {tmp1=rtc_rd_byte();


                   *p_rd_time++=tmp1;


                  }




            RTC_CLK=0;


            RTC_RST=0;


           }






//ds1302初始化


void ini_rtc()


         {RTC_CLK=0;


          RTC_RST=0;


          dly(30);


          


          RTC_RST=1;                


          rtc_wt_byte(0x8e);        //写CONTROL寄存器


          rtc_wt_byte(0x00);        //值:去掉写保护


          RTC_RST=0;                //复位




          RTC_RST=1;                //正常工作


          rtc_wt_byte(0x90);        //写TRICKLE CHARGER寄存器


          rtc_wt_byte(0xa9);        //值:使能充电,串联2个二极管,串联2k欧姆的电阻




          RTC_CLK=0;


          RTC_RST=0;


         }






//把4位数字的SEG放到COM1、COM2、COM3、COM4对应的段码


//LCD的管脚定义与LED不同,它不是一个COM对应一位数字,而是对应每个数字的一部分SEG


// 1   2   3   4   5   6   7   8   9  10  11  12  13  14  15 


// <  1f  1a  2f  2a      3f  3a  4f  4a   >              --   ---- COM0 


// <  1g  1b  2g  2b      2g  3b  4g  4b   >          --       ---- COM1 


// <  1e  1c  2e  2c   :  3e  3c  4e  4c   >      --           ---- COM2 


//    1d  1h  2d  2h      3d  3h  4d          --               ---- COM3


void Seg2Seg()


{unsigned char SegXX;




 SegBuf[0]=0;


 SegBuf[1]=0;


 SegBuf[2]=0x08;


 SegBuf[3]=0;


 bi_4a=0;


 bi_4b=0;


 bi_4c=0;



 SegXX=seg_code[DisplayBuf[0]];      //第1位数字


 if (SegXX&0x80) SegBuf[0]|=0x40;


 if (SegXX&0x40) SegBuf[1]|=0x40;


 if (SegXX&0x20) SegBuf[2]|=0x40;


 if (SegXX&0x10) SegBuf[3]|=0x80;


 if (SegXX&0x08) SegBuf[2]|=0x80;


 if (SegXX&0x04) SegBuf[0]|=0x80;


 if (SegXX&0x02) SegBuf[1]|=0x80;


 if (SegXX&0x01) SegBuf[3]|=0x40;


 


  SegXX=seg_code[DisplayBuf[1]];    //第2位数字


 if (SegXX&0x80) SegBuf[0]|=0x10;


 if (SegXX&0x40) SegBuf[1]|=0x10;


 if (SegXX&0x20) SegBuf[2]|=0x10;


 if (SegXX&0x10) SegBuf[3]|=0x20;


 if (SegXX&0x08) SegBuf[2]|=0x20;


 if (SegXX&0x04) SegBuf[0]|=0x20;


 if (SegXX&0x02) SegBuf[1]|=0x20;


 if (SegXX&0x01) SegBuf[3]|=0x10;


 


 


  SegXX=seg_code[DisplayBuf[2]];   //第3位数字


 if (SegXX&0x80) SegBuf[0]|=0x02;


 if (SegXX&0x40) SegBuf[1]|=0x02;


 if (SegXX&0x20) SegBuf[2]|=0x02;


 if (SegXX&0x10) SegBuf[3]|=0x04;


 if (SegXX&0x08) SegBuf[2]|=0x04;


 if (SegXX&0x04) SegBuf[0]|=0x04;


 if (SegXX&0x02) SegBuf[1]|=0x04;


 if (SegXX&0x01) SegBuf[3]|=0x02;


 


  SegXX=seg_code[DisplayBuf[3]];   //第4位数字


 if (SegXX&0x80) bi_4a=1;


 if (SegXX&0x40) bi_4b=1;


 if (SegXX&0x20) bi_4c=1;


 if (SegXX&0x10) SegBuf[3]|=0x01;


 if (SegXX&0x08) SegBuf[2]|=0x01;


 if (SegXX&0x04) SegBuf[0]|=0x01;


 if (SegXX&0x02) SegBuf[1]|=0x01;




}






/*一个BCD码转化成两个十进制数(如:0x79转化成0x07和0x09)*/


BcdToDec(unsigned char BcdValue,unsigned char *pDecValue)


       {//if (BcdValue>=0x9a||(BcdValue&0x0f)>=0x0a) return 0;


       *pDecValue++=(BcdValue&0xf0)>>4;


        *pDecValue=BcdValue&0x0f;


        //return 1;


       }




//初始化MCS51内部资源


InitInterResource()


       {IE=0;       //关全部中断


        TCON=0;     //清全部中断请求


        IP=0;       //清中断优先级   




        TMOD=0x01;  //T0工作方式1(16位定时器)


        TH0=0x00;   //T0定时器辅初值


        TL0=0x00;


        TR0=1;      //允许T0定时


        ET0=1;      //允许T0中断


        EA=0;       //关全局中断


        


        RTC_RST=0;


       }










void main()


    {    


     InitInterResource();


         


     ini_rtc();                    //初始化DS1302


     rtc_wr_time(ClockBuffer);     //写入时间初始值




     EA=1;         //开全局中断


     while(1)


        {         


        }


    }






//定时器0中断服务程序,5ms定时器,4位数码管动态显示驱动


void tmr0_p(void) interrupt 1


    {


     TL0=0x78;     //重新定时5ms


     TH0=0xec;


     Seg2Seg();


     P3M1=0x3c;


     P3M0=0x00;


          switch(ScanCoun)                //动态扫描显示


         { 


          case 0:                        //COM0正向驱动


          P1= SegBuf[0];


          BI_4= bi_4a;


          COM0=0;           


          P3M1=0x1c;                      //除COM0输出外,其余COM设为输入


          P3M0=0x00; 


          break;


          


          case 1:                       //COM0反向驱动


          P1= ~SegBuf[0];


          BI_4= ~bi_4a;


          COM0=1;              


          P3M1=0x1c;


          P3M0=0x00;


          break;


          


          


          case 2:                       //COM1正向驱动


          P1= SegBuf[1];


          BI_4= bi_4b;


          COM1=0;             


          P3M1=0x2c;


          P3M0=0x00;


          break;


          


          case 3:                       //COM1反向驱动


          P1= ~SegBuf[1];


          BI_4= ~bi_4b;


          COM1=1;                  


          P3M1=0x2c;


          P3M0=0x00;


          break;


          


          


          case 4:                       //COM2正向驱动


          P1= SegBuf[2];


          BI_4= bi_4c;


          COM2=0;                   


          P3M1=0x34;


          P3M0=0x00;


          break;


          


          case 5:                       //COM2反向驱动


          P1= ~SegBuf[2];


          BI_4= ~bi_4c;


          COM2=1;                  


          P3M1=0x34;


          P3M0=0x00;


          break;


          


          case 6:                       //COM3正向驱动


          P1= SegBuf[3];


          COM3=0;                   


          P3M1=0x38;


          P3M0=0x00;


          


          RTC_RST=0;


          rtc_rd_time(ClockBuffer);    //读时间


          BcdToDec(ClockBuffer[0],DisplayBuf+2);     //秒送入显示缓冲


          BcdToDec(ClockBuffer[1],DisplayBuf);       //分送入显示缓冲


          BI_4= ~bi_4c;


          break;


          


          case 7:                       //COM3反向驱动


          P1= ~SegBuf[3];


          COM3=1;                   


          P3M1=0x38;


          P3M0=0x00;


          


          break;


          


         }




     ScanCoun++;       //下一位


     if (ScanCoun>7) ScanCoun=0;       


     }




推荐新闻
段码LCD液晶显示屏能被应用到哪些领域
段码LCD显示屏发展历史久使用时间长,经过几十年的应用改进产品的性能不断优化,因为其造价便宜使用寿命...
段码LCD液晶显示屏的优点有哪些
LCD显示屏能够显示图案数字等被应用于汽车、化工、医药等行业,使用段码LCD液晶显示屏能够获取屏幕上...
如何选择段码LCD液晶显示屏
段码LCD液晶显示屏被用在出租车计价表、体重秤、收银机等多种机器上,用来显示商品价格和体重信息,显示...
选择定制段码LCD液晶显示屏的好处有哪些
显示屏本身的价格相比起其他种类的显示屏来说会更高因为拥有更好的质量,在挑选种类时要根据自己的需要选择...
  • QQ咨询

  • QQ咨询

  • QQ咨询

  • 微信咨询

  • 微信咨询

  • 电话咨询

    杨总18813866468

Please select customer service to chat

  • 微信咨询

    Long press to identify the QR code
  • 微信咨询

    Long press to identify the QR code
Click on the phone to make a call