Teil 2 -- Ein digitales Thermomether order rede I2C mit deinem Microcontroller

ArticleCategory: [Choose a category, do not translate this]

Hardware

AuthorImage:[Here we need a little image from you]

[Photo of the Author]

TranslationInfo:[Author + translation history. mailto: or http://homepage]

original in en Guido Socher

en to de Guido Socher

AboutTheAuthor:[A small biography about the author]

Guido mag Linux weil es ein wirklich gutes System ist, um eigene Hardware zu entwickeln.

Abstract:[Here you write a little summary]

In diesem zweiten Teil werden wir ein LCD display in unser Thermomether einbauen und ich werde erkl�ren wie die Software funktioniert.

Die Leser, die neu hinzugekommen sind, sollten zuerst den ersten Teil (Februar 2005 Artikel 365) lesen.

ArticleIllustration:[This is the title picture for your article]

[Illustration]

ArticleBody:[The article body]

Die neuen Teile

In dem vorrangegangenen Artikel haben wir schon den wichtigsten Teil der Hardware, die n�tig war um Temperaturen zu messen, aufgebaut. In diesem Artikel gibt es nun ein sehr einfaches gtk GUI und ein LCD display.

Es ist sehr einfach diese beiden Dinge hinzuzuf�gen, deshalb werde ich den Rest des Artikels darauf verwenden die I2C Software und die Analogdigitalwandler Software zu erkl�ren.

Das LCD-Display

Als Display benugtzen wir ein HD44780 kompatibles Display, wie ich es schon in �lteren Artikeln eingesetzt hatte. Diese Displays sind sehr einfach in Verbindung mit Microcontrollern zu benutzen, da man einfach ASCII Zeichen an das Display schicken kann.
HD44780 compatible LCD display

Wie f�r alle anderen Artikel in dieser Serie gibt es auch hier wieder die Bauteile bei shop.tuxgraphics.org
Ich benutze den gleichen LCD-Treiber wie in den �lteren Artikeln. Die Dateien, die den Treiber implementieren sind lcd.c, lcd.h und lcd_hw.h. Sie sind Teil des Paketes, welches sich am Ende des Artikels herrunterladen l��t. Das Interface f�r diesen Code ist wirklich einfach zu benutzen:
// call this once:
// initialize LCD display, cursor off
lcd_init(LCD_DISP_ON);

// to write some text we first clear
// the display:
lcd_clrscr();
lcd_puts("Hello");
// go to the second line:
lcd_gotoxy(0,1); 
lcd_puts("LCD");
Wie diese HD44780 Displays genau funktionieren ist in dem linuxfocus September2002 Artikel "HD44780 kompatible LCD-Displays verstehen" erkl�rt.

Die Software ist so geschrieben, da� sie mit 16x2 und 20x2 Zeichen Displays funktioniert.

board change Es gibt leider im Schaltbild ein �nderung. Ich habe entdeckt, da� einige LCD Displays einen h�heren kapazitiven Innenwiderstand haben als andere. Das ist vermutlich so, weil sie einen besseren ESD Schutz haben. Diese h�here Last kann Bit-Errors beim Programmieren des Microcontrollers verursachen, wenn das Display an die SCK und MOSI Leitungen des Microcontrollers angschlossen ist.

Als erste L�sung f�r dieses Problem habe ich einfach ein paar Widerst�nde in die Leitungen zum Display eingel�tet. Das funktionierte problemlos bei mir, aber einige Leser, speziell Leute mit Laptops hatten immer noch Probleme.

Um das Problem vollst�ndig zu vermeiden habe ich dann das Schaltungsdiagramm ge�ndert und die D7 und RS Pins des Display an PD7 und PD6 angeschlossen. Es ist kein Problem das auf der Platine zu �ndern. Dazu ist lediglich ein kurzes St�ck Draht unter der Platine n�tig und die Verbindung zu PB3 mu� mit einem Messer unterbrochen werden.

Circuit diagram

Ein einfaches GUI

F�r die Leser, die gerne ein GUI auf Ihrem Desktop haben, habe ich ein wirklich einfaches GUI entwickelt. Es besteht aus 2 Textzeilen die die Ausgabe es Befehls i2ctemp_linux wiedergeben (das GUI ruft einfach den Befehl i2ctemp_linux auf und dieser liest die Temperatur via I2C).
GUI

Jetzt haben wir ein richtig cooles Thermomether: Den Rest des Artikels werde ich jetzt damit verwenden die Interna der Software zu erkl�ren.

Wie es funktioniert: Analogdigitalwandler

Der Atmega8 hat zwei Modi. Einen in dem er permanent analog zu digital wandelt und immer einen Interrupt ausl�st, wenn ein Konvertierung fertig ist. Die Applikation kann dann dem Interrupt benutzen um schnell des Ergebnis aus den Registern in Variablen zu kopieren.

In dem anderen Modus, der sich "single shot mode" nennt wird nur ein Konvertierung durchgef�hrt. Dieser Mode ist immer noch recht schnell. Mit der Zeit, die man braucht um alle Voreinstellungen richtig zu setzen kann man immer noch 100 Konvertierungen pro Sekunde erreichen. Das ist mehr als schnell genug f�r unsere Zwecke. Wir nehmen deshalb diesen Modus.

Als Eing�nge kann der Atmega8 die Pins ADC0 bis ADC3 benutzen. Daneben gibt es noch die Pins AGND (analog ground, Verbunden mit der normalen Masse), AREF (reference voltage) und AVCC (verbunden mit +5V).

W�hrend der AD-Wandlung wird das analoge Signal mit AREF verglichen. Ein analoges Signal das gleich mit AREF ist, entspricht einem digitalen Wert von 1023. AREF kann eine externe Referenz zwischen 0 und 5V sein. Ohne externe Referenz kann man immer noch exakte Messungen machen, indem man entweder die interne Referenzspannung (2.56V), oder AVCC benutzt. Welche dieser Optionen benutzt werden soll, l��t sich �ber die REFS0 und REFS1 Bits im ADMUX Register einstellen.

Der Analogdigitalwandler kann zu einem Zeitpunkt nur einen der Eing�nge ADC0-ADC3 konvertieren. Bevor die Konvertierung beginnt mu� man festlegen, welcher Eingang benutzt werden soll und das geht auch �ber Bits im ADMUX Register.

Eine einfache AD-Wandlung w�rde dann so aussehen:
volatile static int analog_result;
volatile static unsigned char analog_busy;

analog_busy=1; // busy mark the ADC function
channel=0; // measure ADC0 
// use internal 2.56V ref
outp((1<<REFS1)|(1<<REFS0)|(channel & 0x07),ADMUX);
outp((1<<ADEN)|(1<<ADIE)|(1<<ADIF)|(1<<ADPS2),ADCSR);
sbi(ADCSR,ADSC); // start conversion
Jetzt wird der Microcontroller die AD-Wandlung durchf�hren und dann die Funktion SIGNAL(SIG_ADC) aufrufen sobald die AD-Wandlung fertig ist. Als Programmierer mu� man darauf achten, da� man die unteren 8 Bits der Ergebisregister immer zuerst lesen mu�.
SIGNAL(SIG_ADC) {
        unsigned char adlow,adhigh;
        adlow=inp(ADCL); /* read low first, two lines. Do not combine
                          the two lines into one C statement */
        adhigh=inp(ADCH);
        analog_result=(adhigh<<8)|(adlow & 0xFF);
        analog_busy=0;
}
Jetzt haben wir das Ergebnis in der Variablen analog_result. Dieser Wert kann nun anderswo im Programm benutzt werden. Ganz einfach.

Wie bei allen Interrupts mu� man einmal global sei(); aufrufen um Interrupts einzuschalten. Das wird im Haupprogramm gemacht und ist deshalb hier nicht aufgef�hrt.

Es gibt eine Menge Bits und Flags, die ich kurz erkl�ren werde: Der Atmega8 hat verschiedene M�glichkeiten was die Referenzspannung betrifft:
REFS0=0, REFS1=0benutze eine externe AREF Spannung, die interne Vref ist aus
REFS0=0, REFS1=1AVCC mit optionalen Kondensator an dem AREF Pin
REFS0=1, REFS1=1interne 2.56V Referenz with (optionalem) externem Kondensator an dem AREF Pin
Der optionale externe Kondensator am AREF Pin kann rauschen unterdr�chen und die AREF Spannung stabilisieren.

Wie es funktioniert: I2C Kommunikation, Atmega8 Teil

Im Teil I (Februar 2005 Artikel365) habe ich schon erkl�rt wie das I2C Protokoll funktioniert. Jetzt wollen wir uns die Software etwas n�her ansehen. Der Atmega8 hat Hardwareunterst�tzung f�r I2C Kommunikation. Man mu� deshalb das I2C Protokoll garnicht implementieren. Stattdessen schreibt man eine Zustandsmaschine, die dem Atmega8 sagt was als n�chstes getan werden soll. Hier ein Beispiel:

Ein I2C Paket mit unser eigenen Slave-Adresse ist angekommen. Der Atmega8 wird nun die Funktion SIGNAL(SIG_2WIRE_SERIAL) mit dem Statuscode 0x60 (f�r andere Ereignisse gibt es andere Codes) aufrufen.

--> Jetzt m�ssen wir einige Register setzen, um dem Atmega8 zu sagen, was als n�chstes zutun ist. In diesem Fall sagen wir ihm: Empfange den Datenteil und best�tige mit einem ack-Bit.

Wenn die eigentlichen Daten empfangen wurden, werden wir mit dem Statuscode 0x80 aufgerufen.

--> Nun lesen wir das Datenbyte und sagen dem Atmega8, da� er auch das n�chste empfangen und best�tigen soll.

Wenn die Kommunikation zuende ist, erhalten wir den Statuscode 0xA0 (stop condition) und wir k�nnen unser Applikation sagen, da� eine vollst�ndige Nachricht empfangen wurde.

Die gesamte Zustandsmaschine f�r den I2C Slave und alle m�glichen Statuscodes sind im Datenblatt Seite 183 erkl�rt (siehe Link unter Referenzen am Ende des Artikels).

Das Senden von Daten funktioniert ganz �nlich. Schau einfach mal in den Code rein!

Wie es funktioniert: I2C Kommunikation, Linux Seite

i2c input stage Zun�chst einige Worte zur Hardware. Obwohl I2C ein Bus ist, benutzen wir nur Punkt zu Punkt Kommunikation zwischen einem Slave und dem Linux PC als Master. Wir k�nnen uns deshalb die "pullup" Widerst�nde sparen, solange der Slave die Leitung gegen Masse ziehen kann, ohne eine Kurzschlu� zu verursachen. Wir setzen deshalb die 4.7K Widerst�nde in serie in die Leitung.

Die Spannungspegle m�ssen angepasst werden. Das machen wir mit Z-Dioden, die negative Spannungen auf -0.7V und positive auf max. +5.1V begrenzen.

Nachdem ich inzwischen mehr �ber die Internas des Atmeag8 gelesen habe, denke ich da� man sich eigentlich die Z-Dioden sparen k�nnte, da der Strom �ber die 4.7K klein genug ist, damit auch die internen Schutzvorrichtungen des Atmeag8 gegen �berspannung ausreichen m��ten. Die Z-Dioden schaden aber auch nicht. In der n�chsten Schaltung nehme ich sie vielleicht raus.

Die Linux I2C Software implementiert einen kompletten I2C Stack. Dadurch ist die Linux-Seite unabh�ngig von irgenwelchen Kernelmodulen und Bibliotheken. Es ist einfach ein kleines Programm das unabh�ngig und problemlos funktioniert.

Wenn man sich die Datei i2c_m.c ansiehst (siehe Download) dann stellt man fest, da� wirklich jede I2C Nachricht Bit f�r Bit zusammengebaut wird.

Um die "Bits" zu erzeugen m�ssen wir die physikalischen Leitungen der RC232 Schnittstelle setzen. Das geht �ber ioctl Aufrufe:
        // set RTS pin:
        int arg=TIOCM_RTS;
        ioctl(fd, TIOCMBIS, &arg);
... oder um eine "Null" zu erzeugen:
        // clear RTS pin:
        int arg=TIOCM_RTS;
        ioctl(fd, TIOCMBIC, &arg);
Falls man diesen Code auf ein anderes Betriebsystem portieren m�chte, braucht man lediglich diese Zeilen zu �ndern. Der Rest ist ganz normaler ANSI C-Code.

USB zu RS232

Bei Laptops, die m�glicherwiese heute keine RS232 Schnittstelle mehr haben, kann man einfach einen USB zu RS232 Adapter nehmen. Ich benutze, z.B eine No-name Adapter der einen Prolific 2303 Chip enth�lt. In /proc/bus/usb/devices sieht das bei mir so aus: Vendor=067b ProdID=2303 Rev= 2.02. N�heres zu solchen Adaptern findet sich auch in "Einen ATEN UC-232A USB Adapter unter Linux nutzen (Linuxfocus, November 2001, Artikel 223)".

Zusammenfassung

mount the sensor Ich benutze das Thermometer nun seit 2 Monaten und es gef�llt mir wirklich gut. Ich kann die Temperatur direkt ablesen und die Daten �ber den PC auswerten.

Der Au�ensensor mu� gut gegen Regen und Sonne gesch�tzt sein. Man kann versuchen ihn in irgendwelches Plastik einzuwickeln, aber ich empfehle das nicht. Egal wie dicht man es verpackt, eines Tages kommt etwas Wasser hinein und kann dann nicht mehr raus. Der NTC ist recht robust und es macht ihm eigentlich nichts aus, wenn er mal f�r kurze Zeit feucht wird, solange er dann auch wieder trocknen kann. Eine umgedrehte Tablettendose eigent sich ganz gut. Ich habe sie unten offen gelassen und so kann das Wasser auch wieder raus.


the thermometer


Auch f�r diesen Artikel bekommt man wieder alle Teile (LCD Display, Platine, Microcontroller, ...) �ber den tuxgraphics Online-shop: shop.tuxgraphics.org.
Viel Spa�!

Referenzen