mikrocontroller.net

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


Autor: Sebastian H. (sebimax)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Denke die machen wir alle, da müssen wir durch :)

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja ich programmier noch net lange Microprozessoren. Bin also noch net so 
routiniert :)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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. ;-)

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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?"

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

Autor: Sebastian H. (sebimax)
Datum:

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


Grüße
Sebastian

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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?fa...
AVR134: Real-Time Clock using the Asynchronous Timer

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Sebastian H. (sebimax)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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
  ...
}

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
SUPER danke das hat funktionier :)

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: Stefan Ernst (sternst)
Datum:

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

Hä? Wie meinst du das?

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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) :)

Autor: Daniel C. (cecky)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

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

Cecky

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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 ^^

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Gottfried S. (gottfried)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Stefan Ernst (sternst)
Datum:

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

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm k hab ich mir aus dem forum zusammengestückelt.


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

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/interrupt.h>


void init_Timer1(void) {

  // Hier Timer initialisieren
}


ISR(TIMER1_COMPA_vect) {

  // Hier dein Uhr-Code
}


int main( void ) {

  init_Timer1();

  sei();

  while(1) {}

  return 0;
}

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht 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;
}

Autor: Sebastian H. (sebimax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bitte helft mir :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.