我想建立一个5位数的加/减计数器。当我可以让模拟工作时,我会更乐意购买它的零碎件。到目前为止我使用的是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模拟文件吗?
答案 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
这将导致显示所有可能的数字,包括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