Lernpaket Mikrocontroller Kap 7       

Elektronik-Labor  Lernpakete  AVR  LPmikros                  

7 Interfaces und Datenlogger
 
Die Verwendung der Interface-Software wurde bereits in Kap. 2 vorgestellt. Hier soll das dahinter liegende Programm genauer erläutert werden. Es ergeben sich dabei neue Möglichkeiten und Varianten für spezielle Aufgaben. Der ATtiny85 besitzt 512 Byte RAM und 512 Byte EEPROM. Damit lassen sich erweiterte Interfaces und Datenlogger realisieren.
 
7.1 Das universelle Interface
 
Das Interface-Programm des Lernpakets wurde bereits in Kap. 2 ausführlich vorgestellt und erprobt. Es basiert auf Byte-Kommandos, über die Ausgänge gesteuert oder Eingänge abgefragt werden. Das Interface-Protokoll ist angelehnt an das SIOS-Interface von AK-Modul-Bus und verwendet Gruppen von Byte-Kommandos, die sich leicht erweitern lassen.
 
&H10: digitale Ausgänge setzen 
&H20: digitale Eingänge lesen
&H30: analoge Eingänge lesen
&H40: analoge Ausgänge setzen
 
Das Interface-Programm besteht im Kern aus einer Interpreterschleife, in der Kommandos vom PC ausgewertet und ausgeführt werden. Am Anfang der Schleife wird ein Byte empfangen und als Kommando in die Variable Kom kopiert. Gültige Kommandos sind z.B. die Bytes 1, 16, 17, 18 und 32. Entsprechende Programmabschnitte führen jeweils einen Vergleich mit einer Konstanten aus. Wenn ein Kommando erkannt wurde, folgt eine zugehörige Ausgabe oder Eingabe. Im anderen Fall verzweigt das Programm zum nächsten Vergleich. Die gesamte Kommunikation läuft mit 9600 Baud. Ein typisches Kommando mit zwei Bytes wird daher in etwa zwei Millisekunden ausgeführt. Eine Interface-Abfrage mit dem Kommando 1 liefert die Antwort 100 und dient nur zur Überprüfung der Bereitschaft.   
 
Das SIOS-kompatible Kommando 16 (&H10) dient zur Ausgabe eines folgenden Bytes an den Port B. Mit dem Kommando 17 wird die Datenrichtung festgelegt. In beiden Fällen werden Die Leitungen RXD und TXD ausmaskiert, um die serielle Kommunikation nicht zu stören. Das Kommando 18 initialisiert den PWM-Ausgang PWM0A.
 
Das Kommando 32 (&H20)  fragt den Zustand des Ports B ab. Mit der Abfrage 48 und 49 erhält man 8-Bit-Werte des AD-Wandlers für die Kanäle 2 und 3. Mit 56 und 57 werden dieselben Kanäle mit einer Auflösung von 10 Bit gemessen, wobei die Antwort dann jeweils aus zwei Bytes besteht. Das Kommando 64 schließlich dient zur Ausgabe eines 8-Bit-PWM-Wertes an PWM0A. 
 
 
'ATtiny85 Interface
$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 8
$swstack = 4                                                ' 16
$framesize = 4
 
Dim Kom As Byte
Dim Dat As Byte
Dim U As Word
Dim Hi As Byte
Dim Lo As Byte
Dim N As Byte
Dim Nn As Word
 
Dim D(400) As Byte
 
Open "comb.2:9600,8,n,1" For Input As #1
Open "comb.1:9600,8,n,1" For Output As #2
 
Config Adc = Single , Prescaler = 16
Start Adc
 
Clkpr = 128             '8 MHz
Clkpr = 0
Clkpr = 0
 
Ddrb = &B00000011
 
