Using DAC  on PIC16F1503 - Page 1
Forum section: electronics / general

author: ocset
author_rank: Super Contributor
timestamp: March 22, 2019, 10:55:14 pm
content: HiWe have written this C code (XC8 compiler by microchip) for PIC16F1503.All it is supposed to do is read the voltage from the opamp and then every 10 seconds or so…it will give out a voltage on the DAC output which is representative of the maximum level of the voltage read on the ADC input.However, the DAC output is just always giving zero volts.Do you know what’s wrong, and which document tells the names that one must use to refer to the various registers of the PIC16F1503?Code:// PIC16F1503 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#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 disabled)#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 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 LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdint.h>#include <pic16f1503.h>#define _XTAL_FREQ 4000000uint8_t count;uint8_t count1;uint8_t count2;uint8_t inamp;uint8_t ADCval;uint8_t MAXval;void doADC(void);void doADC(void) {//Initiate ADRESH, ADRESLADRESL = 0x00;ADRESH = 0x00;__delay_us(50);ADCON0bits.GO = 1; //start conversion (GODONE=1)while (ADCON0bits.GO) {;} //Wait for conversion to finish (GODONE CLR)__delay_us(10);ADCval = ADRESH;__delay_us(10);return;}//Pin useage//RA4 (PIN 3) = AN3 = ADC input//RA2 (PIN 11) = AN2 = DACOUT1)//RC3 = PIN7 = General outputvoid main(void) {//Setup registersTRISA = 0x10; //ADC input = RA4TRISC = 0x00; //unused so make all outputs.ANSELA = 0x14; //RA4 = ADC INPUT; RA2 = DAC outputANSELC = 0x00;INTCON = 0x00; //disable all interruptsFVRCON = 0x00;ADCON0 = 0x0C; //Select ADC channel AN3ADCON1 = 0x60; //Left justified; FOSC/64;VDD=REFADCON0bits.ADON = 1; //Turn on ADC moduleDACCON0 = 0xA0; //DAC enabled and vref=vddWPUA = 0x00; //weak pullups disabledPORTA = 0x00; //zero outputsPORTC = 0x00; //zero outputsCM1CON1 = 0x00; //disabled comparatorCM2CON1 = 0x00; //disabled comparator__delay_ms(10);MAXval = 0;count = 0; //Do ten flashes to show your in the "zone".while(1){LATCbits.LATC3 = 0;__delay_ms(10);LATCbits.LATC3 = 1;__delay_ms(10);count = count + 1;if (count >= 10) {break;}}here:count1 = 0;while (1) {doADC();if (ADCval >= MAXval) {MAXval == ADCval;}count1 = count1 + 1;if (count1 >= 100) {break;}}//Now put MAXval representor out on DAC.if (MAXval >= 0x7F) {DACCON1bits.DACR = 0x1F;}if (MAXval <= 0x7F) {DACCON1bits.DACR = 0x00;}goto here;while(1) {;}//-----------------------------------------------------------------return;}

author: aldi
author_rank: Contributor
timestamp: March 23, 2019, 09:32:48 am
content: Quote from: treez on March 22, 2019, 10:55:14 pmThe datasheet?Are you sure the code is running, and not stuck in a while loop?

author: mikerj
author_rank: Super Contributor
timestamp: March 23, 2019, 02:58:09 pm
content: Code:if (ADCval >= MAXval) {MAXval == ADCval;}The above line is not correct, you are performing a equality test (==) rather than an assignment (=). Additionally you only want the assignment to be made if ADCval is greater than MAXval, though this won't be causing you any problems.It should be:Code:if (ADCval > MAXval){MAXval = ADCval;}Make it a habit to put the code block after the if statement rather than on the same line. Not only is it visually easier to process (IMO), if/when you progress to using a debugger it means you can easily set a breakpoint on the conditionally executed code.

author: ocset
author_rank: Super Contributor
timestamp: March 23, 2019, 05:38:57 pm
content: Thanks , the schematic for the above code is as attachedThe following line, does not work...Code:{DACCON1bits.DACR = 0x1F;}However, when i use ....Code:DACCON1bits.DACR0 = 1;DACCON1bits.DACR1 = 1;DACCON1bits.DACR2 = 1;DACCON1bits.DACR3 = 1;DACCON1bits.DACR4 = 1;...this works, and i can set/alter the DACR value.However , this was just my hacking about, there was nothing in the datasheet to tell of this.Do you know where the document is that tells of this?

author: cv007
author_rank: Frequent Contributor
timestamp: March 23, 2019, 06:54:55 pm
content: Code://Pin useage//RA4 (PIN 3) = AN3 = ADC input//RA2 (PIN 11) = AN2 = DACOUT1)//RC3 = PIN7 = General outputA good place to start would be to get the pins right- DACOUT1 is on RA0, pin13.

