Forum: Projekte & Code ADS1115 Initialisierung ADC auslesen ATmega8 Assembler ASM


von Bernhard S. (bernhard)


Angehängte Dateien:

Lesenswert?

Geschätztes Forum,

ein kleines Beispiel, wie ein ADS1115 in Assembler und mit einem
ATmega8 (1MHz) initialisiert und ausgelesen werden kann.

Nach Programmstart werden die beiden Config Register auf ihre
Default-Werte gesetzt und anschließend wieder ausgelesen und 
ausgewertet.

Anzeige: 8385

Wird dieser Wert nicht ausgelesen, dann liegt vermutlich ein I2C/TWI 
Übertragungsfehler vor. (LED gelb + rot blinkt).

Nun erfolgt die eigentliche Initialisierung, MUX, PGA + MODE
und der ADC verrichtet seine Arbeit und zeigt sein Ergebnis im Display 
an.

Vorsicht:

Der ADS1115 verlangt einen SCL-Takt  0.4...3.4 MHz.
Mit einer Taktfrquenz außerhalb dieses Bereiches kommt er nicht zurecht.
Und die Registerwerte stimmen nicht.

Das MUX-Register ist sehr wichtig, hier im Beispiel wird IN0 gegen GND 
gemessen.

Ich habe versucht, den Assembler-Code so gut wie möglich zu 
kommentieren, damit man jeden Schritt nachvollziehen kann.

Für konstruktive Hinweise bin ich sehr dankbar.

Bernhard

von Falk B. (falk)


Lesenswert?

Bernhard S. schrieb:
> Der ADS1115 verlangt einen SCL-Takt  0.4...3.4 MHz.
> Mit einer Taktfrquenz außerhalb dieses Bereiches kommt er nicht zurecht.
> Und die Registerwerte stimmen nicht.

Das sind Fake News(tm). Das Ding funktioniert bis runter auf 0,01MHz, 
aka 10kHz.

von Wastl (hartundweichware)


Lesenswert?

Bernhard S. schrieb:
> Für konstruktive Hinweise bin ich sehr dankbar.

Die Abblock-Kondensatoren am Spannungsregler sind zu klein.
Beachte (beherzige) die Empfehlungen im Datenblatt des
(unbekannten) Reglers.

An AVcc und Vcc gehören jeweils keramische Abblock-Kondensatoren
mit 100nF bis 1uF. Der Elko dort ist nicht relevant bzw.
deplaziert.

von Bernhard S. (bernhard)



Lesenswert?

Falk B. schrieb:
> Das Ding funktioniert bis runter auf 0,01MHz, aka 10kHz.

Falk, ich gebe Dir Recht.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Bernhard S. schrieb:
> Für konstruktive Hinweise bin ich sehr dankbar.

Hallo Bernhard,

grundsätzlich sieht dein Projekt gut aus

- systematisches Konzept mit Unterfunktionen
- Funktionen sinnvoll auf Dateien aufgeteilt
- weitestgehend sinnvolle Namen für Register
- viele gute Kommentare

Hier jetzt ein paar Verbesserungsvorschläge

- keine Papageikommentare; wenn Funktions- und Variablennamen gescheit 
gewählt werden, sind die selbsterklärend
- zuviele überflüssige Kommentare verschlechtern die Lesbarkeit und 
Verständnis
- Kommentare die bei Änderungen übersehen werden sind dann falsch
- man sollte die Parameter der Befehle alle gleich ausrichten, damit die 
einheitlich in einer Spalte stehen, das ist besser lesbar
- ebenso die Kommentare
1
SRAM_CLEAR_w:
2
  ST   z+,temp
3
  cpi  ZH, HIGH(RAMEND)  ; Vergleich?    
4
  brlo SRAM_CLEAR_w    ; kleiner => SPRUNG  
5
  cpi  ZL, LOW(RAMEND)  ; Vergleich?    
6
  brlo SRAM_CLEAR_w    ; kleiner => SPRUNG  
7
  breq SRAM_CLEAR_w    ; gleich  => SPRUNG

- man läßt den Assembler die Daten anlegen und verwalten, nicht manuell!
- die Vorsilbe adr_ ist Unsinn, denn die Labels sind immer Adressen
- Wenn man viele Variablen mit gleichem Namen und ner Nummer am Ende 
hat, schreit das nach einem Array
1
; SRAM Daten              
2
.dseg
3
.org SRAM_START             
4
ZEIGER:    .byte 1
5
DIGITS:    .byte 8
6
ADS_MSB:  .byte 1
7
ADS_LSB:  .byte 1

- man braucht hier keine Klammern
1
; Begrüssung "ADS1115"                    
2
  ldi temp, ASCII_A
3
  STS adr_DIGIT7,temp

- wenn man so ein Array füllen will, geht das so einfacher, weniger 
Tipperei und fehleranfällig
- Man sollte wenn möglich die Datenreihenfolge auch logisch von 
vorn/oben nach unten wählen, damit man nicht immer verdreht denken muss
1
; Begrüssung "ADS 1115"                    
2
  ldi    ZL, low(DIGITS)
3
  ldi    ZH, HIGH(DIGITS)
4
    
5
    ldi     temp, DISP_A
6
  st      z+, temp
7
  ldi     temp, DISP_d
8
  st      z+, temp
9
    ldi     temp, DISP_S
10
  st      z+, temp
11
    ldi     temp, DISP_AUS
12
    st      z+, temp
