PIC12 DAC hat keinen Ausgang

Ich habe einen PIC12F1571 (Datenblatt hier: http://ww1.microchip.com/downloads/en/DeviceDoc/40001723b.pdf ), den ich programmiert habe, um einen analogen Eingang zu lesen, den gelesenen Wert zu verarbeiten und dann einen verwandten auszugeben Wert auf dem Onchip-DAC.

Zum Testen habe ich ein Potentiometer an den analogen Eingang angeschlossen und kann im MPLAB-Debugger sehen, dass der richtige Wert vom PIC gelesen wird (ADRESH/ADRESL werden vom ADC entsprechend eingestellt). Ich habe auch überprüft, ob die DAC-Bits in den Registern DACCON0 und DACCON1 richtig gesetzt sind. Im Debugger kann ich sehen, dass der DAC auf den richtigen Ausgang gesetzt wird, aber am Ausgangspin liegt keine Spannung an.

Ich habe die Richtung meines TRISA-Registers auf die entsprechenden Pins überprüft, sichergestellt, dass das alternative Pin-Funktionsregister keine Konflikte aufweist und dass alles andere deaktiviert ist.

Code ist unten. Ich habe den PIC so eingerichtet, dass RA4 - Pin 3 (Analogkanal 3) als ADC-Eingang und RA0 - Pin 7 als DAC-Ausgang verwendet wird.

#if defined(__XC)
  #include <xc.h>         /* XC8 General Include File */
#endif

#include <stdio.h>
#include <stdlib.h>

#include <pic12f1571.h>

#define SYS_FREQ        500000L
//#define FCY             SYS_FREQ/4

//Set up using the Memory View (Window -> PIC Memory Views -> Configuration Bits
// CONFIG1
#pragma config FOSC = INTOSC       //  (ECH, External Clock, High Power Mode (4-32 MHz); device clock supplied to CLKIN pin)
#pragma config WDTE = OFF        // Watchdog Timer Enable (WDT enabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOREN = OFF    // Low Power Brown-out Reset enable bit (LPBOR is disabled)
#pragma config LVP = OFF         // Low-Voltage Programming Enable (Low-voltage programming enabled)


void setup(void)
{
 /* Configure Interrupts
 * INTCON - Interrupt Control Register:
 * Set GIE (Global Interrupt Enable)
 * Set PEIE (Peripheral Interrupt Enable bit (for ADC interrupts)
 * Set TMR0IE (Timer0 Overflow Interrupt Enable bit)
 *
 * PEI1 - Peripheral Interrupt Enable Register:
 * Set ADIE (ADC Interrupt Enable bit)
 */
    INTCON = 0xE0;
    PIE1 = 0x40;
    PIE2 = 0x00;
    PIE3 = 0x00;

/* Configure PORTA for the following:
 *
 * Configure TRISA for Port A Direction Control
 * only have 1 input pin - RA4
 * 1 output pin - RA0 (for DAC1)
 *
 * Configure ODCONA for Open-drain Control
 * PORTA configured as standard push-pull
 *
 * Configure SLRCONA for Slew Rate Control
 * Slew rate is unlimited
 *
 * Configure INLVLA for Input Threshold Control
 * Doesn't need to be set since all input is analog
 *
 * Configure ANSEL registers for ADC operation on AN3 (RA4/pin 3)
 */
    TRISA = 0x10;
    ODCONA = 0x00;
    SLRCONA = 0x00;
    INLVLA = 0x00;
    ANSELA = 0x10;

    /* Configure TIMER0
     *
     * In OPTION_REG:
     * Select Internal instruction clock
     * Select no prescaler on the timer
     *
     *  */
    OPTION_REG = 0x84;

    /* Configure ADC
     *
     * Set ADCON0 to the following:
     * CHS set to analog channel AN3 = 00011 (RA4/pin 3)
     * ADON set to ADC enabled = 1
     *
     * Set ADCON1 to the following:
     * ADFM set to left justified = 0 (so that we can get away with reading a
     *   single byte for our converted value)
     * ADCS Conversion clock source set to Fosc/8 = 001
     * ADPREF set to Vdd reference = 00
     *
     * Set ADCON2 to trigger on Timer0 overflow
     * ADCON2:TRIGSEL = 0011

     */
    ADCON0 = 0x0D;
    ADCON1 = 0x10;
    ADCON2 = 0x30;

    /* Configure up DAC
     * Set DACCON0 register:
     * DACEN set to DAC enabled = 1
     * DACOE set to voltage level output = 1
     * DACPSS<1:0> is set to Vdd = 00
     *
     * DACCON1 register contains the DACR bits (i.e. the output value)
     *
     */
    DACCON0 = 0xA0;
    DACCON1 = 0x00;

    // Set APFCON register to
    APFCON = 0xFF;
}

void interrupt isr(void)
{
    if(TMR0IF)
    {
        TMR0IF = 0; /* Clear TIMER0 Overflow Interrupt Flag*/
        //ADC will automatically start converting now

    //    ++counter;
    }

    if(ADIF)
    {   /* Clear ADC Completion Interrupt Flag */
        ADIF = 0;
        DACCON1 = ADRESH >> 3;
    }
}

int main(int argc, char** argv) {
    setup();
    while(1);
    return (EXIT_SUCCESS);
}

Was vermisse ich? Das sollte einfach sein...

Antworten (4)

Ich denke, der Code hat die ganze Zeit funktioniert - das Problem war, dass der DAC nichts ausgeben würde, wenn der PIC für den Debug-Modus programmiert war. Dies liegt daran, dass der RA0-Pin auch für ICSPDAT verwendet wird, also gab es einen Konflikt und ich vermute, der Compiler/die IDE hat beschlossen, tatsächlich nichts auszugeben - ich hatte überprüft, dass es nicht nur ein Pulldown im PICKit3-Programmierer war Trennen des Drahtes. Definitiv ein Problem bei der Programmierung des PIC im Debug-Modus.

Programmierte den PIC im regulären Modus und die DAC-Ausgänge sind in Ordnung - obwohl, wenn das PICKit3 mit dem DAC-Ausgangspin verbunden bleibt, die maximale Spannung 1/3 von Vdd beträgt. Das macht auch Sinn.

Am Ende sein Benutzerfehler.

Es sieht nicht so aus, als würden Sie Ihrem ADC sagen, dass er eine Konvertierung durchführen soll, obwohl Sie das Modul aktiviert haben. Auf dem PIC18F, den ich verwende, muss ich speziell eine 1 in das GO/~DONE-Bit von ADCON0 schreiben, um ihm mitzuteilen, dass er etwas konvertieren soll. Wenn es fertig ist, wird es den Interrupt auslösen. Es wird nicht konvertiert, ohne dass Sie es zuerst anfordern, was Sie niemals tun, wenn Sie Ihren Code ansehen - Sie warten einfach ewig. Wenn man sich das Datenblatt ansieht, sieht es so aus, als ob es genauso funktioniert wie der Chip, den ich verwende.

Der ADC in diesem PIC12F hat einen Triggermodus, in dem er bei einem Überlauf von TIMER0 automatisch gestartet werden kann (und dies auch tut, wie im Debugger verifiziert). // ADCON2 so einstellen, dass es bei Timer0-Überlauf auslöst // ADCON2:TRIGSEL = 0011 Ich habe den Code mit explizitem Setzen von GO/~DONE ausprobiert und das Verhalten ist dasselbe. Trotzdem quakt der DAC nicht.
Das Beste, was Sie tun können, ist, das Problem zu halbieren. Ignorieren Sie den ADC vorerst und werfen Sie einfach ein paar Zahlen auf den DAC. Damit erübrigt sich jede Spekulation über den ADC-Anteil. Außerdem muss weniger Code gepostet werden.

Wenn Sie über DAC sprechen, zeige ich Ihnen einen folgenden Code.

Aber ich denke, Sie verwechseln ADC mit DAC.

Es funktioniert genau mit meinem eigenen pic12f1572.

int main(void)
{    
    OSCCON = 0b01111000; // for example,16 MHz    
    ANSELA = 0b00000000; // all pins to digital    
    PORTA  = 0b00000000; // all port bits off    
    TRISA  = 0b00001000; // all pins to outputs except RA3 (MCLR)    
    ADCON0 = 0b01111000;  // use DAC   
    DACCON0= 0b10100000;  // DAC enable, VDD as reference  
    DACCON1= 0b00011111;  // for example,32 as output = VDD
}

Ich verwende den pic12F1572, um einen DAC bereitzustellen, stellte jedoch fest, dass die richtige Antwort angezeigt wurde, wenn ich ein Oszilloskop auf den Ausgang legte, aber wenn ich eine Last von viel weniger als 100 k anschloss, war der Ausgang nichtlinear oder null. Ich überprüfte das Datenblatt und es implizierte, dass dies ein Relais war, das nur zum Erzeugen von Referenzspannungen gedacht war, die innerhalb des Chips verwendet werden sollten. Meine Lösung bestand darin, einen kleinen FET-Operationsverstärker als Treiber an den Ausgang zu legen, und alles ist in Ordnung.