HC-SR04 Assembler für Abstandmessung

OP (Firma: CSC) Persönliche Seite #3660801
Lesenswert?

Mein erstes fertiges Projekt:

Abstandsmessung mit HC-SR04 in Assembler

Soweit meine Suchen ergaben, gibt es noch keinen fertigen Assembler-Code 
für das Ultraschall-Teil im Forum (oder Netz). Jedenfalls bin ich nicht 
fündig geworden und habe daher ohne Vorlage selbst ein Programm 
geschrieben.

Für Anregungen bin ich absolut offen. Da es mein erstes 
Assembler-Projekt ist, reicht es für mich zunächst, dass alles 
funktioniert. Verbesserungen kommen in der Version 2.0 (z.B. Erweiterung 
der maximalen Messdistanz von 70cm auf 300cm).

Ich hoffe die Dokumentation im Sourcecode ist übersichtlich und 
verständlich.

Anmerkung zu Zeile 250 ff: Die Verschiebung der Register ist natürlich 
unnötig, aber ich wollte das Programm vorerst so belassen, damit es in 
der ersten Version endlich fertig ist.

LG
Chris
Gast #3662377
Lesenswert?

Hi

>Da es mein erstes
>Assembler-Projekt ist, reicht es für mich zunächst, dass alles
>funktioniert.

Nicht ganz. Dein Programmteil 'Berechnung' ist fehlerhaft. Bei einer 
Differenz timer1-timer0=50 müsste am Ende der Multiplikation 
(50*16*1715) 1372000 herauskommen. Dein Programm errechnet 1411200.
1
    sub    timer1, timer0    ; t1-t0
2
    ldi    temp1, 255
3
    add    timer1, temp1    ; +255
4
    ldi    temp1, 1
5
    add    timer1, temp1    ; +1

Wenn du zu einem 8-Bit-Register 256 addierst ändert sich am 
Registerinhalt gar nichts. Einen Overflow (Cy-Flag) berücksichtigst du 
ja nicht. Die Addition ist somit sinnfrei.
1
Eins:
2
    subi  r16, byte1(1)
3
    sbci  r17, byte2(1)
4
    sbci  r18, byte3(1)
5
    ....

Dir ist bewusst, das beim Label 'Eins' die Einerstelle schon in r16 
steht?
Da reicht ein '    sts    D_E, r16.

Ist nicht alles.

MfG Spess
OP (Firma: CSC) Persönliche Seite #3662691
Lesenswert?

Danke spess53! Ich arbeite gerade alles durch, um es auf 300cm zu 
erweitern. und da ist es mir aufgefallen. War ein dummer Fehler; 
außerdem fehlt das High-Register... Auch die Routine für die 
Multiplikation habe ich rausgeschmissen und anders gelöst.

@hobbymechaniker: Ich verstehe Deinen Kommentar nicht. Meinst Du die 
fertigen Bausteine, die ich aus dem Tutorial übernommen habe (LCD)?
OP (Firma: CSC) Persönliche Seite #3666611
Lesenswert?

Version 2.0 - korrigiert und einzatzfähig

Hardware:
- ATmega 8 (Standardbeschaltung (AVR-Tutorial: Equipment: Selbstbau)
- HC-SR04 (Trigger an PORTB, Echo an PORTD, LCD and PORTC)
- LCD (16x2, HD44780)

Bug:
- angezeigter Abstand konstant ca. 5mm zu wenig. Ich habe die Berechnung 
und Anzeige mit vorberechneten Werten geteste und es ergab den korrekten 
Abstand. Im Programm ist der Teil, der die Messung durchführt zu einfach 
für Fehler(?):
   - steigende Flanke des Echo (HC-SR04) löst INT0 aus (Overflow-
     Counter wird auf 0 gesetzt, Timer-Stand wird gespeichert)
   - fallende Flanke löst INT1 aus, der wieder dem Timerstand
     speichert und die Interrupts deaktiviert (keine weiteren Overflows
     während der Berechnung)
   - umgerechnen und ausgeben

Änderungen zur Version 1:
- Korrektur der Berechnungsfehler
- max. Messdistanz 300cm (statt bisher 70cm)
- ein paar Vereinfachungen und Verschönderungen im Sourcecode

Falls jemand dieses Programm praktisch ausprobiert, wäre es interessant, 
wie die Ergebnisse mit anderen HC-SR04s aussehen (was die Messfehler 
angeht). Bitte posten.

Ich gebe das Program natürlich vollkommen frei was copyright angeht.

Über Rückmeldungen, Verbesserungsvorschläge usw. freue ich mich. Es ist 
mein ersten Projekt und ich bin sehr froh, dass es funktioniert und (so 
weit ich es bisher getestet habe) nur einen Bug hat :)