Do
  Get #1 , Kom
  If Kom = 1 Then
    Put #2 , 100
  End If
  If Kom = 16 Then
    Get #1 , Dat
    Dat = Dat And &B00011011
    Dat = Dat Or &B00000010
    Portb = Dat
  End If
  If Kom = 17 Then
    Get #1 , Dat
    Dat = Dat And &B00011011
    Dat = Dat Or &B00000010
    Ddrb = Dat
  End If
  If Kom = 18 Then
     Config Timer0 = Pwm , Prescale = 64 , Compare A
         Pwm = Clear Up
     Pwm0a = 0
  End If
  If Kom = 32 Then
     Dat = Pinb
     Put #2 , Dat
  End If
  If Kom = 48 Then
     U = Getadc(2)
     Shift U , Right , 2
     Put #2 , U
  End If
  If Kom = 49 Then
     U = Getadc(3)
     Shift U , Right , 2
     Put #2 , U
  End If
  If Kom = 56 Then
     U = Getadc(2)
     Hi = High(u)
     Lo = Low(u)
     Put #2 , Hi
     Put #2 , Lo
  End If
  If Kom = 57 Then
     U = Getadc(3)
     Hi = High(u)
     Lo = Low(u)
     Put #2 , Hi
     Put #2 , Lo
  End If
  If Kom = 64 Then
    Get #1 , Dat
    Pwm0a = Dat
  End If


Loop
 
Listing 7.1: I/O-Funktionen des Interface-Programms


 
7.2 Das Oszilloskop
 
Das Interface enthält eine Oszilloskop-Funktion. Im Einkanal-Betrieb (Kommando 100) werden 361 Messwerte im Byte-Format gespeichert. Sofort nach der eigentlichen Messung schickt das Programm die Daten an den PC.
 
 
 
Config Adc = Single , Prescaler = 16

If Kom = 100 Then
    For Nn = 1 To 362
      U = Getadc(2)
      Shift U , Right , 2
      D(nn) = U
    Next Nn
    For Nn = 1 To 361
      Dat = D(nn)
      Put #2 , Dat
    Next Nn
  End If
 
  If Kom = 101 Then
    For N = 0 To 180
      U = Getadc(2)
      Shift U , Right , 2
      Nn = N * 2
      Nn = Nn + 1
      D(nn) = U
      U = Getadc(3)
      Shift U , Right , 2
      Nn = Nn + 1
      D(nn ) = U
    Next N
    For Nn = 1 To 362
      Dat = D(nn)
      Put #2 , Dat
    Next Nn
  End If
 
Listing 7.2: Die Oszilloskop-Funktion
 
Die Zweikanal-Variante wird mit dem Kommando 101 gestartet und liefert 181 ineinander geschachtelte Werte für jeden Kanal. Die Geschwindigkeit hängt von der Einstellung des AD-Wandlers ab. Für maximale Auflösung sollte der AD-Wandler mit einem Takt zwischen 50 kHz und 200 kHz betrieben werden. Mit der Einstellung Prescaler = 16 hat man bereits einen Takt von 500 kHz. Das ist jedoch problemlos, weil die Auflösung auf 8 Bit reduziert wird. Jede Einzelmessung benötigt damit etwa 70 µs, sodass man eine Abtastrate von ca. 14 kHz bekommt. Damit braucht die Serie mit 361 Einzelmessungen etwa 25 ms.
 
Der Timer 0 wird mit  Prescaler = 64 betreiben und liefert damit eine PWM-Frequenz von 244 Hz. Die Frequenz wurde relativ niedrig gewählt, damit Experimente mit dem eigenen Oszilloskop im Interface möglich sind. Wenn es aber auf eine einfache Glättung der PWM-Ausgangsspannung ankommt, ist eine höhere Frequenz besser.
 
Die schnellere Variante des Interface-Programms ist Interface2.bas. Der Timer0 wird mit Prescaler = 1, betrieben, sodass die PWM-Frequenz  auf 16 kHz steigt. Der AD-Wandler läuft nun mit Prescaler = 4, was die Abtastrate auf 36 kHz erhöht. Das Oszilloskop stellt nun einen Bereich von 10 ms dar. Bild 7.1 zeigt, dass trotz der hohen Abtastrate noch eine gute Auflösung erreicht wird.   
 

 
Abb. 7.1: Ein Signal mit 1 kHz
 
