Witam! Siedzę już drugi dzień nad multipleksem w budziku i tracę już cierpliwość.
Podejrzewam, że problem leży w zmiennych. Jednak trudno mi go zlokalizować, bo za długo siedzę nad tym samym. Przydałoby się świeże spojrzenie na ten kod.
Pokrótce opiszę problem. Po wstawieniu wartości odpowiadającej za wyświetlenie "--:--" do tablicy "toDisplay" nie mogę w dalszej części programu wyświetlić nic nowego. Chcę, żeby po upływie sekundy program zaktualizował godzinę. Jedyne co otrzymuje to wyłączenie co sekundę wyświetlacza na ułamek sekundy i ponowne wyświetlenie "--:--" i tak w kółko.
Poniżej wstawiam kod. Rzucie na niego okiem.
Timer1 odpowiada za multipleks wyświetlacza. Dane do wyświetlenia pobiera z tablicy "toDisplay". Dodatkowo sprawdza czy ma zostać włączona dioda alarmu. Timer2 działa asynchronicznie z kwarcem 32,768kHz. Wykonuje standardowe instrukcje liczenia czasu. Nic zmyślnego. Funkcja "Display_Update()" 'konwertuje' czas z struktury "Clock" do tablicy "toDisplay". Dodatkowo włącza diodę sekundnika. Zamieszanie z diodami sekundnika i alarmu komplikują nieco sprawę, ale akurat ta część programu działa dobrze.
Podejrzewam, że problem leży w zmiennych. Jednak trudno mi go zlokalizować, bo za długo siedzę nad tym samym. Przydałoby się świeże spojrzenie na ten kod.
Pokrótce opiszę problem. Po wstawieniu wartości odpowiadającej za wyświetlenie "--:--" do tablicy "toDisplay" nie mogę w dalszej części programu wyświetlić nic nowego. Chcę, żeby po upływie sekundy program zaktualizował godzinę. Jedyne co otrzymuje to wyłączenie co sekundę wyświetlacza na ułamek sekundy i ponowne wyświetlenie "--:--" i tak w kółko.
Poniżej wstawiam kod. Rzucie na niego okiem.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define F_CPU 2000000UL
#define F_OSC 2000000UL
/*
Anody wyświetlacza - PORTB
Wyswietlacz 1 - PB0
Wyswietlacz 2 - PB1
Wyswietlacz 3 - PB2
Wyswietlacz 4 - PB3
Katody wyswietlacza - PORTD
Segment A - PD0
Segment B - PD1
Segment C - PD2
Segment D - PD3
Segment E - PD4
Segment F - PD5
Segment G - PD6
Dioda alarmu - PB4
Buzzer - PB5
Sekundnik - PD7
Przyciski - PORTC
Przycisk A - PC0
Przycisk B - PC1
Przycisk C - PC2
Przycisk D - PC3
Przycisk E - PC4
*/
#define LED_Alarm PB4
#define LED_Sec PD7
// Zmienne
struct {
unsigned char Hours;
unsigned char Minutes;
unsigned char Seconds;
unsigned char LEDisOn;
char delta;
} Clock;
struct {
unsigned char isSet;
unsigned char isActive;
unsigned char Hour;
unsigned char Minute;
} Alarm;
volatile char toDisplay[4];
char digit[10] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10 };
// Definicje funkcji
void SecLed_Toggle(void); // Wylacza/wylacza diody sekundnika
void Alarm_LedOn(void); // Wlacz diode alarmu
void Alarm_LedOff(void); // Wylacz diode alarmu
void Buzzer_On(void); // Wlacz buzzer
void Buzzer_Off(void); // Wylacz buzzer
void Clock_IncHour(void); // Zwieksz godzine zegara
void Clock_IncMinute(void); // Zwieksz minuty zegara
void Alarm_IncHour(void); // Zwieksz godzine alarmu
void Alarm_IncMinute(void); // Zwieksz minuty alarmu
void Display_Update(void); // Uakutalnia wyswietlacz
/*
a
-------
| |
f| |b
| g |
-------
| |
e| |c
| |
-------
d
gfedcba
0 - 1000000 - 0x40
1 - 1111001 - 0x79
2 - 0100100 - 0x24
3 - 0110000 - 0x30
4 - 0011001 - 0x19
5 - 0010010 - 0x12
6 - 0000010 - 0x02
7 - 1111000 - 0x78
8 - 0000000 - 0x00
9 - 0010000 - 0x10
*/
unsigned char display = 0;
ISR(TIMER1_COMPA_vect) {
//SIGNAL(SIG_OVERFLOW1) { // Multipleks wyswietlacza
PORTD = toDisplay[display];
if(Alarm.isSet) { // Dodatkowo wlacza diode alarmu
PORTB = ~((1<<display)|(1<<LED_Alarm));
} else {
PORTB = ~(1<<display);
}
display++;
if(display > 3)
display = 0;
/*
switch(display) {
case 0:
PORTD = toDisplay[0];
PORTB = ~(1<<0);
display++;
break;
case 1:
PORTD = toDisplay[1];
PORTB = ~(1<<1);
display++;
break;
case 2:
PORTD = toDisplay[2];
PORTB = ~(1<<2);
display++;
break;
case 3:
PORTD = toDisplay[3];
PORTB = ~(1<<3);
display++;
break;
case 4:
display = 0;
break;
}*/
}
//SIGNAL(SIG_OVERFLOW2) { // RTC (1 przerwanie/1 sek)
ISR(TIMER2_OVF_vect) {
Clock.Seconds++; // Dodaj sekunde
if (Clock.Seconds == 60) { // Jesli minelo 60 sekund
Clock.Minutes++; // Dodaj minute
if (Clock.Minutes == 60) { // Jesli minelo 60 minut
Clock.Hours++; // Dodaj godzine
if (Clock.Hours == 24) { // Jesli minely 24 godziny
Clock.Hours = 0; // Zeruj godziny
}
Clock.Minutes = 0; // Zeruj minuty
}
Clock.Seconds = 0; // Zeruj sekundy
}
toDisplay[0] = 0x40;
}
void SecLed_Toggle(void) {
Clock.LEDisOn = !Clock.LEDisOn;
}
void Display_Update(void) {
if(Clock.LEDisOn) { // Wlacza sekundnik
toDisplay[0] = (~(1<<LED_Sec) & digit[Clock.Minutes / 10]);
toDisplay[1] = (~(1<<LED_Sec) & digit[Clock.Minutes % 10]);
toDisplay[2] = (~(1<<LED_Sec) & digit[Clock.Seconds / 10]);
toDisplay[3] = (~(1<<LED_Sec) & digit[Clock.Seconds % 10]);
} else {
toDisplay[0] = digit[Clock.Minutes / 10];
toDisplay[1] = digit[Clock.Minutes % 10];
toDisplay[2] = digit[Clock.Seconds / 10];
toDisplay[3] = digit[Clock.Seconds % 10];
}
}
int main(void) {
// Konfiguracja pinow
DDRB = 0xFF; // Wyjscie (Digit)
PORTB = 0xFF; // Ustaw stan wysoki (wylacza wyswietlacz, diode alarmu i buzzer)
DDRD = 0xFF; // Wyjscie
PORTD = 0xFF; // Ustaw stan wysoki (wylacza segmenty wyswietlaczy i diody sekundika)
DDRC = 0x00; // Wejscie
PORTC = 0x1F; // Pin PC5 bez rezystora pull-up
TCCR1B |= (1<<CS10); // Ustaw timer1 z preskalerem 1
TCCR1B |= (1<<WGM12); // Ustaw timer1 w tryb CTC
OCR1A = 4999; // Do ilu liczy timer1;dla uzyskania 200Hz
TIMSK |=(1<<OCIE1A); // Wlacza przerywania Timer0
// Timer2 - RTC
TIMSK &= ~((0<<TOIE2)|(0<<OCIE2)); // Wylacza przerywania Timer2
ASSR |= (1<<AS2); // Tryb asynchroniczny, z oscylatorem 32,768kHz
TCNT2 = 0x00; // Licznik Timer2 = 0
TCCR2 |= ((1<<CS22)|(1<<CS20)); // Preskaler 128
while (ASSR & 0x07) { }; // Czekaj az Timer2 jest uaktualniony
TIMSK |= (1<<TOIE2); // Wlacz przerywania Timer0
Clock.Hours = 0;
Clock.Minutes = 0;
Clock.Seconds = 0;
Clock.LEDisOn = 0x01;
Alarm.Hour = 0;
Alarm.Minute = 0;
Alarm.isSet = 0;
Alarm.isActive = 0;
toDisplay[0] = 0xBF; // Wyswietla --:--
toDisplay[1] = 0xBF;
toDisplay[2] = 0xBF;
toDisplay[3] = 0xBF;
sei(); // Wlacz przerywania
unsigned char tempSeconds = 0;
while(1) { // Petla glowna
if(tempSeconds != Clock.Seconds) {
tempSeconds = Clock.Seconds;
SecLed_Toggle();
Display_Update();
}
}
}Timer1 odpowiada za multipleks wyświetlacza. Dane do wyświetlenia pobiera z tablicy "toDisplay". Dodatkowo sprawdza czy ma zostać włączona dioda alarmu. Timer2 działa asynchronicznie z kwarcem 32,768kHz. Wykonuje standardowe instrukcje liczenia czasu. Nic zmyślnego. Funkcja "Display_Update()" 'konwertuje' czas z struktury "Clock" do tablicy "toDisplay". Dodatkowo włącza diodę sekundnika. Zamieszanie z diodami sekundnika i alarmu komplikują nieco sprawę, ale akurat ta część programu działa dobrze.
