找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1932|回复: 15
收起左侧

AVR单片机按键消抖程序问题请教

[复制链接]
ID:881204 发表于 2021-8-23 17:19 | 显示全部楼层 |阅读模式
大佬们好!我用ATTINY24A做一个按键控制IO输出的功能。
原理图如下:

目前的问题是:
1、我的按键消抖好像没作用(调不同的DELAY时间,有变化,但不解决问题)
2、在我PA0按键按下不松手时(也就是按键输入一直为0)。这个时候,PB1口输出为0.4V,只有我松开按键以后,PB1口才会变为0V或3.3V。
原代码如下:
#include <avr/io.h>
void delay (unsigned int ms);
int main(void)
{
        unsigned char temp=0;
        while(1)
        {
                temp = (PINA & (_BV(DDA0)));  //KEY
        if (!temp)
        {
                delay(200);
                        if(!temp)
                        {
                         DDRB = 0x0F;
                         PORTB = 0x00;
                        }
        }
                                temp = (PINA & (_BV(DDA0))); //KEY
                                if (!temp)
                                {
                                delay(200);
                                        if(!temp)
                                        {
                                        DDRB = 0x0F;
                                        PORTB = 0x02;
                                        }
                                }
        }
          return 0;
}

void delay (unsigned int ms)
        {
                unsigned int i,j;
                for(i=0;i<ms;i++)
                {
                        for(j=0;j<1000;j++);
                }
        }


请各位大佬帮忙看看是什么问题,谢谢!
回复

使用道具 举报

ID:752974 发表于 2021-8-24 08:20 | 显示全部楼层
按键消抖常用的两种方法,电容滤波,软件延时。和什么单片机无关。
回复

使用道具 举报

ID:881204 发表于 2021-8-25 09:12 | 显示全部楼层
munuc_w 发表于 2021-8-24 08:20
按键消抖常用的两种方法,电容滤波,软件延时。和什么单片机无关。

大佬好,是和什么单片机没关系,我只是想把我遇到的问题情况说的全面一点,并不是说和单片机有关。
我发了原代码,也就是想请大佬们帮我看看有什么问题。
谢谢指导!
回复

使用道具 举报

ID:161164 发表于 2021-8-25 09:56 | 显示全部楼层
不明白你的代码为什么要这样写
根据你的代码,当按下PA0时
PB1会产生2.5Hz的方波(假设delay的时间是ms)
放开PA0后,PB1就会比较随机的停在0V或3.3V

如果你想点动PA0来控制PB1
大约可以这样改(没用过AVR,看了一下手册):
  1. int main(void)
  2. {
  3.         unsigned char temp=0;
  4.         DDRB = 0x0F;//输入输出设定只要设一次
  5.         while(1)
  6.         {
  7.                 temp = (PINA & (_BV(DDA0)));  //KEY
  8.                 if (!temp)
  9.                 {
  10.                         delay(200);
  11.                         if(!temp)
  12.                         {//方法1
  13.                                 if(PORTB & 0x02)
  14.                                 {
  15.                                         PORTB &= 0xFD;
  16.                                 }else{
  17.                                         PORTB |= 0x02;
  18.                                 }
  19.                                 //方法2
  20.                                 //PORTB ^= 0x02;//异或
  21.                         }
  22.                 }
  23.         }
  24.         return 0;
  25. }
复制代码





回复

使用道具 举报

ID:881204 发表于 2021-8-25 11:40 | 显示全部楼层
本帖最后由 灰小伙 于 2021-8-25 15:52 编辑
lkc8210 发表于 2021-8-25 09:56
不明白你的代码为什么要这样写
根据你的代码,当按下PA0时
PB1会产生2.5Hz的方波(假设delay的时间是ms)

谢谢大佬指点,我的工作目的是:按一次KEY,PB1输出高;再按一次KEY,PB1输出低。并且一直这样检测是否有按键输入,如果有的话,PB1的输出就翻转,并保持到下一次按键输入。
谢谢!
回复