Interface2.bas erhält drei zusätzliche Kommandos, mit denen man die Zeitachse des Oszilloskops zwischen 10 ms und 200 ms verändern kann. Die Byte-Kommandos 97, 98 und 99 können über das Terminal gesendet werden.
 
 
 
 
 
  If Kom = 97 Then
    Config Adc = Single , Prescaler = 4    'Scope 10 ms
  End If
  If Kom = 98 Then
    Config Adc = Single , Prescaler = 16   'Scope 25 ms
  End If
  If Kom = 99 Then
    Config Adc = Single , Prescaler = 128  'Scope 200ms
  End If
 
Listing 7.3: zusätzliche Kommandos in Interface2.bas
 
7.3 Ein Transientenrecorder
 
Das Programm Logger1.bas realisiert einen Datenlogger, mit dem schnelle Messdaten erfasst und dann seriell im Textformat übertragen werden sollen. Die Funktion ähnelt einem Oszilloskop, man kann jedoch das Zeitverhalten und die Auflösung in weiten Grenzen anpassen. Die Daten lassen sich dann in eine Datei übertragen und auswerten. Insgesamt sollen 200 Messdaten im RAM zwischengespeichert werden.
 
 
'Logger1.bas  Datenlogger B4
$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 8
$swstack = 4
$framesize = 4
 
Dim Dat As Word
Dim N As Byte
Dim Dummy As Byte
Dim Daten(200) As Word
 
Config Portb.3 = Output
Config Adc = Single , Prescaler = Auto
Open "comb.1:9600,8,n,1" For Output As #1
Open "comb.2:9600,8,n,1" For Input As #2
 
Do
  Portb.3 = 1
  For N = 1 To 200
    Dat = Getadc(2)
    Daten(n) = Dat
  Next N
  Portb.3 = 0
  Get#2 , Dummy
  For N = 1 To 200
    Print #1 , N;
    Print #1 , " , ";
    Dat = Daten(n)
    Print #1 , Dat
  Next N
  Get#2 , Dummy
Loop
 
End
 
Listing 7.4: Lesen und Schreiben im RAM
 
Ein  Daten-Array lässt sich mit Dim Daten(200) as Word erzeugen. Man hat dann Platz für 200 Daten im Word-Format. Weil jedes Word zwei Byte belegt, werden insgesamt 400 Byte des verfügbaren Speichers von 512 Byte belegt. Andere Variablen und die Strack-Bereiche benötigen ebenfalls Speicher, sodass nicht mehr viel Platz übrig bleibt. Einen Überblick vermittelt die beim Kompilieren erzeugte Datei Logger1.rpt.
 
Report       : Logger1
Date         : 11-18-2015
Time         : 12:49:37
 
Compiler     : BASCOM-AVR LIBRARY V 2.0.7.8
Processor    : TINY85
SRAM         : 200 hex
EEPROM       : 200 hex
ROMSIZE      : 2000 hex
 
ROMIMAGE     : 2B2 hex  -> Will fit into ROM
ROMIMAGE     :  690 dec
FLASH USED   :  8  %
BAUD         : 9600 Baud
XTAL         : 8000000 Hz
BAUD error   : 100.%
 
Stack start  : 25F hex
Stack size   : 8 hex
S-Stacksize  : 4 hex
S-Stackstart : 258 hex
Framesize    : 4 hex
Framestart   : 250 hex
Space left   :  91  dec
 
Listing 7.5 Report zur Speichernutzung
 
