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
我想构建一个 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
这将导致显示所有可能的数字,包括 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