CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
ADC help
Hi, PIC16F18325 MPLAB X using MCC So im trying to use ADC to read a voltage from a Potentiometer. When the Pot reaches a certain value, i want it to toggle an led by switching from input to output over and over while LATA5 = 0. (LED is always on so i want to turn it off and on repeatedly) Ive done it all in MCC so all the back code is there, ADC is enabled Using FOSC/4 or /2 Right aligned Positive ref: VDD Negative: VSS No auto trigger Heres my main code:
void main (void)
{
SYSTEM_Initialize();
while(1)
{
ADC_Initialize();
if (ADC_GetConversion(Pot_RA0) > 150)
{
LATA5 = 0;
TRISA5 = 0;
__delay_ms(500);
TRISA5 = 1;
__delay_ms(500);
}
}
}
Now the problem im having is; When coded like this: (ADC_GetConversion(Pot_RA0) > 150) The led will always flash until the number in the statement (150) is met. I want to swap it around so the led doesnt flash until 150 is met. If i change the statement to: "if (ADC_GetConversion(Pot_RA0) < 150)" just changing the bigger than to smaller than, it just constantly flashes no matter where the Pot positioned. Ive tried all values from 0-1023 but it just flashes no matter what. What am i doing wrong? I have been trying for hours now but cannot get it working the way i need it.
|
upand_at_them
Super Member
- Total Posts : 765
- Reward points : 0
- Joined: 2005/05/16 07:02:38
- Location: Pennsylvania
- Status: offline
Your while(1) loop is constantly initializing the ADC. Why?
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Dont know how i missed that, ive moved it to the line under SYSTEM_Initialize but it hasnt made a noticable difference
|
davea
Super Member
- Total Posts : 585
- Reward points : 0
- Joined: 2016/01/28 13:12:13
- Location: Tampa Bay FL USA
- Status: offline
reconfigure ADC to FRC and auto trigger in MCC or set the the go/done bit and wait for it to auto clear read the data sheet
|
BroadwellConsultingInc
Super Member
- Total Posts : 97
- Reward points : 0
- Joined: 2020/06/09 06:07:55
- Location: 0
- Status: offline
What is the value of your pot? You want to keep input impedance to 5k or less typically. So you may have problems if you're using a 100k pot. Usually this is more of a problem if you're switching between A/D channels, though. We really need to see your A/D initialization code. "150" means one thing if you've set it up for right justified results, but quite a bit less if left justified.
|
BroadwellConsultingInc
Super Member
- Total Posts : 97
- Reward points : 0
- Joined: 2020/06/09 06:07:55
- Location: 0
- Status: offline
Also, the value for Pot_RA0 .
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Using FOSC/4 or /2 Right aligned Positive ref: VDD Negative: VSS No auto trigger Its right aligned but i have tried both. Sorry, i have only been doing this a couple of months, im not sure on the impedance. I thought ADC just takes the voltage from the pin and gives it a reference between 0-1023 so all i need to find is the correct number. The Pot is actually a hall sensor though pink:
|
ric
Super Member
- Total Posts : 29435
- Reward points : 0
- Joined: 2003/11/07 12:41:26
- Location: Australia, Melbourne
- Status: online
CptChronic ... I thought ADC just takes the voltage from the pin and gives it a reference between 0-1023 so all i need to find is the correct number.
It does that by momentarily connecting the pin to an internal capacitor. At that moment, there is a rush of curent into the capacitor. If the source impedance is too high, it will prevent the capacitor fulling charging during this "acquisition time". There is a detailed description in the PIC datasheet about what is an acceptable impedance for the source.
To get a useful answer, always state which PIC you are using!
|
ggrr_pic
New Member
- Total Posts : 1
- Reward points : 0
- Joined: 2020/11/20 17:45:10
- Location: 0
- Status: offline
try to put an "else" statement, in order to take actions when value is not met. You are no taking into account what state should be at that pin when the adc reading are changing out of the range. while(1) {
if ( ADC_GetConversion(Pot_RA0) > 150) {
// or if ( ADC_GetConversion(Pot_RA0) < 150) {
TRISA5=0;
__delay_ms(500);
TRISA5=1
__delay_ms(500);
} else {
TRISA5=1;
//or TRISA5=0
}
}//while(1)
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Thats alot of math Ric, i have had a look but i dont understand how to work it out. I can see its 10k ohms in the data sheet but googling how to work out the impedance has lost me completely. I really cant get my head around this, if i have it set to > 100 (if ADC_GetConversion(PotA0) > 100) the led flashes all the time until the pot is pulled all the way in. (until its less than 100) Which surely means all i need to do is change the > (more than) to < (less than) So, The way i have it working is when the ADC value is more than 100 the led will flash (this is pot not passed half way). I want to flip it so when the ADC value is less than 100, it makes the led flash. Changing to < should make it... If the conversion is less than 100, make the led flash This should now mean that when the pot is pulled in the led will flash....right??
|
davea
Super Member
- Total Posts : 585
- Reward points : 0
- Joined: 2016/01/28 13:12:13
- Location: Tampa Bay FL USA
- Status: offline
Thats alot of math Ric, i have had a look but i dont understand how to work it out. I can see its 10k ohms in the data sheet but googling how to work out the impedance has lost me completely. theirs nothing to work out it just states no more then 10k (in series with a drive voltage of 0 ohm) your using a hall sensor the output impedance of it will be less then 200 ohm (could be as low 30 ohm)
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Oh ok, this is what i found when searching yesterday. Impedance Z = R or XLor XC(if only one is present) Impedance in series only Z = √(R2 + X2) (if both R and one type of X are present) Impedance in series only Z = √(R2 + (|XL - XC|)2) (if R, XL, and XC are all present) Impedance in any circuit = R + jX (j is the imaginary number √(-1)) Resistance R = ΔV / I Inductive reactance XL = 2πƒL = ωL Capacative reactance XC = 1 / 2πƒC = 1 / ωC
I have no clue what any of that means, starting to think i should of done the electronics course first, ive got it on my list after i learn the programming as this is more important right now. But from what your saying, im well within the 10k. I really cant get my head around why that code doesnt work, neither can anyone else from the look of it. Ive posted in a few places with no joy. Its important that i read the voltage and the code only engages once a certain voltage is met. Im so lost sad:
|
ric
Super Member
- Total Posts : 29435
- Reward points : 0
- Joined: 2003/11/07 12:41:26
- Location: Australia, Melbourne
- Status: online
Let us see ALL of your code. I suspect this is something else that you're missing, e.g. an incorrect WDT setting.
To get a useful answer, always state which PIC you are using!
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Thanks ric, i do appreciate your help. All config files are below. WDT = OFF main.c/** Generated Main Source File Company: Microchip Technology Inc. File Name: main.c Summary: This is the main file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs Description: This header file provides implementations for driver APIs for all modules selected in the GUI. Generation Information : Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.6 Device : PIC16F18325 Driver Version : 2.00 */ #include "mcc_generated_files/mcc.h" /* Main application */ void main(void) { // initialize the device SYSTEM_Initialize(); ADC_Initialize(); ANSELAbits.ANSA0 = 1; // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits // Use the following macros to: // Enable the Global Interrupts //INTERRUPT_GlobalInterruptEnable(); // Enable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptEnable(); // Disable the Global Interrupts //INTERRUPT_GlobalInterruptDisable(); // Disable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptDisable();
while (ADC_IsConversionDone()) { if (ADC_GetConversion(RT) < 200) { LATA = 0; LATA5 = 0; TRISA5 = 0; __delay_ms(500); TRISA5 = 1; __delay_ms(500); } else { NOP(); // do nothing } } }
adc.c #include <xc.h> #include "adc.h" #include "device_config.h"
/** Section: Macro Declarations */
#define ACQ_US_DELAY 5
void (*ADC_InterruptHandler)(void);
/** Section: ADC Module APIs */
void ADC_Initialize(void) { // set the ADC to the options selected in the User Interface // ADFM right; ADNREF VSS; ADPREF VDD; ADCS FOSC/8; ADCON1 = 0x90; // ADACT no_auto_trigger; ADACT = 0x00; // ADRESL 0; ADRESL = 0x00; // ADRESH 0; ADRESH = 0x00; // ADGO stop; ADON enabled; CHS ANA0; ADCON0 = 0x01; }
void ADC_SelectChannel(adc_channel_t channel) { // select the A/D channel ADCON0bits.CHS = channel; // Turn on the ADC module ADCON0bits.ADON = 1; }
void ADC_StartConversion(void) { // Start the conversion ADCON0bits.ADGO = 1; }
bool ADC_IsConversionDone(void) { // Start the conversion return ((bool)(!ADCON0bits.ADGO)); }
adc_result_t ADC_GetConversionResult(void) { // Conversion finished, return the result return ((adc_result_t)((ADRESH << 8) + ADRESL)); }
adc_result_t ADC_GetConversion(adc_channel_t channel) { // select the A/D channel ADCON0bits.CHS = channel; // Turn on the ADC module ADCON0bits.ADON = 1;
// Acquisition time delay __delay_us(ACQ_US_DELAY);
// Start the conversion ADCON0bits.ADGO = 1;
// Wait for the conversion to finish while (ADCON0bits.ADGO) { }
// Conversion finished, return the result return ((adc_result_t)((ADRESH << 8) + ADRESL)); }
void ADC_TemperatureAcquisitionDelay(void) { __delay_us(200); } /** End of File */ device_config.c/** @Generated PIC10 / PIC12 / PIC16 / PIC18 MCUs Source File
@Company: Microchip Technology Inc.
@File Name: mcc.c
@Summary: This is the device_config.c file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs
@Description: This header file provides implementations for driver APIs for all modules selected in the GUI. Generation Information : Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.6 Device : PIC16F18325 Driver Version : 2.00 The generated drivers are tested against the following: Compiler : XC8 2.30 and above or later MPLAB : MPLAB X 5.40 */ // Configuration bits: selected in the GUI
// CONFIG1 #pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits->Oscillator not enabled #pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits->HFINTOSC (1MHz) #pragma config CLKOUTEN = OFF // Clock Out Enable bit->CLKOUT function is disabled; I/O or oscillator function on OSC2 #pragma config CSWEN = ON // Clock Switch Enable bit->Writing to NOSC and NDIV is allowed #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
// CONFIG2 #pragma config MCLRE = ON // Master Clear Enable bit->MCLR/VPP pin function is MCLR; Weak pull-up enabled #pragma config PWRTE = OFF // Power-up Timer Enable bit->PWRT disabled #pragma config WDTE = OFF // Watchdog Timer Enable bits->WDT disabled; SWDTEN is ignored #pragma config LPBOREN = OFF // Low-power BOR enable bit->ULPBOR disabled #pragma config BOREN = ON // Brown-out Reset Enable bits->Brown-out Reset enabled, SBOREN bit ignored #pragma config BORV = LOW // Brown-out Reset Voltage selection bit->Brown-out voltage (Vbor) set to 2.45V #pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit->The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit->Stack Overflow or Underflow will cause a Reset #pragma config DEBUG = OFF // Debugger enable bit->Background debugger disabled
// CONFIG3 #pragma config WRT = OFF // User NVM self-write protection bits->Write protection off #pragma config LVP = ON // Low Voltage Programming Enable bit->Low Voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored.
// CONFIG4 #pragma config CP = OFF // User NVM Program Memory Code Protection bit->User NVM code protection disabled #pragma config CPD = OFF // Data NVM Memory Code Protection bit->Data NVM code protection disabled
mcc.c/** @Generated PIC10 / PIC12 / PIC16 / PIC18 MCUs Source File
@Company: Microchip Technology Inc.
@File Name: mcc.c
@Summary: This is the mcc.c file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs
@Description: This header file provides implementations for driver APIs for all modules selected in the GUI. Generation Information : Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.6 Device : PIC16F18325 Driver Version : 2.00 The generated drivers are tested against the following: Compiler : XC8 2.30 and above or later MPLAB : MPLAB X 5.40 */ #include "mcc.h"
void SYSTEM_Initialize(void) {
PMD_Initialize(); PIN_MANAGER_Initialize(); OSCILLATOR_Initialize(); WDT_Initialize(); ADC_Initialize(); }
void OSCILLATOR_Initialize(void) { // NOSC HFINTOSC; NDIV 4; OSCCON1 = 0x62; // CSWHOLD may proceed; SOSCPWR Low power; SOSCBE crystal oscillator; OSCCON3 = 0x00; // LFOEN disabled; ADOEN disabled; SOSCEN disabled; EXTOEN disabled; HFOEN disabled; OSCEN = 0x00; // HFFRQ 4_MHz; OSCFRQ = 0x03; // HFTUN 0; OSCTUNE = 0x00; }
void WDT_Initialize(void) { // WDTPS 1:65536; SWDTEN OFF; WDTCON = 0x16; }
void PMD_Initialize(void) { // CLKRMD CLKR enabled; SYSCMD SYSCLK enabled; FVRMD FVR enabled; IOCMD IOC enabled; NVMMD NVM enabled; PMD0 = 0x00; // TMR0MD TMR0 enabled; TMR1MD TMR1 enabled; TMR4MD TMR4 enabled; TMR5MD TMR5 enabled; TMR2MD TMR2 enabled; TMR3MD TMR3 enabled; NCOMD DDS(NCO) enabled; TMR6MD TMR6 enabled; PMD1 = 0x00; // DACMD DAC enabled; CMP1MD CMP1 enabled; ADCMD ADC enabled; CMP2MD CMP2 enabled; PMD2 = 0x00; // CCP2MD CCP2 enabled; CCP1MD CCP1 enabled; CCP4MD CCP4 enabled; CCP3MD CCP3 enabled; PWM6MD PWM6 enabled; PWM5MD PWM5 enabled; CWG2MD CWG2 enabled; CWG1MD CWG1 enabled; PMD3 = 0x00; // MSSP1MD MSSP1 enabled; UART1MD EUSART enabled; MSSP2MD MSSP2 enabled; PMD4 = 0x00; // DSMMD DSM enabled; CLC3MD CLC3 enabled; CLC4MD CLC4 enabled; CLC1MD CLC1 enabled; CLC2MD CLC2 enabled; PMD5 = 0x00; } /** End of File */
pin_manager.c/** Generated Pin Manager File
Company: Microchip Technology Inc.
File Name: pin_manager.c
Summary: This is the Pin Manager file generated using PIC10 / PIC12 / PIC16 / PIC18 MCUs
Description: This header file provides implementations for pin APIs for all pins selected in the GUI. Generation Information : Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.81.6 Device : PIC16F18325 Driver Version : 2.11 The generated drivers are tested against the following: Compiler : XC8 2.30 and above MPLAB : MPLAB X 5.40
Copyright (c) 2013 - 2015 released Microchip Technology Inc. All rights reserved. */
#include "pin_manager.h"
void PIN_MANAGER_Initialize(void) { /** LATx registers */ LATA = 0x00; LATC = 0x00;
/** TRISx registers */ TRISA = 0x37; TRISC = 0x3F;
/** ANSELx registers */ ANSELC = 0x3F; ANSELA = 0x17;
/** WPUx registers */ WPUA = 0x00; WPUC = 0x00;
/** ODx registers */ ODCONA = 0x00; ODCONC = 0x00;
/** SLRCONx registers */ SLRCONA = 0x37; SLRCONC = 0x3F;
/** INLVLx registers */ INLVLA = 0x3F; INLVLC = 0x3F; } void PIN_MANAGER_IOC(void) { }
/** End of File */
|
rpg7
Super Member
- Total Posts : 1424
- Reward points : 0
- Joined: 2003/11/07 12:47:35
- Status: offline
There is quite a lot of importance attached to getting the impedance low enough. In reality if one is just using a pot to see what happens when changing the voltage into the A>D the max and min readings will have low impedance and if there is a little non-linearity due to the impedance increasing when the slider is near the middle it will probably not be noticed. When using a fixed ratio divider to accurately measure voltages (for example) then the impedance requirements need to be respected.
|
Murton Pike Systems
Super Member
- Total Posts : 139
- Reward points : 0
- Joined: 2020/09/10 02:13:01
- Location: 0
- Status: offline
For PIC ADC I always use a 4k7 pot with 1k resistor in series with wiper to PIC. The 1k limits current into ADC pin if accidentally configured as an output.
|
davea
Super Member
- Total Posts : 585
- Reward points : 0
- Joined: 2016/01/28 13:12:13
- Location: Tampa Bay FL USA
- Status: offline
void main(void) { // initialize the device SYSTEM_Initialize(); ANSELAbits.ANSA0 = 1; // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits // Use the following macros to: // Enable the Global Interrupts //INTERRUPT_GlobalInterruptEnable(); // Enable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptEnable(); // Disable the Global Interrupts //INTERRUPT_GlobalInterruptDisable(); // Disable the Peripheral Interrupts //INTERRUPT_PeripheralInterruptDisable(); LATA5 = 1; while (1){ ADC_StartConversion(); // <<<<<<<<<<<<<<<<<<< // delay not needed if channel not changed while (!ADC_IsConversionDone()){CLRWDT();} // loop till done if (ADC_GetConversion(RT) < 200){ TRISA5 = 0; // set pin as output __delay_ms(500); CLRWDT(); TRISA5 = 1; // set pin as input __delay_ms(500); CLRWDT(); } } } look it over see the deference //INTERRUPT_PeripheralInterruptDisable(); TRISA5 = 0; // set pin as output while (1){ ADC_StartConversion(); // delay not needed if channel not changed while (!ADC_IsConversionDone()){CLRWDT();} // loop till done if (ADC_GetConversion(RT) < 200){ LATA5 = 0; // set pin lo __delay_ms(500); CLRWDT(); LATA5 = 1; // set pin hi __delay_ms(500); CLRWDT(); } } } the correct way davea
post edited by davea - 2020/11/25 10:46:33
|
oliverb
Super Member
- Total Posts : 369
- Reward points : 0
- Joined: 2009/02/16 13:12:38
- Location: 0
- Status: offline
CptChronic Oh ok, this is what i found when searching yesterday.
Impedance Z = R or XLor XC(if only one is present) Impedance in series only Z = √(R2 + X2) (if both R and one type of X are present) Impedance in series only Z = √(R2 + (|XL - XC|)2) (if R, XL, and XC are all present) Impedance in any circuit = R + jX (j is the imaginary number √(-1)) Resistance R = ΔV / I Inductive reactance XL = 2πƒL = ωL Capacative reactance XC = 1 / 2πƒC = 1 / ωC
I have no clue what any of that means, starting to think i should of done the electronics course first, ive got it on my list after i learn the programming as this is more important right now. But from what your saying, im well within the 10k. I really cant get my head around why that code doesnt work, neither can anyone else from the look of it. Ive posted in a few places with no joy. Its important that i read the voltage and the code only engages once a certain voltage is met. Im so lost sad: 
OK so electronic theory can be a really deep rabbit hole, but in this context (ADC input vs sensor output) impedance is very similar to resistance, except that if I say resistance you might assume that I mean literally a resistor, but impedance is more like "anything that obstructs the flow of current", so parts that have an output that acts as though it has a resistor in series even though there isn't an actual resistor are said to have an impedance. The more "complex" aspects of impedance come from the way inductors and capacitors behave. For example you're frequently told to connect a bypass capacitor across the supply pins. Now a good capacitor has an almost unmeasurable resistance if measured with a simple ohm meter (DC) but has an impedance that falls with increasing frequency, so at the MHz frequencies that PIC chips run at it presents a near short circuit, meaning it suppresses switching "noise" from the PIC.
|
CptChronic
Starting Member
- Total Posts : 45
- Reward points : 0
- Joined: 2016/11/20 20:58:44
- Location: 0
- Status: offline
Ah that makes a little more sense Oliver, thank you. Im using a hall sensor guys, not a pot. My apologies for the confusion in my first post. Got me all excited like a kid at christmas then Davea, it doesnt work though. :cry: Turning the pin high and low doesnt work, i need to change the pin from its normal state to low and repeat this process to get the led to flash. If i use your code but use the TRIS coding i already had, i get the same result as i had previously. (flashes until trigger is pulled in) The WDT isnt enabled either so why do i need to keep clearing it? Thanks for your input anyway buddy. I really cannot get my head around why it wont work. Could it be because the voltage is so low compared to the input voltage? Input voltage is 3.3v When trigger is not pulled it reads: 0.11v When trigger is pulled in fully it reads: 0.01v
post edited by CptChronic - 2020/11/25 15:32:53
|
ric
Super Member
- Total Posts : 29435
- Reward points : 0
- Joined: 2003/11/07 12:41:26
- Location: Australia, Melbourne
- Status: online
CptChronic When trigger is not pulled it reads: 0.11v When trigger is pulled in fully it reads: 0.01v
It pribably needs a pullup resistor on the signal wire. Many hall effect sensors have an open collector output.
To get a useful answer, always state which PIC you are using!
|