搜索
bottom↓
回复: 6

我看到有的led显示屏的按键具有连_发共能,连_发时数字翻转的很快,我用lcd做显示器连_

[复制链接]

出0入0汤圆

发表于 2008-8-21 15:12:34 | 显示全部楼层 |阅读模式
例如:我在马老师的实验板上装了一块lcd1602,按照demo_9_2.c中的按键连_发功能,编了一段程序。连_发时在lcd上显示加1后的数字。从0-999需要很长时间。观察后1秒钟大约跳2个数字。如何才能加快速度呢?

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2008-8-21 15:21:15 | 显示全部楼层
1 LCD属于慢性器件,所以显示时间远大于LED
2 1秒跳两个数字,只跟程序延时有关,一般LCD的响应时间也是ms级的。
3 跟具描述可能是你的LCD写函数的等待LCD响应的查询(忙检测),进入一个‘死’循环了。可以改成固定延时试试。可能是硬件连接不好引起的忙检测失败。
------
我没有例子,无法测试。

出0入0汤圆

 楼主| 发表于 2008-8-21 15:42:14 | 显示全部楼层
程序是马老师+阿艺的。请测试一下,看看如何能增加显示的速度。在马老师的实验板上装上1602lcd,用cvcvr编译,lcd接的是B口。
按键是PD7

/*下面是<1602LCD.h>文件内容

在使用LCD之前先了解一下4位数据线传输的原理
1:LCD在E由 1->0 时对RS和DB4-DB7进行取样和执行操作
2:RS=0 时表示"准备"写指令,RS=1 时表示"准备"写显示的数据
3:不管是指令数据还是显示数据,数据位都是8位,由于LCD用的是4个数据线,所以在传输时先传输数据的高4位(Msb),
   然后再传输数据的低4位(Lsb)
    比如说我们要写一个指令,指令是0b11001000 ( 高4位是1100,低4位是1000 )  
那么就要这样:
先传输高4位  |  接着传输低4位
   E=1 ;     |    E=1 ;
   RS=0 ;    |    RS=0 ;
   DB7=1;    |    DB7=1;
   DB6=1;    |    DB6=0;
   DB5=0;    |    DB5=0;
   DB4=0;    |    DB4=0;
   E=0;      |    E=0;
这样,我们就完成了写一个指令了,相反,写显示数据时就是把RS=1就可以了
对LCD的写操作只有写指令和写显示数据两种,所以,一个"写指令函数"和一个"写显示数据函数"就可以满足全部要求
// 04:lcd_init()            //LCD初始化函数
// 05:lcd_dictate(byte)     //写指令的函数
// 07:lcd_gotoxy(x,y)       //列行定位函数
// 06:lcd_putchar(byte)     //以ASCII方式显示一个字节变量
// 08:lcd_hex(byte)         //以十六进制显示一个字节变量
// 09:lcd_byte(byte)        //以十进制显示一个字节变量
// 10:lcd_putsf(地址, 个数) //显示FLASH里面的字符串
*/
#include <mega16.h>
#include <delay.h>
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>   
#define RS        PORTB.0               
#define RS_DDRn    DDRB.0  

#define RW        PORTB.1  
#define RW_DDRn    DDRB.1      

#define E         PORTB.2
#define E_DDRn     DDRB.2   

#define DB4       PORTB.4
#define DB4_DDRn   DDRB.4   

#define DB5       PORTB.5
#define DB5_DDRn   DDRB.5

#define DB6       PORTB.6
#define DB6_DDRn   DDRB.6  

#define DB7       PORTB.7  
#define DB7_DDRn   DDRB.7
#define DB7_PINn   PINB.7  

unsigned int byte;   
unsigned  char   flash string[]="input:";
unsigned  char key_stime_counter ;    // 时间计数单元,
bit                 key_stime_ok;
/******************************
*写LCD
*datas是数据,高4位有效,rs决定datas是显示还是指令,read_bf决定是否需要读取忙标志BF      
*******************************/
   
