搜索
bottom↓
回复: 39

[原创]一个功能强大的1602LCD四位数据线驱动程序

[复制链接]

出0入0汤圆

发表于 2006-2-13 02:50:49 | 显示全部楼层 |阅读模式
驱动程序

#include <iom8v.h>

#include <macros.h>

#include "LCD_1602.h"

void delay_nms(unsigned int n);

void delay_nus(unsigned int n);

unsigned char lcd_data[32];//32字节显存,记录LCD上显示的数据

unsigned char data[32];//32字节缓存,保存将要写入LCD的数据

unsigned char add;//显存地址标号

unsigned char new=32;//显存标号

unsigned int num=0;

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

TC1602B LCD DISPLAY

建立时间:2005年12月12号

修改日期:2005年12月12号

LCD_write函数功能:当command=0时,向LCD写入数据,否则向LCD写

                   入命令

LCD第一行显示寄存器地址:0X80-0X8F

LCD第二行显示寄存器地址:0XC0-0XCF

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

void LCD_init(void)

  {

     LCD_EN_DDR|=LCD_EN;//设定该引脚方向为输出

         LCD_RS_DDR|=LCD_RS;//设定该引脚方向为输出

         LCD_D4_DDR|=LCD_D4;//设定数据口为输出

         LCD_D5_DDR|=LCD_D5;//设定数据口为输出  

         LCD_D6_DDR|=LCD_D6;//设定数据口为输出  

         LCD_D7_DDR|=LCD_D7;//设定数据口为输出

         

          LCD_EN_PORT&=~LCD_EN;//EN设为低电平

          LCD_RS_PORT&=~LCD_RS;//RS设为低电平

          LCD_D4_PORT&=~LCD_D4;//数据口置低电平

          LCD_D5_PORT&=~LCD_D5;//数据口置低电平

          LCD_D6_PORT&=~LCD_D6;//数据口置低电平

          LCD_D7_PORT&=~LCD_D7;//数据口置低电平

          

    LCD_write_char(0,0x33);      //4bit test

        delay_nms(25);

        LCD_write_char(0,0x32);

        delay_nms(15);

        LCD_write_char(0,0x28);

        delay_nms(15);

    LCD_write_char(0,0x0C);      //显示开

        delay_nms(15);

    LCD_write_char(0,0x01);      //显示清屏

        delay_nms(15);

    LCD_write_char(0,0x06);      //显示光标移动设置       

        LCD_clear();

        delay_nms(10);

        LCD_init_CGRAM();

  }

/*-----------------------------------------------------------------------

LCD_write_char    : 写一个字节到LCD的函数

编写日期             :2005-12-12

最后修改日期      :2005-12-12                

-----------------------------------------------------------------------*/

void LCD_write_char(unsigned command,unsigned data)

  {

    if (command == 0)

           LCD_RS_PORT &= ~LCD_RS;   //RS=0  写地址

        else

    LCD_RS_PORT |= LCD_RS;    //RS=1 写数据

       

    LCD_write_DATA_PORT(data);//写高4位

    LCD_write_DATA_PORT(data<<4);//写低4位

        delay_nus(250);

        num++;//统计向LCD发送的字节数

  }

/*-----------------------------------------------------------------------

LCD_write_DATA_PORT : 写数据到LCD数据口函数



输入参数data   :要写入的数据(仅高4位)

编写日期          :2005-12-12

最后修改日期   :2005-12-12                

-----------------------------------------------------------------------*/

void LCD_write_DATA_PORT(unsigned char data)