author: AndyC_772
author_rank: Super Contributor
timestamp: March 23, 2019, 07:07:08 pm
content: There's definitely a pin assignment error here, DACOUT1 is on AN0, and DACOUT2 is on AN2.Setting DACCON0 = 0xA0 means DACOE1 is set, but not DACOE2.However, you've also set ANSELA = 0x14, which means AN2 (DACOUT2) is defined as analogue. AN0 (DACOUT1) is in digital mode, and since TRISA has all the lower bits clear, the signal on DACOUT1 is a digital output (zero, it seems).

author: ocset
author_rank: Super Contributor
timestamp: March 24, 2019, 03:04:01 pm
content: Thanks,The below builds ok, but I bet when I put it in the hardware, the writing to the DAC register will go wrong, as it did before. Do you know what’s wrong with ….DACCON1 = 0x04;Code:// PIC16F1503 Configuration Bit Settings// 'C' source line config statements// CONFIG1#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#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 disabled)#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 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 LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdint.h>#include <pic16f1503.h>#define _XTAL_FREQ 4000000uint8_t count;uint8_t count1;uint8_t count2;uint8_t inamp;uint8_t ADCval;uint8_t MAXval;void doADC(void);void doADC(void) {RC4 = 1;//Initiate ADRESH, ADRESLADRESL = 0x00;ADRESH = 0x00;ADCON0bits.GO = 1; //start conversion (GODONE=1)while (ADCON0bits.GO) {;} //Wait for conversion to finish (GODONE CLR)ADCval = ADRESH;RC4 = 0;return;}//Pin useage//RA4 (PIN 3) = AN3 = ADC input//RA2 (PIN 11) = AN2 = DACOUT)//RC3 = PIN7 = General output//RC4 = PIN 6 = GENERAL OUTPUT = ADC indicator (see when ADC is done)void main(void) {//Setup registersOSCCON = 0x6A; //Select 4MHz intoscTRISA = 0x10; //ADC input = RA4TRISC = 0x00; //unused so make all outputs.ANSELA = 0x10; //RA4 = ADC INPUT;RA2 = DAC outputANSELC = 0x00;INTCON = 0x00; //disable all interruptsFVRCON = 0x00;ADCON0 = 0x0D; //Select ADC channel AN3; ADC enabledADCON1 = 0x60; //Left justified; FOSC/64; VDD=REFADCON0bits.ADON = 1; //Turn on ADC moduleDACCON0 = 0x90; //DAC enabled, vref=vdd, DACOUT2 enabledWPUA = 0x00; //weak pullups disabledPORTA = 0x00; //zero outputsPORTC = 0x00; //zero outputsCM1CON1 = 0x00; //disabled comparatorCM2CON1 = 0x00; //disabled comparator__delay_ms(10);MAXval = 0;count = 0; //Do ten flashes to show your in the "zone".while(1){LATCbits.LATC3 = 0;__delay_ms(10);LATCbits.LATC3 = 1;__delay_ms(10);count = count + 1;if (count >= 10) {break;}}here://This code picks out the mains peak.MAXval = 0;count1 = 0;while (1) {doADC();if (ADCval >= MAXval){MAXval = ADCval;}count1 = count1 + 1;if (count1 >= 100) {break;}}//Now put MAXval representor out on DAC (ie mains peak representor)if (MAXval < 0x9C) {DACCON1 = 0x00;} //MAINS <180VACif ((MAXval >= 0x9C) && (MAXval < 0xA4)) {DACCON1 = 0x02;} //MAINS 180-190VACif ((MAXval >= 0xA4) && (MAXval < 0xAD)) {DACCON1 = 0x04;} //MAINS 191-200VACif ((MAXval >= 0xAD) && (MAXval < 0xB6)) {DACCON1 = 0x06;} //MAINS 201-210VACif ((MAXval >= 0xB6) && (MAXval < 0xBE)) {DACCON1 = 0x08;} //MAINS 211-220VACif ((MAXval >= 0xBE) && (MAXval < 0xC7)) {DACCON1 = 0x0A;} //MAINS 221-230VACif ((MAXval >= 0xC7) && (MAXval < 0xD0)) {DACCON1 = 0x0C;} //MAINS 231-240VACif ((MAXval >= 0xD0) && (MAXval < 0xD8)) {DACCON1 = 0x0E;} //MAINS 241-250VACif ((MAXval >= 0xD8) && (MAXval < 0xE1)) {DACCON1 = 0x11;} //MAINS 251-260VACif ((MAXval >= 0xE1) && (MAXval < 0xEA)) {DACCON1 = 0x13;} //MAINS 261-270VACif ((MAXval >= 0xEA) && (MAXval < 0xF2)) {DACCON1 = 0x15;} //MAINS 271-280VACif ((MAXval >= 0xF2) && (MAXval < 0xFB)) {DACCON1 = 0x17;} //MAINS 281-290VACif (MAXval >= 0xFB) {DACCON1 = 0x19;} //MAINS >291VACgoto here;//-----------------------------------------------------------------return;}Also, do you think setting the INTOSC frequency with the OSCCON register will work?Its never worked before for us.Our code never works first time...do you know what the problems with our code above may be?

