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
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.