Die Messwerterfassung startet nach jedem Reset, und damit auch mit einem neuen Öffnen des Bascom-Terminals. Während der Messung wird B3 hochgesetzt. Eine hier angeschlossene LED zeigt die Dauer der Messung an. Man sieht in diesem Fall nur einen kurzen Lichtblitz, weil die gesamte Messung nach etwa 50 ms beendet ist.
 
Nach der Messung wartet das Programm auf ein beliebiges Zeichen vom Terminal. Man kann z.B. ein Leerzeichen eingeben. Dann werden alle 200 Daten übertragen. Zur Vereinfachung der späteren Auswertung wird jeweils die Nummer des Messpunktes und Komma als Trennzeichen mit ausgegeben.
 

 
Abb. 7.2  Messdaten im RAM
 
Mit Terminal/Open Log lassen sich alle empfangenen Messdaten in eine Log-Datei speichern, deren Dateinamen und Speicherort man angeben kann. Nach der Übertragung muss die Dateien mit Close Log geschlossen werden. Die Log-Datei lässt sich dann z.B.  mit Excel auswerten und darstellen.
 
 
 

 
Abb. 7.3: Eine 300-Hz-Schwingung
 
 
7.4 Langzeit-Datenlogger
 
Im Gegensatz zum RAM bleiben Daten im EEPROM auch nach dem Abschalten der Betriebsspannung erhalten. Das EEPROM des Tiny85 hat eine Speichergröße von 512 Byte und kann sinnvoll zur Speicherung von Messdaten verwendet werden. Hier werden 500 Byte-Daten zur Helligkeit im Sekundentakt erfasst und gespeichert. Als Sensor dient der Fototransistor. Der Auslesevorgang entspricht dem Datenlogger im letzten Beispiel.
 

Abb. 7.4: Datenlogger mit roter LED als „Startschlüssel“
 
Bei einer Langzeitmessung ist es wichtig das Ende der Datenerfassung zu kennen. Außerdem braucht man eine Möglichkeit, ein erneutes Überschreiben der Daten zu verhindern. Der Mikrocontroller könnte z.B. mobile Messdaten aufnehmen, die dann später am PC ausgelesen werden sollen. Zur Aktivierung der Messung wird in diesem Beispiel eine rote LED eingesetzt. Am Port B3 wird beim Start der Pullup eingeschaltet. Die rote LED leuchtet schwach. Aber der Controller erkennt einen Low-Zustand, weil die LED-Spannung deutlich unter 2,5 V liegt.
 
 
'Logger2.bas  Datenlogger B3, 500 Bytes im EEPROM
$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 8
$swstack = 8
$framesize = 8
 
 
Dim Dat As Word
Dim Dbyte As Byte
Dim N As Word
Dim Dummy As Byte
 
 
Config Adc = Single , Prescaler = Auto
Open "comb.1:9600,8,n,1" For Output As #1
Open "comb.2:9600,8,n,1" For Input As #2
 
Do
  Portb.4 = 1                    'Pullup
  Waitms 10
  If Pinb.4 = 0 Then
    For N = 1 To 500
      Dat = Getadc(3)
      Shift Dat , Right , 2
      Dbyte = Dat
      Writeeeprom Dbyte , N
      Print #1 , Dbyte
      Waitms 1000
    Next N
  End If
  Portb.4 = 0
 
  Get #2 , Dummy
  For N = 1 To 500
    Print #1 , N;
    Print #1 , " , ";
    Readeeprom Dbyte , N
    Print #1 , Dbyte
  Next N
  Get #2 , Dummy
Loop
 
End
 
 
Listing 7.6: Der Datenlogger
 
Die Beispielmessung in Abb.7. 5 zeigt den Helligkeitsverlauf bei Sonnenschein und teilweise bewölktem Himmel
 

 
Abb. 7.5: Langzeitmessung der Helligkeit
 
 
7.5 Kennlinienschreiber
 
Eine Kennlinie beschreibt den Zusammenhang von Strom und Spannung an einem Bauteil. Mit einer regelbaren Spannungsquelle und zwei Messgeräten kann man Wertepaare erfassen, die dann in einem I/U-Diagramm aufgetragen werden.
 