author: MarkF
author_rank: Super Contributor
timestamp: March 24, 2019, 10:03:08 pm
content: Your code is madness.It hurts my head.Consistent formatting would help a lot.Avoid GOTO at ALL costs.There's no real thought to the logic flow and choices made. You can't afford this in small MCUs with limited memory and execution rate.It's not that hard?For a 4MHz Fosc clock, your Tad selection of Fosc/64 is outside the recommended range.What is your desired sample rate and output rate?You schematic states 200us samples and output maximum every second.However, your posts and code seem to indicate 100ms sample rate and ever 10 sec output.A 200us sample rate is pretty ambitious. I tried to do 200us and increased the MCU clock to max (16MHz) but you will need to put a scope on RC3 and check the time between pulses. You may have to reduce the DELAY or remove it all together.You can adjust the sample rate and reporting rate with the DELAY and if (count >= 5000).Code:// PIC16F1503 Configuration Bit Settings// CONFIG1#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)#pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input)#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 disabled)#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 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 LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)#include <xc.h>#include <stdint.h>#define _XTAL_FREQ 16000000L// Pin usage// RA2(pin 11) == AN2 == DACOUT2// RA4(pin 3) == AN3 == ADC input// RC2(pin 8) == Timing output (report)// RC3(pin 7) == Timing output (sample)//============================================================void main(void){int count=0;uint8_t ADCval;uint8_t ADCmax;OSCCON = 0x7A; // 16MHz internal oscTRISA = 0b11111111;TRISC = 0b11110011;ANSELA = 0b00010000;ANSELC = 0b00000000;OPTION_REGbits.nWPUEN = 1; // Disable all weak pull-upsADCON0 = 0x0D; // AN3 | ADC enableADCON1 = 0x50; // Left justified | Fosc/16 | Vdd referenceDACCON0 = 0x90; // DAC enable | DACOUT2DACCON1 = 0;ADCmax = 0; // Clear max value for reportwhile (1) {// Read AN3LATCbits.LATC3 = 1; // set sample pulse highADCON0bits.GO = 1;while (ADCON0bits.GO_nDONE);ADCval = ADRESH;if (ADCval > ADCmax) ADCval = ADCmax;LATCbits.LATC3 = 0; // set sample pulse lowcount++; // Increment loop countif (count >= 5000) { // 1 sec?count = 0;LATCbits.LATC2 = 1; // set report pulse high// Update DACOUT2DACCON1 = ADCmax >> 3; // Only use top 5 bitsADCmax = 0; // Clear ADCmax for next reporting timeLATCbits.LATC2 = 0; // set report pulse low}__delay_us(200); // crude 200us timing loop}}Do I get a commission? Once again, we have to do you work.

author: MarkF
author_rank: Super Contributor
timestamp: March 25, 2019, 12:11:47 am
content: If you want the ADCmax to DACCON1 mapping in your last post, the following code would be better:(ReplaceDACCON1 = ADCmax >> 3; // Only use top 5 bitsin my previous code.)Also, it looks like you want even divisions in the values??? If so, there are errors in your values.Code:if (ADCmax >= 0xFB) DACCON1 = 0x18; // MAINS > 290VACelse if (ADCmax >= 0xF2) DACCON1 = 0x16; // MAINS 281-290VACelse if (ADCmax >= 0xE9) DACCON1 = 0x14; // MAINS 271-280VACelse if (ADCmax >= 0xE0) DACCON1 = 0x12; // MAINS 261-270VACelse if (ADCmax >= 0xD7) DACCON1 = 0x10; // MAINS 251-260VACelse if (ADCmax >= 0xCE) DACCON1 = 0x0E; // MAINS 241-250VACelse if (ADCmax >= 0xC5) DACCON1 = 0x0C; // MAINS 231-240VACelse if (ADCmax >= 0xBC) DACCON1 = 0x0A; // MAINS 221-230VACelse if (ADCmax >= 0xB3) DACCON1 = 0x08; // MAINS 211-220VACelse if (ADCmax >= 0xAA) DACCON1 = 0x06; // MAINS 201-210VACelse if (ADCmax >= 0xA1) DACCON1 = 0x04; // MAINS 191-200VACelse if (ADCmax >= 0x98) DACCON1 = 0x02; // MAINS 181-190VACelse DACCON1 = 0x00; // MAINS < 181VAC