void g_lcd_h(unsigned char datas,unsigned char rs,unsigned char read_bf)
{   
  RS_DDRn =1;                         //RS/RW/E设置为输出
  RW_DDRn =1;
  E_DDRn  =1;   
  if(read_bf)                        //如果需要读LCD忙标志就read_bf=1,
    {        
      DB4_DDRn=0;                     //先把4个数据口设置为输入
      DB5_DDRn=0;
      DB6_DDRn=0;
      DB7_DDRn=0;
      RS=0;  
      RW=1;                           //读BF
      E=1;
      E=1;                            //相同的操作相当于等待几个时钟周期
      E=1;
    }
  RS=rs;                              //写指令或者数据
  RW=0;                               //写  
  DB4_DDRn=1;                         //把4个数据口设置为输出
  DB5_DDRn=1;
  DB6_DDRn=1;
  DB7_DDRn=1;  
  E=1;   
  if(datas&128) DB7=1; else DB7=0;    //如果按位与后非0执行DB7=1
  if(datas&64)  DB6=1; else DB6=0;
  if(datas&32)  DB5=1; else DB5=0;
  if(datas&16)  DB4=1; else DB4=0;
  E=0;                                //LCD在E下降沿时对RS与DB4-DB7进行取样
}  

/******************************
*写指令函数      
*******************************/
void g_lcd_dictate(unsigned char data)   
{  
  g_lcd_h(data,0,1);                    //输出高4位  
  g_lcd_h(data*16,0,1);                 //输出低4位 data*16相当data中的数据左移4位
}  

/******************************
*写显示函数      
*******************************/   
void g_lcd_putchar(unsigned char data)   
{   
  g_lcd_h(data,1,1);                    //输出高4位  
  g_lcd_h(data*16,1,1);                 //输出低4位
}

/******************************
*列/行定位函数,最开头的地址是0列0行   
*要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符
*1602液晶内部显示地址
*比如第二行第一个字符的地址是40H,那么是否直接写入40H就可以将光标定位在第二行第一个字符的
*位置呢? 这样不行,因为写入显示地址时要求最高位D7恒定为高电平1所以实际写入的数据应该?
*?1000000B(40H)+10000000B(80H)=11000000B(C0H) =128
*******************************/  

void g_lcd_gotoxy(unsigned char x, unsigned char y)   
{      
  if(x<=15 && y<=1)                    //防止输入的数据不正确
    {                                 
      if(y==0) g_lcd_dictate(x+128);     //第0行的地址是从0开始
      if(y==1) g_lcd_dictate(x+192);     //第1行......      
    }
}  
/******************************
*初始化函数   
*******************************/
  
void g_lcd_init(void)
{   
  unsigned char i;
     delay_ms(100);
     for(i=0;i<=2;i++)
     {
         g_lcd_h(0x30,0,0);        //初始化语句   
         delay_ms(6);         
     }
  while(DB7_PINn);                //等待,直到DB7=0   
  g_lcd_dictate(0x20);                     //功能设置指令. 4位数据口
  g_lcd_dictate(0x28);                     //功能设置指令.2行显示、5*7点阵字符。  
  g_lcd_dictate(0x01);                     //清屏指令.
  g_lcd_dictate(0x06);                     //输入方式指令代码.数据读、写操作后光标右移1个字符位   
  //lcd_dictate(0x0f);                     //显示参数设定 .显示开、光标开、闪烁开。
  //lcd_gotoxy(0,0);                       //光标定位到第0列第0行
  delay_ms(6);
}  


      
/******************************
*以十六进制的方式显示一个字符变量  
*******************************/

void g_lcd_hex(unsigned char byte_data)                 
{
  unsigned char temp_data;  
   
  temp_data=byte_data>>4;                             //求高4位
  if(temp_data<10) temp_data+=48; else temp_data+=55; //转化为ASCII值
  g_lcd_putchar(temp_data);                             //显示
   
  temp_data=byte_data&15;                             //求低4位
  if(temp_data<10) temp_data+=48; else temp_data+=55; //转化为ASCII值
  g_lcd_putchar(temp_data);                             //显示
}   

/******************************
*以十进制的方式显示一个字符变量  
*******************************/
  
void g_lcd_byte(unsigned int byte_data)                 
{
  unsigned int temp_data;  
   
  temp_data=byte_data/100;                            //求百位数
  g_lcd_putchar(temp_data+48);                          //转化为ASCII值再显示
   
  temp_data=byte_data/10%10;                          //求十位数
  g_lcd_putchar(temp_data+48);                          //转化为ASCII值再显示
   
  temp_data=byte_data%10;                             //求个位数
  g_lcd_putchar(temp_data+48);                          //转化为ASCII值再显示
}   

/******************************
*显示FLASH里面的字符串
*******************************/

