Forum: Mikrocontroller und Digitale Elektronik Binär UHR Programmcode in AVR-GCC


von Sebastian H. (sebimax)


Angehängte Dateien:

Lesenswert?

Hallo,

ich programmiere im moment eine Binär Uhr und habe jetzt das Uhren 
Script fertig :)

Ich weiß das es nicht genau ist, aber ich werde das ganze bei 
gelegenheit mit einem Quarz anpassen.


Nun weiß ich allerdings nicht ob der Quellcode so stimmt (ich kann ihn 
leider auch nicht testen).


Würde mich freuen wenn ihn mal jemand schnell durchlesen könnte und mir 
sagen könnte ob das so funktioniert.


Grüße
Sebastian

von gast (Gast)


Lesenswert?

> _delay_ms(1000);
das wird je nach verwendetem quarz nicht klappen, du solltest lieber 
einen timer verwenden (max einstellbare zeit: 262.1 ms / F_CPU in MHz)
die abfragen benötigen ja auch zeit, du hast also deine 1000ms+zeit für 
abfragen, also definitiv mehr als 1s

von Gottfried S. (gottfried)


Lesenswert?

Einige Anfängerfehler sind enthalten:
if (s2 = 6)
muss geändert werden auf
if (s2 == 6)
sonst wird der Wert 6 zu s2 zugewiesen und das ergibt immer "Wahr"
gleiches bei h2 und m2

[edit]
noch etwas:
if (h1 > 9) && (h2 < 2)
 sollte so aussehen
if ((h1 > 9) && (h2 < 2))  oder if (h1 > 9 && h2 < 2)

[edit]
Und Strichpunkte nicht vergessen
  h2 = h2 + 1
  h1 = 0

von Stefan E. (sternst)


Lesenswert?

Und folgende Zeile ist auch von der Logik her falsch:
if (h2 = 2) && (h1 < 5)

von Sebastian H. (sebimax)


Lesenswert?

wow gleich so viele Fehler ^^

Ich werde sie mal berichtigen und dann nochmal den Code schicken.

Achja @Stefan Ernst:
   Ich find den Fehler in der Logic nicht. Meinst du das ich es
   so schreiben soll oder etwas anderes?
      -> if ((h1 == 5) &&(h2 == 2))

Achja und @ Gast:
   Wie soll ich das mit dem delay_ms(1000) dann anders schreiben?

Danke schonmal für eure Hilfe.

von Gottfried S. (gottfried)


Lesenswert?

Denke die machen wir alle, da müssen wir durch :)

von Sebastian H. (sebimax)


Lesenswert?

Ja ich programmier noch net lange Microprozessoren. Bin also noch net so 
routiniert :)

von Stefan E. (sternst)


Lesenswert?

> Achja @Stefan Ernst:
>   Ich find den Fehler in der Logic nicht. Meinst du das ich es
>   so schreiben soll oder etwas anderes?
>      -> if ((h1 == 5) &&(h2 == 2))

Bei "if ((h2 == 2) && (h1 < 5))" hat der Tag nur 20 Stunden,
und bei obiger Zeile hat er 25 Stunden. ;-)

von Sebastian H. (sebimax)


Lesenswert?

OH danke....


Also richtig ist es dann so:
      if ((h1 == 4) && (h2 == 2))
      {
      h2 = 0;
      h1 = 0;
    }


Danke :)

Hätte mich dann gewundert wenn der Tag 25 Stunden hat ^^


Wie soll ich das mit dem Delay_ms(1000) anders schreiben damit die Uhr 
genauer wird?

von Stefan E. (sternst)


Lesenswert?

> Wie soll ich das mit dem Delay_ms(1000) anders schreiben damit die Uhr
> genauer wird?

Du konfigurierst einen der Timer so, dass er ein mal pro Sekunde einen 
Interrupt auslöst, und in der Interruptroutine machst du dann deine 
Berechnungen. Dann ist deine Uhr so genau, wie der Takt des AVR.
Falls der Timer sich nicht auf 1s konfigurieren lässt, kannst du ihn 
z.B. auch auf 10ms programmieren, und dann erst mal eine Variable bis 
100 zählen lassen, quasi als Vorstufe zu den Sekunden.

von Gottfried S. (gottfried)


Lesenswert?

Am besten einen externen 32.768kHz Uhrenquarz und per Interrupt im 
Sekundentakt die Uhrzeit erhöhen siehe hier 
Beitrag "Warum Uhrenquarz 32,768 kHz?"

von Sebastian H. (sebimax)


Lesenswert?

Wie kann man dass den Umrechnen...


Also zum Beispiel woher weiß man das wieveile interupts in der Sekunde 
ein 16 MHz Quarz auslöst?

von Stefan E. (sternst)


Lesenswert?

Sebastian H. wrote:
> Also zum Beispiel woher weiß man das wieveile interupts in der Sekunde
> ein 16 MHz Quarz auslöst?

