Xen
Newbie level 1
- Joined
- Apr 12, 2013
- Messages
- 1
- Helped
- 0
- Reputation
- 0
- Reaction score
- 0
- Trophy points
- 1,281
- Activity points
- 1,293
Hi, I'm fairly new to PIC programming in C, I've completed a few projects but I've got a bug in this one and I can't understand the problem. I've looked through the datasheet and Google with no inspiration.
Its a PIC18F4520 and I'm using MPLAB with the HI-TECH C compiler.
Basically, all I have are 4 pots on channels 0 to 3. I need to read each one of these continuously and then change the outcome of the ADC for each to 0-127. I'm doing this using a timer interrupt to start the ADC process and an ADC interrupt to analyse the outcome. Each time, the channel number for ADC is increased by 1 and reset to 0 after 3 so it is cycling through the channels.
My code reads the first pot perfectly with full range 0-127. The second pot seems to be stuck in the range of around 71-74 (after scaling to 0-127), the third and fourth pots have a wider range but the value seem to vary depending on the position of the first pot!
Here is the code:
(main.c)
(isr.c)
Its a PIC18F4520 and I'm using MPLAB with the HI-TECH C compiler.
Basically, all I have are 4 pots on channels 0 to 3. I need to read each one of these continuously and then change the outcome of the ADC for each to 0-127. I'm doing this using a timer interrupt to start the ADC process and an ADC interrupt to analyse the outcome. Each time, the channel number for ADC is increased by 1 and reset to 0 after 3 so it is cycling through the channels.
My code reads the first pot perfectly with full range 0-127. The second pot seems to be stuck in the range of around 71-74 (after scaling to 0-127), the third and fourth pots have a wider range but the value seem to vary depending on the position of the first pot!
Here is the code:
(main.c)
Code:
#include <htc.h>
#include <stdio.h>
#include "lcd.h"
//Chip Settings
__CONFIG(1,0x0200);
__CONFIG(2,0X1E1F);
__CONFIG(3,0X8100 & PBADDIS); // Disable Port B Analogue use.
__CONFIG(4,0X00C1);
__CONFIG(5,0XC00F);
//Globally accessible variables
volatile char PotVal[4]; //Pot Values, Scaled to 0-127
void init(void)
{
//Port Settings
TRISA = 0b00011111; //Input mode for the 4 Pots and the RA4 Button.
TRISB = 0b00000001; //Input mode for the RB0 Button.
TRISD = 0b00000000; //LCD Port
//LCD Initialisation and Splash Screen
lcd_init();
//Timer Settings
T0CON = 0b10000000; // Pot Read Timer Settings
TMR0IF=0; // Clear Interrupt Flag
TMR0IE=1; // Enable Interrupt
TMR0IP=0; // Low Priority
//ADC Settings
ADCON0=2; // Make sure the GO/DONE bit is set prior to activating the ADC
ADFM=1; // Make sure Right Justification is on
ADIF=0; // Clear interrupt flag
ADIE=1; // Interrupt driven
ADIP=1; // High Priority
ADON=1; // Switch on the ADC module
ei(); //Enable Interrupts!
}
void main(void)
{
init();
char outStr[16];
while(1)
{
sprintf(outStr, "%d %d %d %d ", PotVal[0], PotVal[1], PotVal[2], PotVal[3]);
lcd_goto(0); // select first line
lcd_puts(outStr);
}
}
(isr.c)
Code:
// Interrupt Service Routine
#include <htc.h>
#include <stdio.h>
extern volatile char PotVal[4]; //Pot Values, Scaled to 0-127
char ADC_Chan=-1; //Start at -1 because first timer interrupt will set to 0.
//ADC Variables
unsigned int total, last_value[4]={1024,1024,1024,1024}; //'Last' values out of range so variables WILL be updated on first run through
void interrupt isr(void){
if((TMR0IE)&&(TMR0IF)){
//If Timer Interrupt
TMR0IE=0; //Disable interrupt to prevent sending a request whilst conversion still in progress.
ADC_Chan++; //Move to next channel for next conversion
if(ADC_Chan>3) ADC_Chan=0;
ADCON0 = ADCON0 & 0b00000011; // Clear the top 6 bits. By and-ing a mask (00000011), bits with a 0 are cleared, bits with a 1 are unchanged.
ADCON0 = ADCON0 | (ADC_Chan<<2); //0b00001100 – Puts the channel bits in ADCON0 bits 2 and 3 without changing other values;
NOP(); // Wait 4 uS NOP() is detailed in the HiTech C Manual
NOP(); // along with other interesting features.
NOP(); // We need to wait a minimum of 4uS between switching channels
NOP();
GODONE=1; // Start a conversion on channel
while(GODONE) continue;
TMR0IF=0; //Reset Interrupt Flag
}
if((ADIE)&&(ADIF)){
//If ADC Interrupt
total = ((256*ADRESH)+ADRESL);
if((total >= (last_value[ADC_Chan]+8)) || (total <= (last_value[ADC_Chan]-8)) || total == 0 || total == 1023) //Prevents value flicking between numbers if its near a boundary, but still allows max and min.
{
PotVal[ADC_Chan]=total/8;
}
last_value[ADC_Chan]=total;
TMR0IE=1; //Ready for another ADC request
ADIF=0; //Reset Interrupt Flag
}
}