{   

    if((data>>4)%2)

          LCD_D4_PORT |=LCD_D4;

        else

          LCD_D4_PORT &=~LCD_D4;

       

        if((data>>5)%2)

          LCD_D5_PORT |=LCD_D5;

        else

          LCD_D5_PORT &=~LCD_D5;

          

        if((data>>6)%2)

          LCD_D6_PORT |=LCD_D6;

        else

          LCD_D6_PORT &=~LCD_D6;

          

        if((data>>7)%2)

          LCD_D7_PORT |=LCD_D7;

        else

          LCD_D7_PORT &=~LCD_D7;

          

          LCD_EN_PORT |= LCD_EN; //EN端产生一个由低电平变高电平,写LCD

          delay_nus(25);

      LCD_EN_PORT &= ~LCD_EN; //EN端产生一个由高电平变低电平,写LCD

          delay_nus(25);

}

/*-----------------------------------------------------------------------

LCD_clear    : 清除屏幕的函数



输入参数      :无

编写日期      :2005/10/18       

       说明      :        lcd_data[]也会被清0

-----------------------------------------------------------------------*/

void LCD_clear(void)

  {  

     unsigned char i;

     LCD_write_char(0,0x01);//显示清屏

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

           {

              lcd_data=0;

           }

           delay_nus(500);

  }

/*-----------------------------------------------------------------------

LCD_check   : 统计发送数据到LCD次数的函数



输入参数      :x,y 显示结果的座标

编写日期      :2005/10/18       

       说明      :如果每秒调用一次,就是统计每秒的次数

-----------------------------------------------------------------------*/

void LCD_check(unsigned char x,unsigned char y) //检测每秒钟写LCD

                                                                      //次数的函数

  {  

    unsigned char  i;

        unsigned char  lcd[2]={0};

        add=y*16+x;//设置起始座标

        lcd[0]=num/10+48;

                lcd[1]=num%10+48;

        num=0;  

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

      {

              if(lcd_data[add]==lcd){}

                          else

                             {data[add]=lcd;}

                          add++;

      }

        LCD_updata;

  }

/*-----------------------------------------------------------------------

LCD_write_string  : 英文字符串显示函数



输入参数:*s       :英文字符串指针;

                 X、Y    : 显示字符串的位置

                                 e          : 把从最后一个字符到x=e之间的内容删除

编写日期          :2005/10/18               

-----------------------------------------------------------------------*/

void LCD_write_string(unsigned char x,unsigned char y, const unsigned char *s,unsigned char e)

  {

    if(y<2)

        add=y*16+x;//设置起始座标

    while (*s)

      {

            if(lcd_data[add]==*s)//如果LCD上显示的数和

                   {}                             //待写入的数相同的话

                else{data[add]=*s;}//要显示的数据存入显存

               s ++;//指针加1

               add++;//显存地址加1

      }

          if(y==1)

            e+=16;

          for(;e>=add;add++)

           {data[add]=' ';}

        LCD_updata;

  }

/*-----------------------------------------------------------------------

LCD_write_number  : 数字显示函数



输入参数:

          X、Y    : 显示字符串的位置

               d     :在第d位插入小数点

                 data      :要显示的数据 长整形

                     *s     :数据的单位

                 e       : 把从最后一个字符到x=e之间的内容删除

编写日期       :2005/10/18                        

-----------------------------------------------------------------------*/

void LCD_write_number(unsigned char x,unsigned char y,unsigned char d,unsigned long dat,const unsigned char *s,unsigned char e)

  {

    unsigned char  i;

        unsigned char b=0;

        unsigned char c='.';

        unsigned char lcd[10]={0};

        if(y<2)//如果Y>1则不重新计算地址

    add=y*16+x;//设置起始座标

   

   for (i=10;i>0;i--)

      {

        lcd=dat%10+48;

                dat=dat/10;

      }

          

        for(i=1;i<11;i++)

           {

             if(i==11-d)

                   {  

                      if(lcd_data[add]==c)

                             {}

                          else

                             {data[add]=c;}     

                          add++;

                        }   

             if((lcd-48+b)==0)

             {

                   if(i>=(10-d))

                   {

                      if(lcd_data[add]==lcd)

                             {}

                          else

                             {data[add]=lcd;}     

                          add++;

                        }          

                   else

                   {}            

                 }

                 else

                 {

                      if(lcd_data[add]==lcd)

                             {}

                          else

                             {data[add]=lcd;}      

                          add++;

                 b=1;

                 }

           }

           while (*s)

      {

        if(lcd_data[add]==*s)//如果LCD上显示的数和

                   {}                             //待写入的数相同的话

                else{data[add]=*s;}//要显示的数据存入显存

               s ++;//指针加1

               add++;//显存地址加1

      }

          if(y==1)

            e+=16;

          for(;e>=add;add++)

           {data[add]=' ';}

            LCD_updata;

  }

