Projekte & Code
›
Thread
ADS1115 Initialisierung ADC auslesen ATmega8 Assembler ASM
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
FB
Falk B.
(falk)
02.02.2026 21:10
#8003344
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.
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.
Falk B. schrieb:
Das Ding funktioniert bis runter auf 0,01MHz, aka 10kHz.
Falk, ich gebe Dir Recht.
FB
Falk B.
(falk)
06.02.2026 11:27
#8005091
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
06.02.2026 11:29 :
Bearbeitet durch User
FB
Falk B.
(falk)
13.02.2026 14:43
#8009112
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
Hallo Falk,
Danke für Deine sehr fleißigen Hinweise.
Gruß Bernhard
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
Noch kein Account?
Die Registrierung ist kostenlos und dauert nur eine Minute.
Jetzt registrieren