that's cool...... 1 count in 1023 is small..small error..... that error with 0 volts could be where pic ground is in relation to pot low end...... ground pot low end close to pic ground.....
what about the fluxuating readings ?
that's cool...... 1 count in 1023 is small..small error..... that error with 0 volts could be where pic ground is in relation to pot low end...... ground pot low end close to pic ground.....
what about the fluxuating readings ?
I found the math behind the Arduino map function and have replicated it in a subroutine in PBP:
It doesn't look like this is working as expected - any ideas?Code:PR2 = 62 ; For 16Mhz OSC the desired output freq of 15,873Hz is ; achieved with this PR2 value (8-bit resolution ; with 1:4 prescaler) ; PWM freq must be ~ 16-20kHz to reduce noise MinDuty CON 100 ; Minimum speed to rotate motor for this application MaxDuty VAR WORD ; According to Darrel: ; MaxDuty = (PR2 + 1) * 4 MaxDuty = (PR2 + 1) * 4 ; 252 but with prescaler resolution it's actually 250 MotorDuty VAR WORD ; Actual duty cycle for motor MaxADCVal CON 255 ; 255 for 8-bit; 1023 for 10-bit ADCInVal VAR BYTE ; stores ADCIN result read from trim pot compVal VAR BYTE ; stores last-changed ADC value Main: gosub Do_ADC pause 100 If ADCInVal <> compVal Then #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["new ADCInVal=", DEC ADCInVal, " ", 13, 10] ; Send text followed by carriage return and linefeed #ENDIF GOSUB Map_ADC_Val_to_PWM_Duty gosub ChngMotorHPWM compVal = ADCInVal endif GOTO Main Do_ADC: PAUSEUS 50 ' Wait for A/D channel acquisition time ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 = 1 ' Wait for it to complete WEND ADCInVal = ADRESH return Map_ADC_Val_to_PWM_Duty: ' Arduino Map function to emulate: ' =============================== ' map(value, fromLow, fromHigh, toLow, toHigh) ' long map(long x, long in_min, long in_max, long out_min, long out_max) ' { ' return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; ' } MotorDuty = (ADCInVal - 0) * (MaxDuty - MinDuty)/(MaxADCVal - 0) + MinDuty #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["MotorDuty=", DEC MotorDuty, " ", 13, 10] ; Send text followed by carriage return and linefeed pause 1500 HSEROUT [LCD_INST, LCD_CLR] #ENDIF RETURN
Hi,
I don't know exactly how you expect it to work but if Iäm not mistaken your formula, when re-written looks like:When ADCInVal = 1 Motor Duty will be 100Code:MotorDuty = ADCInVAL * 252 / 255 + 100
When ADCInVAL = 255 MotorDuty will be 352
Is that what you're seeing?
/Henrik.
(MaxDuty - MinDuty) would be 250(2)-100= 150
this would make more sense if your pwm value is a byte
it now becomes
Code:MotorDuty = ADCInVAL */ 150(2) + 100
not knowing whats in the sub ChngMotorHPWM
snippets lead to speculation
I'm using 8-bit resolution for PWM so it should be a byte but I have the variable defined as WORD in case the math takes it over 255:
Do you think the issue would be resolved if I change the datatype of MotorDuty to BYTE? I was also thinking I might switch to 10-bit resolution for both ADC and PWM to get the finest grain control of the motor speed, but that may be overkill.Code:MotorDuty VAR WORD ; Actual duty cycle for motor ChngMotorHPWM: CCP3CON.4 = MotorDuty.0 CCP3CON.5 = MotorDuty.1 CCPR3L = MotorDuty >> 2 CCP4CON.4 = MotorDuty.0 CCP4CON.5 = MotorDuty.1 CCPR4L = MotorDuty >> 2 RETURN
> Do you think the issue would be resolved....
What issue? What exactly is it that doesn't work the way you expect? What do you expect and what does it do?
75% dutycycle (8bit resolution) +/-25% from an 8bit ADC readin:191 is 75% of 255, your initial PWM duty cycle. When ADCvalue (BYTE) is 0 PWMDuty (BYTE) will be 255=100%. When ADCValue is 255 PWMDuty will be 127=50%.Code:PWMDuty = 191 + (64 - ADCValue >> 1)
/Henrik.
/Henrik.
Well, they were rock solid. Now the readings are varying quite a lot and even with Melanie's 'averaging' code to pick the middle 8 values from 16 it's still jumping around a lot (and still doesn't read 0 when the trim pot wiper is at the GND end). If I measure the voltage reaching pin 6 (AN1) with a voltmeter it seems accurate and steady, varying from +5V to 0. What am I doing wrong now?
Code:'**************************************************************** '* Name : Nacelle_Steady-On_Lights_12F1840_16Mhz_Int.pbp * '* Author : Ross A. Waddell * '* Notice : Copyright (c) 2016 * '* : All Rights Reserved * '* Date : 02/02/2016 * '* Version : 1.0 * '* Notes : Steady-on nacelle engine lights (TOS Enterprise) * '* : * '**************************************************************** ' TODO: ' Add gamma correction ' Increase ADC resolution to 1024 ' Update PWM frequency/prescaler to use higher resolution ' The PWM/fade works perfectly when **not** connected to a FET ' - if using a FET, the LEDs 'pulse' and blink but don't fade in/out ' - use a 2N2222A transistor DEFINE OSC 16 ' Set oscillator 16Mhz ' For production version of this code, comment out the line below re: ' LCD debugging and also update config fuses to have code protect on #DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' *************************************************************** ' Pin Connections ' *************************************************************** ' VDD -> pin 1 -> +5V ' RA5/Rc -> pin 2 -> EUSART receive ' RA2 -> pin 5 -> 1kohm -> 2N2222A transistor -> LEDs ' RA1 -> pin 6 -> Trim pot input ' RA0/Tx -> pin 7 -> EUSART transmit (LCD) ' VSS -> pin 8 -> GND ' *************************************************************** ' EUSART Settings for Tx/Rc (e.g. LCD) ' *************************************************************** ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings ' > as the values are dependent on the OSC and desired baud rate DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08% ' *************************************************************** ' Device Fuses ' *************************************************************** ' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ' 16MHz internal osc pause 100 ' for EEPROM issue APFCON.2 = 0 ; Tx on RA0 for LCD display APFCON.7 = 1 ; Rc on RA5 APFCON.0 = 0 ; CCP1 on RA2 ' Some LCD serial modules need inverted data, some do not ' Enable the line below if needed, but for SparkFun SerLCD it should be ' commented out 'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ' From Mister E's Multi-Calc (EUSART): ' ***************************************************************** SPBRGH = 1 BAUDCON.3 = 1 ' Enable 16 bit baudrate generator ' ***************************************************************** FVRCON = 0 ' Fixed Voltage Reference is disabled ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only 'ADCON0 = %00000101 ' ADC (analog-to-digital) is enabled on AN1 (RA1) only 'PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1 = %10010000 ; Right-justified results in 10-bits; Fosc/8 as timer; ; VREF is connected to VDD TRISA = %00100010 ' Make all pins output except for RA1 (trim pot input) ' and RA5 (EUSART Rc) ADCInVal VAR WORD ; stores ADCIN result read from trim pot LEDBrVal VAR WORD FadeInPause CON 25 ; Pause during LED fade in i VAR WORD ' *************************************************************** ' Set up PWM on CCP1 ' *************************************************************** CCP1CON = %00001100 ; Use CCP1 in PWM mode ' Set duty cycle registers initially to 0 CCP1CON.4 = 0 CCP1CON.5 = 0 CCPR1L = 0 ' Use Mister E's PICMultiCalc_1.3.1.exe application (Windows only) ' to determine prescaler and PR2 values for given OSC frequency (e.g. 16Mhz) ' and duty cycle (use 100% to see highest actual value) ' ************************ ' CCP1 uses TMR2 ' ************************ T2CON = %00000110 ; Timer2 on with 1:16 prescaler PR2 = 255 ; For 16Mhz OSC the desired output freq of 976.563Hz ; is achieved with this PR2 value (10-bit resolution ; with 1:16 prescaler) MaxDuty VAR WORD ; According to Darrel: ; MaxDuty = (PR2 + 1) * 4 MaxDuty = (PR2 + 1) * 4 ; 1024 MinDuty CON 0 ; Minimum brightness for this application MaxADCVal CON 1023 ; 255 for 8-bit; 1023 for 10-bit compVal VAR WORD ; stores last-changed ADC value CounterA var BYTE ' Just a BYTE Temporary working variable DataW var WORD ' Just a WORD Temporary working variable RawData var WORD [16] ' Array holding ADC Result #IFDEF USE_LCD_FOR_DEBUG ' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395) ' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' ' for list of control codes) LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness LCD_BR_LVL CON 140 ' 140==40% #ENDIF ' Should only need to do this one time to adjust backlight brightness '#IFDEF USE_LCD_FOR_DEBUG ' HSEROUT [LCD_BR_CMD, LCD_BR_LVL] ' PAUSE 5 '#ENDIF #IFDEF USE_LCD_FOR_DEBUG pause 1000 HSEROUT [LCD_INST, LCD_CLR, "LCD Init"] pause 5 HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"] pause 500 #ENDIF GOSUB DO_ADCIN_Chk LEDBrVal = ADCInVal compVal = LEDBrVal 'compVal = ADCInVal 'GOSUB Map_VrefInVal_to_PWM_Duty #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["LEDBrVal=",DEC LEDBrVal," "] pause 500 #ENDIF ' Fade in LED to final brightness FOR i = 0 to LEDBrVal CCP1CON.4 = i.0 CCP1CON.5 = i.1 CCPR1L = i >> 2 pause FadeInPause #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["i=",DEC i," "] #ENDIF NEXT i Main: GOSUB DO_ADCIN_Chk PAUSE 100 IF ADCInVal <> compVal THEN #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, " "] #ENDIF LEDBrVal = ADCInVal compVal = LEDBrVal gosub ChngLEDBrightness ENDIF GOTO Main '*********** Read ADC or USART Rc inputs ******************************* Do_ADCIN_Chk: ' Stuff 16 Element WORD Array full of ADC values ' ---------------------------------------------- For CounterA=0 to 15 ADCON0 = %00000101 ' Select Channel, Turn-On A/D ' 7=0 Unused ' 6=0 Unused ' 5=0 ) ' 4=0 ) ' 3=0 ) selects AN1 ' 2=0 ) ' 1=0 Go-done Bit ' 0=1 switch-On ADC Module Pauseus 50 ' Wait for channel to setup ADCON0.1 = 1 ' Start conversion While ADCON0.1=1:Wend ' Wait for conversion DataW.HighByte=ADRESH ' Read variable from ADC and save DataW.LowByte=ADRESL RawData(CounterA)=DataW Next CounterA ' Sort ADC Input ' -------------- CounterA=0 GetADCSortLoop: If RawData(CounterA+1) < RawData(CounterA) then DataW=RawData(CounterA) RawData(CounterA)=RawData(CounterA+1) RawData(CounterA+1)=DataW If CounterA>0 then CounterA=CounterA-2 endif CounterA=CounterA+1 If CounterA < 15 then goto GetADCSortLoop ' Quanticise, discarding top and bottom FOUR elements ' ---------------------------------------------------- DataW=0 For CounterA=4 to 11 DataW=DataW+RawData(CounterA) Next CounterA ADCInVal=DataW>>3 ' Divide Result by EIGHT ' Read trim pot Vref to set LED brightness ' PAUSEUS 50 ' Wait for A/D channel acquisition time ' ADCON0.1 = 1 ' Start conversion ' WHILE ADCON0.1 = 1 ' Wait for it to complete ' WEND ' ADCInVal.HighBYTE = ADRESH ' ADCInVal.LOWBYTE = ADRESL return '*********** Set duty registers **************************************** ChngLEDBrightness: CCP1CON.4 = LEDBrVal.0 CCP1CON.5 = LEDBrVal.1 CCPR1L = LEDBrVal >> 2 RETURN
after setting adc input you need to Wait A/D channel acquisition time before you Start conversion
There's a PAUSEUS 50 there - isn't that sufficient?
yep , must get some glasses. still looking
I removed the CCP stuff to leave just the ADC and still the value jumps around by +- 6 or more:
Code:DEFINE OSC 16 ' Set oscillator 16Mhz ' For production version of this code, comment out the line below re: ' LCD debugging and also update config fuses to have code protect on #DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' *************************************************************** ' Pin Connections ' *************************************************************** ' VDD -> pin 1 -> +5V ' RA5/Rc -> pin 2 -> EUSART receive ' RA2 -> pin 5 -> 1kohm -> 2N2222A transistor -> LEDs ' RA1 -> pin 6 -> Trim pot input ' RA0/Tx -> pin 7 -> EUSART transmit (LCD) ' VSS -> pin 8 -> GND ' *************************************************************** ' EUSART Settings for Tx/Rc (e.g. LCD) ' *************************************************************** ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings ' > as the values are dependent on the OSC and desired baud rate DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08% ' *************************************************************** ' Device Fuses ' *************************************************************** ' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ' 16MHz internal osc pause 100 ' for EEPROM issue APFCON.2 = 0 ; Tx on RA0 for LCD display APFCON.7 = 1 ; Rc on RA5 APFCON.0 = 0 ; CCP1 on RA2 ' Some LCD serial modules need inverted data, some do not ' Enable the line below if needed, but for SparkFun SerLCD it should be ' commented out 'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ' From Mister E's Multi-Calc (EUSART): ' ***************************************************************** SPBRGH = 1 BAUDCON.3 = 1 ' Enable 16 bit baudrate generator ' ***************************************************************** FVRCON = 0 ' Fixed Voltage Reference is disabled ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only ADCON0 = %00000101 ' ADC (analog-to-digital) is enabled on AN1 (RA1) only PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1 = %10010000 ; Right-justified results in 10-bits; Fosc/8 as timer; ; VREF is connected to VDD TRISA = %00100010 ' Make all pins output except for RA1 (trim pot input) ' and RA5 (EUSART Rc) ADCInVal VAR WORD ; stores ADCIN result read from trim pot compVal VAR WORD #IFDEF USE_LCD_FOR_DEBUG ' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395) ' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' ' for list of control codes) LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness LCD_BR_LVL CON 140 ' 140==40% #ENDIF ' Should only need to do this one time to adjust backlight brightness '#IFDEF USE_LCD_FOR_DEBUG ' HSEROUT [LCD_BR_CMD, LCD_BR_LVL] ' PAUSE 5 '#ENDIF #IFDEF USE_LCD_FOR_DEBUG pause 1000 HSEROUT [LCD_INST, LCD_CLR, "LCD Init"] pause 5 HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"] pause 500 #ENDIF GOSUB DO_ADCIN_Chk compVal = ADCInVal #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["ADCInVal=",DEC ADCInVal," "] pause 500 #ENDIF Main: GOSUB DO_ADCIN_Chk PAUSE 100 IF ADCInVal <> compVal THEN #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, " "] #ENDIF compVal = ADCInVal ENDIF GOTO Main '*********** Read ADC or USART Rc inputs ******************************* Do_ADCIN_Chk: ' Read trim pot Vref to set LED brightness PAUSEUS 50 ' Wait for A/D channel acquisition time ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 = 1 ' Wait for it to complete WEND ADCInVal.HighBYTE = ADRESH ADCInVal.LOWBYTE = ADRESL return
Switched to using a 16F1825 that was previously rock solid and it's still jumping around like crazy. Could it be this 5V switching voltage regulator? This code was what I used previously to test 10-bit ADC and is what I just loaded onto the 16F1825:
EDIT: Tried the standard 7805 voltage reg approach and it's more stable but still jumps around by 3-4. Could it be the settings for my serial LCD on EUSART Tx?Code:' **************************************************************** ' PIC16F1825 ' **************************************************************** #DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' Vdd -> pin 1 -> +5V ' RC5/Rx -> pin 5 -> EUSART receive ' RC4/Tx -> pin 6 -> EUSART transmit (LCD) ' RA1 -> pin 12 -> trim pot input (1 uF electrolytic cap?) ' Vss -> pin 14 -> GND DEFINE OSC 16 ; Set oscillator 16Mhz ' *************************************************************** ' EUSART Settings for Tx/Rc (e.g. LCD) ' *************************************************************** ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings ' > as the values are dependent on the OSC and desired baud rate DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08% ' *************************************************************** ' Device Fuses ' *************************************************************** #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ; 16MHz internal osc pause 100 APFCON0.2 = 0 ; Tx on RC4 for LCD display APFCON0.7 = 0 ; Rx on RC5 ' Some LCD serial modules need inverted data, some do not ' Enable the line below if needed, but for SparkFun SerLCD it should be ' commented out 'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ' From Mister E's Multi-Calc (EUSART): ' ***************************************************************** SPBRGH = 1 BAUDCON.3 = 1 ' Enable 16 bit baudrate generator ' ***************************************************************** ANSELC = 0 ; Digital only for all PortC pins TRISC = 0 ; Make all PORTC pins output TRISA = %00000010 ; Make all pins output except for RA1 (trim pot input) ANSELA = %00000010 ; Analog on PORTA.1 (AN1) only FVRCON = 0 ; Fixed Voltage Reference is disabled ADCON0 = %00000101 ; ADC enabled on AN1 (RA1) only; ADC conversion enabled PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1 = %10010000 ; Right-justified results in 10-bits; Fosc/8 as timer #IFDEF USE_LCD_FOR_DEBUG ' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395) ' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' ' for list of control codes) LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness LCD_BR_LVL CON 140 ' 140==40% #ENDIF ' Should only need to do this one time to adjust backlight brightness '#IFDEF USE_LCD_FOR_DEBUG ' HSEROUT [LCD_BR_CMD, LCD_BR_LVL] ' PAUSE 5 '#ENDIF #IFDEF USE_LCD_FOR_DEBUG pause 1000 HSEROUT [LCD_INST, LCD_CLR, "LCD Init"] pause 5 HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"] pause 500 #ENDIF ADCInVal VAR WORD ; stores ADCIN result read from trim pot compVal VAR WORD ; stores last-changed ADC value GOSUB Do_ADC compVal = ADCInVal ; set initial compare value #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["ADCInVal=",DEC ADCInVal," "] pause 500 #ENDIF Main: gosub Do_ADC pause 100 If (compVal > (ADCInVal + 1)) or (compVal < (ADCInVal - 1)) THEn ' If this method of reading ADC is as rock-solid as it appears. ' then I can remove the +/- 1 before doing anything; it would be ' IF ADCInVal <> compVal ' DO SOMETHING HERE compVal = ADCInVal #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, " "] #ENDIF endif GOTO Main Do_ADC: PAUSEUS 50 ' Wait for A/D channel acquisition time ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 = 1 ' Wait for it to complete WEND ADCInVal.HighBYTE = ADRESH ADCInVal.LOWBYTE = ADRESL return
Last edited by RossWaddell; - 18th February 2016 at 23:17.
I 'm using a pickit2 to power this test so an 0,1 are unavailable (used by pickit) so I changed code to use an3
and debug via serout . needless to say it works just fine.
you may need an oscilloscope to look at your an input and power supply for noise (dvm's won't do it)
have you installed bypass caps on the regulator input/output and the pic vdd pin ?
a bit of c across the pot wiper to gnd won't hurt either
Code:' **************************************************************** ' PIC16F1825 ' **************************************************************** ;#DEFINE USE_LCD_FOR_DEBUG ; comment out for non-debug use ' Vdd -> pin 1 -> +5V ' RC5/Rx -> pin 5 -> EUSART receive ' RC4/Tx -> pin 6 -> EUSART transmit (LCD) ' RA1 -> pin 12 -> trim pot input (1 uF electrolytic cap?) ' Vss -> pin 14 -> GND DEFINE OSC 16 ; Set oscillator 16Mhz ' *************************************************************** ' EUSART Settings for Tx/Rc (e.g. LCD) ' *************************************************************** ' > use Mister E PIC Multi-Calc application to get register/DEFINE settings ' > as the values are dependent on the OSC and desired baud rate DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1 DEFINE HSER_CLROERR 1 ' Clear overflow automatically DEFINE HSER_SPBRG 160 ' 9600 Baud @ 16MHz, -0.08% ' *************************************************************** ' Device Fuses ' *************************************************************** #CONFIG __config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CP_OFF & _CPD_OFF __config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF #ENDCONFIG ' *************************************************************** ' Initialization ' *************************************************************** OSCCON = %01111000 ; 16MHz internal osc pause 100 APFCON0.2 = 0 ; Tx on RC4 for LCD display APFCON0.7 = 0 ; Rx on RC5 ' Some LCD serial modules need inverted data, some do not ' Enable the line below if needed, but for SparkFun SerLCD it should be ' commented out 'BAUDCON.4 = 1 ; Transmit inverted data to the Tx pin ' From Mister E's Multi-Calc (EUSART): ' ***************************************************************** SPBRGH = 1 BAUDCON.3 = 1 ' Enable 16 bit baudrate generator ' ***************************************************************** ANSELC = 0 ; Digital only for all PortC pins TRISC = 0 ; Make all PORTC pins output ANSELA = %00001000 ; Analog on PORTA.4(AN3) only ADCON1 = %10100000 ; Right-justified results in 10-bits; Fosc/32 as timer; ; VREF is connected to VDD TRISA = %111110 ' Make all pins output except for RA1 (trim pot input) FVRCON = 0 ; Fixed Voltage Reference is disabled ; ADCON0 = %00000101 ; ADC enabled on AN1 (RA1) only; ADC conversion enabled PAUSEUS 20 ; wait for the analog switch 'glitch' to die down ADCON1 = %10010000 ; Right-justified results in 10-bits; Fosc/8 as timer #IFDEF USE_LCD_FOR_DEBUG ' Display control codes for SerLCD serial LCD (SparkFun part #LCD-09395) ' (see 'Dropbox\PBP Projects\PIC Datasheets\SerLCD_V2_5 Datasheet.pdf' ' for list of control codes) LCD_INST CON 254 ' instruction LCD_CLR CON 1 ' Clear screen LCD_L1 CON 128 ' LCD line 1 LCD_L2 CON 192 ' LCD line 2 LCD_BR_CMD CON 124 ' command character for adjusting backlight brightness LCD_BR_LVL CON 140 ' 140==40% #ENDIF ' Should only need to do this one time to adjust backlight brightness '#IFDEF USE_LCD_FOR_DEBUG ' HSEROUT [LCD_BR_CMD, LCD_BR_LVL] ' PAUSE 5 '#ENDIF #IFDEF USE_LCD_FOR_DEBUG pause 1000 HSEROUT [LCD_INST, LCD_CLR, "LCD Init"] pause 5 HSEROUT [LCD_INST, LCD_L2, "SerLCD_V2_5"] pause 500 #ENDIF ADCInVal VAR WORD ; stores ADCIN result read from trim pot compVal VAR WORD ; stores last-changed ADC value GOSUB Do_ADC compVal = ADCInVal ; set initial compare value #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["ADCInVal=",DEC ADCInVal," "] pause 500 #ENDIF lata.0=1 pause 2000 serout2 PORTA.0,84, ["ready",13,10 ] Main: gosub Do_ADC pause 100 If (compVal > (ADCInVal + 1)) or (compVal < (ADCInVal - 1)) THEn ' If this method of reading ADC is as rock-solid as it appears. ' then I can remove the +/- 1 before doing anything; it would be ' IF ADCInVal <> compVal ' DO SOMETHING HERE compVal = ADCInVal #IFDEF USE_LCD_FOR_DEBUG HSEROUT [LCD_INST, LCD_CLR] pause 5 HSEROUT ["new ADCInVal", LCD_INST, LCD_L2, DEC ADCInVal, " "] #ENDIF endif GOTO Main Do_ADC: ADCON0 = %00001101 ' Select Channel 3, Turn-On A/D PAUSEUS 50 ' Wait for A/D channel acquisition time ADCON0.1 = 1 ' Start conversion WHILE ADCON0.1 = 1 ' Wait for it to complete WEND ADCInVal.HighBYTE = ADRESH ADCInVal.LOWBYTE = ADRESL serout2 PORTA.0,84, ["adc ",#ADCInVal,13,10 ] return
Last edited by richard; - 19th February 2016 at 00:01. Reason: typo
At 8-bit ADC it works much better; very little (if any) variation. Since I only need to adjust the brightness between 75-100% maybe 8-bit will be OK.
Bookmarks