void g_lcd_putsf(flash unsigned char *string , unsigned char n) //显示FLASH里面的字符串
{         
  unsigned char i=0;
  while(i<n)
       {   
         g_lcd_putchar( string[ i ] ) ;                 //顺序显示字符
         i++;                          
       }
}  

/******************************
*Timer 0 比较匹配中断服务,2ms定时
*******************************/

interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
        if (++key_stime_counter >=5)
        {
                key_stime_counter = 0;
                key_stime_ok = 1;                                // 10ms到
        }
}

#define key_input        PIND.7                        // 按键输入口
#define key_state_0        0
#define key_state_1        1
#define key_state_2        2
#define key_state_3        3
unsigned char read_key_n(void)
{
   static unsigned char key_state = 0, key_time = 0;
        unsigned char key_press, key_return = 0;

        key_press = key_input;                                // 读按键I/O电平
        switch (key_state)
        {
                case key_state_0:                                // 按键初始态
                        if (!key_press) key_state = key_state_1;        // 键被按下,状态转换到键确认态
                        break;
                case key_state_1:                                // 按键确认态
                        if (!key_press)
            {
                key_state = key_state_2;        // 按键仍按下,状态转换到计时1
                key_time = 0;                                // 清另按键时间计数器
            }
                        else
                            key_state = key_state_0;        // 按键已抬起,转换到按键初始态
                        break;
                case key_state_2:
                        if (key_press)
            {
                key_state = key_state_0;        // 按键已释放,转换到按键初始态
                key_return = 1;                        // 输出"1"
                        }
                        else if (++key_time >= 100)                // 按键时间计数
                        {
                                key_state = key_state_3;        // 按下时间>1s,状态转换到计时2
                                key_time = 0;                                // 清按键计数器
                                key_return = 2;                        // 输出"2"
                        }
                        break;
                case key_state_3:
                        if (key_press)
                            key_state = key_state_0; //按键已释放,转换到按键初始态
                        else
                        {
                                if (++key_time >= 50)                // 按键时间计数
                                {
                                        key_time = 0;                        // 按下时间>0.5s,清按键计数器
                                        key_return = 2;                // 输出"2"
                                }
                        }
                        break;
        }       
    return key_return;         
}
/******************************
*main()函数
*******************************/

void main(void)
{   
   lcd_init(16);                     //1602LCD初始化函数  
   lcd_clear();                      //LCD清屏指令是
   DDRD.7=0;                             // PD7为输入方式
   
   // T/C0 初始化
   TCCR0 = 0x0B;                        // 内部时钟,64分频(4M/64=62.5KHz),CTC模式
   TCNT0 = 0x00;
   OCR0 = 0x7C;                                // OCR0 = 0x7C(124),(124+1)/62.5=2ms
   TIMSK = 0x02;                        // 允许T/C0比较匹配中断
   
   #asm("sei")                                // 开放全局中断
   
   while (1)        
   {     
       if (key_stime_ok)                               
       {
           key_stime_ok = 0;                                // 10ms到
           switch (read_key_n())                 // 按键确认按下
           {
                case 1:
                byte++;                          // 加1
                break;
                case 2:       
                byte++;                        // 加10
                break;
            }
           lcd_gotoxy(0,0);                //光标定位到第0列第0行   
           lcd_putsf(string);             //显示FLASH里面的字符串              
           g_lcd_byte(byte);              //以十进制的方式显示一个字符变量  
           if(byte==999)byte=0;     
       }
   }
}

出0入0汤圆

 楼主| 发表于 2008-8-21 15:57:40 | 显示全部楼层
我想根据lcd上显示的时间来控制led的亮灭。请给个思路吧,实例、链接都可以谢谢。

出0入0汤圆

发表于 2008-9-5 20:55:08 | 显示全部楼层
if

出0入0汤圆

发表于 2008-9-12 04:23:43 | 显示全部楼层
书中已经明确说明,按下1S后,每隔0.5S自动加10(1),1S当然变化2次了。

你真的看明白了吗?

要想加快,改动函数read_key_n()中case key_state_3下的

if(++key_time >= 50)     //50*10 = 500ms



if(++key_time >= 5)      //5*10 = 50ms

那么50ms就加1了,那么1秒内可以变化20次。

“滴水穿石”,这个水要滴在同一个地方,最后才能穿石。东滴一些,西滴一些,到处乱滴,石头不会穿的。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-10-2 23:18

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

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