为何这个按键电路出问题
最近在论坛上看到有前辈说用一片74HC164控制1602和8个按键。发现思路可行,自己也画了个,如图1所示。但是编程时候遇到困难,就是按键按下,单片机能识别按键的值,但是一放开后就很奇怪的编程0值(0也是我的一个按键值),现在程序如下,能驱动1602,主要按键这块有点问题,我觉得思路没有任何错误,其中按键扫描的思路就是输出00000001,看按键返回口是否为高电平,在输出00000010,看按键返回口是否为高电平,依次循环,直到检测完毕为止,(目前没加消抖措施,直接是按键识别)。单片机是ATMEGA48,我主要是为了节省单片机IO口程序如下:按键识别的:
#include <iom48v.h>
#include <macros.h>
#defineucharunsigned char
#defineuint unsigned int
#definekongzhi PORTB
#defineEN 3
#defineCLK 0
#defineDQ 1
#defineKEY 2
void LCD_INIT(void);
void LCD_STRING(uchar x,uchar y,uchar *p);
void LCDSHOW_CHAR(uchar x,uchar y,uchar ch);
void LCDSHOW_DATA(uchar x,uchar y,uchar num);
void HC164_SEND(uchar byte);
void write_com(uchar com);
void write_dat(uchar dat);
void delayms(uint z);
void delayus(uint z);
uchar KEY_TEST(void);
uchar keyvalue;
void main()
{
LCD_KEY_INIT();
LCDSHOW_CHAR(1,1,'A');
LCDSHOW_DATA(1,2,6);
while(1)
{
keyvalue=KEY_TEST();
// if(keyvalue<=7)
LCDSHOW_DATA(5,1,keyvalue);
}
}
/******************************************************************
函数名称:LCD_KEY_INIT()
入口参数:无
函数功能:LCD函数初始化,包括控制端口的初始化、液晶屏的初始化、按键检测口的初始化
******************************************************************/
void LCD_KEY_INIT(void)
{
DDRB|=BIT(CLK)|BIT(DQ)|BIT(EN);
DDRB&=~BIT(KEY); //按键检测口设置成输入
write_com(0x38);
delayms(1);
write_com(0x0c);
delayms(1);
write_com(0x06);
delayms(1);
write_com(0x01);
delayms(5);
}
/*****************************************************************
函数名称:LCD_STRING(uchar x,uchar y,uchar *p)
函数参数: 坐标(x,y),字符串指针p
函数功能:定点写字符串函数
******************************************************************/
void LCD_STRING(uchar x,uchar y,uchar *p)
{
if(y==1)
write_com(0x80+x);
else if(y==2)
write_com(0xc0+x);
while(*p)
{
write_dat(*p);
p++;
}
}
/******************************************************************
函数名称:LCDSHOW_DATA(uchar x,ucahr y,uchar j)
入口参数:坐标(x,y),数字j
函数功能:定坐标显示数字j
******************************************************************/
void write_com(uchar com)//写命令函数
{
HC164_SEND(com); //先写数据
kongzhi&=~BIT(CLK);//RS与CLK复用,时序上需注遥不能再拉高了,否则数据会变
kongzhi&=~BIT(EN);
delayus(1);
kongzhi|=BIT(EN);
delayus(1);
kongzhi&=~BIT(EN);
}
/******************************************************************
函数名称:LCDSHOW_DATA(uchar x,ucahr y,uchar j)
入口参数:坐标(x,y),数字j
函数功能:定坐标显示数字j
******************************************************************/
void write_dat(uchar dat)//写数据函数
{
HC164_SEND(dat);
kongzhi|=BIT(CLK);
//RS与CLK复用,此时其实不必拉高,因为之前在输入数据完毕的时候已经是拉高了
kongzhi&=~BIT(EN);
delayus(1);
kongzhi|=BIT(EN);
delayus(1);
kongzhi&=~BIT(EN);
}
/******************************************************************
函数名称:LCDSHOW_CHAR(uchar x,ucahr y,uchar ch)
入口参数:坐标(x,y),字母ch
函数功能:定坐标显示字母ch
******************************************************************/
void LCDSHOW_CHAR(uchar x,uchar y,uchar ch)
{
if(y==1)
write_com(0x80+x);
else if(y==2)
write_com(0xc0+x);
write_dat(ch);
}
/******************************************************************
函数名称:LCDSHOW_DATA(uchar x,ucahr y,uchar num)
入口参数:坐标(x,y),数字num
函数功能:定坐标显示数字num
******************************************************************/
void LCDSHOW_DATA(uchar x,uchar y,uchar num)
{
if(y==1)
write_com(0x80+x);
else if(y==2)
write_com(0xc0+x);
write_dat(0x30+num);
}
/******************************************************************
函数名称:HC164_SEND(uchar byte )
入口参数:byte
函数功能:将一个数据输入到74hc164的输出端,数据的低位对应Q0,数据高位对应Q7
******************************************************************/
void HC164_SEND(uchar byte )
{
signed char i; //这里不能使用 char ,因为char 默认为unsigned char,没有负数
for(i=7;i>=0;i--)
{
kongzhi&=~BIT(CLK); //时钟拉低N拉高做准备
if(byte & (1<<i))
kongzhi|=BIT(DQ);
else
kongzhi&=~BIT(DQ); //若byte的某位为1,则输出1,否则输出0
kongzhi|=BIT(CLK); //时钟拉高,移入数据
}
}
/******************************************************************
函数名称:delayms(uint z)
入口参数:z
函数功能:粗略延时z ms
******************************************************************/
void delayms(uint z)
{
uint i,j;
for( i=0;i<z;i++)
for(j=0;j<1141;j++); //1141是在8MHz晶振下,通过软件仿真反复实验得到的数值
}
/******************************************************************
函数名称:delayus(uint z)
入口参数:z
函数功能:粗略延时z us
******************************************************************/
void delayus(uint z)
{
uint i;
z=z*5/4; //5/4是在8MHz晶振下,通过软件仿真反复实验得到的数值
for( i=0;i<z;i++);
}
/******************************************************************
函数名称: KEY_TEST(void)
入口参数:无
函数功能:只读一个按键的值函数
******************************************************************/
uchar KEY_TEST(void)
{
uchar i;
for(i=0;i<=7;i++)
{
HC164_SEND(BIT(i));
if(PINB&BIT(KEY))
{
LCDSHOW_DATA(9,1,i);//检测有没有一直进这个if语句,果然进了,但不知为何
returni;//检测到第i个键被按下了 ,返回相应键值
}
}
return 8;
} {:curse:}电路出问题电路呢 snwuzhisheng 发表于 2012-6-8 08:05 static/image/common/back.gif
电路出问题电路呢
电路就是上面图所示的呀,其他没了,按键的keyback连到的是单片机一个IO口 上拉下拉没有的 BG4RFF 发表于 2012-6-16 00:03 static/image/common/back.gif
上拉下拉没有的
我用的是ATMEGA48,内部有上拉的,还要加下拉吗 晚辈,听劝,先把数字逻辑电路基础学好,再学什么单片机。
硬件电路都看不懂,后面什么都是浮云。
就说LZ位的按键扫描电路,假定KEYBACK接AVR的引脚(内部上拉)作为按键扫描的输入,那么
1.如果一个按键也没有按下,不管164输出什么值,读到都是“1”
2.因此要扫描第1个按键是否按下,164应该输出11111110。此时如果第1按键按下,读到为"0",而其它按键按下,读到的都是1
3.以此可知,要扫描第2个按键是否按下,164应该输出11111101。此时如果第2按键按下,读到为"0",而其它按键按下,读到的都是1,----------
可怕的是,当164的8个输出有0有1时,比如11111110,而用户恰好同时按下了第1和第2个按键(其它3-8同理),164烧掉了。因为由于2个按键都按下形成的短路,使得164的D1输出5v("1")与164的D0的地(“0”)短接,164去掉了。
要使用类似的电路,至少要在164和按键之间串入8个二极管。
本帖最后由 xinxin3219 于 2012-6-21 19:53 编辑
machao 发表于 2012-6-19 22:49 static/image/common/back.gif
晚辈,听劝,先把数字逻辑电路基础学好,再学什么单片机。
硬件电路都看不懂,后面什么都是浮云。
谢谢马老师的指导,的确当初程序和硬件电路设计的时候没考虑仔细。
虽然PINX是存储引脚电平实际状态的,我却忽略了“实际”这两个字,上拉状态下引脚电平都是1,必须用0才能改变。
第二个就是164输出级是一个非门,推拉式输出结构。任意两个键同时按下,形成低阻通路,然后是会烧掉的。
最后再次谢谢的指导{:lol:}
顺便问一句:串二极管是有什么特性能用在这儿,串电阻不行吗 xinxin3219 发表于 2012-6-21 16:23 static/image/common/back.gif
谢谢马老师的指导,的确当初程序和硬件电路设计的时候没考虑仔细。
虽然PINX是存储引脚电平实际状态的, ...
串联二极管可以组成一个基本的 与门/非门,逻辑才好控制 pengxin213 发表于 2012-6-21 23:30 static/image/common/back.gif
串联二极管可以组成一个基本的 与门/非门,逻辑才好控制
您的意思我不是很理解,不过后来我想了想串联二极管可以使得每任意两个键同时按下时,不会使两个MOS流过大电流,因为支路里有两个方向相反的二极管,是不会导通的
页:
[1]