Forum: Mikrocontroller und Digitale Elektronik AVR Einsteiger: Einfache Blinksteuerung


von Vincent (Gast)


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:
1
[avrasm]
2
.include    "m8def.inc"
3
4
  ldi    r16,0xFF
5
  out    DDRD,r16
6
  ldi    r16,0b11111111
7
  ldi    r17,0b00000000
8
.equ c1 = 50000
9
10
  ldi r18,10
11
12
13
Prog:
14
  
15
KURZ:  
16
    
17
    ldi R25,HIGH(c1) 
18
    ldi R24,LOW(c1) 
19
  Loop2: ; LED aus
20
    out  PORTD,r17
21
    sbiw R24,1 
22
    brne Loop2 
23
    
24
    
25
    
26
    ldi R25,HIGH(c1)
27
    ldi R24,LOW(c1) 
28
  Loop3: ;LED an
29
    out PORTD,r16
30
    sbiw R24,1 
31
    brne Loop3 
32
33
    dec r18
34
    brne KURZ
35
36
37
    ldi r18,10
38
39
LANG:
40
41
42
    ldi R25,HIGH(c1) 
43
    ldi R24,LOW(c1) 
44
  Loop4: ; LED aus
45
    out  PORTD,r17
46
    NOP
47
    NOP
48
    NOP
49
    NOP
50
    NOP
51
    sbiw R24,1 
52
    brne Loop4 
53
    
54
    
55
    
56
    ldi R25,HIGH(c1)
57
    ldi R24,LOW(c1) 
58
  Loop5:  ;LED an
59
    out PORTD,r16
60
    NOP
61
    NOP
62
    NOP
63
    NOP
64
    NOP
65
    sbiw R24,1 
66
    brne Loop5 
67
    
68
    
69
    dec r18
70
    brne LANG
71
    ldi r18,10  
72
  
73
  
74
  
75
  
76
  
77
  rjmp Prog
78
79
[/avrasm]

von Stefan B. (stefan) Benutzerseite


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.
1
.include    "m8def.inc"
2
3
.equ c1 = 50000 ; Wartezeit
4
5
Reset:
6
  ldi    r16,0xFF          ; DDR auf Ausgang schalten
7
  out    DDRD,r16
8
9
  ldi    r16,0b11111111    ; Wert für LEDs 0..7 AUS (active-low)
10
  ldi    r17,0b00000000    ; Wert für LEDs 0..7 AN (active-low)
11
12
Programmanfang:
13
  
14
; ##################
15
; Kurze Blinksequenz
16
; ##################
17
    ldi    r18,10     ; Blinkzahl = 10
18
KURZ_BLINKEN:  
19
20
    ldi R25,HIGH(c1)  ; 16-Bit Wartezeit laden
21
    ldi R24,LOW(c1) 
22
KURZE_LED_AUS:
23
    out  PORTD,r17   
24
    sbiw R24,1 
25
    brne KURZE_LED_AUS 
26
   
27
    ldi R25,HIGH(c1)
28
    ldi R24,LOW(c1) 
29
KURZE_LED_AN:
30
    out PORTD,r16
31
    sbiw R24,1 
32
    brne KURZE_LED_AN 
33
34
    dec r18            ; Blinkzahl um 1 vermindern
35
    brne KURZ_BLINKEN  ; Schleife solange Blinkzahl ungleich 0
36
37
; ##################
38
; Lange Blinksequenz
39
; ##################
40
    ldi    r18,10      ; Blinkzahl = 10
41
LANG_BLINKEN:
42
    ldi R25,HIGH(c1)   ; 16-Bit Wartezeit laden
43
    ldi R24,LOW(c1) 
44
LANGE_LED_AUS:
45
    out  PORTD,r17
46
    NOP                ; 5xNOP "extra" Warten
47
    NOP
48
    NOP
49
    NOP
50
    NOP
51
    sbiw R24,1 
52
    brne LANGE_LED_AUS 
53
54
    ldi R25,HIGH(c1)
55
    ldi R24,LOW(c1) 
56
LANGE_LED_AN:
57
    out PORTD,r16
58
    NOP
59
    NOP
60
    NOP
61
    NOP
62
    NOP
63
    sbiw R24,1 
64
    brne LANGE_LED_AN 
65
  
66
    dec r18
67
    brne LANG_BLINKEN
68
  
69
    rjmp Programmanfang

von oldmax (Gast)


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

von Vincent (Gast)


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

von Stefan B. (stefan) Benutzerseite


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?

von Vincent (Gast)


Lesenswert?

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

von Stefan B. (stefan) Benutzerseite


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).

von Vincent (Gast)


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. ;-)

von Stefan B. (Gast)


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.

von Vincent (Gast)


Lesenswert?

Meinst du ich sollte den Einstieg lieber mit C wagen?

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

von Christopher G. (cbg)


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.

von Vincent (Gast)


Lesenswert?

Ok, dann war mein Entschluss doch nicht so falsch^^

Vielen Dank erstmal.

mfg
vincent

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.