ATmega8 up/down 计数器计数不正确

ATmega8 up/down counter not counting correctly

我想构建一个 5 位数的 up/down 计数器。当我能让模拟工作时,我会更乐意购买零件来构建它。到目前为止,我使用的是 ATmega8,但坦率地说,只要组件相当便宜,任何解决方案都适合我。

我在网上找到了一个简单的递增计数器,并将其更改为也包含递减函数。我从代码中删除了一些可怕的 _delay_ms(1000) 语句,这些语句可能是为了防止在输入被保留时进行多次计数?它使计数器非常缓慢且反应迟钝。这是我到目前为止所拥有的:

我遇到的问题是它不向上计数,向下计数时不显示零。

代码: #包括 #包括 #包括 #include

#define F_CPU 4000000

volatile uint16_t digits[5]={0,0,0,0,0}; //INITIALISE VARIABLE TO STORE INDIVIDUAL DIGITS OF THE NUMBER

void breakup(uint16_t num) {  //FUNCTION TO FIND THE INDIVIDUAL DIGITS OF THE NUMBER
                              // AND STORE THEM IN A GLOBAL VARIABLE
    DDRD=0xFF; // INITIALISE PORTD AS ALL OUTPUT
    PORTD=0x00;
    unsigned int i=0;
    while (num!=0) {
        digits[i]=num%10;
        num=num/10;
        i++;
    }
    for(i=0;i<5;i++) {
        PORTD=(1<<i); // 'i'th PORTD GIVEN HIGH
        display(digits[i]);
        _delay_us(600);
        PORTD=(0<<i); //'i'th PORTD GIVEN LOW
    }
}

void display (uint16_t num) { // Bit patterns changed from the original to correct for my hardware layout.
    DDRB=0b11111111;
    PORTB=0xFF;
    switch(num) {
        case 0:
        PORTB=0b00111111;
        break;
        case 1:
        PORTB=0b00000110;
        break;
        case 2:
        PORTB=0b01011011;
        break;
        case 3:
        PORTB=0b01001111;
        break;
        case 4:
        PORTB=0b01100110;
        break;
        case 5:
        PORTB=0b01101101;
        break;
        case 6:
        PORTB=0b01111101;
        break;
        case 7:
        PORTB=0b00000111;
        break;
        case 8:
        PORTB=0b01111111;
        break;
        case 9:
        PORTB=0b01101111;
        break;
        default:
        PORTB=0xFF;
    }
}

int main(void) {
    DDRB=0xFF; //Initialise PORTB as all outputs.
    DDRC=0x00;   //Initialise PORTC as all inputs.
    PORTC=0b01000000;  //Enable internal pullup for the reset pin.
    char x;
    char down_button_press = 0;
    char up_button_press = 0;
    uint16_t i, c=5;
    while(1) {
        x=PINC&0b00000001; //Check condition of PC0 DOWN button.
        if (x==0 && down_button_press==0) {
            c--;
            breakup(c); //Pass c to the breakup routine and display.
            down_button_press++;
        }
        if (x==1) {
        down_button_press = 0;
        }
        x=PINC&0b00000010; //Check condition of PC1 UP button.
        if (x==0 && up_button_press==0) {
            c++;
            breakup(c); //Pass c to the breakup routine and display.
            up_button_press++;
        }
        if (x==1) {
        up_button_press = 0;
        }
        else
        breakup(c);
    }
}

最后的代码中的递增和递减计数位基本相同,所以我不知道为什么它倒数而不是递增。为了在按下按钮时停止计数器进行多次计数,我包含了一种闩锁 && up_button_press==0。它不应该是去抖动代码,它只是让我在每次按下按钮时得到单次递增和单次递减。 我设法解决的问题是,它不算数,因为当按钮回到高位时上锁存器没有清除 - 所以 && up_button_press==0 条件永远不会为真:

if (x==1) {
    up_button_press = 0;
    }

如果有人可以帮助我使它正常工作,我将不胜感激。如果有帮助,我可以添加 Proteus 模拟文件吗?

你的错误在这里:

