博文

【046】基于HD44780的1602简单驱动(C51)(2007-5-26 1:36:00)


[相关] (001)基于HD44780液晶芯片的16×2字符型液晶(1602)简介。


lcd.h:

  • /*********************************************************************  
  • * 标题: 基于HD44780的1602简单驱动(C51)  
  • * 文件: lcd.h  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 参考: AVR单片机与CPLD/FPGA综合应用入门  
  • * 日期: 2007.5.10  
  • * 修改: 2007.5.26  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 硬件连接定义及函数原型声明,此处P0,P2,P2_0等在AT89X51.h中定义,  
  •         也可用sfr, sbit自行定义。  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • *********************************************************************/  
  •   
  • #ifndef LCD_H   
  • #define LCD_H   
  •   
  • #include <AT89X51.h>   
  •   
  • #define LCD_DATA_PORT P0  // 液晶BD0~BD7与P0口相连   
  •   
  • #define LCD_RS P2_0       // 液晶 RS  引脚与P2.0相接   
  • #define LCD_RW P2_1       // 液晶 R/W 引脚与P2.1相接   
  • #define LCD_E  P2_2       // 液晶 E   引脚与P2.2相接   
  • #define LCD_BF P0_7       // 液晶 DB7 引脚与P0.7相接 Busy Flag   
  •   
  • // 函数原型   
  •   
  • // 向LCD写命令字   
  • extern void lcd_command(unsigned char cmd);   
  •   
  • // 设置显示位置(即写入显示地址),行列均从0开始   
  • extern void lcd_goto_xy(unsigned char x, unsigned char y);   
  •   
  • // 写字符(传入的参数实际为所需显示字符的地址,即液晶字符产生器中字符的地址)   
  • extern void lcd_putc(unsigned char c);   
  •   
  • // 指定位置写字符   
  • extern void lcd_xy_putc(unsigned char x, unsigned char y, unsigned char c);   
  •   
  • // 写字符串   
  • extern void lcd_puts(unsigned char *s);   
  •   
  • // 指定位置写字符串   
  • extern void lcd_xy_puts(unsigned char x, unsigned char y, unsigned char *s);   
  •   
  • // LCD初始化   
  • extern void lcd_init(void);   
  •   
  • #endif //LCD_H  



    lcd.c:
  • /*********************************************************************  
  • * 标题: 基于HD44780的1602简单驱动(C51)  
  • * 文件: lcd.c  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 参考: AVR单片机与CPLD/FPGA综合应用入门  
  • * 日期: 2007.5.10  
  • * 修改: 2007.5.26  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 硬件连接定义在lcd.h中  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • *********************************************************************/  
  •   
  • #include "lcd.h"   
  •   
  • // 本地函数   
  •   
  • void lcd_delay_us(unsigned char us) // 延时微秒@12M,ms最大值255   
  • {   
  •     while(--us)   
  •     {   
  •         ;   
  •     }   
  • }   
  •   
  • void lcd_delay_ms(unsigned char ms) // 延时毫秒@12M,ms最大值255   
  • {      
  •     unsigned char i;   
  •     while(ms--)   
  •     {   
  •         for(i = 0; i < 124; i++)   
  •         {   
  •             ;   
  •         }   
  •     }   
  • }   
  •   
  •   
  • // 产生一个使能脉冲   
  •   
  • void lcd_e_toggle(void)   
  • {   
  •     LCD_E = 1;   
  •     lcd_delay_us(3);   
  •     LCD_E = 0;   
  • }   
  •   
  •   
  • // 循环检测LCD忙标志(BF),直到其值为0,方可执行下一指令   
  •   
  • void lcd_wait_until_finish(void)   
  • {   
  •     LCD_RW = 1;              // RW置1,状态为读   
  •     LCD_RS = 0;              // RS置0,读状态时RS需置低电平       
  •     LCD_E = 1;               // E 置1,读取信息   
  •        
  •     while(LCD_BF)            // 循环直至BF=0   
  •     {   
  •         ;   
  •     }   
  •     LCD_E = 0;               // E重置为0   
  • }   
  •   
  •   
  • // 公共函数   
  •   
  • // 向LCD写命令字   
  •   
  • void lcd_command(unsigned char cmd)   
  • {   
  •     LCD_RW = 0;              // RW置0,状态为写   
  •     LCD_RS = 0;              // RS置0,写入命令字   
  •        
  •     LCD_DATA_PORT = cmd;     // 将命令字cmd送入LCD的数据端口   
  •     lcd_e_toggle();          // 产生使能脉冲,在下降沿开始执行,将命令字读入   
  •     lcd_wait_until_finish(); // 等待执行完毕   
  • }   
  •   
  •   
  • // 设置显示位置(即写入显示地址),x,y均从0开始   
  •   
  • void lcd_goto_xy(unsigned char x, unsigned char y)   
  • {   
  •     unsigned char p;       // p为字符显示位置,即DDRAM中的地址   
  •     if (y==0)   
  •     {   
  •         p = 0x00 + x;      // (0,0)显示位置为0x00   
  •     }   
  •     else  
  •     {   
  •         p = 0x40 + x;      // (0,1)显示位置为0x40   
  •     }   
  •     lcd_command(p + 0x80); // 写入显示地址时DB7须为高电平,加0x80   
  • }   
  •   
  •   
  • // 写字符(传入的参数实际为所需显示字符的地址,即液晶字符产生器中字符的地址)   
  •   
  • void lcd_putc(unsigned char c)   
  • {   
  •     LCD_RW = 0;               // RW置0,状态为写   
  •     LCD_RS = 1;               // RS置1,写入数据   
  •        
  •     LCD_DATA_PORT = c;        // 将字符c(实际上是字符的地址)送入LCD数据端口   
  •     lcd_e_toggle();           // 使能脉冲   
  •     lcd_wait_until_finish();  // 等待完成   
  • }   
  •   
  •   
  • // 指定位置写字符   
  •   
  • void lcd_xy_putc(unsigned char x, unsigned char y, unsigned char c)   
  • {   
  •     lcd_goto_xy(x,y);   
  •     lcd_putc(c);   
  • }   
  •   
  •   
  • // 写字符串   
  •   
  • void lcd_puts(unsigned char *s)   
  • {   
  •     while(*s)   
  •     {   
  •         lcd_putc(*s);   
  •         s++;   
  •     }   
  • }   
  •   
  •   
  • // 指定位置写字符串   
  •   
  • void lcd_xy_puts(unsigned char x, unsigned char y, unsigned char *s)   
  • {   
  •     lcd_goto_xy(x, y);   
  •     lcd_puts(s);   
  • }   
  •   
  • // LCD初始化   
  •   
  • void lcd_init(void)   
  • {   
  •     lcd_delay_ms(12);          // 上电后适当延时   
  •     lcd_command(0x38);         // 设为8位接口模式,显示2行字符   
  •     lcd_command(0x06);         // 写入新数据后光标右移   
  •     lcd_command(0x0c);         // 显示功能开,不显示光标   
  •     lcd_command(0x01);         // 清屏   
  • }




    测试:

  • #include "lcd.h"   
  •   
  • void main(void)   
  • {   
  •     while(1)   
  •     {   
  •         lcd_init();                // 初始化LCD   
  •            
  •         lcd_goto_xy(0,0);          // 字符位置:(0,0)   
  •         lcd_putc('a');             // 显示字符"a"   
  •   
  •         lcd_putc(0x62);            // 在(1,0)显示字符"b"(在CGROM中的地址为0x62,与ASCII码对应)   
  •   
  •         lcd_xy_putc(3,0,'c');      // 在(3,0)显示字符"c"   
  •   
  •         lcd_goto_xy(0,1);          // 字符位置:(0,1)   
  •         lcd_puts("Hello world!");  // 显示字符串"Hello world!"   
  •                
  •         lcd_xy_puts(16-3,1,"^_^"); // 在(13,1)列显示字符串"^_^"   
  •     }   
  • }



    注意:由于仿真模型与实际硬件有差异,上述驱动直接仿真会有问题,有兴趣可以参考一下这个帖子

  • 阅读全文(3498) | 评论:4 | 复制链接

    (001)基于HD44780液晶芯片的16×2字符型液晶(1602)简介(2007-5-13 19:05:00)

    声明:本文内容选自《AVR单片机与CPLD/FPGA综合应用入门》及《smc 1602A LCM 使用说明书》,自用资料存档,请勿转载!否则因此引起的版权问题本人概不负责!

    液晶显示器以其微功耗、小体积、使用灵活等诸多优点在袖珍式仪表和低功耗应用系统中得到越来越广泛的应用。液晶显示器通常可分为两大类,一类是点阵型,另一类是字符型。点阵型液晶通常面积较大,可以显示图形;而一般的字符型液晶只有两行,面积小,只能显示字符和一些很简单的图形,简单易控制且成本低。目前市面上的字符型液晶绝大多数是基于HD44780液晶芯片的,所以控制原理是完全相同的,为HD44780写的控制程序可以很方便地应用于市面上大部分的字符型液晶。

    字符型LCD通常有14条引脚线(市面上也有很多16条引脚线的LCD,多出来的2条线是电源线VCC(15脚)和地线GND(16脚),其控制原理与14脚的LCD完全一样),定义如下表所示:

                            字符型LCD的引脚定义

    ┌────┬────┬────┬──────┬────────────┐
    ㄧ 引脚号 ㄧ 引脚名 ㄧ  电平  ㄧ  输入/输出 ㄧ         作用           ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   1    ㄧ  Vss   ㄧ        ㄧ            ㄧ 电源地                 ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   2    ㄧ  Vcc   ㄧ        ㄧ            ㄧ 电源(+5V)              ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   3    ㄧ  Vee   ㄧ        ㄧ            ㄧ 对比调整电压           ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   4    ㄧ  RS    ㄧ  0/1   ㄧ    输入    ㄧ 0=输入指令             ㄧ
    ㄧ        ㄧ        ㄧ        ㄧ            ㄧ 1=输入数据             ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   5    ㄧ  R/W   ㄧ  0/1   ㄧ    输入    ㄧ 0=向LCD写入指令或数据  ㄧ
    ㄧ        ㄧ        ㄧ        ㄧ            ㄧ 1=从LCD读取信息        ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   6    ㄧ  E     ㄧ 1,1→0 ㄧ    输入    ㄧ 使能信号,1时读取信息, ㄧ
    ㄧ        ㄧ        ㄧ        ㄧ            ㄧ 1→0(下降沿)执行指令   ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   7    ㄧ  DB0   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line0(最低位)  ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   8    ㄧ  DB1   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line1          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ   9    ㄧ  DB2   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line2          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ  10    ㄧ  DB3   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line3          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ  11    ㄧ  DB4   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line4          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ  12    ㄧ  DB5   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line5          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ  13    ㄧ  DB6   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line6          ㄧ
    ├────┼────┼────┼──────┼────────────┤
    ㄧ  14    ㄧ  DB7   ㄧ  0/1   ㄧ  输入/输出 ㄧ 数据总线line7(最高位)  ㄧ
    └────┴────┴────┴──────┴────────────┘

    HD44780内置了192个常用字符,存于字符产生器CGROM(Character Generator ROM)中,另外还有几个允许用户自定义的字符产生RAM,称为CGRAM(Character Generator RAM)。下图说明了CGROM和CGRAM与字符的对应关系(由于本书中未用到自定义特殊字符的功能,所以本节不对CGRAM作详细介绍。以下如未特别说明,则"字符码"指CGROM的字符号,"地址"指DDRAM的地址)。

    字符码0x00~0x0F为用户自定义的字符图形RAM(对于5X8点阵的字符,可以存放8组,5X10点阵的字符,存放4组),0x20~0x7F为标准的ASCII码,0xA0~0xFF为日文字符和希腊文字符,其余字符码(0x10~0x1F及0x80~0x9F)没有定义。



    除了CGROM和CGRAM外,LCD内部还有一个DDRAM(Display Data RAM),用于存放待显示内容,LCD控制器的指令系统规定,在送待显示字符代码的指令之前,先要送DDRAM的地址(即待显示的字符显示位置)。16×2的字符型LCD的DDRAM地址与显示位置的对应关系如下:


                    DDRAM地址与显示位置的对应关系

    ╭┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╮
    ┊                                                                ┊
    ┊00H 01H 02H 03H 04H 05H 06H 07H 08H 09H 0AH 0BH 0CH 0DH 0EH 0FH ┊
    ┊                                                                ┊
    ┊40H 41H 42H 43H 44H 45H 46H 47H 48H 49H 4AH 4BH 4CH 4DH 4EH 4FH ┊
    ┊                                                                ┊
    ╰┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈╯

    如果读者到现在对DDRAM的用法还是很迷惘,希望下面这个简单的例子能帮助读者理解。假设要在第1行第2列写入字符"A",这时先写入第1行第2列对应的DDRAM的地址:01H(参见上图),然后再往DDRAM中写入"A"的字符码0x41(参见字符与字符码对照表),这样LCD的第1行第2列就会出现字符A了。也就是说,DDRAM的内容对应于把要显示的字符地址,而DDRAM的地址就对应于显示字符的位置。总而言之,希望在LCD的某一特定位置显示某一特定字符,一般要遵循"先指定地址,后写入内容"的原则;但如果希望在LCD上显示一串连续的字符(如单词等),并不需要每次写字符码之前都指定一次地址,这是因为液晶控制模块中有一个计数器叫地址计数器AC(Address Counter)。地址计数器的作用是负责记录写入DDRAM数据的地址,或从DDRAM读出数据的地址。该计数器的作用不仅仅是"写入"和"读出"地址,它还能根据用户的设定自动进行修改。比如,如果规定地址计数器在"写入DDRAM内容"这一操作完成后自动加1,那么在第1行第1列定写入一个字符后,如果不对字符显示位置(DDRAM地址)重新设置,再写入一个字符,则这个新的字符会出现在第1行第2列。

    那么如何对DDRAM的内容和地址进行操作呢,下面是HD44780的指令集及其设置说明,请浏览该指令集,并找出对DDRAM的内容和地址进行操作的指令。


    清屏指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /ms  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ    清屏    ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧ 1.64 ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:<1> 清除液晶显示器,即将DDRAM的内容全部填入"空白"的ASCII码20H;
          <2> 光标归位,即将光标撤回液晶显示屏的左上方;
          <3> 将地址计数器(AC)的值设为0。


    光标归位指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /ms  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ  光标归位  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧ X  ㄧ 1.64 ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:<1> 把光标撤回到显示器的左上方;
          <2> 把地址计数器(AC)的值设置为0;
          <3> 保持DDRAM的内容不变。


    进入模式设置指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ进入模式设置ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧI/D ㄧ S  ㄧ  40  ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:设定每次定入1位数据后光标的移位方向,并且设定每次写入的一个字符是否移动。参数设定的
          情况如下所示:
          位名    设置
          I/D     0=写入新数据后光标左移        1=写入新数据后光标右移
          S       0=写入新数据后显示屏不移动    1=写入新数据后显示屏整体右移1个字符


    显示开关控制指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ显示开关控制ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧ D  ㄧ C  ㄧ B  ㄧ  40  ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情况如下:
          位名    设置
           D      0=显示功能关     1=显示功能开
           C      0=无光标         1=有光标
           B      0=光标闪烁       1=光标不闪烁


    设定显示屏或光标移动方向指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ设定显示屏或ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧS/C ㄧR/L ㄧ X  ㄧ X  ㄧ  40  ㄧ
    ㄧ光标移动方向ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ    ㄧ      ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:使光标移位或使整个显示屏幕移位。参数设定的情况如下:
          S/C     R/L      设定情况
          0       0        光标左移1格,且AC值减1
          0       1        光标右移1格,且AC值加1
          1       0        显示器上字符全部左移一格,但光标不动
          1       1        显示器上字符全部右移一格,但光标不动


    功能设定指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼───┤
    ㄧ  功能设定  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧ DL ㄧ N  ㄧ F  ㄧ X  ㄧ X  ㄧ 40   ㄧ
    └──────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴───┘
    功能:设定数据总线位数、显示的行数及字型。参数设定的情况如下:
          位名    设置
          DL      0=数据总线为4位        1=数据总线为8位
          N       0=显示1行              1=显示2行
          F       0=5×7点阵/每字符      1=5×10点阵/每字符


    设定CGRAM地址指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┼──┴──┴──┴──┴──┴──┼───┤
    ㄧ设定CGRAM   ㄧ 0  ㄧ 0  ㄧ 0  ㄧ 1  ㄧ     CGRAM的地址(6位)             ㄧ  40  ㄧ
    ㄧ   地址     ㄧ    ㄧ    ㄧ    ㄧ    ㄧ                                  ㄧ      ㄧ
    └──────┴──┴──┴──┴──┴─────────────────┴───┘
    功能:设定下一个要存入数据的CGRAM的地址。


    设定DDRAM地址指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┴──┴──┴──┴──┴──┴──┼───┤
    ㄧ设定CGRAM   ㄧ 0  ㄧ 0  ㄧ 1  ㄧ          DDRAM的地址(7位)              ㄧ 40   ㄧ
    ㄧ   地址     ㄧ    ㄧ    ㄧ    ㄧ                                        ㄧ      ㄧ
    └──────┴──┴──┴──┴────────────────────┴───┘
    功能:设定下一个要存入数据的DDRAM的地址。


    读取忙信号或AC地址指令

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┼──┴──┴──┴──┴──┴──┴──┼───┤
    ㄧ读取忙碌信号ㄧ 0  ㄧ 1  ㄧ FB ㄧ           AC内容(7位)                  ㄧ  40  ㄧ
    ㄧ  或AC地址  ㄧ    ㄧ    ㄧ    ㄧ                                        ㄧ      ㄧ
    └──────┴──┴──┴──┴────────────────────┴───┘
    功能:<1> 读取忙碌信号BF的内容,BF=1表示液晶显示器忙,暂时无法接收单片机送来的数据或指令;
              当BF=0时,液晶显示器可以接收单片机送来的数据或指令;
          <2> 读取地址计数器(AC)的内容。


    数据写入DDRAM或CGRAM指令一览

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┴──┴──┴──┴──┴──┴──┴──┼───┤
    ㄧ 数据写入到 ㄧ    ㄧ    ㄧ                                              ㄧ      ㄧ
    ㄧ DDRAM或    ㄧ 1  ㄧ 0  ㄧ            要写入的数据 D7~D0               ㄧ  40  ㄧ
    ㄧ CGRAM      ㄧ    ㄧ    ㄧ                                              ㄧ      ㄧ
    └──────┴──┴──┴───────────────────────┴───┘
    功能:<1> 将字符码写入DDRAM,以使液晶显示屏显示出相对应的字符;
          <2> 将使用者自己设计的图形存入CGRAM。


    从CGRAM或DDRAM读出数据的指令一览

    ┌──────┬─────────────────────────────┬───┐
    ㄧ            ㄧ                      指令编码                            ㄧ 执行 ㄧ
    ㄧ  指令功能  ├──┬──┬──┬──┬──┬──┬──┬──┬──┬──┤ 时间 ㄧ
    ㄧ            ㄧ RS ㄧR/W ㄧDB7 ㄧDB6 ㄧDB5 ㄧDB4 ㄧDB3 ㄧDB2 ㄧDB1 ㄧDB0 ㄧ /us  ㄧ
    ├──────┼──┼──┼──┴──┴──┴──┴──┴──┴──┴──┼───┤
    ㄧ  从CGRAM或 ㄧ    ㄧ    ㄧ                                              ㄧ      ㄧ
    ㄧ  DDRAM读出 ㄧ 1  ㄧ 1  ㄧ            要读出的数据 D7~D0               ㄧ  40  ㄧ
    ㄧ  数据      ㄧ    ㄧ    ㄧ                                              ㄧ      ㄧ
    └──────┴──┴──┴───────────────────────┴───┘
    功能:读取DDRAM或CGRAM中的内容。

    细心的读者肯定发现了,在上面的指令集中,有RS、R/W和8位数据总线,却小了一个使能位E。使能位E对执行LCD指令起着关键作用,E有两个有效状态,高电平(1)和下降沿(1→0)。当E为高电平时,如果R/W为0,则LCD从单片机读入指令或者数据;如果R/W为1,则单片机可以从LCD中读出状态字(BF忙状态)和地址。而E的下降沿指示LCD执行其读入的指令或者显示其读入的数据。下面是HD44780的时序图和时间参数表:



    在此不准备细究其时序图,对初学者来说,只要记住,在将E置高电平前,先设置好RS和R/W信号,在E下降沿到来之前,准备好写入的命令字或数据。只需在适当的地方加上延时,就可以满足要求了

    基本操作时序:

    读状态  输入:RS=L,RW=H,E=H                             输出:DB0~DB7=状态字
    写指令  输入:RS=L,RW=L,E=下降沿脉冲,DB0~DB7=指令码   输出:无
    读数据  输入:RS=H,RW=H,E=H                             输出:DB0~DB7=数据
    写数据  输入:RS=H,RW=L,E=下降沿脉冲,DB0~DB7=数据     输出:无



    相关【046】基于HD44780的1602简单驱动(C51) 


    阅读全文(4403) | 评论:2 | 复制链接

    【045】数码管显示简单电子钟(2007-5-5 16:33:00)

  • ;**************************************************************************   
  • ; 标题: 数码管显示电子钟(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.3   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  • sec_l  equ  30h        ;30单元存储秒个位值   
  • sec_h  equ  31h        ;31单元存储秒十位值   
  • bar_2  equ  32h        ;32单元存储"-"段码的偏移量   
  • min_l  equ  33h        ;33单元存储分个位值   
  • min_h  equ  34h        ;34单元存储分十位值   
  • bar_5  equ  35h        ;35单元存储"-"段码的偏移量   
  • hou_l  equ  36h        ;36单元存储时个位值   
  • hou_h  equ  37h        ;37单元存储时十位值   
  •   
  • sec    equ  38h        ;38单元为秒计数器(00s-59s)   
  • min    equ  39h        ;39单元为分计数器(00m-59m)   
  • hou    equ  40h        ;40单元为时计数器(00h-23h)   
  •   
  • cou    equ  41h        ;41单元为软计数器,对10ms时基信号累加到1s   
  •   
  • dis_b  equ  42h        ;dis_b(42单元)作为位码选通数码管   
  • dis_r  equ  43h        ;dis_r(43单元)为取段码时的偏移量   
  •   
  • key_v  equ  44h        ;存储键值   
  • key_t  equ  45h        ;按键扫描中临时存储键值   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh           ;定时器0的中断入口地址   
  •           ajmp  time0           ;跳到定时器0的中断服务程序处   
  •           org   001bh           ;定时器1的中断入口地址   
  •           ajmp  time1           ;跳到定时器1的中断服务程序处   
  •           org   0030h  
  • start:       
  •           mov   p2,#0xff        ;关所有数码管   
  •           mov   p1,#0xff        ;p1为准双向口,作输入时先写1   
  •           mov   key_v,#0xff     ;初始键值为ff   
  •              
  •           mov   bar_2,#10       ;'-'段码偏移量为10   
  •           mov   bar_5,#10       ;'-'段码偏移量为10   
  •           mov   dis_b,#0x7f     ;初始选通P2.7口数码管   
  •           mov   dis_r,#0        ;初始化偏移量为0   
  •           mov   sec,#0          ;秒计数清零   
  •           mov   min,#0          ;分计数清零   
  •           mov   hou,#0          ;时计数清零   
  •           mov   cou,#0          ;软计数器清零   
  •              
  •           mov   tmod,#00010001b ;定时/计数器0、1工作于方式1   
  •           mov   th0,#0xd8       ;预置定时常数55536(d8f0),产生10ms时基信号   
  •           mov   tl0,#0xf0  
  •           mov   th1,#0xfc       ;预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •           mov   tl1,#0x18  
  •              
  •           setb  ea              ;开总中断   
  •           setb  et0             ;定时/计数器0允许中断   
  •           setb  et1             ;定时/计数器1允许中断   
  •           setb  tr0             ;开定时/计数器0   
  •           setb  tr1             ;开定时/计数器1   
  •              
  • key:  
  •           mov   a,p1            ;读入键值   
  •           mov   key_t,a         ;存储到临时变量中   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key             ;未改变则重新扫描   
  •           lcall d_10ms          ;有键按下则延时10ms消抖   
  •           mov   a,p1            ;再次读入键值   
  •           mov   key_t,a         ;存入临时变量   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key             ;未改变则为抖动继续扫描   
  •           mov   key_v,key_t     ;确定为键按下则保存键值   
  •           lcall key_to          ;调用键处理部分   
  •           ajmp  key             ;循环扫描按键   
  •   
  • key_to:                         ;键处理子程序   
  •           mov   a,key_v         ;读入键值   
  •           cjne  a,#0xef,next    ;不是P1.4口键值则查下一个   
  •           ajmp  k1              ;是则转去执行该键的处理   
  • next:     cjne  a,#0xdf,back    ;也不是P1.5口键值则结束   
  •           ajmp  k2              ;是则转去执行该键的处理   
  • k1:       mov   a,min           ;读入分计数器的值   
  •           cjne  a,#59,k1_add    ;分计数值未到59   
  •           mov   min,#0          ;分钟加到59时则清零   
  •           ajmp  back            ;结束   
  • k1_add:   inc   min             ;分加1   
  •           ajmp  back            ;结束   
  • k2:       mov   a,hou           ;读入时计数器的值   
  •           cjne  a,#23,k2_add    ;时计数值未到23   
  •           mov   hou,#0          ;时加到23时则清零   
  •           ajmp  back            ;结束   
  • k2_add:   inc   hou             ;时加1               
  • back:     ret                   ;结束   
  • ;--------------------------------------------------------------------------------   
  • time0:                        ;定时器0中断服务程序   
  •          push  psw            ;保护现场   
  •          push  acc  
  •             
  •          inc   cou            ;软计数器加1   
  •          mov   a,cou          ;计数器值送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   cou,#0         ;计到100后软计数器清零(到1s)   
  •             
  •          inc   sec            ;秒计数器加1(进位10ms*100=1s)   
  •          mov   a,sec          ;秒计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   sec,#0         ;计到60后秒计数器清零   
  •             
  •          inc   min            ;分计数器加1(进位60s=1m)   
  •          mov   a,min          ;分计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   min,#0         ;计到60后分计数器清零   
  •             
  •          inc   hou            ;时计数器加1(进位60m=1h)   
  •          mov   a,hou          ;时计数值送入a   
  •          cjne  a,#24,over     ;未计到24则返回继续计数   
  •          mov   hou,#0         ;计到24后时计数器清零,重新计时   
  •             
  • over:    mov   th0,#0xd8      ;重置定时常数   
  •          mov   tl0,#0xf0  
  •          pop   acc            ;恢复现场   
  •          pop   psw  
  •          reti                 ;中断返回   
  • ;--------------------------------------------------------------------------------   
  • time1:                     ;定时器1中断服务程序   
  •          push  psw         ;保护现场   
  •          push  acc  
  •          push  b  
  •                            ;以下是秒计数器值个位十位分开   
  •          mov   a,sec       ;秒计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   sec_l,b     ;余数b(秒个位值)送入秒个位存储单元   
  •          mov   sec_h,a     ;商a(秒十位值)送入秒十位存储单元   
  •                            ;以下是分计数器值个位十位分开   
  •          mov   a,min       ;分计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   min_l,b     ;余数b(分个位值)送入分个位存储单元   
  •          mov   min_h,a     ;商a(分十位值)送入分十位存储单元   
  •                            ;以下是时计数器值个位十位分开   
  •          mov   a,hou       ;时计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   hou_l,b     ;余数b(时个位值)送入时个位存储单元   
  •          mov   hou_h,a     ;商a(时十位值)送入时十位存储单元   
  •             
  •          mov   dptr,#table ;数码管段码表首址送入dptr   
  •             
  •          mov   a,#sec_l    ;取秒个位值的地址   
  •          add   a,dis_r     ;基址+偏移量   
  •          mov   r0,a        ;R0为欲显示值的地址   
  •          mov   a,@r0       ;取欲显示值送入a   
  •                            ; dis_r  :   0     1     2     3     4     5     6     7   
  •                            ;对应单元: sec_l sec_h bar_2 min_l min_h bar_5 hou_l hou_h   
  •          movc  a,@a+dptr   ;取对应值的段码   
  •          mov   p0,a        ;段码送入P0口   
  •          mov   p2,dis_b    ;位码送入P2口   
  •             
  •          inc   dis_r       ;偏移量加1,下次中断时显示下个数   
  •          anl   dis_r,#0x07 ;dis_r增到8时自动清0(使之在0到7间循环)   
  •             
  •          mov   a,dis_b     ;位码循环右移,下次中断时选通下个数码管   
  •          rr    a  
  •          mov   dis_b,a  
  •             
  •          mov   th1,#0xfc   ;重置定时常数   
  •          mov   tl1,#0x18  
  •             
  •          pop   b  
  •          pop   acc         ;恢复现场   
  •          pop   psw  
  •          reti  
  •   
  • d_10ms:  mov   r5,#20      ;1+(1+2*255)*20+2*20=10.261ms@12M   
  • temp1:   mov   r6,#255     ;1+2*255   
  •          djnz  r6,$   
  •          djnz  r5,temp1   
  •          ret  
  •               
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    -  对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 数码管显示电子钟(C语言)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.3  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  • #include <intrins.h>   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void key_scan();          // 按键扫描   
  • void key_to();            // 按键处理   
  •   
  • uchar code dis_code[11] = {0xc0,0xf9,0xa4,0xb0,0x99,       //段码表   
  •                           // 0    1    2    3    4         对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90,0xbf};   
  •                           // 5    6    7    8    9    -   
  •   
  • uchar data dis[8];       // dis[0]为秒个位值,dis[1]为秒十位值   
  •                          // dis[2],dis[5]为'-'段码的偏移量   
  •                          // dis[3]为分个位值,dis[4为分十位值   
  •                          // dis[6]为时个位值,dis[7]为时十位值   
  •   
  • uchar data sec = 0;      // 秒计数器(00s-59s)   
  • uchar data min = 0;      // 分计数器(00m-59m)   
  • uchar data hou = 0;      // 时计数器)00h-23h)   
  •   
  • uchar data cou  = 0;     // 软计数器,对10ms时基信号累加到1s   
  •   
  • uchar data dis_b;        // dis_b为位码选通数码管   
  • uchar data dis_r;        // dis_r为取段码时的偏移量   
  •   
  • uchar data key_v = 0;    // 存储键值   
  • uchar data key_t = 0;    // 按键扫描中临时存储键值   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •     P1 = 0xff;           // p1为准双向口,作输入时先写1   
  •     dis[2] = 10;         // '-'在段码表中偏移量为10   
  •     dis[5] = 10;         // '-'在段码表中偏移量为10   
  •     dis_b = 0x7f;        // 初始选通P2.7口数码管   
  •     dis_r = 0;           // 初始化偏移量为0   
  •        
  •     TMOD = 0x11;         // 定时/计数器0,1工作于方式1   
  •     TH0 = 0xd8;          // 预置定时常数55536(d8f0),产生10ms时基信号   
  •     TL0 = 0xf0;   
  •     TH1 = 0xfc;          // 预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •     TH1 = 0x18;   
  •     EA = 1;              // 开总中断   
  •     ET0 = 1;             // 定时/计数器0允许中断   
  •     ET1 = 1;             // 定时/计数器1允许中断   
  •     TR0 = 1;             // 开闭定时/计数器0   
  •     TR1 = 1;             // 启动定时/计数器1   
  •     while(1)   
  •     {   
  •         key_t = P1;            // 读入键值   
  •         if(key_t != key_v)     // 键值改变   
  •         {   
  •             delay_ms(10);      // 延时10ms消抖   
  •             key_t = P1;        // 再次读入键值   
  •             if(key_t != key_v) // 键值仍未改变则不是抖动   
  •             {   
  •                 key_v = key_t; // 保存键值   
  •                 key_to();      // 键处理   
  •             }   
  •         }   
  •     }   
  • }   
  • void key_to()                  // 按键处理子程序   
  • {   
  •     if(key_v == 0xef)          // P1.4口键值   
  •     {   
  •         if(min == 59)          // 分计数已加到59   
  •             min = 0;           // 清零之   
  •         else  
  •             min++;             // 否则加1   
  •     }   
  •     else  
  •     {   
  •         if(key_v == 0xdf)      // P1.5口键值   
  •         {   
  •             if(hou == 23)      // 时计数已加到23   
  •                 hou = 0;       // 清零之   
  •             else  
  •                 hou++;         // 否则加1   
  •         }   
  •     }   
  • }   
  • void tiem0(voidinterrupt 1   // T/C0中断服务程序(产生10ms时基信号)   
  • {   
  •     cou++;                     // 软计数器加1   
  •     if(cou == 100)             // 计数值到100(1s)   
  •     {   
  •         cou = 0;               // 软计数器清零   
  •         sec++;                 // 秒计数器加1(进位10ms*100=1s)   
  •         if(sec == 60)          // 秒计数值到60   
  •         {   
  •             sec = 0;           // 秒计数器清零   
  •             min++;             // 分计数器加1(进位60s=1m)   
  •             if(min == 60)      // 分计数到60   
  •             {   
  •                 min = 0;       // 分计数器清零   
  •                 hou++;         // 时计数器加1(进位60m=1h)   
  •                 if(hou == 23)  // 时计数到23   
  •                     hou = 0;   // 时计数器清零   
  •             }   
  •         }   
  •     }   
  •     TH0 = 0xd8;                // 重置定时常数   
  •     TL0 = 0xf0;   
  • }   
  • void time1(voidinterrupt 3   // T/C1中断服务程序(延时1ms数码管动态显示)   
  • {   
  •     dis[0] = sec % 10;         // 秒计数器个位赋绐dis[0]   
  •     dis[1] = sec / 10;         // 秒计数器十位赋绐dis[1]   
  •     dis[3] = min % 10;         // 分计数器个位赋绐dis[3]   
  •     dis[4] = min / 10;         // 分计数器十位赋绐dis[4]   
  •     dis[6] = hou % 10;         // 时计数器个位赋绐dis[6]   
  •     dis[7] = hou / 10;         // 时计数器十位赋绐dis[7]   
  •   
  •     P0 = dis_code[dis[dis_r]]; // 段码送P0口(dis[0]...dis[7])   
  •     P2 = dis_b;                // 位码送P2口   
  •   
  •     dis_r++;                   // 偏移量加1,下次中断时显示下个数   
  •     dis_r &= 0x07;             // dis_r增到8时自动清0(使之在0到7间循环)   
  •        
  •     dis_b = _cror_(dis_b,1);   // 位码循环右移,下次中断时选通下个数码管   
  •   
  •     TH1 = 0xfc;                // 重置定时常数   
  •     TL1 = 0x18;   
  •   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }



  • 阅读全文(4553) | 评论:6 | 复制链接

    【044】秒表-八位数码管显示(2007-5-5 16:31:00)

  • ;**************************************************************************   
  • ; 标题: 秒表-八位数码管显示(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.3   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  • dot_l  equ  30h        ;30单元存储百分之一秒值   
  • dot_h  equ  31h        ;31单元存储十分之一秒值   
  • sec_l  equ  32h        ;32单元存储秒个位值   
  • sec_h  equ  33h        ;33单元存储秒十位值   
  • min_l  equ  34h        ;34单元存储分个位值   
  • min_h  equ  35h        ;35单元存储分十位值   
  • hou_l  equ  36h        ;36单元存储时个位值   
  • hou_h  equ  37h        ;37单元存储时十位值   
  •   
  • dot    equ  38h        ;38单元为百分之一秒计数器(0.00s-0.99s)   
  • sec    equ  39h        ;39单元为秒计数器(00s-59s)   
  • min    equ  40h        ;40单元为分计数器(00m-59m)   
  • hou    equ  41h        ;41单元为时计数器(00h-00h)   
  •   
  • dis_b  equ  42h        ;dis_b(42单元)作为位码选通数码管   
  • dis_r  equ  43h        ;dis_r(43单元)为取段码时的偏移量   
  •   
  • key_t  equ  44h        ;44单元为键按下的次数标记   
  •   
  • K      bit  p1.4       ;K键与P1.4相连   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh          ;定时器0的中断入口地址   
  •           ajmp  time0          ;跳到定时器0的中断服务程序处   
  •           org   001bh          ;定时器1的中断入口地址   
  •           ajmp  time1          ;跳到定时器1的中断服务程序处   
  •           org   0030h  
  • start:       
  •           mov   p2,#0xff       ;关所有数码管   
  •           mov   p1,#0xff       ;p1为准双向口,作输入时先写1   
  •   
  •           mov   dis_b,#0x7f    ;初始选通P2.7口数码管   
  •           mov   dis_r,#0       ;初始化偏移量为0   
  •           mov   dot,#0         ;百分之一秒计数器清零   
  •           mov   sec,#0         ;秒计数清零   
  •           mov   min,#0         ;分计数清零   
  •           mov   hou,#0         ;时计数清零   
  •           mov   key_t,#0       ;键按下次数清零   
  •              
  •           mov  tmod,#00010001b ;定时/计数器0、1工作于方式1   
  •           mov  th0,#0xd8       ;预置定时常数55536(d8f0),产生10ms时基信号   
  •           mov  tl0,#0xf0  
  •           mov  th1,#0xfc       ;预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •           mov  tl1,#0x18  
  •              
  •           setb ea              ;开总中断   
  •           setb et0             ;定时/计数器0允许中断   
  •           setb et1             ;定时/计数器1允许中断   
  •           clr  tr0             ;关定时/计数器0   
  •           setb tr1             ;开定时/计数器1   
  •              
  • lop:  
  •           jb    K,lop          ;键(P1.4)未按下则返回   
  •           lcall d_10ms         ;延时10ms消抖   
  •           jb    K,lop          ;是抖动则返回重新扫描   
  •           jnb   K,$            ;等待键松开   
  •           lcall key_to         ;调用键处理部分   
  •           ajmp  lop            ;循环显示   
  •   
  • key_to:                        ;键处理子程序   
  •           inc   key_t          ;键按下次数加1   
  •           mov   a,key_t        ;按下次数送入a   
  •           cjne  a,#1,key_2     ;不是1次继续检测是否是第2次   
  •           setb  tr0            ;第1次按下启动定时器0   
  •           ret  
  • key_2:    cjne  a,#2,key_3     ;也不是2次继续检测是否是第3次   
  •           clr   tr0            ;第2次按下关闭定时器0   
  •           ret  
  • key_3:    cjne  a,#3,back      ;也不为3则结束   
  •           mov   dot,#0         ;第3次按下将四个计数器清零   
  •           mov   sec,#0  
  •           mov   min,#0  
  •           mov   hou,#0  
  •           mov   key_t,#0       ;按键次数清零   
  • back:     ret  
  • ;--------------------------------------------------------------------------------   
  • time0:                        ;定时器0中断服务程序   
  •          push  psw            ;保护现场   
  •          push  acc  
  •             
  •          inc   dot            ;百分之一秒计数器加1   
  •          mov   a,dot          ;计数器值送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   dot,#0         ;计到100后清零   
  •          inc   sec            ;秒计数器加1(进位10ms*100=1s)   
  •          mov   a,sec          ;秒计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   sec,#0         ;计到60后秒计数器清零   
  •          inc   min            ;分计数器加1(进位60s=1m)   
  •          mov   a,min          ;分计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   min,#0         ;计到60后分计数器清零,重新计时   
  •          inc   hou            ;时计数器加1(进位60m=1h)   
  •          mov   a,hou          ;时计数器送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   hou,#0         ;计到100后清零   
  •             
  • over:    mov   th0,#0xd8      ;重置定时常数   
  •          mov   tl0,#0xf0  
  •          pop   acc            ;恢复现场   
  •          pop   psw  
  •          reti                 ;中断返回   
  • ;--------------------------------------------------------------------------------   
  • time1:                      ;定时器1中断服务程序   
  •          push  psw          ;保护现场   
  •          push  acc  
  •          push  b  
  •                             ;以下是百分之一秒计数器值个位十位分开   
  •          mov   a,dot        ;百分之一秒计数器值送入a(被除数)   
  •          mov   b,#10        ;除数10送入b   
  •          div   ab           ;a除以b   
  •          mov   dot_l,b      ;余数b(百分之一秒值)送入百分之一秒存储单元   
  •          mov   dot_h,a      ;商a(十分之一秒值)送入十分之一秒存储单元    
  •                             ;以下是秒计数器值个位十位分开   
  •          mov   a,sec        ;秒计数器值送入a(被除数)   
  •          mov   b,#10        ;除数10送入b   
  •          div   ab  
  •          mov   sec_l,b      ;余数b(秒个位值)送入秒个位存储单元   
  •          mov   sec_h,a      ;商a(秒十位值)送入秒十位存储单元   
  •                             ;以下是分计数器值个位十位分开   
  •          mov   a,min        ;分计数器值送入a(被除数)   
  •          mov   b,#10        ;除数10送入b   
  •          div   ab  
  •          mov   min_l,b      ;余数b(分个位值)送入分个位存储单元   
  •          mov   min_h,a      ;商a(分十位值)送入分十位存储单元   
  •                             ;以下是时计数器值个位十位分开   
  •          mov   a,hou        ;时计数器值送入a(被除数)   
  •          mov   b,#10        ;除数10送入b   
  •          div   ab  
  •          mov   hou_l,b      ;余数b(小时个位值)送入时个位存储单元   
  •          mov   hou_h,a      ;商a(小时十位值)送入时十位存储单元   
  •             
  •          mov   dptr,#table  ;数码管段码表首址送入dptr   
  •             
  •          mov   a,#dot_l     ;取百分之一秒值的地址   
  •          add   a,dis_r      ;基址+偏移量   
  •          mov   r0,a         ;R0为欲显示值的地址   
  •          mov   a,@r0        ;取欲显示值送入a   
  •                             ; dis_r  :   0     1     2     3     4     5     6     7   
  •                             ;对应单元: dot_l dot_h sec_l sec_h min_l min_h hou_l hou_h   
  •          movc  a,@a+dptr    ;取对应值的段码   
  •          mov   p2,dis_b     ;位码送入P2口   
  •             
  •          mov   r0,dis_b     ;取位码判断是否为需加小数点的位[liuwentao]   
  •          cjne  r0,#0xdf,b3  ;不是P2.5再判断是否为P2.3   
  •          ajmp  add_dot      ;是P2.5则段码加上小数点显示   
  • b3:      cjne  r0,#0xf7,b1  ;也不是P2.3再判断是否为P2.1   
  •          ajmp  add_dot      ;是P2.3则段码加上小数点显示   
  • b1:      cjne  r0,#0xfd,com ;也不是P2.1则正常送段码   
  •   
  • add_dot: anl   a,#0x7f      ;是P2.5,P2.3,P2.1则段码和7f做与操作使对应位显示小数点   
  • com:     mov   p0,a         ;段码送入P0口   
  •   
  •          inc   dis_r        ;偏移量加1,下次中断时显示下个数   
  •          anl   dis_r,#0x07  ;dis_r增到8时自动清0(使之在0到7间循环)   
  •             
  •          mov   a,dis_b      ;位码循环右移,下次中断时选通下个数码管   
  •          rr    a  
  •          mov   dis_b,a  
  •             
  •          mov   th1,#0xfc    ;重置定时常数   
  •          mov   tl1,#0x18  
  •             
  •          pop   b  
  •          pop   acc          ;恢复现场   
  •          pop   psw  
  •          reti  
  •   
  • d_10ms:  mov   r5,#20       ;1+(1+2*255)*20+2*20=10.261ms@12M   
  • temp1:   mov   r6,#255      ;1+2*255   
  •          djnz  r6,$   
  •          djnz  r5,temp1   
  •          ret  
  •               
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    -  对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 八位数码管显示(C语言)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.3  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  • #include <intrins.h>   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void key_scan();          // 按键扫描   
  • void key_to();            // 按键处理   
  •   
  • uchar code dis_code[11] = {0xc0,0xf9,0xa4,0xb0,0x99,       //段码表   
  •                           // 0    1    2    3    4           对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90,0xbf};   
  •                           // 5    6    7    8    9    -   
  •   
  • uchar data dis[8];       // dis[0]为百分之一秒值,dis[1]为十分之一秒值   
  •                          // dis[2]为秒个位值,dis[3]为秒十位值   
  •                          // dis[4]为分个位值,dis[5]为分十位值   
  •                          // dis[5]为时个位值,dis[6]为时十位值   
  •   
  • uchar data dot = 0;      // 百分之一秒计数器(0.00s-0.99s)   
  • uchar data sec = 0;      // 秒计数器(00s-59s)   
  • uchar data min = 0;      // 分计数器(00m-59m)   
  • uchar data hou = 0;      // 时计数器(00h-99h)   
  •   
  • uchar data dis_b;        // dis_b为位码选通数码管   
  • uchar data dis_r;        // dis_r为取段码时的偏移量   
  •   
  • uchar data key_t = 0;    // 按键次数,初始为0   
  •   
  • sbit  K = P1^4;          // K键与P1.4相连   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •     P1 = 0xff;           // p1为准双向口,作输入时先写1   
  •     dis[2] = 10;         // '-'在段码表中偏移量为10   
  •     dis[5] = 10;         // '-'在段码表中偏移量为10   
  •     dis_b = 0x7f;        // 初始选通P2.7口数码管   
  •     dis_r = 0;           // 初始化偏移量为0   
  •        
  •     TMOD = 0x11;         // 定时/计数器0,1工作于方式1   
  •     TH0 = 0xd8;          // 预置定时常数55536(d8f0),产生10ms时基信号   
  •     TL0 = 0xf0;   
  •     TH1 = 0xfc;          // 预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •     TH1 = 0x18;   
  •     EA = 1;              // 开总中断   
  •     ET0 = 1;             // 定时/计数器0允许中断   
  •     ET1 = 1;             // 定时/计数器1允许中断   
  •     TR0 = 0;             // 关闭定时/计数器0   
  •     TR1 = 1;             // 启动定时/计数器1   
  •     while(1)   
  •     {   
  •         if(K != 1)             // 有键按下   
  •         {   
  •             delay_ms(10);      // 延时10ms去抖   
  •             if(K != 1)         // 确定是有键按下   
  •             {   
  •                 while(K != 1); // 等待键松开   
  •                 key_to();      // 按键处理   
  •             }   
  •         }   
  •     }   
  • }   
  • void key_to()                  // 按键处理子程序   
  • {   
  •     key_t++;                   // 按键次数加1   
  •     if(key_t == 1)             // 第一次按下   
  •         TR0 = 1;               // 启动定时器0   
  •     else  
  •     {   
  •         if(key_t == 2)         // 第二次按下   
  •             TR0 = 0;           // 关闭定时器0   
  •         else  
  •         {   
  •             if(key_t == 3)     // 第三次按下   
  •             {   
  •                 dot = 0;       // 四个计数器清零   
  •                 sec = 0;   
  •                 min = 0;   
  •                 hou = 0;   
  •                 key_t = 0;     // 按键次数清零   
  •             }   
  •         }   
  •     }   
  •   
  • }   
  • void tiem0(voidinterrupt 1   // T/C0中断服务程序(产生10ms时基信号)   
  • {   
  •     dot++;                     // 百分之一秒计数器加1   
  •     if(dot == 100)             // 计数值到100   
  •     {   
  •         dot = 0;               // 清零   
  •         sec++;                 // 秒计数器加1(进位10ms*100=1s)   
  •         if(sec == 60)          // 秒计数值到60   
  •         {   
  •             sec = 0;           // 秒计数器清零   
  •             min++;             // 分计数器加1(进位60s=1m)   
  •             if(min == 60)      // 分计数到60   
  •             {   
  •                 min = 0;       // 分计数器清零   
  •                 hou++;         // 时计数器加1(进位60m=1h)   
  •                 if(hou == 100) // 时计数器到100   
  •                     hou = 0;   // 时计数器清零   
  •             }   
  •         }   
  •     }   
  •     TH0 = 0xd8;                // 重置定时常数   
  •     TL0 = 0xf0;   
  • }   
  • void time1(voidinterrupt 3   // T/C1中断服务程序(延时1ms数码管动态显示)   
  • {   
  •     uchar data t = 0;          // 段码临时变量   
  •        
  •     dis[0] = dot % 10;         // 百分之一秒计数器个位分离出来赋绐dis[0]   
  •     dis[1] = dot / 10;         // 百分之一秒计数器十位分离出来赋绐dis[1]   
  •     dis[2] = sec % 10;         // 秒计数器个位赋绐dis[2]   
  •     dis[3] = sec / 10;         // 秒计数器十位赋绐dis[3]   
  •     dis[4] = min % 10;         // 分计数器个位赋绐dis[4]   
  •     dis[5] = min / 10;         // 分计数器十位赋绐dis[5]   
  •     dis[6] = hou % 10;         // 时计数器个位赋绐dis[6]   
  •     dis[7] = hou / 10;         // 时计数器十位赋绐dis[7]   
  •        
  •     t = dis_code[dis[dis_r]];  // 取出段码放入临时变量t   
  •        
  •     // 判断位码如果为显示P2.5,P2.3,P2.1则对应段码应加上小数点显示   
  •     // 和0x7f(01111111)做与操作使原段码加上小数点变为新段码   
  •        
  •     if(dis_b == 0xdf | dis_b == 0xf7 | dis_b == 0xfd)   
  •         t &= 0x7f;   
  •        
  •     P2 = dis_b;                // 位码送P2口   
  •     P0 = t;                    // 段码送P0口   
  •   
  •     dis_r++;                   // 偏移量加1,下次中断时显示下个数   
  •     dis_r &= 0x07;             // dis_r增到8时自动清0(使之在0到7间循环)   
  •        
  •     dis_b = _cror_(dis_b,1);   // 位码循环右移,下次中断时选通下个数码管   
  •   
  •     TH1 = 0xfc;                // 重置定时常数   
  •     TL1 = 0x18;   
  •   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }



  • 阅读全文(3456) | 评论:9 | 复制链接

    【043】秒表-六位数码管有效显示(2007-5-5 16:30:00)

  • ;**************************************************************************   
  • ; 标题: 秒表-六位数码管有效显示(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.2   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  • dot_l  equ  30h        ;30单元存储百分之一秒值   
  • dot_h  equ  31h        ;31单元存储十分之一秒值   
  • bar_2  equ  32h        ;32单元存储"-"段码的偏移量   
  • sec_l  equ  33h        ;33单元存储秒个位值   
  • sec_h  equ  34h        ;34单元存储秒十位值   
  • bar_5  equ  35h        ;35单元存储"-"段码的偏移量   
  • min_l  equ  36h        ;36单元存储分个位值   
  • min_h  equ  37h        ;37单元存储分十位值   
  •   
  • dot    equ  38h        ;38单元为百分之一秒计数器(0.00s-0.99s)   
  • sec    equ  39h        ;39单元为秒计数器(00s-59s)   
  • min    equ  40h        ;40单元为分计数器(00m-99m)   
  •   
  • dis_b  equ  41h        ;dis_b(41单元)作为位码选通数码管   
  • dis_r  equ  42h        ;dis_r(42单元)为取段码时的偏移量   
  •   
  • key_t  equ  43h        ;43单元为键按下的次数标记   
  •   
  • K      bit  p1.4       ;K键与P1.4相连   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh          ;定时器0的中断入口地址   
  •           ajmp  time0          ;跳到定时器0的中断服务程序处   
  •           org   001bh          ;定时器1的中断入口地址   
  •           ajmp  time1          ;跳到定时器1的中断服务程序处   
  •           org   0030h  
  • start:       
  •           mov   p2,#0xff       ;关所有数码管   
  •           mov   p1,#0xff       ;p1为准双向口,作输入时先写1   
  •              
  •           mov   bar_2,#10      ;'-'段码偏移量为10   
  •           mov   bar_5,#10      ;'-'段码偏移量为10   
  •           mov   dis_b,#0x7f    ;初始选通P2.7口数码管   
  •           mov   dis_r,#0       ;初始化偏移量为0   
  •           mov   dot,#0         ;百分之一秒计数器清零   
  •           mov   sec,#0         ;秒计数清零   
  •           mov   min,#0         ;分计数清零   
  •           mov   key_t,#0       ;键按下次数清零   
  •              
  •           mov  tmod,#00010001b ;定时/计数器0、1工作于方式1   
  •           mov  th0,#0xd8       ;预置定时常数55536(d8f0),产生10ms时基信号   
  •           mov  tl0,#0xf0  
  •           mov  th1,#0xfc       ;预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •           mov  tl1,#0x18  
  •              
  •           setb ea              ;开总中断   
  •           setb et0             ;定时/计数器0允许中断   
  •           setb et1             ;定时/计数器1允许中断   
  •           clr  tr0             ;关定时/计数器0   
  •           setb tr1             ;开定时/计数器1   
  •              
  • lop:  
  •           jb    K,lop          ;键(P1.4)未按下则返回   
  •           lcall d_10ms         ;延时10ms消抖   
  •           jb    K,lop          ;是抖动则返回重新扫描   
  •           jnb   K,$            ;等待键松开   
  •           lcall key_to         ;调用键处理部分   
  •           ajmp  lop            ;循环显示   
  •   
  • key_to:                        ;键处理子程序   
  •           inc   key_t          ;键按下次数加1   
  •           mov   a,key_t        ;按下次数送入a   
  •           cjne  a,#1,key_2     ;不是1次继续检测是否是第2次   
  •           setb  tr0            ;第1次按下启动定时器0   
  •           ret  
  • key_2:    cjne  a,#2,key_3     ;也不是2次继续检测是否是第3次   
  •           clr   tr0            ;第2次按下关闭定时器0   
  •           ret  
  • key_3:    cjne  a,#3,back      ;也不为3则结束   
  •           mov   dot,#0         ;第3次按下将三个计数器清零   
  •           mov   sec,#0  
  •           mov   min,#0  
  •           mov   key_t,#0       ;按键次数清零   
  • back:     ret  
  • ;--------------------------------------------------------------------------------   
  • time0:                        ;定时器0中断服务程序   
  •          push  psw            ;保护现场   
  •          push  acc  
  •             
  •          inc   dot            ;百分之一秒计数器加1   
  •          mov   a,dot          ;计数器值送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   dot,#0         ;计到100后清零   
  •          inc   sec            ;秒计数器加1(进位10ms*100=1s)   
  •          mov   a,sec          ;秒计数值送入a   
  •          cjne  a,#60,over     ;未计到60则返回继续计数   
  •          mov   sec,#0         ;计到60后秒计数器清零   
  •          inc   min            ;分计数器加1(进位60s=1m)   
  •          mov   a,min          ;分计数值送入a   
  •          cjne  a,#100,over    ;未计到100则返回继续计数   
  •          mov   min,#0         ;计到100后分计数器清零,重新计时   
  •             
  • over:    mov   th0,#0xd8      ;重置定时常数   
  •          mov   tl0,#0xf0  
  •          pop   acc            ;恢复现场   
  •          pop   psw  
  •          reti                 ;中断返回   
  • ;--------------------------------------------------------------------------------   
  • time1:                     ;定时器1中断服务程序   
  •          push  psw         ;保护现场   
  •          push  acc  
  •          push  b  
  •                            ;以下是百分之一秒计数器值个位十位分开   
  •          mov   a,dot       ;百分之一秒计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab          ;a除以b   
  •          mov   dot_l,b     ;余数b(百分之一秒值)送入百分之一秒存储单元   
  •          mov   dot_h,a     ;商a(十分之一秒值)送入十分之一秒存储单元    
  •                            ;以下是秒计数器值个位十位分开   
  •          mov   a,sec       ;秒计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   sec_l,b     ;余数b(秒个位值)送入秒个位存储单元   
  •          mov   sec_h,a     ;商a(秒十位值)送入秒十位存储单元   
  •                            ;以下是分计数器值个位十位分开   
  •          mov   a,min       ;分计数器值送入a(被除数)   
  •          mov   b,#10       ;除数10送入b   
  •          div   ab  
  •          mov   min_l,b     ;余数b(分个位值)送入分个位存储单元   
  •          mov   min_h,a     ;商a(分十位值)送入分十位存储单元   
  •             
  •          mov   dptr,#table ;数码管段码表首址送入dptr   
  •             
  •          mov   a,#dot_l    ;取百分之一秒值的地址   
  •          add   a,dis_r     ;基址+偏移量   
  •          mov   r0,a        ;R0为欲显示值的地址   
  •          mov   a,@r0       ;取欲显示值送入a   
  •                            ; dis_r  :   0     1     2     3     4     5     6     7   
  •                            ;对应单元: dot_l dot_h bar_2 sec_l sec_h bar_5 min_l min_h   
  •          movc  a,@a+dptr   ;取对应值的段码   
  •          mov   p0,a        ;段码送入P0口   
  •          mov   p2,dis_b    ;位码送入P2口   
  •             
  •          inc   dis_r       ;偏移量加1,下次中断时显示下个数   
  •          anl   dis_r,#0x07 ;dis_r增到8时自动清0(使之在0到7间循环)   
  •             
  •          mov   a,dis_b     ;位码循环右移,下次中断时选通下个数码管   
  •          rr    a  
  •          mov   dis_b,a  
  •             
  •          mov   th1,#0xfc   ;重置定时常数   
  •          mov   tl1,#0x18  
  •             
  •          pop   b  
  •          pop   acc         ;恢复现场   
  •          pop   psw  
  •          reti  
  •   
  • d_10ms:  mov   r5,#20      ;1+(1+2*255)*20+2*20=10.261ms@12M   
  • temp1:   mov   r6,#255     ;1+2*255   
  •          djnz  r6,$   
  •          djnz  r5,temp1   
  •          ret  
  •               
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    -  对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 秒表-六位数码管有效显示(C51)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.3  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  • #include <intrins.h>   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void key_scan();          // 按键扫描   
  • void key_to();            // 按键处理   
  •   
  • uchar code dis_code[11] = {0xc0,0xf9,0xa4,0xb0,0x99,       //段码表   
  •                           // 0    1    2    3    4         对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90,0xbf};   
  •                           // 5    6    7    8    9    -   
  •   
  • uchar data dis[8];       // dis[0]为百分之一秒值,dis[1]为十分之一秒值   
  •                          // dis[2],dis[5]为'-'段码的偏移量   
  •                          // dis[3]为秒个位值,dis[4]为秒十位值   
  •                          // dis[6]为分个位值,dis[7]为分十位值   
  •   
  • uchar data dot = 0;      // 百分之一秒计数器(0.00s-0.99s)   
  • uchar data sec = 0;      // 秒计数器(00s-59s)   
  • uchar data min = 0;      // 分计数器(00m-99m)   
  •   
  • uchar data dis_b;        // dis_b为位码选通数码管   
  • uchar data dis_r;        // dis_r为取段码时的偏移量   
  •   
  • uchar data key_t = 0;    // 按键次数,初始为0   
  •   
  • sbit  K = P1^4;          // K键与P1.4相连   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •     P1 = 0xff;           // p1为准双向口,作输入时先写1   
  •     dis[2] = 10;         // '-'在段码表中偏移量为10   
  •     dis[5] = 10;         // '-'在段码表中偏移量为10   
  •     dis_b = 0x7f;        // 初始选通P2.7口数码管   
  •     dis_r = 0;           // 初始化偏移量为0   
  •        
  •     TMOD = 0x11;         // 定时/计数器0,1工作于方式1   
  •     TH0 = 0xd8;          // 预置定时常数55536(d8f0),产生10ms时基信号   
  •     TL0 = 0xf0;   
  •     TH1 = 0xfc;          // 预置定时常数64536(fc18),产生1ms间隔用于动态显示   
  •     TH1 = 0x18;   
  •     EA = 1;              // 开总中断   
  •     ET0 = 1;             // 定时/计数器0允许中断   
  •     ET1 = 1;             // 定时/计数器1允许中断   
  •     TR0 = 0;             // 关闭定时/计数器0   
  •     TR1 = 1;             // 启动定时/计数器1   
  •     while(1)   
  •     {   
  •         if(K != 1)             // 有键按下   
  •         {   
  •             delay_ms(10);      // 延时10ms去抖   
  •             if(K != 1)         // 确定是有键按下   
  •             {   
  •                 while(K != 1); // 等待键松开   
  •                 key_to();      // 按键处理   
  •             }   
  •         }   
  •     }   
  • }   
  • void key_to()                  // 按键处理子程序   
  • {   
  •     key_t++;                   // 按键次数加1   
  •     if(key_t == 1)             // 第一次按下   
  •         TR0 = 1;               // 启动定时器0   
  •     else  
  •     {   
  •         if(key_t == 2)         // 第二次按下   
  •             TR0 = 0;           // 关闭定时器0   
  •         else  
  •         {   
  •             if(key_t == 3)     // 第三次按下   
  •             {   
  •                 dot = 0;       // 三个计数器清零   
  •                 sec = 0;   
  •                 min = 0;   
  •                 key_t = 0;     // 按键次数清零   
  •             }   
  •         }   
  •     }   
  •   
  • }   
  • void tiem0(voidinterrupt 1   // T/C0中断服务程序(产生10ms时基信号)   
  • {   
  •     dot++;                     // 百分之一秒计数器加1   
  •     if(dot == 100)             // 计数值到100   
  •     {   
  •         dot = 0;               // 清零   
  •         sec++;                 // 秒计数器加1(进位10ms*100=1s)   
  •         if(sec == 60)          // 秒计数值到60   
  •         {   
  •             sec = 0;           // 秒计数器清零   
  •             min++;             // 分计数器加1(进位60s=1m)   
  •             if(min == 100)     // 分计数到100   
  •                 min = 0;       // 分计数器清零   
  •         }   
  •     }   
  •     TH0 = 0xd8;                // 重置定时常数   
  •     TL0 = 0xf0;   
  • }   
  • void time1(voidinterrupt 3   // T/C1中断服务程序(延时1ms数码管动态显示)   
  • {   
  •     dis[0] = dot % 10;         // 百分之一秒计数器个位分离出来赋绐dis[0]   
  •     dis[1] = dot / 10;         // 百分之一秒计数器十位分离出来赋绐dis[1]   
  •     dis[3] = sec % 10;         // 秒计数器个位赋绐dis[3]   
  •     dis[4] = sec / 10;         // 秒计数器十位赋绐dis[4]   
  •     dis[6] = min % 10;         // 分计数器个位赋绐dis[6]   
  •     dis[7] = min / 10;         // 分计数器十位赋绐dis[7]   
  •   
  •     P0 = dis_code[dis[dis_r]]; // 段码送P0口(dis[0]...dis[7])   
  •     P2 = dis_b;                // 位码送P2口   
  •   
  •     dis_r++;                   // 偏移量加1,下次中断时显示下个数   
  •     dis_r &= 0x07;             // dis_r增到8时自动清0(使之在0到7间循环)   
  •        
  •     dis_b = _cror_(dis_b,1);   // 位码循环右移,下次中断时选通下个数码管   
  •   
  •     TH1 = 0xfc;                // 重置定时常数   
  •     TL1 = 0x18;   
  •   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }



  • 阅读全文(2702) | 评论:1 | 复制链接

    【042】四位数码管对外部中断0响应计数(2007-5-5 16:29:00)

  • ;**************************************************************************   
  • ; 标题: 四位数码管对外部中断0响应计数(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.2.28   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  •          org   0000h  
  •          ajmp  start   
  •          org   0003h        ;外部中断0入口   
  •          ljmp  int_0        ;跳到外部中断0的中断服务程序处   
  •          org   0030h  
  • start:   mov   30h,#0       ;30单元存储个位值   
  •          mov   31h,#0       ;31单元存储十位值   
  •          mov   32h,#0       ;32单元存储百位值   
  •          mov   33h,#0       ;33单元存储千位值   
  •          mov   p2,#0xff     ;关所有数码管   
  •          mov   dptr,#table  ;数码管段码表首址送入dptr   
  •             
  •          setb  it0          ;外部中断0下降沿触发   
  •          setb  ea           ;开总中断   
  •          setb  ex0          ;开外部中断0   
  •             
  • lop:     lcall display      ;调用显示子程序   
  •          ajmp  lop          ;循环等待中断发生   
  •   
  • int_0:                      ;外部中断0的中断服务程序   
  •          inc   30h          ;个位值加1   
  •          mov   a,30h        ;个位值送入a   
  •          cjne  a,#10,over   ;个位未到10则结束此次循环   
  •          mov   30h,#0       ;个位到10清零   
  •             
  •          inc   31h          ;十位值加1(个位到10的进位)   
  •          mov   a,31h        ;十位值送入a   
  •          cjne  a,#10,over   ;十位未到10则结束此次循环   
  •          mov   31h,#0       ;十位到10清零   
  •             
  •          inc   32h          ;百位值加1(十位到10的进位)   
  •          mov   a,32h        ;百位值送入a   
  •          cjne  a,#10,over   ;百位未到10则结束此次循环   
  •          mov   32h,#0       ;百位到10清零   
  •             
  •          inc   33h          ;千位值加1(百位到10的进位)   
  •          mov   a,33h        ;千位值送入a   
  •          cjne  a,#10,over   ;千位未到10则结束此次循环   
  •          mov   33h,#0       ;千位到10清零   
  •   
  • over:    reti               ;中断返回   
  •   
  • display:                    ;显示子程序            
  •          mov   r0,#50       ;用于延长四位数的显示时间   
  • d_lop:      
  •          mov   a,30h        ;取个位值   
  •          movc  a,@a+dptr    ;个位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0x7f     ;开个位显示(P2.7口控制个位数码管)   
  •          lcall d_1ms        ;延时1ms使四位数码管动态显示时能看清   
  •             
  •          mov   a,31h        ;取十位值   
  •          movc  a,@a+dptr    ;十位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xbf     ;开十位显示(P2.6口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          mov   a,32h        ;取百位值   
  •          movc  a,@a+dptr    ;百位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xdf     ;开百位显示(P2.5口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          mov   a,33h        ;取千位值   
  •          movc  a,@a+dptr    ;千位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xef     ;开千位显示(P2.4口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          djnz  r0,d_lop     ;延长每个四位数的显示时间   
  •          ret  
  •   
  • d_1ms:                      ;延时1ms子程序@12M(1.001ms)   
  •          mov   r7,#250      ;1+(1+1+2)*250=1001   
  • temp:    nop  
  •          nop  
  •          djnz  r7,temp   
  •          ret  
  •   
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90  ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 四位数码管对外部中断0响应计数(C51)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.2  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  •   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void display();           // 显示子程序   
  •   
  • uchar code dis_code[10] = {0xc0,0xf9,0xa4,0xb0,0x99,  //段码表   
  •                           // 0    1    2    3    4      对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90};   
  •                           // 5    6    7    8    9   
  •   
  • uchar data dis_0 = 0;     // 个位值   
  • uchar data dis_1 = 0;     // 十位值   
  • uchar data dis_2 = 0;     // 百位值   
  • uchar data dis_3 = 0;     // 千位值   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •        
  •     IT0 = 1;             // 外部中断0下降沿触发   
  •     EA = 1;              // 开总中断   
  •     EX0 = 1;             // 开外部中断0   
  •        
  •     while(1)   
  •     {   
  •         display();       // 调用显示子程序等待中断   
  •     }   
  • }   
  •   
  • void int_0() interrupt 0             // 外部中断0中断服务程序   
  • {   
  •         dis_0++;                     // 个位值加1   
  •         if(dis_0 == 10)              // 个位未到10则结束   
  •         {   
  •             dis_0 = 0;               // 个位到10清零           
  •             dis_1++;                 // 十位值加1(个位到10的进位)   
  •             if(dis_1 == 10)          // 十位未到10则结束   
  •             {   
  •                 dis_1 = 0;           // 十位到10清零           
  •                 dis_2++;             // 百位值加1(十位到10的进位)   
  •                 if(dis_2 == 10)      // 百位未到10则结束   
  •                 {   
  •                     dis_2 = 0;       // 百位到10清零           
  •                     dis_3++;         // 千位值加1(百位到10的进位)   
  •                     if(dis_3 == 10)  // 千位未到10则结束   
  •                         dis_3 = 0;   // 千位到10清零   
  •                 }   
  •             }   
  •         }   
  • }   
  •   
  • void display()                // 显示子程序   
  • {   
  •     uchar data i = 50;        // 用于延长每四位数的显示时间   
  •     while(i--)                // 直到i减为0   
  •     {   
  •         P0 = dis_code[dis_0]; // 取个位的段码   
  •         P2 = 0x7f;            // 开个位显示(P2.7口控制个位数码管)   
  •         delay_ms(1);          // 延时1ms使四位数码管动态显示时能看清   
  •            
  •         P0 = dis_code[dis_1]; // 取十位的段码   
  •         P2 = 0xbf;            // 开十位显示(P2.6口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •            
  •         P0 = dis_code[dis_2]; // 取百位的段码   
  •         P2 = 0xdf;            // 开百位显示(P2.5口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •            
  •         P0 = dis_code[dis_3]; // 取千位的段码   
  •         P2 = 0xef;            // 开千位显示(P2.4口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •     }   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }  



  • 阅读全文(2318) | 评论:0 | 复制链接

    【041】四位数码管计数演示(2007-5-5 16:28:00)

  • ;**************************************************************************   
  • ; 标题: 四位数码管计数演示(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.2   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  •          org   0000h  
  •          ajmp  start   
  •          org   0030h  
  • start:   mov   30h,#0       ;30单元存储个位值   
  •          mov   31h,#0       ;31单元存储十位值   
  •          mov   32h,#0       ;32单元存储百位值   
  •          mov   33h,#0       ;33单元存储千位值   
  •          mov   p2,#0xff     ;关所有数码管   
  •          mov   dptr,#table  ;数码管段码表首址送入dptr   
  •             
  • lop:     lcall display      ;调用显示子程序   
  •   
  •          inc   30h          ;个位值加1   
  •          mov   a,30h        ;个位值送入a   
  •          cjne  a,#10,over   ;个位未到10则结束此次循环   
  •          mov   30h,#0       ;个位到10清零   
  •             
  •          inc   31h          ;十位值加1(个位到10的进位)   
  •          mov   a,31h        ;十位值送入a   
  •          cjne  a,#10,over   ;十位未到10则结束此次循环   
  •          mov   31h,#0       ;十位到10清零   
  •             
  •          inc   32h          ;百位值加1(十位到10的进位)   
  •          mov   a,32h        ;百位值送入a   
  •          cjne  a,#10,over   ;百位未到10则结束此次循环   
  •          mov   32h,#0       ;百位到10清零   
  •             
  •          inc   33h          ;千位值加1(百位到10的进位)   
  •          mov   a,33h        ;千位值送入a   
  •          cjne  a,#10,over   ;千位未到10则结束此次循环   
  •          mov   33h,#0       ;千位到10清零   
  •   
  • over:    ajmp  lop          ;循环   
  •   
  • display:                    ;显示子程序            
  •          mov   r0,#50       ;用于延长四位数的显示时间   
  • d_lop:      
  •          mov   a,30h        ;取个位值   
  •          movc  a,@a+dptr    ;个位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0x7f     ;开个位显示(P2.7口控制个位数码管)   
  •          lcall d_1ms        ;延时1ms使四位数码管动态显示时能看清   
  •             
  •          mov   a,31h        ;取十位值   
  •          movc  a,@a+dptr    ;十位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xbf     ;开十位显示(P2.6口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          mov   a,32h        ;取百位值   
  •          movc  a,@a+dptr    ;百位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xdf     ;开百位显示(P2.5口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          mov   a,33h        ;取千位值   
  •          movc  a,@a+dptr    ;千位数对应的段码送入a中   
  •          mov   p0,a         ;段码送入P0口   
  •          mov   p2,#0xef     ;开千位显示(P2.4口控制十位数码管)   
  •          lcall d_1ms        ;延时1ms作用同上   
  •             
  •          djnz  r0,d_lop     ;延长每个四位数的显示时间   
  •          ret  
  •   
  • d_1ms:                      ;延时1ms子程序@12M(1.001ms)   
  •          mov   r7,#250      ;1+(1+1+2)*250=1001   
  • temp:    nop  
  •          nop  
  •          djnz  r7,temp   
  •          ret  
  •   
  • table:  db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90  ;段码表   
  •          ;   0    1    2    3    4    5    6    7    8    9    对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 四位数码管计数演示(C51)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.2  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  •   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void display();           // 显示子程序   
  •   
  • uchar code dis_code[10] = {0xc0,0xf9,0xa4,0xb0,0x99,  //段码表   
  •                           // 0    1    2    3    4      对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90};   
  •                           // 5    6    7    8    9   
  •   
  • uchar data dis_0 = 0;     // 个位值   
  • uchar data dis_1 = 0;     // 十位值   
  • uchar data dis_2 = 0;     // 百位值   
  • uchar data dis_3 = 0;     // 千位值   
  •   
  • void main()   
  • {   
  •     P2 = 0xff;           // 关所有数码管   
  •   
  •     while(1)   
  •     {   
  •         display();       // 调用显示子程序   
  •            
  •         dis_0++;         // 个位值加1   
  •         if(dis_0 != 10)  // 个位未到10则结束此次循环   
  •             continue;   
  •   
  •         dis_0 = 0;       // 个位到10清零           
  •         dis_1++;         // 十位值加1(个位到10的进位)   
  •         if(dis_1 != 10)  // 十位未到10则结束此次循环   
  •             continue;   
  •   
  •         dis_1 = 0;       // 十位到10清零           
  •         dis_2++;         // 百位值加1(十位到10的进位)   
  •         if(dis_2 != 10)  // 百位未到10则结束此次循环   
  •             continue;   
  •   
  •         dis_2 = 0;       // 百位到10清零           
  •         dis_3++;         // 千位值加1(百位到10的进位)   
  •         if(dis_3 != 10)  // 千位未到10则结束此次循环   
  •             continue;   
  •   
  •         dis_3 = 0;       // 千位到10清零   
  •     }   
  • }   
  • void display()                // 显示子程序   
  • {   
  •     uchar data i = 50;        // 用于延长每四位数的显示时间   
  •     while(i--)                // 直到i减为0   
  •     {   
  •         P0 = dis_code[dis_0]; // 取个位的段码   
  •         P2 = 0x7f;            // 开个位显示(P2.7口控制个位数码管)   
  •         delay_ms(1);          // 延时1ms使四位数码管动态显示时能看清   
  •            
  •         P0 = dis_code[dis_1]; // 取十位的段码   
  •         P2 = 0xbf;            // 开十位显示(P2.6口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •            
  •         P0 = dis_code[dis_2]; // 取百位的段码   
  •         P2 = 0xdf;            // 开百位显示(P2.5口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •            
  •         P0 = dis_code[dis_3]; // 取千位的段码   
  •         P2 = 0xef;            // 开千位显示(P2.4口控制十位数码管)   
  •         delay_ms(1);          // 延时1ms作用同上   
  •     }   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }   
  •   
  • /* 计数部分还可用如下方式实现  
  •  
  •         dis_0++;                     // 个位值加1  
  •         if(dis_0 == 10)              // 个位未到10则结束  
  •         {  
  •             dis_0 = 0;               // 个位到10清零          
  •             dis_1++;                 // 十位值加1(个位到10的进位)  
  •             if(dis_1 == 10)          // 十位未到10则结束  
  •             {  
  •                 dis_1 = 0;           // 十位到10清零          
  •                 dis_2++;             // 百位值加1(十位到10的进位)  
  •                 if(dis_2 == 10)      // 百位未到10则结束  
  •                 {  
  •                     dis_2 = 0;       // 百位到10清零          
  •                     dis_3++;         // 千位值加1(百位到10的进位)  
  •                     if(dis_3 == 10)  // 千位未到10则结束  
  •                         dis_3 = 0;   // 千位到10清零  
  •                 }  
  •             }  
  •         }  
  • */ 



  • 阅读全文(3089) | 评论:3 | 复制链接

    【039】两位数码管对直控按键计数(2007-5-5 16:25:00)

  • ;**************************************************************************   
  • ; 标题: 两位数码管对直控按键计数(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.2   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  •   
  • dis_0 equ 30h        ;dis_0(30单元)存储个位值   
  • dis_1 equ 31h        ;dis_1(31单元)存储十位值   
  • dis_b equ 32h        ;dis_b(32单元)作为位码选通数码管   
  • dis_r equ 33h        ;dis_r(33单元)为切换dis_0和dis_1的偏移量   
  • count equ 34h        ;count(34单元)为计数器   
  • key_v equ 35h        ;key_v(35单元)存储键值   
  • key_t equ 36h        ;key_t(36单元)检测键值时临时存储键值   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh           ;定时器0的中断入口地址   
  •           ajmp  time0           ;跳到定时器0的中断服务程序处   
  •           org   0030h  
  • start:    mov   count,#0        ;计数器清0   
  •           mov   p2,#0xff        ;关所有数码管   
  •           mov   dis_b,#0x7f     ;初始选通P2.7口数码管   
  •           mov   dis_r,#0        ;初始化偏移量为0   
  •             
  •           mov   tmod,#00000001b ;定时/计数器0工作于方式1   
  •           mov   th0,#0xfc       ;预置定时常数64536(fc18)   
  •           mov   tl0,#0x18  
  •           setb  ea              ;开总中断   
  •           setb  et0             ;定时/计数器0允许中断   
  •           setb  tr0             ;启动定时/计数器0   
  •              
  • lop:      lcall key_scan        ;调用键扫描子程序   
  •           lcall key_to          ;调用键处理子程序   
  •           ajmp  lop             ;循环   
  •   
  • ;-------------------------------------------------------------------------   
  • key_scan:                       ;键扫描子程序   
  •           mov   a,p1            ;当前键值送入a   
  •           mov   key_t,a         ;存储到临时变量中   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key_scan        ;未改变则继续扫描   
  •           lcall d_10ms          ;有键按下则延时10ms消抖   
  •           mov   a,p1            ;再次读入键值   
  •           mov   key_t,a         ;键值存储到临时变量中   
  •           xrl   a,key_v         ;检测键值是否改变   
  •           jz    key_scan        ;未改变则继续扫描   
  •           mov   key_v,key_t     ;将最终读到的键值存入key_v   
  •           ret  
  •   
  • key_to:                         ;按键处理子程序   
  •           mov   a,key_v         ;读入键值   
  •           cjne  a,#0xef,next    ;不是P1.4口键值则查下一个   
  •           ajmp  key_1           ;是P1.4口键则转到键处理部分   
  • next:     cjne  a,#0xdf,back    ;也不是P1.5口键值则结束   
  •           ajmp  key_2           ;是P1.5口键则转到键处理部分   
  • back:     ret                   ;结束   
  • key_1:                          ;P1.4口键处理部分   
  •           inc   count           ;计数器加1   
  •           mov   a,count         ;计数器值送入a   
  •           cjne  a,#100,over_1   ;未计到100不处理   
  •           mov   count,#0        ;计到100则清零   
  • over_1:   ret  
  • key_2:                          ;P1.5口键处理部分   
  •           mov   a,count         ;计数器值送入a   
  •           cjne  a,#0,over_2     ;计数值不为0   
  •           mov   count,#99       ;若计数值为0则置为99   
  •           ret  
  • over_2:   dec   count           ;计数值不为0则减1   
  •           ret  
  • ;-------------------------------------------------------------------------   
  •   
  • time0:                       ;定时器0中断服务程序,用于数码管动态显示(1ms)   
  •           mov   dptr,#table  ;段码表首址送入dptr   
  •              
  •           mov   a,count      ;计数器值送入a(被除数)   
  •           mov   b,#10        ;除数10送入b   
  •           div   ab           ;a除以b   
  •           mov   dis_0,b      ;余数b(个位值)送入个位存储单元   
  •           mov   dis_1,a      ;商a(十位值)送入十位存储单元    
  •                              ;以上是将计数值个位十位分开   
  •                              ;以下是将分开的个位十位分别在两个数码管上显示   
  •   
  •           mov   a,#dis_0     ;个位值的地址送入a   
  •           add   a,dis_r      ;基址+偏移量   
  •           mov   r0,a         ;r0为欲显示值的地址   
  •           mov   a,@r0        ;欲显示值送入a   
  •                              ;(dis_t=0时为dis_0值,dis_t=1时为dis_1值)   
  •           movc  a,@a+dptr    ;对应的段码送入a中   
  •           mov   p0,a         ;段码送入P0口   
  •           mov   p2,dis_b     ;位码送入P2口   
  •              
  •           xrl   dis_r,#0x01  ;异或01使偏移量在0和1间切换   
  •           xrl   dis_b,#0xc0  ;异或c0使位码在7f(P2.7)和bf(P2.6)间循环   
  •   
  •           mov   th0,#0xfc    ;重置定时常数64536(fc18)   
  •           mov   tl0,#0x18  
  •           reti  
  •   
  • d_10ms:   mov   r5,#20        ;1+(1+2*255)*20+2*20=10.261ms@12M   
  • temp:     mov   r6,#255       ;1+2*255   
  •           djnz  r6,$   
  •           djnz  r5,temp   
  •           ret  
  •   
  • table:    db 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90  ;段码表   
  •            ;   0    1    2    3    4    5    6    7    8    9    对应内容   
  •   
  • end 


  • /**************************************************************************  
  • * 标题: 两位数码管对直控按键计数(C51)  
  • * 作者: wentao     http://blog.liuwentao.net  
  •                    http://wentao.programfan.com  
  • * 日期: 2007.3.2  
  • * 软件: Keil C51 V8.02  
  • * 芯片: AT89X51  
  • * 说明: 实验板实测通过,数码管为8位共阳  
  • * 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!   
  • **************************************************************************/  
  •   
  • #include <reg51.h>   
  • #define uchar unsigned char   
  •   
  • void delay_ms(uchar ms);  // 延时毫秒@12M,ms最大值255   
  • void key_scan();          // 按键扫描   
  • void key_to(uchar key_v); // 按键处理   
  •   
  • uchar code dis_code[10] = {0xc0,0xf9,0xa4,0xb0,0x99,  //段码表   
  •                           // 0    1    2    3    4      对应内容   
  •                            0x92,0x82,0xf8,0x80,0x90};   
  •                           // 5    6    7    8    9   
  •   
  • uchar data dis[2];        // dis[0]为个位值,dis[1]为十位值   
  • uchar data dis_b;         // 选通数码管的位码   
  • uchar data dis_r;         // 个位十位段码切换的偏移量   
  • uchar data count;         // 计数器   
  • uchar data key_v;         // 存储键值   
  • uchar data key_t;         // 扫描按键时临时存储键值   
  •   
  • void main()   
  • {   
  •     count = 0;           // 计数器清零   
  •     P2 = 0xff;           // 关所有数码管   
  •     dis_b = 0x7f;        // 初始选通P2.7口数码管   
  •     dis_r = 0;           // 初始化偏移量为0   
  •        
  •     TMOD = 0x01;         // 定时/计数器0工作于方式1   
  •     TH0 = 0xfc;          // 装载定时常数64536(fc18)   
  •     TL0 = 0x18;   
  •     EA = 1;              // 开总中断   
  •     ET0 = 1;             // 定时/计数器0允许中断   
  •     TR0 = 1;             // 启动定时/计数器0   
  •     while(1)             // 执行主程序,等待中断   
  •     {   
  •         key_scan();     // 扫描按键   
  •         key_to(key_v);  // 处理按键   
  •     }   
  • }   
  • void key_scan()                // 按键扫描   
  • {   
  •     while(1)   
  •     {   
  •         key_t = P1;            // 读入键值   
  •         if(key_t != key_v)     // 若键值改变   
  •         {   
  •             delay_ms(10);      // 延时10ms消抖   
  •             key_t = P1;        // 再次读入键值   
  •             if(key_t != key_v) // 确定有键按下   
  •             {   
  •                 key_v = key_t; // 保存键值   
  •                 break;         // 跳出循环结束扫描   
  •             }   
  •         }   
  •     }   
  • }   
  • void key_to(uchar key_v)       // 按键处理   
  • {   
  •     if(key_v == 0xef)          // 若为P1.4口按键   
  •     {   
  •         count++;               // 计数器加1   
  •         if(count == 100)       // 计到100后清零   
  •             count = 0;   
  •     }   
  •     else  
  •     {   
  •         if(key_v == 0xdf)      // 若为P1.5口按键   
  •         {   
  •             if(count == 0)     // 若计数器为0则置为99   
  •                 count = 99;   
  •             else               // 不为0则减1   
  •                 count--;   
  •         }   
  •     }   
  • }   
  • void time0(voidinterrupt 1   // T/C0中断服务程序(延时1ms数码管动态显示)   
  • {   
  •     dis[1] = count / 10;       // 计数器十位分离出来赋绐dis[1]   
  •     dis[0] = count % 10;       // 计数器个位分离出来赋绐dis[0]   
  •   
  •     P0 = dis_code[dis[dis_r]]; // 段码送P0口,dis_r=0时为个位dis[0]的值   
  •                                //            dis_r=1时为十位dis[1]的值   
  •     P2 = dis_b;                // 位码送P2口   
  •   
  •     dis_r ^= 0x01;             // 异或01使偏移量在0和1间切换   
  •     dis_b ^= 0xc0;             // 异或c0使位码在7f(P2.7)和bf(P2.6)间循环   
  •   
  •     TH0 = 0xfc;                // 重置定时常数   
  •     TL0 = 0x18;   
  •   
  • }   
  • void delay_ms(uchar ms)       // 延时毫秒@12M,ms最大值255   
  • {   
  •     uchar i;   
  •     while(ms--)   
  •         for(i = 0; i < 124; i++);   
  • }



  • 阅读全文(3360) | 评论:6 | 复制链接

    【040】两位数码管对直控按键计数键增强(加速键)(2007-5-5 16:25:00)

  • ;**************************************************************************   
  • ; 标题: 两位数码管对直控按键计数键增强(加速键)(汇编)   
  • ; 作者: wentao     http://blog.liuwentao.net   
  • ;                  http://wentao.programfan.com   
  • ; 日期: 2007.3.2   
  • ; 软件: Keil A51 V8.00    
  • ; 芯片: AT89X51   
  • ; 说明: 实验板实测通过,数码管为8位共阳   
  • ; 声明: 自用存档!另仅供需要的朋友参考,请勿用做不道德转载及商业用途!    
  • ;**************************************************************************   
  • dis_0       equ 30h        ;dis_0(30单元)存储个位值   
  • dis_1       equ 31h        ;dis_1(31单元)存储十位值   
  • dis_b       equ 32h        ;dis_b(32单元)作为位码选通数码管   
  • dis_r       equ 33h        ;dis_r(33单元)为切换dis_0和dis_1的偏移量   
  • count       equ 34h        ;count(34单元)为计数器   
  • key_v       equ 35h        ;key_v(35单元)存储键值   
  • key_t       equ 36h        ;key_t(36单元)检测键值时临时存储键值   
  • key_age     equ 37h        ;键龄计数器   
  • key_def     equ 38h        ;默认键值   
  •   
  •           org   0000h  
  •           ajmp  start   
  •           org   000bh             ;定时器0的中断入口地址   
  •           ajmp  time0             ;跳到定时器0的中断服务程序处   
  •           org   0030h  
  • start:    mov   count,#0          ;计数器清0   
  •           mov   p2,#0xff          ;关所有数码管   
  •           mov   dis_b,#0x7f       ;初始选通P2.7口数码管   
  •           mov   dis_r,#0          ;初始化偏移量为0   
  •           mov   key_age,#0        ;键龄计数器置0   
  •           mov   key_def,#0xff     ;默认键值为0b11111111,使用P1.4~P1.7,必要时需将低4位屏蔽   
  •             
  •           mov   tmod,#00000001b   ;定时/计数器0工作于方式1   
  •           mov   th0,#0xfc         ;预置定时常数64536(fc18)   
  •           mov   tl0,#0x18  
  •           setb  ea                ;开总中断   
  •           setb  et0               ;定时/计数器0允许中断   
  •           setb  tr0               ;启动定时/计数器0   
  •              
  • lop:      lcall key_scan          ;调用键扫描子程序   
  •           mov   a,key_age         ;读入键龄计数器的值   
  •           cjne  a,#10,general     ;键龄计数值未到10   
  •                                   ;键龄达到预设值,即长按状态下已执行了普通的键处理10次   
  •                                   ;再保持长按状态,则会进行加速键处理   
  •           lcall d_50ms            ;加速键处理时的延时   
  •           ajmp  goon   
  •              
  • general:  inc   key_age           ;长按而未到所需键龄时(这里是10次)对键龄计数器累加   
  •           lcall d_200ms           ;普通键处理时的延时   
  • goon:     lcall key_to            ;调用键处理子程序   
  •           ajmp  lop               ;循环   
  •   
  • ;-------------------------------------------------------------------------   
  • key_scan:                       ;键扫描子程序   
  •           mov   a,p1            ;当前键值送入a   
  •           mov   key_t,a         ;存储到临时变量中   
  •           xrl   a,key_def  &nb