LG
Christian
P.S. Datenblatt des HC-SR04 ist im ersten Beitrag ganz oben.
Angehängte Dateien:
Gast #3668417
Lesenswert?

Hi

>Version 2.0 - korrigiert und einzatzfähig

Wohl etwas voreilig.
1
Int1_ISR:
2
    ...
3
    rjmp  main1  ; !!!!!!!!!!!!!!!!!!!
4
  reti

Damit bekommst du früher oder später einen Stackoverflow.
Am besten du verlagerst die ganze Brechnung und Ausgabe in
deinen Mainloop. In der ISR werden nur der Timer eingelesen
und ein Flag gesetzt.

[/avrasm]
.def temp1    = r16
    ...
    mov    r16, timer0
[/avrasm]

Was nun? Ist r16 nun temp1 oder nicht? Du musst dich schon
entscheiden ob du dieses .def-Gedödel benutzt oder nicht. Im
ersten Fall haben die Registerbezeichnungen Rxy nichts mehr
Programm zu suchen. Oder du verzichtest, wie ich persönlich,
ganz darauf.

>; Berechnung der Zeit (t = (t1 - t0 + 256 * ovfl) * 16 [µs] )

>; Berechnung des Abstandes ( dist [cm] = time [ms] * 17,15
>;             ----> dist [cm] = time [µs]  1715  10^-5
>;             ====> dist [cm] = time [µs]  49  35 * 10^-5
>; die Bytes sind von highest zu lowest: distHH  distH  distL / distLL

Wenn man das mal zusammenfasst kommt man auf

t = ((256 * ovfl + t1) - t0 )  16  1715. Also eine 16-Bit-
Subtraktion und eine 16x16-Bit-Multiplikation. Warum machst du das
nicht?
1
Berechnung:
2
    clr    r2             ; Null
3

4
    sub timer1, timer0    ; 16-Bit-Subtraktion
5
    sbc ovfl, r2          ;
6

7
    ldi temp1, low(16*1715); 16x16 Bit Multiplikation
8
    ldi temp2,high(16*1715)
9

10
    mul timer1,temp1
11
    mov distLL,r0
12
    mov distL, r1
13

14
    mul ovfl,  temp2
15
    mov distH, r0
16
    mov distHH,r1
17

18
    mul timer1,temp2
19
    add distL, r0
20
    adc distH, r1
21
    adc distHH,r2
22

23
    mul ovfl,  temp1
24
    add distL, r0
25
    adc distH, r1
26
    adc distHH,r2
27
    ....
Fertig. Mit etwa einem Drittel deines Codes.

>- ein paar Vereinfachungen und Verschönderungen im Sourcecode

Ich habe eher den Eindruck, das du das Programm verschlimmbesserst hast.

Vereinfachung wäre z.B. die obige Berechnung oder den Spagetticode der
Ausgabe durch eine Schleife
1
text:      .db "Abstand [cm]:",0
2

3
Ausgabe:   ldi ZL, Low(text<<1)
4
           ldi ZH,high(text<<1)
5

6
           ldi temp1, 0b10000000    ; Ausgabe in erster Zeile: 'Abstand [cm]:'
7
           rcall lcd_command
8

9
Ausgabe10: lpm temp1, Z+
10
           tst temp1
11
           breq Ausgabe20          
12
           
13
           rcall lcd_data
14

15
           rjmp Ausgabe10
16

17
Ausgabe20:  ...
zu ersetzen.

MfG Spess
OP (Firma: CSC) Persönliche Seite #3668950
Lesenswert?

Danke Spess!!! Da sieht man den Unterschied zwischen Programmier-Babay 
(zumidest bei Assembler) und denen, die schon laufen können. Deine 
Vorschläge finde ich echt elegant!

spess53 schrieb:

> Damit bekommst du früher oder später einen Stackoverflow.

Ups. Gar nicht bedacht...

> [/avrasm]
> .def temp1    = r16
>     ...
>     mov    r16, timer0
> [/avrasm]
>
> Was nun? Ist r16 nun temp1 oder nicht?

Meine Überlegung war, eine allgemeine Routine zu schreiben. Daher der 
Wechsel zu r16 usw.

> t = ((256 * ovfl + t1) - t0 )  16  1715. Also eine 16-Bit-
> Subtraktion und eine 16x16-Bit-Multiplikation. Warum machst du das
> nicht?

Das gefällt mir! Ich hätte die Ide nie gehabt. Dass ein Übertrag mit r2 
funktioniert, war mir neu.

> Vereinfachung wäre z.B. die obige Berechnung oder den Spagetticode der
> Ausgabe durch eine Schleife

Was soll ich sagen... Danke! Dass Du meinen Code durchgehst und 
Vorschläge machst, hilft mir absolu weiter! Danke!

LG
Chris

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren