搜索
bottom↓
回复: 8

为何这个按键电路出问题

[复制链接]

出0入0汤圆

发表于 2012-6-7 14:18:26 | 显示全部楼层 |阅读模式
最近在论坛上看到有前辈说用一片74HC164控制1602和8个按键。发现思路可行,自己也画了个,如图1所示。但是编程时候遇到困难,就是按键按下,单片机能识别按键的值,但是一放开后就很奇怪的编程0值(0也是我的一个按键值),现在程序如下,能驱动1602,主要按键这块有点问题,我觉得思路没有任何错误,其中按键扫描的思路就是输出00000001,看按键返回口是否为高电平,在输出00000010,看按键返回口是否为高电平,依次循环,直到检测完毕为止,(目前没加消抖措施,直接是按键识别)。单片机是ATMEGA48,我主要是为了节省单片机IO口



程序如下:按键识别的:
                      #include <iom48v.h>
#include <macros.h>

#define  uchar  unsigned char
#define  uint    unsigned int
#define  kongzhi PORTB
#define  EN      3
#define  CLK    0
#define  DQ     1
#define  KEY    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语句,果然进了,但不知为何
                         return  i;  //检测到第i个键被按下了 ,返回相应键值
                       
                      }         
                }
               
        return 8;
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

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

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2012-6-8 08:05:57 | 显示全部楼层
电路出问题  电路呢

出0入0汤圆

 楼主| 发表于 2012-6-8 20:55:48 | 显示全部楼层
snwuzhisheng 发表于 2012-6-8 08:05
电路出问题  电路呢

电路就是上面图所示的呀,其他没了,按键的keyback连到的是单片机一个IO口

出0入0汤圆

发表于 2012-6-16 00:03:05 | 显示全部楼层
上拉下拉没有的

出0入0汤圆

 楼主| 发表于 2012-6-19 08:57:12 | 显示全部楼层
BG4RFF 发表于 2012-6-16 00:03
上拉下拉没有的

我用的是ATMEGA48,内部有上拉的,还要加下拉吗

出0入0汤圆

发表于 2012-6-19 22:49:23 | 显示全部楼层
晚辈,听劝,先把数字逻辑电路基础学好,再学什么单片机。
硬件电路都看不懂,后面什么都是浮云。

就说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个二极管。

出0入0汤圆

 楼主| 发表于 2012-6-21 16:23:06 | 显示全部楼层
本帖最后由 xinxin3219 于 2012-6-21 19:53 编辑
machao 发表于 2012-6-19 22:49
晚辈,听劝,先把数字逻辑电路基础学好,再学什么单片机。
硬件电路都看不懂,后面什么都是浮云。


谢谢马老师的指导,的确当初程序和硬件电路设计的时候没考虑仔细。
虽然PINX是存储引脚电平实际状态的,我却忽略了“实际”这两个字,上拉状态下引脚电平都是1,必须用0才能改变。
第二个就是164输出级是一个非门,推拉式输出结构。任意两个键同时按下,形成低阻通路,然后是会烧掉的。
最后再次谢谢的指导
顺便问一句:串二极管是有什么特性能用在这儿,串电阻不行吗

出0入0汤圆

发表于 2012-6-21 23:30:56 | 显示全部楼层
xinxin3219 发表于 2012-6-21 16:23
谢谢马老师的指导,的确当初程序和硬件电路设计的时候没考虑仔细。
虽然PINX是存储引脚电平实际状态的, ...

串联二极管可以组成一个基本的 与门/非门,逻辑才好控制

出0入0汤圆

 楼主| 发表于 2012-6-25 18:01:50 | 显示全部楼层
pengxin213 发表于 2012-6-21 23:30
串联二极管可以组成一个基本的 与门/非门,逻辑才好控制

您的意思我不是很理解,不过后来我想了想串联二极管可以使得每任意两个键同时按下时,不会使两个MOS流过大电流,因为支路里有两个方向相反的二极管,是不会导通的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-4-27 03:08

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

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