Um die Messung automatisch durchzuführen, wird hier eine Spannungsquelle mit dem PWM-Ausgang und einem Tiefpassfilter gebildet. Der Analogeingang ADC3 misst direkt die Spannung am Messobjekt. Der Strom kann aus der Spannungsdifferenz zur Leerlauf-PWM-Spannung und dem Widerstand im RC-Filter berechnet werden.


Abb. 7.6: Aufnehmen einer LED-Kennlinie 
 
Das Programm Kennlin1.bas addiert jeweils fünf Messwerte pro Messpunkt. Damit wird einerseits eine Glättung erreicht und anderseits ohne weitere Umrechnung ein Messbereich von 5115 mV, also näherungsweise 5 V. Pro AD-Stufe wird nämlich mit 5 mV gerechnet. Der PWM-Ausgang hat nur eine Auflösung von 8 Bit und kommt entsprechend auf 20 mV pro Stufe, reicht also rechnerisch bis 20 mV * 255 = 5100 mV. Die Differenz beider Spannungen liefert direkt den Strom in µA.
 
Eine Messung wird mit einem beliebigen Zeichen gestartet. Im Terminal erscheinen dann Spannungen und Ströme, getrennt durch ein Komma. In dieser Form lassen sich die Daten in eine Tabellenkalkulation einlesen und grafisch auswerten.
 
2089 , 2871
2090 , 2890
 
Abb. 7.7 zeigt die typische Diodenkennlinie einer grünen LED. In Abb. 7.8 sieht man eine andere LED mit Vorwiderstand. Aus der Steigung lässt sich der Widerstand mit 1 kΩ bestimmen.
 
'Kennlin1.bas  Kennlinie PWM, ADC3
$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 8
$swstack = 4
$framesize = 4
 
 
Dim U_dat As Word
Dim I_dat As Word
Dim N As Byte
Dim I As Byte
Dim Dummy As Byte
Dim Daten(200) As Word
 
Config Portb.0 = Output
Config Adc = Single , Prescaler = Auto
Open "comb.1:9600,8,n,1" For Output As #1
Open "comb.2:9600,8,n,1" For Input As #2
 
 
Config Timer0 = Pwm , Prescale = 1 , Compare A Pwm = Clear Up
Pwm0a = 0
 
Do
  Get#2 , Dummy
  For N = 1 To 255
    Pwm0a = N
    Waitms 10 0
    U_dat = 0
    For I = 1 To 5
      U_dat = U_dat + Getadc(3)
    Next I
    I_dat = N * 20
    I_dat = I_dat - U_dat
    Print #1 , U_dat;
    Print #1 , " , ";
    Print #1 , I_dat
  Next N
  Pwm0a = 0
Loop
 
End
 
Listing 7.7: Messung von Kennlinien
 

 
Abb. 7.7: Kennlinie einer grünen LED 
 
 

 
Abb. 7.8: Kennlinie LED mit Vorwiderstand
 
 
 
7.6 Der MCS-Bootloader
 
Alle ATmega-Controller besitzen einen Bootbereich im Flash, der über einen Boot-Vektor angesprungen werden kann, wenn man ihn über die Fuses aktiviert. Bei jedem Neustart verzweigt der Mikrocontroller dann zunächst in den Bootbereich. Das Bootprogramm wartet auf eine Reaktion, die eine Neuprogrammierung einleiten soll. Bleibt sie aus, verzweigt der Controller an die normale Reset-Adresse $0000. Wenn jedoch ein Programm wie Bascom eine entsprechende Nachricht schickt, geht das Bootprogramm in den Programmiermodus, um ein neues Programm in den untern Flash-Bereich zu schreiben.
 
