AD-Wandler bei PIC16F87X

Der PIC16F87x hat einen 10 Bit AD-Wandler
PIC16F871, PIC16F877 haben 8 Kanäle, andere nur 5 Kanäle
Unten vorgestellte Programm läuft auf allen PIC16F87x -Typen.

Funktion ADC() startet eine AD-Wandlung
benötigt als Parameter der Kanalnummer,
und liefert gemessenen Wert.
Kanalnummer kann 0...8 sein.
Ausgabewert der ADC()-Funktion ist 10 Bit groß und kann zwischen 0...1024 liegen.

Am Anfang des Main-Programms wird AD-Wandler konfiguriert:
Es werden alle Kanäle benutzt.
Referenzspannung ist Versorgungsspannung (in unserem Fahl: 5V ).
Daten werden rechtsbündig ausgegeben (bei hochwertigen Byte wird nur Bit0, Bit1 benutzt )

Um Ergebnisse sichtbar zu machen, werden die seriell zum Rechner übertragen.
Um dieses Ziel zu erreichen, bekommt PIC ein TTL => RS232 Pegelwandler und wird über Nullmodemkabel mit serieller Schnittstelle des Rechners verbunden.

Schaltplan - Im Schaltplan habe ich zum Eingängen des ADC 8 Fadern (bzw. Potentiometern ) angeschlossen. Somit lassen sich Spannungen von 0V bis 5V einstellen. Nach der AD-Wandlung dass sind Werte: 0 - Fader am Anschlag unten, 1024 - Fader am Anschlag oben.

Im Unterprogramm InitUSART() wird serielle Schnittstelle des PICs konfiguriert:
Asynchrone Modus wird eingestellt.
Baudrate wird auf 9600 Baud eingestellt.

Kommunikationsprotokoll mit dem PC ist ganz einfach.
PC sendet Kanalnummer, daraufhin PIC macht eine Messung und sendet gemessenen Wert als 2 Bits
(zuerst niedere Datenbyte, danach obere Datenbyte).
Danach wartet PIC wieder auf eine Kanalnummer.

Kanalnummer wird als Zahl (Binärwert) erwartet, nicht als String (ACSII ).
Zum Testen empfehle ich COM-Terminal, damit kann man einfache Zahlen und Strings über Serielle Schnittstelle senden und empfangen.

// Testprogramm: AD-Wandler auslesen und Werte zum PC übertagen
// Serielle Kommunikation mit (9600,N,8,1) TX==>RC6, RX==>RC7 TTL-RS232-Conwerter

// 20 MHz
#include <D:\cc5\16F871.H>

// Speicherschutz12,13,4,5=aus,Debug11=aus,ProgrammFlash9=an,EEpromRead8=an,
// NiedervoltProgr7=aus, NiederVoltReset6=an,EinschaltTimer3=an,
// WachDogTimer2=aus,Oszillator0,1=XC
#pragma config |= 0b.11.111101.11.00.10

#pragma origin 100          // Adresse des Programms

//******************************************************************************
void InitUSART()
{
    BRGH=1;
    SPBRG=129;              // (9600 baud @ 20MHz input clock)
    SPEN = 1;               // Set_Serial_Pins;
    SYNC = 0;               // Set_Async_Mode;
    TX9 = 0;                // Set_8bit_Tx;
    RX9 = 0;                // Set_8bit_Rx;
    CREN = 1;               // Enable_Rx;
    TXEN = 1;               // Enable_Tx;
    RCIE=0;                 // Rx Interrupt aus
}
//*******  Zeitverzögerung-Fnktion  *************************************************

void delay_mks( char mikro)
{
    #asm
    wdh9    nop
    nop
    decfsz  mikro,f
    goto    wdh9
    #endasm
}
//*******  AD-Wandler-Fnktion  ***************************************************

uns16 ADC(char kanal)
{
    uns16 Antwort;
    ADCON0 &= 0b.1100.0111; // 3 Bits, die KanalNummer angeben, reseten
    kanal= kanal << 3 ;     // Kanalnummer auf richtige Position rotieren
    ADCON0 |= kanal;        // und durch ODER-Funktion in Register übertragen
    delay_mks(50);          // Warten, damit interne Meßkondensator geladen wird.
    GO=1;                   // Starten der Wandlung
    while(GO);              // Solange warten bis Wandlung abgeschlossen ist
    Antwort.low8=ADRESL;    // Ergebnisse in Variable speichern
    Antwort.high8=ADRESH;
    return Antwort;
}
//*************************************************************************************

void main(void)
{
    uns16 a;                // Variablen
    char n;

    //++  Einstellungen des AD-Wandlers  ++++++++++++++++++++++++++++
    ADCON1=0;               // Ganzer PortA als Analog Vdd Vss
    ADON=1;                 // ADC-Einschalten
    ADCS1=1 ;               // Geschwingigkeit der ADC
    ADCS0=0 ;
    ADFM=1;                 // Rechts Ausrichtung
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    TRISC=0b.1011.1100;     // RC6>TX, RC7>RX
    InitUSART();            // Hardwareschnittstelle des PICs einstellen

    while(1)                // Ganzes Programm ist Endlosschleife
    {
        while(!RCIF);       // Warte auf Empfang
        n=RCREG;            // Empfange Kanalnummer
        a=ADC(n);           // AD-Wandlung
        while(!TXIF);       // Prüfen, ob Sender frei ist
        TXREG = a.low8;     // Niederes Datenbyte senden
        while(!TXIF);       // Prüfen, ob Sender frei ist
        TXREG = a.high8;    // Oberes Datenbyte senden

    }                       // Ende der Schleife
}                           // Ende des Hauptprogramms

 

Um das ganze zu visualisieren, habe ich ein Programm in Visual Basic geschrieben, das die Messwerte als Zahl und Schieberposition darstellt.

Programm zum Auslesen der 8-Kanaläle des AD- Wandlers
bei einem PIC16F877 / PIC16F871 über serielle Schnittstelle.
Ausführbare Programm herunterladen
Quellcode in VB herunterladen
 

Datenübertragung erfolgt mit 9600 Baud, keine Paritätsbit, ein Stoppbit.
Datenaktualisierung erfolgt 10 mal pro Sekunde.
Rechner sendet Nummer des Kanals (0, 1, 2, 3, ...) und empfängt 2 Byte: erstes ist niederes Datenbyte , zweites ist oberes Datenbyte.
Auflösung des AD- Wandlers bei PIC ist 10Bit. Also werden Zahlenwerte von 0 bis 1024 übertragen.
Programm benutzt eine DLL -Datei mit Namen "Port.DLL". Diese Datei muss entweder in gleichem Verzeichnis mit der "AD.exe" sein
oder im Verzeichnis C:\WINDOWS\SYSTEM sein.

Mit dem Drücken der Schaltfläche "Start" wird serieller Port geöffnet und kontinuierliche Auslesen des AD -Wandlers angefangen.
In oberen Textfeldern tragen Sie maximalen Wert Ihres Messsignals ein. Unter den Schiebern erhalten Sie umgerechnete Messwerte angezeigt. Mit dem Schliessen des Fensters wird serieller Port geschlossen und Programm beendet.

Es ist cool. Man schiebt Fadern und gleichzeitig bewegen sich Schiebern auf dem Bildschirm. Mit dieser Hardware kann man zum Beispiel RGB - Farben mischen (kann ich realisieren). Wer sich mit dem WinAmp versteht könnte damit Equalizer steuern.