[技术讨论]

74HC595驱动四位数码管和四个按键编程思路

[复制链接]
楼主: followme001
手机看帖
扫描二维码
随时随地手机跟帖
followme001|  楼主 | 2018-1-31 11:23 | 显示全部楼层 |阅读模式
QQ图片20180131111752.png QQ图片20180131111824.png
第一个图是两片74HC595级联驱动四位共阴数码管电路,另一个图是与单片机相连的I/O口,数码管显示部份好弄,只要想显示什么就往595送什么数据就行,但按键部份就比较难理解了,怎么检测是哪个按键按下呢?有知道的说说是什么原理吗?谢谢。

相关帖子

ayb_ice| | 2018-1-31 17:03 | 显示全部楼层
C2换成电阻是可以的,从KEY读状态,一次读一个键(取决于当前显示的数码管)

使用特权

评论回复
followme001|  楼主 | 2018-2-1 08:23 | 显示全部楼层
ayb_ice 发表于 2018-1-31 17:03
C2换成电阻是可以的,从KEY读状态,一次读一个键(取决于当前显示的数码管) ...

明白。

使用特权

评论回复
followme001|  楼主 | 2018-2-1 11:48 | 显示全部楼层
yyy71cj 发表于 2018-2-1 11:20
显然,四个按键共了四个数码管选通口,说明按键与数码管是不能同时工作的,只能分时。
所以,按键与数码管 ...

嗯,分时扫描,讲得很详细。

使用特权

评论回复
followme001|  楼主 | 2018-2-3 11:57 | 显示全部楼层
本帖最后由 followme001 于 2018-2-3 15:59 编辑
yyy71cj 发表于 2018-2-1 11:20
显然,四个按键共了四个数码管选通口,说明按键与数码管是不能同时工作的,只能分时。
所以,按键与数码管 ...

      while (1)
        {        
                if (Flag_1ms)            //1ms扫描一位数码管
                {
                        Flag_1ms = 0;
                        key_value = display(0,1,2,3);   //四个数码管显示数字0,1,2,3
                        if (key_value == 1)
                        {
                                LED0 = !LED0;    //按键对应LED亮灭来指示
                        }
                }



u8 display(u8 num1,u8 num2,u8 num3,u8 num4)
{
        static u8 dig = 0;  //扫描的数码管位,0第一位,1第二位,2第三位....
        static u8 key_count = 0;
        switch(dig)
        {
                case 0:                                
                        hc595_in(Duan_Data[num1]);  //送段码
                        hc595_in(Wei_Data[0]);          //送位码,这个是选通第一位数码管,送0xFE
                        hc595_out();                         //锁存,输出显示
                        dig += 1;        
                        if (KEY == 0)
                        {
                                if (++key_count > 2)   //8ms按键消抖
                                {        
                                        if (KEY == 0)     //再次检测,如果按下就认为真的有按键按下。
                                        {
                                                key_count = 0;
                                                return 1;   //返回1代表有按键按下
                                        }
                                }
                        }               
                break;
               
                case 1:
                        hc595_in(Duan_Data[num2]);
                        hc595_in(Wei_Data[1]);    //这是选通第二位,送0xFD
                        hc595_out();
                        dig += 1;
                break;

                case 2:
                        hc595_in(Duan_Data[num3]);
                        hc595_in(Wei_Data[2]);
                        hc595_out();
                        dig += 1;
                break;

                case 3:
                        hc595_in(Duan_Data[num4]);
                        hc595_in(Wei_Data[3]);
                        hc595_out();
                        dig = 0;
                break;

                default:
                break;
        }
        return 0;    //返回0代表没有键按下。
}

以上是我的程序片段,有时候正常,大多时候是不正常的。不知道问题出在哪里。

使用特权

评论回复
followme001|  楼主 | 2018-2-3 11:59 | 显示全部楼层
本帖最后由 followme001 于 2018-2-3 14:08 编辑
followme001 发表于 2018-2-3 11:57
while (1)
        {        
                if (Flag_1ms)            //1ms扫描一位数码管
u8 const Duan_Data[] =
{
        0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F//0,1,2,3,4,5,6,7,8,9
};

u8 const Wei_Data[] =
{
        0xFE,0xFD,0xFB,0xF7,0xFF,0xFF,0xFF,0xFF
};

void hc595_in(u8 dat)
{
        u8 i;
        for (i = 0; i < 8; i++)
        {
                SCK = 0;
                if((dat & 0x80) == 0x80)
                {
                        SIN = 1;
                }
                else
                {
                        SIN = 0;
                }               
                dat <<= 1;
                SCK = 1;
        }
}

void hc595_out(void)
{
        RCK = 0;
        RCK = 1;
}

使用特权

评论回复
followme001|  楼主 | 2018-2-3 16:05 | 显示全部楼层
本帖最后由 followme001 于 2018-2-3 16:22 编辑
yyy71cj 发表于 2018-2-3 15:02
注释太少,看起来吃力。
我提两点建议,1:1m扫描的频率太高
                     2:你的延时去抖检测 ...

那我先看看视频吧。问题是只有选通对应的数码管位时才能检测对应的按键呢。 QQ图片20180203161237.png

1,2,3,4代表四个数码管的选通时间,1为发送0xFE时的,2为发送0xFD时的,以此类推。

使用特权

评论回复
gx_huang| | 2018-2-4 10:55 | 显示全部楼层
yyy71cj 发表于 2018-2-3 21:38
数码管容易控制,按键要复杂一些,检测按键的时候,数码管必须全部处于暗状态 ...

不会吧,扫描到哪一位,在哪一位的最后时刻,检测哪路的按键,并不需要显示全暗的。

使用特权

评论回复
followme001|  楼主 | 2018-2-5 14:40 | 显示全部楼层
yyy71cj 发表于 2018-2-3 21:38
数码管容易控制,按键要复杂一些,检测按键的时候,数码管必须全部处于暗状态 ...

若数码管显示完,轮到检测按键,如果此时数码管全暗的话,数码管就会什么都没显示了。

使用特权

评论回复
wfl102824| | 2018-3-24 16:46 | 显示全部楼层
第二片595有多出4个输出口,可以按键选择与数码管选择分开....

使用特权

评论回复
followme001|  楼主 | 2018-3-26 14:36 | 显示全部楼层
wfl102824 发表于 2018-3-24 16:46
第二片595有多出4个输出口,可以按键选择与数码管选择分开....

这电路是公司老产品用得很成熟的电路。我就自己练练手。

使用特权

评论回复
followme001|  楼主 | 2018-3-26 14:37 | 显示全部楼层
wfl102824 发表于 2018-3-24 16:46
第二片595有多出4个输出口,可以按键选择与数码管选择分开....

这电路是公司老产品用得很成熟的电路。我就自己练练手。

使用特权

评论回复
天命风流| | 2018-6-8 12:14 | 显示全部楼层
赞              

使用特权

评论回复
followme001|  楼主 | 2018-6-11 20:06 | 显示全部楼层
过了一段时间,在网上查找到了这种按键与显示混合的电路的编程方法,有了以下一个可正常使用的版本。还有一种方法是在display_scan()里的状态机中,把按键扫描也当成是"一位数码管"来处理,也就是五种状态:检测按键-》选通第一位数码管-》选通第二位数码管-》选通第三位数码管-》选通第四位数码管。接下来看看能不能把版主里贴子的内容《编程魔法师》之对象实战——按键篇里的可以短按,长按,双击的结合在一起。

#define NULL      0x00
#define MENU     0x01
#define DOWN   0x02
#define UP          0x04
#define ENTER   0x08
u8 Key_Value = NULL;   //全局变量,供上层使用。

void hc595(u8 seg,u8 bit)
{
    u8 i;
    u16 dat = 0;
   
    dat = seg;
    dat = dat << 8 | bit;
   
    for (i = 0; i < 16; i++)
    {
        if ((dat & 0x8000) == 0x8000)
        {
            SIN_ON();
        }
        else
        {
            SIN_OFF();
        }
        SCK_ON();
        SCK_OFF();
        dat <<= 1;
    }
   
    RCK_ON();
    RCK_OFF();  
}

void display_scan(void)   //定时器中断,2ms调用一次;
{
    static u8 index = 0;
   
    hc595(Dis_Buf[4],Bit_Dat[4]);
   
    switch (index)
    {
        case 0:
            hc595(Dis_Buf[0],Bit_Dat[0]);
            if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == Bit_RESET)
            {
                    Key_Value |= MENU;
            }
            else
            {
                    Key_Value &= ~MENU;
            }
         break;
        
        case 1:
            hc595(Dis_Buf[1],Bit_Dat[1]);
            if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == Bit_RESET)
            {
                    Key_Value |= DOWN;
            }
            else
            {
                    Key_Value &= ~DOWN;
            }        
         break;

        case 2:
            hc595(Dis_Buf[2],Bit_Dat[2]);
            if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == Bit_RESET)
            {
                    Key_Value |= UP;
            }
            else
            {
                    Key_Value &= ~UP;
            }        
         break;
               
        case 3:
            hc595(Dis_Buf[3],Bit_Dat[3]);
            if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14) == Bit_RESET)
            {
                    Key_Value |= ENTER;
            }
            else
            {
                    Key_Value &= ~ENTER;
            }        
         break;               
    }
    index++;
    index = index & 0x03;
}