/*-----------------------------------------------------------------------

LCD_write_time  : 数字显示函数



输入参数:

          X、Y    : 显示数据的起始的位置

                  h,m,s   :时,分,秒

编写日期          :2005-10-19                

-----------------------------------------------------------------------*/

void LCD_write_time(unsigned char x,unsigned char y,unsigned char h,unsigned char m,unsigned char s)

  {

    unsigned char  i;

        unsigned char  lcd[8]={0};

        if(y<2)

        add=y*16+x;//设置起始座标LCD_set_xy( X, Y );  

        lcd[0]=h/10+48;

        lcd[1]=h%10+48;

        lcd[2]=':';

        lcd[3]=m/10+48;

        lcd[4]=m%10+48;

        lcd[5]=':';  

        lcd[6]=s/10+48;

        lcd[7]=s%10+48;

/*时和分之间的:的闪动效果

        if(lcd[7]%2)

           lcd[2]=':';

           else

           lcd[2]=' ';*/

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

      {

              if(lcd_data[add]==lcd)

                             {}

                          else

                             {data[add]=lcd;}   

                          add++;

      }

        LCD_updata;

  }

/*----------------------------------------------------

    LCD_write_new:写显存函数

        data[]:32字节的显存

        new:显存标号

        编写日期:2005/10/18

-----------------------------------------------------*/  

void  LCD_write_new(void)

  {   

    unsigned char address;

        unsigned char new_add=1;//1表示要更新地址

        while(new<32)//显存共32个字节,标号从0--31

      {   

                 if(new==16)//换行

                    new_add=1;          

             if(data[new])//跳过为0的显存

            {  

                        if(new_add)//当new_add=0时表示无需更新地址

                      {

                         if(new>15)

                               address=0xb0+new;

                                 else

                               address=0x80+new;

                               LCD_write_char(0,address);//设置起始地址

                       }                            

                          LCD_write_char(1,data[new]);//写数据

                          lcd_data[new]=data[new];

                          data[new]=0;//写完数据后,显存清0

                          new_add=0;

                        }

                else

                   new_add=1;

                   new++;//

      }

  }

/*----------------------------------------------------

    LCD_write_CGRAM:写CGRAM的函数

        输入参数:

          X、Y    : 显示数据的起始的位置

                        n    : 存入LCD的图案的编号

        编写日期:2005/10/18

-----------------------------------------------------*/

void LCD_write_CGRAM(unsigned char x,unsigned char y,unsigned char n)

{  

   if(y<2)

   add=y*16+x;//设置起始座标

    if(n==0)//0表示空数据

        n+=8;//所以要加上8  (0>8/1>9/2>10...7>15)  

        data[add]=n;      

        LCD_updata;

}

/*----------------------------------------------------

    LCD_init_CGRAM:初始化CGRAM的函数

       

        编写日期:2005/10/18

-----------------------------------------------------*/

