|
Bitte beachte die Copyrighthinweise.
Vergrößerung des Auflösungsvermögens von ADCs
1 Aufgabenstellung
· Erstellung eines Microcontrollerprogramms, welches 1000 Werte über den ADC einliest und daraus eine Verteilung erstellt bzw. Mittelwert und Standardabweichung berechnet
2 Allgemeines
Ein 16bit Analog-Digital-Konverter besitzt normalerweise eine Auflösung von 16bit.
Wird ein bestimmter Spannungswert gemessen, ergibt sich normalerweise ein bestimmtes, stehendes Bitmuster (Zahl n) am Ausgang.
Überlagert man nun eine Rauschspannung mit z.B. ½ LSB, so werden auch die Zahlen n+1 bzw. n-1 oder größere Abweichungen auftreten. Aus mehreren Messwerten kann somit eine Verteilung ermittelt werden, aus der z.B. ein 17bit oder 18bit Messwert errechnet werden kann!
3 Programmierung in C für die 51er MC-Familie
Das Programm wurde in C erstellt und mit dem Keil C51 Compiler übersetzt.
3.1 KEIL C51 Compiler (Windows, Evaluation Version)
Vor dem Starten von Windows kann folgende Batchdatei ausgeführt werden, die die Pfade des BIN, INC und LIB Verzeichnisses setzt. Somit muss dies nicht bei jedem neuen Projekt unter [Options]-[Environment Pathspecs] eingestellt werden.
Wird kein Parameter übergeben, wird das Verzeichnis G:\WinApps\C51Eval gesetzt. Da SET unter Win95 nur in der aktuellen DOS-Box wirkt, wird zusätzlich winset aufgerufen ([Win95-CD]\ADMIN\APPTOOLS\ENVVARS\).
C51b.bat:
:: Umgebung fuer uVision C51 Compiler setzen
:: Verzeichnis uebergeben?
:: wenn nicht, auf G:\WinApps\C51Eval setzen
if "%1" == "" %0 G:\WinApps\C51Eval
SET path=%1\bin;%path%
SET C51LIB=%1\LIB
SET C51INC=%1\INC
winset path=%1;%path%
winset C51LIB=%1\LIB
winset C51INC=%1\INC
Danach wird unter Windows das Programm mVision/5 evaluation (bin\uvw51e.exe) gestartet (Eval Version 1.01, Toolset Keil 8051 C Compiler ver5).
Zum Testen der Übersetzbarkeit des Quelltextes reicht es, nur die *.C - Datei zu laden und über [Project]-[Compile File] zu kompilieren. Hierbei wird jedoch nur eine *.OBJ - Datei erzeugt. Möchte man das Programm in den Microcontroller mittels des Monitors M51 laden und danach ausführen, benötigt man eine *.HEX - Datei.
Dazu ist es nötig, über [Project]-[New Project] ein neues Projekt anzulegen und die Quelldatei über [Insert] hinzuzufügen. Über [Project]-[Make: Build Project] kann nun die *.HEX - Datei erstellt werden.
Zur Fehlersuche empfiehlt es sich, unter [Options]-[C51 Compiler]-[Listing] die Option Include assembly code (fügt übersetzten ASM-Sourcecode in das Listfile ein, auch mit #pragma code möglich) und unter [Options]-[Make]-[Misc] die Option Ignore Warnings (Linker stoppt nicht bei Warnings) zu aktivieren.
3.2 KEIL C51 Compiler (DOS, Vollversion)
Mit der Evaluation Version existieren verschiedene Einschränkungen. Vor allem können durch den Linker keine Dateien mit mehr als 2kB erzeugt werden oder es können keine A51-Dateien übersetzt werden.
Für die Assemblerdatei startup.a51 wurde deshalb die DOS-Vollversion verwendet:
c51 adcstat.c debug objectextend ¬ bl51 startup.obj, adcstat.obj ¬ oh51 startup ¬
3.3 Beim Kompilieren auftretende Fehler und ihre Ursachen:
Fehler |
Ursache |
Lösung |
Could not execute Translator. |
Pfade nicht gesetzt. |
Pfade über [Options] oder Batchdatei setzten. |
Linking *** Error: Command File <Pfad> not found |
Verzeichnisname enthält einen Bindestrich. |
Verzeichnis umbenennen. |
Could not read RETVAL file |
Projektdateien befinden sich im ROOT-Verzeichnis eines Datenträgers. |
Dateien in Unterverzeichnis verschieben. |
Could not read RETVAL file |
Projekt und C-Dateien befinden sich nicht im selben Verzeichnis. |
Dateien in gleiches Verzeichnis verschieben. |
Linking *** Fatal Error 211: I/O Error on Input File Exeption 0029H: Access to file denied File: <Pfad><Datei> |
Im Verzeichnis der Projektdatei befindet sich ein gleichnamiges Unterverzeichnis. |
Projektdatei oder Unterverzeichnis umbenennen. |
Linking *** Fatal Error 210: I/O Error on Input File Exeption 0021H: Path or File not found File: <Pfad><Datei.OBJ> |
Im selben Verzeichnis befindet sich die Datei C51.bat. |
C51.bat umbenennen (Wird vermutlich statt BIN\C51.EXE ausgeführt). |
Im allgemeinen kann gesagt werden, dass der Compiler sehrt gut optimiert und aus gutem C-Code auch guten Assembler-Code produziert.
Folgendes sollte jedoch beachtet werden:
· An den meisten Stellen in Programmen werden unipolare 8Bit Werte verwendet es empfiehlt sich deshalb, den Datentyp unsigned char zu verwenden.
· Der
Compiler führt selbstständig eine Optimierung der DATA_GROUP
durch. In dieser Gruppe sind alle in Haupt- bzw. in den Unterprogrammen
vorkommende Variablen plaziert.
Variablen, die zwar z.B. in einem Unterprogramm benutzt werden, nach dem
Verlassen jedoch nicht mehr benötigt werden, können vom nächsten
Unterprogramm für andere Zwecke belegt werden. Dies wird als Overlaying
bezeichnet. Näheres s. C51Primer [1]
Nicht aufgerufene Funktionen werden für den Overlayingprozess
ignoriert.
· Bei Interruptfunktionen werden neben den Akkus und wichtigen Registern auch alle Register der aktuellen Registerbank über PUSH/POP gesichert. Dies kann durch die Verwendung von using verhindert werden. Aufgerufene Unterprogramme sollten eventuell die gleiche Bank verwenden.
Eine gute Quelle für weitere Fragen stellt der C51Primer dar.
C51Primer: C51 Einführung und Hintergrundinformationen. Auf die Linkseite von http://www.keil.com/ gehen oder direkt auf http://www.hitex.com/index.html und danach auf C51Primer.
4 Programm
Die 1000 Messwerte werden in den externen RAM eingelesen. Auf der verwendeten Platine beginnt dieser aber erst bei 8000h.
Zuerst wurde hierzu in der Datei startup.a51 der Eintrag XDATASTART auf 8000H geändert, das Programm funktionierte jedoch nicht. Es stellte sich heraus, dass unter [Options]-[BL51 Code Banking Linker]-[Size/Location] der Wert Xdata Adress auf 8000 gesetzt werden muss.
Das Programm überschreibt zuerst putchar(), sodass eine Ausgabe mit putchar() bzw. printf() über die zweite Serielle Schnittstelle erfolgt.
In main() wird muss hierzu noch diese Schnittstelle initialisiert werden, danach werden in einer Endlosschleife 1000 Messwerte auf das externe RAM eingelesen.
/*************************************************************************
/* Editor: Florian Rosenauer @ HTBLA Karlstein, Austria-3830 Waidhofen
/* Datum: 16/Mai/1998 Klasse/Gruppe/Kat.Nr : V-EA/-/--
/*************************************************************************
/* Sprache : C51 fuer MC 80C537 (Eval)
/* Programm Nr. : Labor 24 SteG Microcontroller ADC
/* Kurzbeschreibung : Standardabweichung berechnen
/* Zugriff auf xdata geht (Options-BL51-Size/Loc-8000H)
/*************************************************************************
*/
// const float VERSION = 1.02;
/************************************************************************/
#pragma listinclude code
#include <stdio.h>
#include <reg517.h>
/* BEGINN --- putchar von Sampl517 --- */
#define XON 0x11
#define XOFF 0x13
char putchar (char c) {
if (c == '\n') {
if (S1CON & 0x01) { /* RI*/
if (S1BUF == XOFF) {
do {
S1CON &= 0xFE; /* RI = 0 */
while (!(S1CON & 0x01)); /* RI */
}
while (S1BUF != XON);
S1CON &= 0xFE; /* RI = 0 */
}
}
while (!(S1CON & 0x02)); /* while (!TI); */
S1CON &= 0xFD; /* TI = 0 */
S1BUF = 0x0d; /* output CR */
}
if (S1CON & 0x01) {
if (S1BUF == XOFF) {
do {
S1CON &= 0xFE; /* RI = 0 */
while (!(S1CON & 0x01)); /* while (!RI) */
}
while (S1BUF != XON);
S1CON &= 0xFE; /* RI = 0 */
}
}
while (!(S1CON & 0x02)); /* while (!TI); */
S1CON &= 0xFD; /* TI = 0 */
return (S1BUF = c);
}
/* ENDE --- putchar von Sampl517 --- */
void main (void) {
unsigned char xdata adcwert[1000]; // 0 bis 999
//unsigned char adctemp;
unsigned int n;
/* BEGINN --- Serial 1 Init von Sampl517 --- */
/* initialize serial interface */
//#if 0
S0CON = 0x5A; /* S0CON */
BD = 1; /* internal Baudrate Generator */
PCON |= 0x80; /* 9600 Baud @ 12 MHz */
//#endif
S1REL = 0xD9; /* Reload Value */
S1CON = 0xB2; /* Init Serial Interface */
/* ENDE --- Serial 1 Init von Sampl517 --- */
// '#endif' wofuer ???
// --- ADC Init ---
ADCON1 = 0; // Kanal0 (P7.0)
ADCON0 = 0; // kein ext. Trig, Einzelwandlung
printf("Init OK");
while (1)
{
// Einlesen der Daten
for (n=0;n<=999;n++)
{
putchar('!');
DAPR = 0; // ADC 0-5V starten
while (BSY); // warten
adcwert[n] = ADDAT;
//adctemp = ADDAT;
//printf("\n%d: %d", n, (int) adctemp);
//printf("\n%d: %d", n, (int) adcwert[n]);
}
printf("Daten eingelesen");
// Ausgabe der eingelesenen Daten zur Kontrolle
for (n=0;n<=999;n++)
{
printf("\n%d: %d", n, (int) adcwert[n]);
}
// Ausgabe Vertleiung (Vertikal)
} //while(1)
} //main()
Aus Zeitgründen war eine Ausgabe der Verteilung nicht mehr möglich.
5 Interpretation der Messergebnisse
Eine interessante Theorie, die leider nicht mehr praktisch bestätigt werden konnte.