我看到有的led显示屏的按键具有连_发共能,连_发时数字翻转的很快,我用lcd做显示器连_
例如:我在马老师的实验板上装了一块lcd1602,按照demo_9_2.c中的按键连_发功能,编了一段程序。连_发时在lcd上显示加1后的数字。从0-999需要很长时间。观察后1秒钟大约跳2个数字。如何才能加快速度呢? 1 LCD属于慢性器件,所以显示时间远大于LED2 1秒跳两个数字,只跟程序延时有关,一般LCD的响应时间也是ms级的。
3 跟具描述可能是你的LCD写函数的等待LCD响应的查询(忙检测),进入一个‘死’循环了。可以改成固定延时试试。可能是硬件连接不好引起的忙检测失败。
------
我没有例子,无法测试。 程序是马老师+阿艺的。请测试一下,看看如何能增加显示的速度。在马老师的实验板上装上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;
}
}
} 我想根据lcd上显示的时间来控制led的亮灭。请给个思路吧,实例、链接都可以谢谢。 if 书中已经明确说明,按下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次。
“滴水穿石”,这个水要滴在同一个地方,最后才能穿石。东滴一些,西滴一些,到处乱滴,石头不会穿的。 试过了,好用。谢谢。
页:
[1]