13
  ldi     temp, DISP_1 
14
    st      z+, temp 
15
  ldi     temp, DISP_1 
16
    st      z+, temp 
17
  ldi     temp, DISP_1 
18
    st      z+, temp 
19
  ldi     temp, DISP_5 
20
    st      z+, temp
21
  rcall   WAIT_1000ms

- im Interrupt macht man zu 99% kein sei, das braucht keiner und ist 
eher gefährlich
- nur in Sonderfällen wenn man WIRKLICH weiß was man tut!
1
TIM0_OVF:
2
;  sei          ; interrupts freigeben, NEIN, DAS MACHT MAN EHER NICHT!          
3
  push TEMP        ; Sichern von "TEMP" im Stack      
4
  in   TEMP,SREG    ; Einlesen des SREG           
5
  push TEMP        ; Schreiben von  SREG  im Stack (KOPIE)  
6
  push TEMP1      ; Sichern von "TEMP1" im Stack      
7
8
  rcall ANZEIGE
9
10
  pop TEMP1      ; Wiederherstellen von "TEMP1"       
11
  pop  TEMP      ; LESEN von SREG vom STACK (KOPIE)    
12
  out  SREG,TEMP    ; Wiederherstellen von SREG        
13
  pop  TEMP      ; Wiederherstellen von "TEMP"       
14
    reti

- deine Funktion zum Multiplexen der Anzeige ist lustig ;-)
- das macht man DEUTLICH einfacher, kürzer und übersichtlicher mit einer 
Schleife
- die Funktion ist besser in Anzeige.asm aufgehoben, hab ich verschoben
- ret bzw reti gehören wie alle anderen Befehle in die 2. Spalte, nicht 
an den Zeilenanfang

Welche Anzeige ist das? Die hier?

https://www.pollin.de/p/daypower-digitalanzeige-modul-led-display-dig-2r-810568

- In deinen ADS115 Funktionen sind viele Dinge drin, die dort nicht 
reingehören, z.B. ADS_READ_2_BYTES
- Dort gehören nur Funktionen rein, die den ADC ansprechen und 
Ergebnisse liefern!
- Die Weiterverarbeitung und Anzeige gehört dort NICHT REIN!
- Eine Funktion sollte nur das machen, was der Name aussagt
- auch in ADS_CONFIG_READ, dort gehört die Eintragung in die 
Anzeigedaten NICHT REIN!
- ultralange Zeilen wie die hier in ADS_INIT sind ungünstig
- vor allem sind die ganzen Null-Bits sinnlos
- der Kommentar ist irreführend, man sollte eher schreiben, was hier 
eingestellt wird, ggf. in eine eigene Zeile darüber

  ldi     temp1, 
0<<ADS_DR2|0<<ADS_DR1|0<<ADS_DR0|0<<ADS_COMP_MODE|0<<ADS_COMP_POL|0<<ADS 
_COMP_LAT|1<<ADS_COMP_QUE1|1<<ADS_COMP_QUE0   ;(default) X83 (MSB)

eher so

  ldi     temp1, 1<<ADS_COMP_QUE1 | 1<<ADS_COMP_QUE0

- in den Funktionen zum Lesen von Registern vom ADC gibt man die 
Registernummer sinnvoll als Dezimalzahl an, binär ist hier eher 
verwirrend
- Funktionsnamen mit FUNKTION_ anfangen ist Unsinn, denn alle 
Funktionsnamen sind Funktionsnamen!
- sinnvollerweise gestaltet man Funktionsnamen so, daß sie 
selbsterklärend sind, meist Verb + Substantiv, z.B. convert_hex_ascii_32
- die Datei zahlen.asm ist sehr aufgeblasen, da kann man viel mit 
Schleifen und Tabellen komprimieren, siehe HEX_ZU_DISPLAY
- BIN_ASC_32 ist in Prinzip OK, aber die Daten sollten man besser im RAM 
als in den Registern speichern, denn das ist eher ein Array
- damit kann man die Daten anschließen deutlich einfacher verarbeiten 
(Schleifen) und hat deutlich weniger Kopier - und Tipparbeit
- Die I2C Sachen hab ich nicht angefaßt, ohne Hardwarwe zum Debuggen ist 
das ungünstig

Schau dir das Projekt mal an und lass es auf dich wirken. Teste mal, ob 
es noch funktioniert. Ich hab ja keine Hardware zum testen.
Siehe auch Strukturierte Programmierung auf Mikrocontrollern

Viel Spaß damit

: Bearbeitet durch User
von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Ich hab noch ein paar Kleinigkeiten verbessert

Macros für den Schreibzugriff der Displaydaten.
Das halbe Dutzend Funktionen zum Warten durch 2 Kernfunktionen mit 
Parametern und Macros ersetzt (WAIT_MS und WAIT_US)
1
; Begrüssung "ADS 1115"                                     
2
    ldi     xl, low(digits)
3
    ldi     xh, HIGH(digits)    
4
    WRITE_DISPLAY DISP_A
5
    WRITE_DISPLAY DISP_d
6
    WRITE_DISPLAY DISP_s
7
    WRITE_DISPLAY DISP_AUS
8
    WRITE_DISPLAY DISP_1
9
    WRITE_DISPLAY DISP_1
10
    WRITE_DISPLAY DISP_1
11
    WRITE_DISPLAY DISP_5
12
    WAIT_MS 1000
13
    rcall   ads_init

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.