To be honest, I have never considered using the PIC 16F1509 digital to analog converter before. I was considering integrating a DAC internally or externally to a microcontroller for my brother’s synth project. I started on the microchip site and found a number of smaller PICs, 12F1501.. 16F1503, that had a 5bit DAC. The 16F753 has a 9bit and the 16F17* series has a 8bit DAC. I stuck with the old standby 16F1509 as I needed a serial port for MIDI and I had it sitting on an easy-to-use dev board. I ordered a 16F17* series PIC a while back because they have some interesting peripherals and I will probably build a board around it for the resolution.
Turns out the DAC is probably the easiest peripheral I’ve used on the PIC. It took me longer to wait for the PICKit to update from 18F configuration to 16F. BUT.. if you’re having issues.. here you go:
A simple voltage follower (or however you want to buffer the output) is needed on the DAC output. It’s not designed to drive anything.
Don’t expect screaming speeds out of this thing…it’s just not going to happen. I ran mine up to 1.3KHz, which is more than enough for what I’m trying to accomplish. If you put an A/D converter in you could use that to control your ramp speed and you’d have yourself a nice driver for your VCO input on test equipment with properly conditioned output.
The code:
/*
* File: main.c
* Author: Charles M Douvier
* Contact at: http://iradan.com
*
* Created on April 13, 2014, 1:14 PM
*
* Target Device:
* 16F1509 on Tautic 20 pin dev board
*
* Project: DAC ramp test
*
* Version:
* 1.0
*
*/
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000 //4Mhz FRC internal osc
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))
#endif
#include
#include
#include
#include
//config bits
#pragma config FOSC=INTOSC, WDTE=OFF, PWRTE=OFF, MCLRE=ON, CP=OFF, BOREN=ON, CLKOUTEN=OFF, IESO=OFF, FCMEN=OFF
#pragma config WRT=OFF, STVREN=OFF, LVP=OFF
#define _XTAL_FREQ 4000000 //defined for delay
int x; //DAC counter
/*
*
*/
void init_io(void) {
TRISAbits.TRISA0 = 0; // output
TRISAbits.TRISA1 = 0; // output
TRISAbits.TRISA2 = 0; // DAC2
TRISAbits.TRISA3 = 0; // output
TRISAbits.TRISA4 = 0; // output
TRISAbits.TRISA5 = 0; // output
// TRISAbits.TRISA6 = 0; // output
// TRISAbits.TRISA7 = 0; // output
ANSELA = 0x00; // all port A pins are digital I/O
TRISBbits.TRISB4 = 0; // RB4 = nc
TRISBbits.TRISB5 = 1; // RB5 = nc
TRISBbits.TRISB6 = 0; // RB6 = nc
TRISBbits.TRISB7 = 0; // RB7 = nc
ANSELB = 0x00; // all port B pins are digital I/O
TRISCbits.TRISC0 = 0; // output
TRISCbits.TRISC1 = 0; // output
TRISCbits.TRISC2 = 0; // output
TRISCbits.TRISC3 = 0; // output
TRISCbits.TRISC4 = 0; // output
TRISCbits.TRISC5 = 0; // output
TRISCbits.TRISC6 = 1; // input
TRISCbits.TRISC7 = 1; // input
ANSELC = 0x00; // all port B pins are digital I/O
}
void init_dac(void)
{
DACCON0bits.DACPSS = 0; //VDD ref
DACCON0bits.DACOE2 = 1; //output 2 enable (RA2)
DACCON0bits.DACEN = 1; //enable DAC
}
int main(void) {
// set up oscillator control register, using internal OSC at 4MHz.
OSCCONbits.IRCF = 0x0d; //set OSCCON IRCF bits to select OSC frequency 4MHz
OSCCONbits.SCS = 0x02; //set the SCS bits to select internal oscillator block
OPTION_REGbits.nWPUEN = 0; // enable weak pullups (each pin must be enabled individually)
init_io();
init_dac();
x = 0;
while (1) {
for (x = 0; x < 31; ++x)
{ //DAC is 5 bit
DACCON1bits.DACR = x; //dump count into DAC value
__delay_us(25);
}
}
return (EXIT_SUCCESS);
}