void LCD_init_CGRAM(void)

  {

     unsigned char CGRAM[8][8]=//CGRAM图案的定义

         {  //1     2      3       4       5      6        7      x

           {0x3F,0x01,0x01,0x01,0x01,0x01,0x3F,0x00},//0

           {0x00,0x04,0x02,0x1F,0x02,0x04,0x00,0x00},//1

           {0x00,0x04,0x0E,0x15,0x04,0x04,0x04,0x00},//2

           {0x00,0x1F,0x15,0x0E,0x04,0x04,0x04,0x00},//3

           {0x00,0x1F,0x15,0x0A,0x04,0x04,0x04,0x00},//4

           {0x00,0x00,0x02,0x06,0x0E,0x1E,0x1E,0x00},//5

           {0x08,0x0C,0x0A,0x09,0x0A,0x0C,0x08,0x00},//6               

           {0x08,0x0C,0x0E,0x0F,0x0E,0x0C,0x08,0x00},//7

         };

           unsigned char ads=0x40;

           unsigned char x,y;

          

           LCD_write_char(0,ads);//写地址

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

             {

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

                {

                 LCD_write_char(1,CGRAM[y][x]);

                }          

                }     

  }

出0入0汤圆

 楼主| 发表于 2006-2-13 02:51:55 | 显示全部楼层
头文件

//定义MCU与LCD的接口

#define LCD_EN_PORT    PORTD

#define LCD_EN_DDR     DDRD

#define LCD_RS_PORT    PORTD

#define LCD_RS_DDR     DDRD

#define LCD_D4_PORT    PORTD

#define LCD_D4_DDR     DDRD

#define LCD_D5_PORT    PORTD

#define LCD_D5_DDR     DDRD

#define LCD_D6_PORT    PORTD

#define LCD_D6_DDR     DDRD

#define LCD_D7_PORT    PORTD

#define LCD_D7_DDR     DDRD



#define LCD_EN         0x40   //PORTD6      

#define LCD_RS         0x80   //PORTD7   

#define LCD_D4         0x20   //PORTD5        

#define LCD_D5         0x10   //PORTD4        

#define LCD_D6         0x08   //PORTD3      

#define LCD_D7         0x04   //PORTD2        



#define LCD_updata  new=0

/*------------------------------------------------

            函数声明

-------------------------------------------------*/

void LCD_init   (void);

void LCD_write_char  (unsigned command,unsigned data);

void LCD_write_DATA_PORT(unsigned char data);

void LCD_write_string(unsigned char x,unsigned char y, const unsigned char *s,unsigned char e);

void LCD_write_number(unsigned char x,unsigned char y,unsigned char d,unsigned long dat,const unsigned char *s,unsigned char e);

void LCD_write_time(unsigned char X,unsigned char Y,unsigned char h,

                                                unsigned char m,unsigned char s);

void LCD_write_new(void);

void LCD_check(unsigned char x,unsigned char y);

void LCD_clear(void);

void LCD_init_CGRAM(void);

void LCD_write_CGRAM(unsigned char x,unsigned char y,unsigned char n) ;

出0入0汤圆

 楼主| 发表于 2006-2-13 02:54:13 | 显示全部楼层
应用范例

点击此处下载armok01102186.rar



终于完成了  马上睡觉

出0入0汤圆

 楼主| 发表于 2006-2-13 12:15:32 | 显示全部楼层
特点:2条控制线+4条数据线可以使用单片机任意一个IO

      4条数据线不再必需使用连续的几个端口 使IO的分配和布线更加灵活

   

      把将要写入LCD的数据和LCD上的数据进行对比(数据比较不需要从LCD读出数据)

      相同则不再写入,很大程度地减小了数据的传输量,从而减小了CPU占用时间

      

      LCD_write_number();可以写整数,定点小数,单位(V、mA...),

      并可指定清除屏幕到某一位

      

      LCD_write_time();按时间格式写入时间



      LCD_check();用来统计一段时间传送给LCD的数据量

      

      void LCD_init_CGRAM(void); //CGRAM初始化



缺点: 占用内存较多,程序空间多

出0入0汤圆

发表于 2006-2-13 13:08:12 | 显示全部楼层
感谢楼主~~!



顺便问问楼主的电量测试范例什么时候发布?

出0入0汤圆

 楼主| 发表于 2006-2-13 13:26:49 | 显示全部楼层
