mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AVR Einsteiger: Einfache Blinksteuerung


Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Ich versuche gerade in das Thema µController-Programmierung 
einzusteigen.
Hierzu habe ich mir einen kleinen USB Programmer gekauft (USB AVR LAB 
mit der Firmware vom AVRISP mkII) und eine Hand voll ATmega8.

Das Grundverständnis, wie jetzt alles funktioniert ist da (Das Forum und 
andere Seiten halfen mir da sehr)

Als kleines Projekt hatte ich vor eine einfache Blinksteuerung zu bauen, 
die 10mal langsam und 10mal schnell blinkt.

Mein Qellcode steht unten und ich hab folgendes Problem: in Realität 
blinkt die LED immer gleich schnell.

Ich habe jetzt schon lange gesucht und den Job des ATMega gemacht und 
den Code per "Fuss" abgelaufen, ich finde da keinen Fehler:
[avrasm]
.include    "m8def.inc"

  ldi    r16,0xFF
  out    DDRD,r16
  ldi    r16,0b11111111
  ldi    r17,0b00000000
.equ c1 = 50000

  ldi r18,10


Prog:
  
KURZ:  
    
    ldi R25,HIGH(c1) 
    ldi R24,LOW(c1) 
  Loop2: ; LED aus
    out  PORTD,r17
    sbiw R24,1 
    brne Loop2 
    
    
    
    ldi R25,HIGH(c1)
    ldi R24,LOW(c1) 
  Loop3: ;LED an
    out PORTD,r16
    sbiw R24,1 
    brne Loop3 

    dec r18
    brne KURZ


    ldi r18,10

LANG:


    ldi R25,HIGH(c1) 
    ldi R24,LOW(c1) 
  Loop4: ; LED aus
    out  PORTD,r17
    NOP
    NOP
    NOP
    NOP
    NOP
    sbiw R24,1 
    brne Loop4 
    
    
    
    ldi R25,HIGH(c1)
    ldi R24,LOW(c1) 
  Loop5:  ;LED an
    out PORTD,r16
    NOP
    NOP
    NOP
    NOP
    NOP
    sbiw R24,1 
    brne Loop5 
    
    
    dec r18
    brne LANG
    ldi r18,10  
  
  
  
  
  
  rjmp Prog

[/avrasm]

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kommentare brauchen keinen Platz im µC ;-)

Die 5x NOP fürs Extrawarten sind lächerlich. Die sind bei lahmer 
Werkseinstellung  von 1 MHz in 5 Microsekunden (5/1000000s) weg!
Bei 50000 Schleifendurchläufen dauert eine Blinkperiode oder Pause in 
der langen Routine 0,25s länger (bei 1 Mhz) als in der kurzen.

.include    "m8def.inc"

.equ c1 = 50000 ; Wartezeit

Reset:
  ldi    r16,0xFF          ; DDR auf Ausgang schalten
  out    DDRD,r16

  ldi    r16,0b11111111    ; Wert für LEDs 0..7 AUS (active-low)
  ldi    r17,0b00000000    ; Wert für LEDs 0..7 AN (active-low)

Programmanfang:
  
; ##################
; Kurze Blinksequenz
; ##################
    ldi    r18,10     ; Blinkzahl = 10
KURZ_BLINKEN:  

    ldi R25,HIGH(c1)  ; 16-Bit Wartezeit laden
    ldi R24,LOW(c1) 
KURZE_LED_AUS:
    out  PORTD,r17   
    sbiw R24,1 
    brne KURZE_LED_AUS 
   
    ldi R25,HIGH(c1)
    ldi R24,LOW(c1) 
KURZE_LED_AN:
    out PORTD,r16
    sbiw R24,1 
    brne KURZE_LED_AN 

    dec r18            ; Blinkzahl um 1 vermindern
    brne KURZ_BLINKEN  ; Schleife solange Blinkzahl ungleich 0

; ##################
; Lange Blinksequenz
; ##################
    ldi    r18,10      ; Blinkzahl = 10
LANG_BLINKEN:
    ldi R25,HIGH(c1)   ; 16-Bit Wartezeit laden
    ldi R24,LOW(c1) 
LANGE_LED_AUS:
    out  PORTD,r17
    NOP                ; 5xNOP "extra" Warten
    NOP
    NOP
    NOP
    NOP
    sbiw R24,1 
    brne LANGE_LED_AUS 

    ldi R25,HIGH(c1)
    ldi R24,LOW(c1) 
LANGE_LED_AN:
    out PORTD,r16
    NOP
    NOP
    NOP
    NOP
    NOP
    sbiw R24,1 
    brne LANGE_LED_AN 
  
    dec r18
    brne LANG_BLINKEN
  
    rjmp Programmanfang

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi
Ein kleiner Tipp. Der Atmega8, wie einige andere auch, haben Timer. Dazu 
gibt es hier ein Tutorial.
Der Timer ruft in bestimmten Zyklen durch einen Interrupt ein kleines 
Unterprogramm auf. Dort kannst du alle Funktionen nachbilden, die 
zeitlich bezogen eine Arbeit vollziehen. Wie bspw. eine LED an- oder 
auszuschalten. Für ein paar Übungen mag es reichen, dies im 
Hauptprogramm zu tun und kleine Delayschleifen zu programmieren, aber 
wenn das Programm wächst und etwas anderes machen soll, sind die mühsam 
errechneten Schleifenzeiten zum Teufel. Daher lies dich mal in die Timer 
ein. Es sollte als Ergebnis ein ms-Takt oder Sekundentakt herauskommen, 
der dir entsprechende Programmteile aufruft.
Nutz die Möglichkeit von Variablen. Mit einer Ex-Or Anweisung kannst du 
ein Bit in die andere Lage kippen
z.B.
LDI R16, 0b11111111
LDS R17, Ablagewert
EOR R17, R16
STS Ablagewert, R17
Wenn du diese 4 Anweisungen im Sekundentakt aufrufst, werden die Bits in 
der Variablen "Ablagewert" entsprechen wechseln.
 Gruß oldmax

Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey danke für die Antworten, ich werde mich mal in Timer einlesen, nur 
soweit war ich zu dem Zeitpunkt als ich das Programm geschrieben habe 
noch nicht^^