Es gibt zahlreiche Boot-Programme für unterschiedliche Systeme. Bascom kennt den eigenen MSC Bootloader, der selbst in Bascom geschrieben ist. Das Programm ist eigentlich nur für ATmega-Controller vorgesehen, weil ein ATtiny keinen ausgewiesenen Bootsektor und eine Boot-Fuses besitzt. Außerdem wird in der Vorlage der Hardware-UART verwendet, der beim ATtiny85 fehlt.
 
Trotzdem konnte der MCS-Bootloader an den ATtiny85 angepasst werden. Der Quelltext liegt dem Lernpaket bei. Zum Kompilieren wird die Bascom-Vollversion benötigt, weil der Code das obere Viertel des 8-k-Flash belegt. Die gesamte Kommunikation wurde auf den Software-UART umgebaut.
 
 
'                      (c) 1995-2009, MCS
'                        Bootloader.bas
'  This sample demonstrates how you can write your own bootloader
'  in BASCOM BASIC
'  VERSION 2 of the BOOTLOADER. The waiting for the NAK is stretched
'  further a bug was resolved for the M64/M128 that have a big page size
'-----------------------------------------------------------------
'This sample will be extended to support other chips with bootloader
'The loader is supported from the IDE
 
'Bootloader changed for ATtiny85 by Burkhard Kainka 2015
'Software UART at 9600 Baud at 8 MHz
'$timeout is not possible,special timeout before Testfor123
'Changes first rjmp in loaded file to rjmp &0D00, Bootloader
'rjmp to start address written to $F80
 
 
$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 8
$swstack = 4
$framesize = 4
 
$loader = $c00                                             
Const Maxwordbit = 5
Const Maxword =(2 ^ Maxwordbit) * 2       '128
Const Maxwordshift = Maxwordbit + 1
Const Cdebug = 0                                           
 
Listing 7.8 Programmkopf des Bootloaders
 
Der fehlende Bootsektor wird durch eine Änderung der Sprungadressen ersetzt. Beim ersten Start ist der untere Bereich mit FF gefüllt. Der Controller läuft dann automatisch in den Bootbereich ab $0C00. Wenn dann ein Anwenderprogramm in den unteren Bereich geladen werden soll, tauscht der modifizierte Bootloader die Sprungadressen aus. An die Adresse $0000 kommt ein Sprung auf den Bootlaoder selbst bei $0C00, damit beim nächsten Start wieder ein neues Programm übertragen werden kann. Ursprünglich stand im Hexfile an der Adresse $0000 ein Sprungbefehl auf den Anfang des Userprogramms. Dieser wird nun an die neue Adresse $0F80 gesetzt. Zum Start des Userprogramms verzweigt der Bootloader zu dieser Adresse und von dort zum Userprogramm.
 
Nach einem Hardware-Reset startet also immer erst der Bootloader. Er wartet kurze Zeit, ob über die serielle Schnittstelle ein Byte 123 empfangen wird, das als Start für einen Bootvorgang vereinbart ist. Bleibt dieses Byte aus, wird das zuletzt geladene Programm im unteren Programmbereich gestartet. Wenn man aber aus Bascom heraus ein neues Programm übertragen möchte, generiert Bascom über die DTR-Leitung einen Reset und stellt dann die Verbindung zum Bootloader her. Das neue Programm wird übertragen und danach gestartet.
 

If Bblock = 1 Then
   Waddress = Buf(2) - $c0
   Waddress = Waddress * 256
   Waddress = Waddress + Buf(1)
   Waddress = Waddress + 1
   Buf(1) = $0ff                    'rjmp $0D00 at 0000
   Buf(2) = $0cb
End If


   Waddress = $1000 + Waddress      'rjmp ... in F80
   Waddress = Waddress - $0f81
   Buf(1) = Waddress And 255
   Waddress = Waddress / 256
   Buf(2) = Waddress + $c0


Do_start:
  Goto $0f80
 
Listing 7.9 Umkopieren von Sprungadressen
 


Elektronik-Labor  Lernpakete  AVR  LPmikros