Das stellt man sich selber entsprechend passend ein.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Die_Timer.2FCounter_des_AVR

von Sebastian H. (sebimax)


Lesenswert?

Danke ich werde mir das tutorial mal durchlesen und dann weitere fragen 
stellen (sofern noch welche vorhanden sind)


Grüße
Sebastian

von Gottfried S. (gottfried)


Lesenswert?

Den Timer auf Asynchronen Modus schalten und den Teiler auf / 128 
einstellen und einen OVF Interrupt schreiben

(32768 / 128 = 256) der Timer läuft von 0 auf 255 und beim Überlauf wird 
der Interrupt ausgeführt.

Beispiele gibt es hier
http://www.atmel.com/dyn/products/app_notes.asp?family_id=607
AVR134: Real-Time Clock using the Asynchronous Timer

von Sebastian H. (sebimax)


Lesenswert?

ok...



könnt mit vielleicht jemand einen einfachen interupt timer für den 
Anfang schicken, damit ich damit ein wenig rumbasteln kann und lernen 
kann wie das ganze funktionert?

von Sebastian H. (sebimax)


Angehängte Dateien:

Lesenswert?

Hallo,

da es mir im moment noch nicht auf die genauigkeit ankommt, habe ich mal 
das Programm weiter geschrieben.


Allerdings zeigt das ganze im moment nur blödsinn an (ausgegeben sollen 
nur die sekunden)


Wo liegt denn der Fehler??

Grüße
Sebastian

von Gottfried S. (gottfried)


Lesenswert?

Kenne nur die Interrupts vom IAR Compiler, bei gcc müsstest du die 
Interrupt Routine anpassen

// Initialisieren des Timers und freichalten des Interrupts
void InitUhr(void)
{
  TIMSK2 = 0;        //TC2 Interrupt Ausschalten
  ASSR = (1<<AS2);   //Timer/counter2 auf asynchronous mode (32,768kHz)
  TCNT2 = 0x00;
  TCCR2A = ((1<<CS22)|(1<<CS20)); //prescaler setzen / 128
  //Einen Uhrenquarz-takt abwarten
  while(ASSR & ((1<<TCN2UB)|(1<<OCR2UB)|(1<<TCR2UB)));
  TIMSK2 = (1<<TOIE2); //8-bit Timer/Counter2 Overflow Interrupt 
aktivieren
}


//Hauptprogramm
void main(void)
{
  ...
  InitUhr();
  while(1)
  {
    ...
  }
}

// Interrupt

#pragma vector=TIMER2_OVF_vect
void Time_Interrupt(void)
{
  // erhöhen der Urzeit
  ...
}

von Gottfried S. (gottfried)


Lesenswert?

Probier mal
_delay_ms(10); auf _delay_ms(1000);

Dann bei den &= die | in Klammer einschließen
PORTA &= ~ (1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA3);
wie folgt
PORTA &= ~ ((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 << PA3));

~ hat die selbe priorität wie | wenn ich mich nicht täusche

von Sebastian H. (sebimax)


Lesenswert?

das mit dem delay_ms hab ich schneller gemacht, damit irgendwas passiert 
:)

Bei _delay_ms(1000) hat das ewig gedauert.


Werde dann mal alle so PORTA &= ~ ((1 << PA0)|(1 << PA1)|(1 << PA2)|(1 
<< PA3)); umschreiben. Hoffe das funktioniert dann.

Fals ihr noch mehr fehler findet unbedingt posten :)

Danke für eure Hilfe ich melde mich dann wieder, wenn ich das geändert 
hab.

von Stefan E. (sternst)


Lesenswert?

So auf den ersten Blick würde ich sagen, du willst auf PA0 bis PA3 das 
Binärmuster von s1 ausgeben, oder?
PORTA &= 0xf0;
PORTA |= s1;

von Stefan E. (sternst)


Lesenswert?

Und wenn du zusätzlich auf PA4 - PA7 s2 ausgeben willst, wird es noch 
einfacher:
PORTA = (s2 << 4) | s1;

von Sebastian H. (sebimax)


Lesenswert?

SUPER danke das hat funktionier :)

von Sebastian H. (sebimax)


Lesenswert?

Die s1 sind aber nicht binär sondern 1 - 9 ^^

Jetzt brauch ich nur noch eine Interruptbefehl mit einem externen Quarz 
(oder am besten den Internen Quarz eines ATMega 16)

von Stefan E. (sternst)


Lesenswert?

Sebastian H. wrote:
> Die s1 sind aber nicht binär sondern 1 - 9 ^^

Hä? Wie meinst du das?

von Sebastian H. (sebimax)


Lesenswert?

naja s1 ist ja eine Variable in der immer + 1 Addiert wird ?

Vielleicht hab ich auch grad nen Denkfehler drin aber ich denke das wenn 
man das eingibt

PORTA = (s2 << 4) | s1;

dann wird als zweiter ausgang s1 ausgegeben (also zum beispiel 3) und 
das ist ja nicht binär :?

