Timer (mit externem Quarz)
Hallo zusammen, ich habe folgendes Problem:
Ich möchte mit dem Timer0 eine Sieben-Segment-Anzeige zum blinken bringen. Das Problem: Es funktioniert nicht ;).
Hier erstmal mein Code:
Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <../../avr/include/util/delay.h>
// gobale Variablen
uint8_t summerOn = 0;
uint8_t timeRunning = 0;
uint8_t counter = 0;
uint8_t _NUM_ARRAY[10] = {(1<<PD1) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD2) | (1<<PD5),
(1<<PD0) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD7),
(1<<PD0) | (1<<PD2) | (1<<PD3) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD5),
(1<<PD0) | (1<<PD1) | (1<<PD3) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD2) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD5) | (1<<PD7)};
uint8_t _NUM_A_ALL_ON = (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7);
uint8_t _NUM_A_ALL_OFF = ~((1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7));
void checkSummer();
void drawDisplay();
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
if ( ! (*port & (1 << pin)) )
{
// Pin wurde auf Masse gezogen, 100ms warten
_delay_ms(50); // max. 262.1 ms / F_CPU in MHz
//_delay_ms(50);
if ( *port & (1 << pin) )
{
// Anwender Zeit zum Loslassen des Tasters geben
//_delay_ms(50);
//_delay_ms(50);
return 1;
}
}
return 0;
}
void checkSummer()
{
/*if (summerOn == 1)
{
PORTB |= (1<<PB1);
PORTB ^= (1<<PB1);
_delay_ms(500);
}*/
}
void drawDisplay()
{
//if (timeRunning == 0)
//{
// PORTD = _NUM_A_ALL_OFF;
//_delay_ms(500);
//PORTD = _NUM_ARRAY[counter];
//}
}
//SIGNAL(SIG_OVERFLOW1)
ISR(TIMER0_OVF_vect)
{
//PORTD = _NUM_A_ALL_OFF;
//_delay_ms(500);
PORTD = _NUM_ARRAY[counter];
PORTB |= (1<<PB1);
}
int main(void)
{
// Ausgänge definieren
DDRD = 0xff; //Ziffern-Anzeige
DDRB |= (1<<PB1); // Summer
// Eingänge definieren
DDRB |= (1<<PB0);
// Display überprüfen
PORTD = _NUM_A_ALL_ON;
// _delay_ms(1000);
// PORTD = _NUM_A_ALL_OFF;
//Timer aktivieren
TCCR0 = (1<<CS01)|(1<<CS00);
TCNT0 = 0;
TIMSK | (1<<TOIE0);
sei();
counter = 6;
while(1)
{
if (debounce(&PINB, PB0))
{
counter += 1;
if (counter > 9)
counter = 0;
if (counter == 9)
summerOn = 1;
}
checkSummer();
drawDisplay();
}
return 0;
}
Sorry für die vielen auskommentierten Textzeilen aber ich habe halt etwas rumprobiert um das Ding zum laufen zu bringen. Ich möchte es nun einfach erstmal schaffen, dass das Programm in die ISR-Routine springt und dort den Summer zum ertönen bringt. Sieht jemand hier irgendeinen Fehler?
Ich verwende übrigens einen externen 4 Mhz Quarz.
Mfg,
Rahvin
Re: Timer (mit externem Quarz)
Zitat:
Zitat von Rahvin
TIMSK | (1<<TOIE0);
Fehlt da nicht ein = ?
Bin mir auch nicht ganz sicher ob
Zitat:
Zitat von Rahvin
PORTB |= (1<<PB1);
PORTB ^= (1<<PB1);
so direkt eine gute Idee ist, denn da wird ja angeschaltet und praktisch verzögerungsfrei wieder aus. Ich denke es wird wohl eher ein Geräusch geben wenn Du zwischen den beiden Befehlen zeitmässig etwas "Luft" (für die Lautsprechermembran zum Schwingen) lässt.
Re: Timer (mit externem Quarz)
Zitat:
Zitat von Steinigtmich
Zitat:
Zitat von Rahvin
TIMSK | (1<<TOIE0);
Fehlt da nicht ein = ?
Stimmt... aber auch mit = geht es nicht.
Zitat:
Zitat von Steinigtmich
Zitat:
Zitat von Rahvin
PORTB |= (1<<PB1);
PORTB ^= (1<<PB1);
Auch da hast du Recht aber die Funktion ist ja auch auskommentiert ;).
Zitat:
Zitat von franzl
Hi,
also einen Eingang definiert man wenn dann so:
// Eingänge definieren
DDRB &=~ (1<<PB0); und nicht so DDRB |= (1<<PB0);
Du hast Recht, das ist mir auch schon aufgefallen, das Problem ist, wenn ich den Eingang so definiere: DDRB &=~ (1<<PB0) dann gehts nicht :shock:
So allerdings funktionierts: DDRB |= (1<<PB0).
Der Taster an PB0 funktioniert (auch wenn der Eingang scheinbar 'falsch' definiert ist). Wenn er gedrückt wird, dann wird ein counter hochgezählt und die Zahl auf der 7-Segment-Anzeige angezeigt. Diese soll dabei jetzt noch blinken und das funktioniert leider nicht :(.
Hier jetzt nochmal der ursprüngliche Code:
Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <../../avr/include/util/delay.h>
// gobale Variablen
uint8_t summerOn = 0;
uint8_t timeRunning = 0;
uint8_t counter = 0;
uint8_t _NUM_ARRAY[10] = {(1<<PD1) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD2) | (1<<PD5),
(1<<PD0) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD7),
(1<<PD0) | (1<<PD2) | (1<<PD3) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD5),
(1<<PD0) | (1<<PD1) | (1<<PD3) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD2) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD7),
(1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD5) | (1<<PD7)};
uint8_t _NUM_A_ALL_ON = (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7);
uint8_t _NUM_A_ALL_OFF = ~((1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6) | (1<<PD7));
void checkSummer();
void drawDisplay();
inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
{
if ( ! (*port & (1 << pin)) )
{
// Pin wurde auf Masse gezogen, 100ms warten
_delay_ms(50); // max. 262.1 ms / F_CPU in MHz
//_delay_ms(50);
if ( *port & (1 << pin) )
{
// Anwender Zeit zum Loslassen des Tasters geben
//_delay_ms(50);
//_delay_ms(50);
return 1;
}
}
return 0;
}
void checkSummer()
{
if (summerOn == 1)
{
PORTB ^= (1<<PB1);
_delay_ms(500);
}
}
void drawDisplay()
{
PORTD = _NUM_ARRAY[counter];
}
//SIGNAL(SIG_OVERFLOW1)
ISR(TIMER0_OVF_vect)
{
//PORTD = _NUM_A_ALL_OFF;
//_delay_ms(500);
//PORTD = _NUM_ARRAY[counter];
PORTB |= (1<<PB1);
}
int main(void)
{
// Ausgänge definieren
DDRD = 0xff; //Ziffern-Anzeige
DDRB |= (1<<PB1); // Summer
// Eingänge definieren
DDRB |= (1<<PB0);
//DDRB &= ~(1<<DDB0);
// Display überprüfen
PORTD = _NUM_A_ALL_ON;
_delay_ms(1000);
PORTD = _NUM_A_ALL_OFF;
//Timer aktivieren
TCCR0 = (1<<CS01)|(1<<CS00);
TCNT0 = 0;
TIMSK |= (1<<TOIE0);
sei();
counter = 0;
while(1)
{
if (debounce(&PINB, PB0))
{
counter += 1;
if (counter > 9)
counter = 0;
if (counter == 9)
summerOn = 1;
}
checkSummer();
drawDisplay();
}
return 0;
}
Dieser Code funktioniert, solange ich das sei(); auskommentiert habe. Also der Taster funktioniert, der Counter wird erhöht und das Display zeigt die entsprechende Zahl an. Ist der Counter == 9, so fängt der Summer an zu piepen.
Ist das sei(); einkommentiert, so sind alle LEDs im Display an, der Schalter reagiert nicht und die ISR-Routine wird nicht ausgeführt, denn sonst würde es ja piepen.
Ich habs mittlerweile auch mit Timer1 ausprobiert aber das klappt auch nicht :(. Hat irgendjemand noch ne Idee?... oder vielleicht eine Erklärung dafür, dass der Taster nur dann funktioniert, wenn ich den Port als Ausgang anstatt Eingang definiere :shock: ?