使用道具 举报

ID:881204 发表于 2021-8-27 10:17 | 显示全部楼层
lkc8210 发表于 2021-8-25 09:56
不明白你的代码为什么要这样写
根据你的代码,当按下PA0时
PB1会产生2.5Hz的方波(假设delay的时间是ms)

谢谢lkc8210大佬的指导,我明白了为什么会产生方波。
只是目前按键的灵敏度还是不够,10次有3-4次按下去没反应,继续努力中。
回复

使用道具 举报

ID:161164 发表于 2021-8-27 10:30 | 显示全部楼层
灰小伙 发表于 2021-8-27 10:17
谢谢lkc8210大佬的指导,我明白了为什么会产生方波。
只是目前按键的灵敏度还是不够,10次有3-4次按下去 ...

把delay(200);改短一点试试
回复

使用道具 举报

ID:881204 发表于 2021-8-27 10:41 | 显示全部楼层
lkc8210 发表于 2021-8-27 10:30
把delay(200);改短一点试试

下面是最新的代码。
void delay (unsigned int ms);
int main(void)
{
        unsigned char temp=0;
        DDRB = 0x0F;
        PORTB = 0x00;//输出低
        while(1)
        {
                temp = (PINA & (_BV(DDA0)));  //KEY按下 检测
        if (!temp)
        {
                delay(20);
                        if(!(PINA & (_BV(DDA0))))
                        {
                        while(!(PINA & (_BV(DDA0))));//KEY释放 检测
                        delay(10);
                         DDRB = 0x0F;
                         PORTB = 0x02; //输出高
                        }
        }
                                temp = (PINA & (_BV(DDA0)));  //_BV是左移一位。
                                if (!temp)
                                {
                                delay(20);
                                        if(!(PINA & (_BV(DDA0))))
                                        {
                                        while(!(PINA & (_BV(DDA0)))); //KEY释放 检测
                                        delay(10);
                                        DDRB = 0x0F;
                                        PORTB = 0x00;//输出低
                                        }
                                }
        }
          return 0;
}

void delay (unsigned int ms)
        {
                unsigned int i,j;
                for(i=0;i<ms;i++)
                {
                        for(j=0;j<1000;j++);
                }
        }
回复

使用道具 举报

ID:161164 发表于 2021-8-27 11:10 | 显示全部楼层
灰小伙 发表于 2021-8-27 10:41
下面是最新的代码。
void delay (unsigned int ms);
int main(void)

???
为什么还是要这样写?
虽然加了释放检测令PB1不会产生方波
但这种写法让PB1 的输出结果取决于是上半部分代码先扫到按键还是下半部分先扫到
太随机了
回复

使用道具 举报

ID:881204 发表于 2021-8-27 11:34 | 显示全部楼层
lkc8210 发表于 2021-8-27 11:10
???
为什么还是要这样写?
虽然加了释放检测令PB1不会产生方波

抱歉,可能是我的思路有问题。
我想的是:为了“随时检测按键输入值(因为只要开机,用户可能按无数次按键)”
回复

使用道具 举报

ID:881204 发表于 2021-8-30 09:58 | 显示全部楼层
换了个思路,情况有所改善,但还是有20%的按键不被认识
代码如下:
int main(void)
{
        unsigned char temp=0;
        unsigned char count = 0;
        unsigned char V6=0;
        DDRB = 0x0F;
        PORTB = 0x00;//初始化,输出低
        while(1)
        {
                temp = (PINA & (_BV(DDA0)));  //KEY按下 检测
                delay(10);
             while(!(PINA & (_BV(DDA0))));//KEY释放 检测
            delay(10);
                 switch(V6)
                 {
            case 0:
            if(temp==0)
            {
                    V6=1;
                    count++;
                    DDRB = 0x0F;
                    PORTB = 0x02; //输出高
            }
            else
            {
                    V6=0;
                    count=0;
                    DDRB = 0x0F;
                    PORTB = 0x00; //输出保持低
            }
            break;
        case 1:
                        if(temp==0)
                        {
                              V6=0;
                               count++;
                               DDRB = 0x0F;
                                PORTB = 0x00; //输出低
                        }
                        else
                        {
                                V6=1;
                                count=0;
                                DDRB = 0x0F;
                                PORTB = 0x02; //输出保持高
                        }
                        break;                       
                                        }
                                }
          return 0;
}
回复