Wäre trotzdem schön wenn ich den Fehler finden könnte denn:

@Stefan:
Ich dachte das Programm macht pro Warteschleife 50000 mal 5x NOP?

mfg
vincent

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vincent schrieb:

> @Stefan:
> Ich dachte das Programm macht pro Warteschleife 50000 mal 5x NOP?

Ja, das tut es auch. Wenn du deinen AVR mit 1000000 Hz (1 MHz) 
betreibst, sieht der Unterschied zwischen kurzer und langer Routine bei 
einer AN oder AUS-Phase für mich so aus:

50000 Schleifendurchläufe * 1/1000000 s pro Takt  1 Takt pro NOP  5 
Anzahl NOPs = 0,25 s

10 mal Blinken (5x An + 5x Aus) => Die lange Routine läuft 2,5 s länger 
als die kurze Routine. Mit einer Stoppuhr und Üben könnte man den 
Unterschied wohl messen. Mit Zukucken und Schätzen würde ich keinen 
Unterschied sehen.

Bei schnellerem Takten als 1 MHz verringert sich der Unterschied 
zwischen beiden Routinen. Dann wird selbst das Handstoppen schwer.

welchen Unterschied hast du denn berechnet oder erwartet?

Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe Testweise mal 20 NOPs eingefügt, nach dem Programmieren blinkt 
die LED trotzdem durchweg schnell.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast du den Code mal im Simulator von AVR Studio getestet und dort mit 
der Stoppuhr die Laufzeit ausgemessen? Ich habe dein Programm nicht auf 
der Hardware gesehen oder im Simulator gehabt.

Abgesehen von zu kurzem Unterschied in der Laufzeit kann es noch andere 
Ursachen für deine Beobachtung geben. Aber wie beim stehengebliebenen 
Auto checke ich zuerst den Benzintank bevor ich über einen Fehler im den 
Verteiler spekuliere...

Eine Ursache "im Motorraum" kann ein regelmäßiger Reset sein, der 
innerhalb der kurzen Routine aktiv wird.

Bei deinem Programm kann man schlecht sehen, ob das Programm zur 
Laufzeit überhaupt in die lange Routine kommt. Hast du mal überlegt, in 
jeder Routine eine andere LEDs blinken zu lassen?

Auf Verdacht würde ich alle Resetmöglichkeiten kontrollieren bzw. 
ausschliessen, d.h. die Watchdog-Fuse kontrollieren und die 
Vektortabelle für die ISRs am Flashanfang freihalten (.org Anweisung).

Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mal zur Simulation die Wartezeiten runtergeregelt und per Hand 
(F11 - AVR Studio) Schritt für Schritt den Code abgefahren.

Laut Simulation durchfährt der AVR beide Routinen.
Naja wer weiß was das ist^^, ich werde jetzt mal mit Timern anfangen.

Mein großes Ziel ist es übrigens eine Schrittmotorsteuerung für 
Fräsmaschinen zu entwickeln, welche DIN/ISO Code einliest. Die Steuerung 
soll Quasi das komplette Fräsprogramm samt PC ablösen.

Quasi:
- Im warmem Wohnzimmer Fräsprogramm erstellen
- Dann auf SD-KARTE
- In den Keller und mittels Steuerung 0-Punkt bestimmen und Fräsprogramm 
starten.

Umgesetzt wird das dann mittels LCD Display.


(Was gelernt und den Kampf gegen die Langeweile besiegt. ;-)

Autor: Stefan B. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schönes, aber engagiertes Projekt. Ich würde so etwas umfangreiches eher 
in C machen als in Assembler. Dümmer wirst du durch Assemblerlernen aber 
nicht.

Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Meinst du ich sollte den Einstieg lieber mit C wagen?

Ich möchte keinen Glaubenskrieg lostreten aber was wäre zum Einstieg 
besser?

Autor: Christopher G. (cbg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In C programmieren schließt das Verständnis darüber, was der Controller 
wirklich  macht nicht aus. Kommt ganz darauf an ob man überhaupt wissen 
will was der Controller genau macht.
Bring mit Assembler ein paar LEDs zum blinken und spiel dich mit Timern 
und irgendeiner Schnittstelle (UART, SPI oder I2C), dann solltest du im 
Prinzip wissen was im Controller passiert. Datenblatt musst du sowieso 
lesen, egal welche Sprache du verwendest.
Die Konfiguration von Timern bzw einer Schnittstelle ist in C zwar nicht 
viel leichter bzw kürzer, dafür ist es bei größeren Projekten durchaus 
nicht blöd auf C zu setzen (Dokumentationstools, generische Module, 
...).

Der Compiler ist auch nicht immer Perfekt und wenn man überprüfen will, 
was er da aus dem C Code gemacht hat, dann muss man Assembler verstehen 
können.

Autor: Vincent (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, dann war mein Entschluss doch nicht so falsch^^

Vielen Dank erstmal.

mfg
vincent

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.