使用特权

评论回复
sznjstarman| | 2018-7-6 20:32 | 显示全部楼层
这种方式,是不能做组合按键的,没法检测2以上的组合键

使用特权

评论回复
followme001|  楼主 | 2018-7-11 16:34 | 显示全部楼层
sznjstarman 发表于 2018-7-6 20:32
这种方式,是不能做组合按键的,没法检测2以上的组合键

是吧。但我也没必要做组合键。这样的电路是为了节约CPU的I/O口

使用特权

评论回复
你好,我刚好最近在做这个电路,能交流一下么 QQ2790658206

使用特权

评论回复
我只想学习啊| | 2019-12-20 14:32 | 显示全部楼层
你好,我最近也遇到了这种按键与显示混合电路的编程问题,请问你有没有继续研究这种电路中按何判断单击,长按,如果有的话可不可以分享一下,如何实现与单击长按相结合,谢谢 方便的话可不可以加下我QQ1808879413,或者回复下QQ 我加你,

使用特权

评论回复
followme001|  楼主 | 2019-12-30 18:43 | 显示全部楼层
我只想学习啊 发表于 2019-12-20 14:32
你好,我最近也遇到了这种按键与显示混合电路的编程问题,请问你有没有继续研究这种电路中按何判断单击,长 ...

其实只是按键按下,弹起的代码不一样,例如按下后直接接I/O口的就是判断是否为“0”,弹起就是否为“1”,然后有些就是判断是否等于一个数值,例如0xFe等等。按键的长按,连按实现原理,你可以看看“从单片机迈向单片机工程师”这个电子书。

使用特权

评论回复
xb503520| | 2022-10-18 15:26 | 显示全部楼层
试了下好像不太行啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

26

主题

154

帖子

1

粉丝