Fals ich mich jetzt irre bitte sagen :

Könnte mir vielleicht noch jemand einen Interruptbefehl mit einem 
externen Quarz (oder am besten den Internen Quarz eines ATMega 16) 
schreiben/schicken damit ich mir das mal anschauen kann (ich lerne sowas 
am besten wenn ich einen funktionierenden code vor mir habe) :)

von Daniel C. (cecky)


Lesenswert?

Hi,

geh doch einfach mal in die Codesammlung und such mal nach Peter 
Danneggers "genaue Sekunde". Kann ich nur Empfehlen.

Cecky

von Sebastian H. (sebimax)


Lesenswert?

#define fosc 80000000  //8 MHz Quarz zwischen XTAL 1 und XTAL 2
#define SEI __enable_interrupt()
#define CLI __disable_interrupt()

void init_Timer1(void)
{
  OCR1A = 0xBB7F;       // TOP = 47999
  TIMSK |= (1<<OCIE1A); // CTC-Interrupt zulassen
  TCCR1B = (1<<CS12) | (1<<WGM12); // Mode 4 (CTC; OCR), Timer starten 
PSC = 256
}
#pragma vector = TIMER1_COMPA_vect
__interrupt void TIMER1_COMPA_Interrupt(void)
{
  //Hier dann das mit der Uhr rein schreiben
}

int main( void )
{
  // Variablen vereinbaren / initialisieren

  init_Timer1();

  // Interrupts freigeben
  SEI;

  while(1)
  {
  }
  return 0;
}


Würde das funktionieren ??

@Daniel: den code kapier ich nicht ^^

von Stefan E. (sternst)


Lesenswert?

Sebastian H. wrote:
> dann wird als zweiter ausgang s1 ausgegeben (also zum beispiel 3) und
> das ist ja nicht binär :?

Und was glaubst du, wie diese 3 im Speicher steht, wie sie vom Prozessor 
verarbeitet wird und wie sie auf dem Port ausgegeben wird, wenn nicht 
binär?

von Sebastian H. (sebimax)


Lesenswert?

k cool :)

das wusste ich nicht :)

Da kann ich ja dann ganz schön viel code einsparen.

Was haltet ihr davon?


#define fosc 80000000  //8 MHz Quarz zwischen XTAL 1 und XTAL 2
#define SEI __enable_interrupt()
#define CLI __disable_interrupt()

void init_Timer1(void)
{
  OCR1A = 0xBB7F;       // TOP = 47999
  TIMSK |= (1<<OCIE1A); // CTC-Interrupt zulassen
  TCCR1B = (1<<CS12) | (1<<WGM12); // Mode 4 (CTC; OCR), Timer starten
PSC = 256
}
#pragma vector = TIMER1_COMPA_vect
__interrupt void TIMER1_COMPA_Interrupt(void)
{
  //Hier dann das mit der Uhr rein schreiben
}

int main( void )
{
  // Variablen vereinbaren / initialisieren

  init_Timer1();

  // Interrupts freigeben
  SEI;

  while(1)
  {
  }
  return 0;
}

von Gottfried S. (gottfried)


Lesenswert?

Sollte funktionieren, nur noch #define fosc von 80 MHz auf 8 MHz setzen.
Laut meinen Berechnungen ist 8000000 / 256 = 31250 auf den du den 
Compare Match setzen solltest

von Stefan E. (sternst)


Lesenswert?

Nein, mit dem GCC wird das ganz sicher nicht gehen.
Das ist Code für einen anderen Compiler (ICC ?).

von Sebastian H. (sebimax)


Lesenswert?

hm k hab ich mir aus dem forum zusammengestückelt.


Könnte mir jemand das ganze nach C für AVR-GCC umschreiben?

von Stefan E. (sternst)


Lesenswert?

1
#include <avr/interrupt.h>
2
3
4
void init_Timer1(void) {
5
6
  // Hier Timer initialisieren
7
}
8
9
10
ISR(TIMER1_COMPA_vect) {
11
12
  // Hier dein Uhr-Code
13
}
14
15
16
int main( void ) {
17
18
  init_Timer1();
19
20
  sei();
21
22
  while(1) {}
23
24
  return 0;
25
}

von Sebastian H. (sebimax)


Lesenswert?

Also so?


#include <avr/interrupt.h>

#define fosc 80000000  //8 MHz Quarz zwischen XTAL 1 und XTAL 2

void init_Timer1(void) {

OCR1A = 0xBB7F;       // TOP = 47999
  TIMSK |= (1<<OCIE1A); // CTC-Interrupt zulassen
  TCCR1B = (1<<CS12) | (1<<WGM12); // Mode 4 (CTC; OCR), Timer starten
PSC = 256


}


ISR(TIMER1_COMPA_vect) {

  // Hier dein Uhr-Code
}


int main( void ) {

  init_Timer1();

  sei();

  while(1) {}

  return 0;
}

von Sebastian H. (sebimax)


Lesenswert?

Bitte helft mir :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.