Im Teil 7 geht es um den ADS1115, einen 16-BIT 4 Kanal AD-Wandler mit Gain Controller. Ziel ist es das Software Interface zu schreiben um die Daten der 4 Kanäle auszulesen und dann weiter zu bearbeiten. Auf dem Extension Board wird der Wandler u.a. dazu verwendet die Daten vom ACS 712 (Strommesser) aufzunehmen. Der ADS1115 lässt sich am besten als fertiges Modul kaufen. Das bestücken auf der Platine ist nicht wirklich spannend und schon gar nicht auf den ersten Versuch erfolgreich. Die Kosten des gesamten Moduls sind übrigens unwesentlich höher als die für den Chip selbst.
Der ADS1115 hat einiges an Zeit gekostet um das Software Modul zu erstellen. Es gibt zwar viele Beispiele im Internet aber die Beschreibung ist dann meist nicht so verständlich wie ich es hätte erwartet. Also musste ich mich da etwas selber durchbeissen. Das Ergebnis war, mal ging es, mal wieder nicht. Verstanden hatte ich es erst nicht. Dabei ist das wenn man es verstanden hat doch so einfach. Letztendlich war das eigentliche Problem eine Fehlinterpretation des Datenblattes. Da die BCM2835 Routinen zum schreiben und lesen auf dem I2C Bus nunmehr gut laufen und der Logic Analyzer fest verkabelt ist, geht das Debuggen auch recht gut von remote und ich muss nicht immer an die Werkbank laufen.
Der ADS1115 hat folgende Kenndaten:
- Bis zu 16 Bit Auflösung
- Programmierbaren Verstärker
- 4 Kanäle mit einstellbarem Multiplexer
- 2 Modi für die Eingänge zur Differentialmessung oder Messung gegen Masse
- Interne Referenzspannung
- 8 bis 860 Samples per Second
Bei der Auflösung ist es wichtig das Datenblatt zu lesen. Der AD Wandler hat die 16 Bit Auflösung nicht über die gesamten Messbereiche. Das ist entscheident wenn das Ergebnis berechnet wird. Bei einem Betrieb an 3.3V Betriebsspannung kann im Messbereich 0 und 1 (6.144Volt und 4.096Volt) nur bis max. 3.3. Volt gemessen werden. Auch ist es sinnvoll im „single Shot“ Modus mehr als eine Messung zu machen. Insbesondere bei umschalten des Multiplexers zwischen den Messungen läuft man Gefahr die Werte von der letzten Messung zu bekommen. Das passiert wenn der Wandler die gemessenen Werte noch nicht in das Ergebnisregister geschrieben hat und der I2C Bus bereits abgefragt wurde. Die Mehrfache Messung hat zu stabilen Ergebnissen geführt. Wie viele Messungen gemacht wreden bis das Ergebnis zurückgeliefert wird ist in der Variablen Messungen in der Routine definiert.
Viele Beispiele im Internet basieren auf Hochsprachen wie Python. Diese sind um ein vielfaches langsamer als in C geschriebener Code. Mein Vermutung ist , bei Hochsprachen passieren aufgrund von timings diese Probleme nicht. Durch Abfragen des Bit 15 kann man herausbekommen ob die Wandlung und der Transfer des Ergbenisses in das Register abgeschlossen ist. Das ist ist Im Code implementiert.
Die Auflösung ergibt sich durch FSR/LSB Size und das sind 15 Bit (32768 Schritte). Die Angabe +-6.144V ergibt sich durch den Betriebsmodus. Im Singel Ended Mode Ain gegen GND sind es 6.144V im Differenzmodus sind es Minus 6.144V bis Plus 6.144V.
Das CONFIG Register und auch das Ergebnisregister wird in der Reihenfolge MSB nach LSB geschrieben, das beudetet das CONFIG Byte 1 enthällt die Daten Bit 15 – Bit 8 und Config Byte 2 enthält die Bits 7 – Bit 0. Ich hatte damit gerechnet (oder es so verstanden) erst wird Config Byte 1 und dann Config Byte 2 abgelegt, die Reihenfolge ist genau anders herum!
Folgendes Codeschnipsel ist das Software Modul zur abfrage des ADS1115.
int16_t ADS1115(char port, char Messbereich, char AD_Address) {
int I2C_Frequenz = 100000;
char AD_readBuf[2];
char AD_writeBuf[3];
int16_t AD_result = 0;
char Kanal;
char Bereich;
int a, counter;
int messungen = 2; //Anzahl Messungen
//
// Init I2C Bus
//
if (!bcm2835_init()) return -1; // I2C INIT
bcm2835_i2c_begin(); // Start I2C operations.
bcm2835_i2c_setSlaveAddress(AD_Address); // I2C address
bcm2835_i2c_set_baudrate(I2C_Frequenz); // 100kHz baudrate
// Eigentlich sollte es mit #define funktionieren, geht aber irgendwie nicht
// aus dem Grund ist es mit const char gelöst
// config Bit 7-0 Optionen
#define AD_config_DataRate_8 (0)
#define AD_config_DataRate_16 (16)
#define AD_config_DataRate_32 (32)
#define AD_config_DataRate_64 (96)
#define AD_config_DataRate_128 (128)
#define AD_config_DataRate_250 (160)
#define AD_config_DataRate_475 (192)
#define AD_config_DataRate_860 (224)
#define AD_config_COMPMODE_tra (0)
#define AD_config_COMPMODE_win (16)
#define AD_config_COM_POL_low (0)
#define AD_config_COM_POL_high (8)
#define AD_config_COM_LAT_non (0)
#define AD_config_COM_LAT_lat (4)
#define AD_config_COM_QUE_1 (0)
#define AD_config_COM_QUE_2 (1)
#define AD_config_COM_QUE_3 (2)
#define AD_config_COM_QUE_dis (3)
// config Bit 15-8 Optionen
#define AD_config_OS_noeffect (0)
#define AD_config_OS_single (128)
#define AD_config_MUX_A0_GND (64)
#define AD_config_MUX_A1_GND (80)
#define AD_config_MUX_A2_GND (96)
#define AD_config_MUX_A3_GND (112)
#define AD_config_PGA_2048 (4)
#define AD_config_PGA_4096 (2)
#define AD_config_PGA_6144 (0)
#define AD_config_MODE_cont (0)
#define AD_config_MODE_single (1)
// ********
#define config_register (1)
#define conversion_register (0)
Messbereich = Messbereich << 1;
if (port == 0) {Kanal = AD_config_MUX_A0_GND;}
if (port == 1) {Kanal = AD_config_MUX_A1_GND;}
if (port == 2) {Kanal = AD_config_MUX_A2_GND;}
if (port == 3) {Kanal = AD_config_MUX_A3_GND;}
for (counter = 0; counter <= messungen; counter++) {
for (a=0;a<4;a++) {
AD_writeBuf[a]=0;
}
// Achtung: CONFIG Byte 2 wird zuerst geschrieben! Siehe Datenblatt Figure 36
//
AD_writeBuf[0] = config_register; //set pointer to config register
AD_writeBuf[1] = Kanal + AD_config_MODE_single + AD_config_OS_single + Messbereich;
AD_writeBuf[2] = AD_config_DataRate_128 + AD_config_COM_QUE_dis;
// Schreibe die CONFIG Register in das DEVICE
//
bcm2835_i2c_write(AD_writeBuf,3);
// Init the Buffers
//
AD_readBuf[0] = 0;
AD_readBuf[1] = 0;
// start Conversion and wait to be finished, result is stored in register on device
//
while ((AD_readBuf[0] && 0x80) == 0) {
bcm2835_i2c_read(AD_readBuf, 2);
}
AD_writeBuf[0] = conversion_register; //set pointer to conversion register;
bcm2835_i2c_write(AD_writeBuf, 1);
bcm2835_i2c_read(AD_readBuf, 2);
// Verschiebe MSB um 8 stellen nach links und dann addiere LSB
AD_result = (AD_readBuf[0] * 256) + AD_readBuf[1];
}
// end and close I2C communication
//
bcm2835_i2c_end();
bcm2835_close();
// Bei Werten um 0V kann der Wandler auch negative Werte ausgeben. Das wird hier kompensiert
//
if (AD_result<0) AD_result = 0;
return AD_result;
}
Hinterlasse einen Kommentar