因为我要回到学校才能整理那些资料



所以可能还要迟几天



那个范例的LCD就是使用了这个驱动程序的



谢谢支持!

出0入0汤圆

发表于 2006-2-13 14:51:58 | 显示全部楼层
這兩個涵數參數之多, 看了有點暈, 不過還是要頂你的!!

void LCD_write_number(unsigned char x,unsigned char y,unsigned char d,unsigned long dat,const unsigned char *s,unsigned char e);

void LCD_write_time(unsigned char X,unsigned char Y,unsigned char h,

                                                unsigned char m,unsigned char s);
-----此内容被avrboy于2006-02-13,14:56:28编辑过

出0入0汤圆

发表于 2006-3-10 22:13:26 | 显示全部楼层
<img src=./emotion/em041.gif

出0入0汤圆

发表于 2007-5-13 13:06:20 | 显示全部楼层
好好玩呀

出0入0汤圆

发表于 2007-5-30 08:15:36 | 显示全部楼层
里面好象没有忙状态检测,我用了你的程序好象不能直接使用,移植的时候有什么特殊需要注意的问题么? 另外你里面没有延时程序,你可能说很简单,但要精确到NS级应该有点要求了。

出0入0汤圆

发表于 2008-8-3 16:15:53 | 显示全部楼层
。。。。。。。。记号个。。。

出0入0汤圆

发表于 2008-8-3 16:30:02 | 显示全部楼层
刚看到贴子,谢谢。

出0入0汤圆

发表于 2008-8-3 18:51:39 | 显示全部楼层
記下了,謝謝!

出0入0汤圆

发表于 2008-8-3 19:18:40 | 显示全部楼层
非常感谢。

出0入0汤圆

发表于 2009-2-26 15:07:24 | 显示全部楼层
正在弄这个呢,谢谢了

出0入0汤圆

发表于 2009-2-26 17:53:34 | 显示全部楼层
学习

出0入18汤圆

发表于 2009-3-11 22:02:25 | 显示全部楼层
感谢哈! 收藏中!

出0入0汤圆

发表于 2009-3-22 09:20:33 | 显示全部楼层
不错,留下记号,继续努力

出0入4汤圆

发表于 2009-3-22 22:30:00 | 显示全部楼层
支持

出0入0汤圆

发表于 2009-3-22 22:44:08 | 显示全部楼层
不错。谢谢。

出0入0汤圆

发表于 2009-4-21 08:54:08 | 显示全部楼层
怎么样利用此程序,设计电子时钟呢

出0入0汤圆

发表于 2009-6-16 08:40:37 | 显示全部楼层
dddddddddddddd

出0入0汤圆

发表于 2010-2-9 13:54:39 | 显示全部楼层
很好

出0入0汤圆

发表于 2010-2-10 11:47:48 | 显示全部楼层
记号,

出0入0汤圆

发表于 2010-3-26 22:17:25 | 显示全部楼层
谢谢,

出0入0汤圆

发表于 2010-6-17 15:05:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-20 00:45:23 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-7-3 17:41:36 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-6-15 16:35:58 | 显示全部楼层
这个有意思

出0入8汤圆

发表于 2011-6-16 11:05:23 | 显示全部楼层
用C语言驱动1602这么繁琐啊,止步了,还是用bascom要简便的多

出0入0汤圆

发表于 2011-6-16 14:44:17 | 显示全部楼层
不 错!!!

出0入0汤圆

发表于 2011-6-16 21:48:54 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-6-16 22:06:49 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-15 01:33:28 | 显示全部楼层
mark

出0入12汤圆

发表于 2011-7-19 00:05:15 | 显示全部楼层
标记标记

出0入0汤圆

发表于 2011-7-19 08:46:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-19 10:19:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-19 13:21:54 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-18 18:35:11 | 显示全部楼层
移植性很强,谢谢楼主
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 09:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表