gaochaoning 发表于 2008-8-21 15:12:34

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

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

mljda 发表于 2008-8-21 15:21:15

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

gaochaoning 发表于 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;   
unsignedchar   flash string[]="input:";
unsignedchar 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 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;   
       }
   }
}

gaochaoning 发表于 2008-8-21 15:57:40

我想根据lcd上显示的时间来控制led的亮灭。请给个思路吧,实例、链接都可以谢谢。

311711 发表于 2008-9-5 20:55:08

if

machao 发表于 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次。

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

gaochaoning 发表于 2009-3-1 13:34:03

试过了,好用。谢谢。
页: [1]
查看完整版本: 我看到有的led显示屏的按键具有连_发共能,连_发时数字翻转的很快,我用lcd做显示器连_