ATmega8向上/向下计数器计数不正确

时间:2016-02-07 19:48:21

标签: c embedded avr

我想建立一个5位数的加/减计数器。当我可以让模拟工作时,我会更乐意购买它的零碎件。到目前为止我使用的是ATmega8,但坦率地说,只要组件价格相当便宜,任何解决方案对我都有用。

我在网上发现了一个简单的向上计数器,并将其更改为包含向下功能。我从代码中删除了一些可疑的_delay_ms(1000)语句,这些语句可能会在输入被保存时阻止多次计数?它使计数器非常缓慢和反应迟钝。这是我到目前为止所拥有的: Circuit diagram

我遇到的问题是它没有计数,当它倒计时它不显示零。

代码:     #包括     #包括     #包括     #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模拟文件吗?

2 个答案:

答案 0 :(得分:2)

你的错误在这里:

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

将为2(因为您的掩码为0x2以检查PORTC的第二位),因此请检查:

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

答案 1 :(得分:1)

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

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