使用道具 举报

ID:161164 发表于 2021-8-30 11:45 | 显示全部楼层
灰小伙 发表于 2021-8-30 09:58
换了个思路,情况有所改善,但还是有20%的按键不被认识
代码如下:
int main(void)

直接取反不香吗?
PORTB = PORTB ^ 0x02;
回复

使用道具 举报

ID:881204 发表于 2021-8-30 12:39 | 显示全部楼层
lkc8210 发表于 2021-8-30 11:45
直接取反不香吗?
PORTB = PORTB ^ 0x02;

大佬,你好~
因为我这个按键要循环4个状态,按1次 输出高。第2次 输出方波1,第3次输出方波2,第4次输出低、
谢谢!
回复

使用道具 举报

ID:161164 发表于 2021-8-30 13:39 | 显示全部楼层
灰小伙 发表于 2021-8-30 12:39
大佬,你好~
因为我这个按键要循环4个状态,按1次 输出高。第2次 输出方波1,第3次输出方波2,第4次输出 ...

方波1和方波2有什么分别?

另外,从你的代码来看
PINB1 只会按1次 输出高。第2次 输出低,如此循环
回复

使用道具 举报

ID:881204 发表于 2021-8-30 14:05 | 显示全部楼层
lkc8210 发表于 2021-8-30 13:39
方波1和方波2有什么分别?

另外,从你的代码来看

占空比不同。
回复

使用道具 举报

ID:881204 发表于 2021-8-30 14:06 | 显示全部楼层
lkc8210 发表于 2021-8-30 13:39
方波1和方波2有什么分别?

另外,从你的代码来看

代码没加入。加了以后 程序执行不了。。。
while(1)
        {
                temp = (PINA & (_BV(DDA0)));  //KEY按下 检测
                delay(2);
             while(!(PINA & (_BV(DDA0))));//KEY释放 检测
            delay(2);
                 switch(V6)
                 {
            case 0:
            if((temp==0)&&(V6==0))
            {
                    V6=1;
                                DDRB = 0x0F;
                                PORTB = 0x01; //输出高
            }
            else
            {
                    V6=0;
                                DDRB = 0x0F;
                                PORTB = 0x00; //输出保持低
            }
            break;
////////////////////////////////////////////////////////////////////////                       
                        case 1:
                        if((temp==0)&&(V6==1))
                        {
                                V6=2;
                                while (1)//输出方波
                                {
                                                                DDRB = 0x0F;
                                                                PORTB = 0x00; //输出低
                                                                delay(10);
                                                                DDRB = 0x0F;
                                                                PORTB = 0x01; //输出高
                                                                delay(10);       
                                                                if(temp==0)
                                                                break;
                                }
                        }
                        else
                        {
                                V6=1;
                                DDRB = 0x0F;
                                PORTB = 0x01; //输出保持高
                        }
                        break;
                        ///////////////////////////////////////////////////////////////////////
                        case 2:
                        if((temp==0)&&(V6==2))
                        {
                    V6=0;
                                DDRB = 0x0F;
                                PORTB = 0x00; //输出低
                        }
                        else
                        {
                                V6=1;
                                DDRB = 0x0F;
                                PORTB = 0x01; //输出保持高
                        }
                        break;
                                                default:
                                                {
                                                        DDRB = 0x0F;
                                                        PORTB = 0x00; //输出低
                                                }                       
                                        }                                 
                                }
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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