x=PINC&0b00000010; //Check condition of PC1 UP button.
...
if (x==1) {
    up_button_press = 0;
如果按下按钮,

x 将是 2(因为你的掩码是 0x2 用于检查 PORTC 的第二位),所以检查:

if (x==2) {
    up_button_press = 0;

如您所知,代码存在一些问题。

1) 关于代码块,在 breakup() 中以:

开头
while (num!=0) {

无论 num

的值如何,此循环应始终迭代 5 次

这将导致显示所有可能的数字,包括 0

以下代码是我实现所需功能的方式。

注意大多数幻数的转换,使其具有有意义的名称。

注意 main() 函数中的逻辑清理。

注意可能显示值的扩展,从 16k 到 99999。

注意杂乱和不需要的变量的删除。

注意使用有意义(且唯一)的变量名。

我想知道为什么使用内部上拉电阻而不是 PINxy 输出来设置 7 段数字。但我保留了它与 OP 发布的代码相同。

#include <stdint.h>

#define F_CPU 4000000

#define NUM_DIGITS (5)
#define MAX_DISPLAYED_VALUE (99999)

#define UP_BUTTON (0b00000010)
#define DN_BUTTON (0b00000001)

#define DIGIT_0   (0b00111111)
#define DIGIT_1   (0b00000110)
#define DIGIT_2   (0b01011011)
#define DIGIT_3   (0b01001111)
#define DIGIT_4   (0b01100110)
#define DIGIT_5   (0b01101101)
#define DIGIT_6   (0b01111101)
#define DIGIT_7   (0b00000111)
#define DIGIT_8   (0b01111111)
#define DIGIT_9   (0b01101111)

// prototypes
void initialize( void );
void display   ( uint8_t digitValue );
void breakup   ( uint32_t num );

uint8_t digits[]={0,0,0,0,0}; //INITIALISE VARIABLE TO STORE INDIVIDUAL DIGITS OF THE NUMBER



int main(void)
{

    uint32_t  num = 0;  // initialize value to display

    initialize();       // initialize hardware

    while(1)
    {
        if (PINC & DN_BUTTON)
        { // then down button pressed
            if( num > 0 )
            {
                num--;
            }
        }

        else if ( PINC & UP_BUTTON)
        { // then up button pressed
            if( num < MAX_DISPLAYED_VALUE )
            {
                num++;
            }
        } // end if which button
        breakup( num );
    } // end while forever
} // end function: main



void breakup(uint32_t num)
{  //FUNCTION TO FIND THE INDIVIDUAL DIGITS OF THE NUMBER
                              // AND STORE THEM IN A GLOBAL VARIABLE
    for( size_t i=0; i< NUM_DIGITS; i++)
    {
        digits[i]= (uint8_t)(num%10);
        num=num/10;
    }

    for( size_t i=0; i<NUM_DIGITS; i++)
    {
        display(digits[i]); // preset the value to display
        PORTD=(1<<i);  // select which 7 segment digit
        _delay_us(600);
        PORTD = 0;    // unselect all the seven segment displays
    }
}



void display ( uint8_t digitValue)
{ // Bit patterns changed from the original to correct for my hardware layout.

    switch(digitValue)
    {
        case 0:
            PORTB=DIGIT_0;
            break;

        case 1:
            PORTB=DIGIT_1;
            break;

        case 2:
            PORTB=DIGIT_2;
            break;

        case 3:
            PORTB=DIGIT_3;
            break;

        case 4:
            PORTB=DIGIT_4;
            break;

        case 5:
            PORTB=DIGIT_5;
            break;

        case 6:
            PORTB=DIGIT_6;
            break;

        case 7:
            PORTB=DIGIT_7;
            break;

        case 8:
            PORTB=DIGIT_8;
            break;

        case 9:
            PORTB=DIGIT_9;
            break;

        default:
            break;
    } // end switch
} // end function: display



void initialize()
{
    DDRB=0xFF;          // all outputs
    //PORTB=0xFF;       // enable all internal pullups

    DDRC=0x00;         // all inputs.
    PORTC=0b01000000;  //Enable internal pullup for the reset pin.

    DDRD=0xFF;         // all outputs
    PORTD=0x00;        // disable all internal pullups
} // end function: initialize