Forum: Projekte & Code HC-SR04 Assembler für Abstandmessung


von Christian H. (Firma: CSC) (chris-h) Benutzerseite



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

von R. F. (rfr)


Lesenswert?

Ein Kommentar, für welche CPUs das geht und für welche nicht, wäre 
hilfreich.

von Detlef K. (adenin)


Lesenswert?

Ist für ATMega8

von chris- (Gast)


Lesenswert?

Sorry. Ja. Atmega8. Für welche anderen uC es funktioniert, muss ich noc 
testen - falls das mit der Software ausreichend ist.
LG
Chris

von spess53 (Gast)


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

von hobbychemiker (Gast)


Lesenswert?

Wenn man schon alles in Assembler machen muss, kann man es auch selber 
mahcne...

von Christian H. (Firma: CSC) (chris-h) Benutzerseite


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

von Christian H. (Firma: CSC) (chris-h) Benutzerseite


Angehängte Dateien:

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.

von spess53 (Gast)


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

von Mike (Gast)


Lesenswert?

spess53 schrieb:
>>; Berechnung des Abstandes ( dist [cm] = time [ms] * 17,15

Das wird genau bei Zimmertemperatur funktionieren, da die 
Schallgeschwindigkeit kräftig von der Temperatur abhängt. Pro Grad 
ändert sie sich um etwa 0.6 m/s

von Christian H. (Firma: CSC) (chris-h) Benutzerseite


Lesenswert?

Mike schrieb:
> Das wird genau bei Zimmertemperatur funktionieren

Ja, daher steht im Datenblatt, dass es für Außeneinsatz sinvoll wäre, 
eine Temeratur- bzw. Feutchitgkeitskompension zu machen. Das wäre ein 
nächster Schritt...

von Christian H. (Firma: CSC) (chris-h) Benutzerseite


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

von Mike (Gast)


Lesenswert?

Christian Haerringer schrieb:
> Ja, daher steht im Datenblatt, dass es für Außeneinsatz sinvoll wäre,
> eine Temeratur- bzw. Feutchitgkeitskompension zu machen.

Die Fehler durch fehlende Berücksichtigung der Feuchte sind wesentlich 
geringer, als der Temperatureffekt.

von spess53 (Gast)


Lesenswert?

Hi

>Ups. Gar nicht bedacht...

Hauptsache du machst da nicht wieder ein 'rjmp main' rein. Das macht 
zwar keinen Stackfehler, ist aber auch nicht besser.

MfG Spess

von Christian H. (Firma: CSC) (chris-h) Benutzerseite


Lesenswert?

:) Nein. Den Vorschlag mit Flag habe ich schon vertanden :)
(rjmp main erinnert mich an Nils Bohr bei der Physikprüfung)

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.