|
|
View previous topic :: View next topic |
Author |
Message |
elmoss
Joined: 23 Nov 2008 Posts: 3
|
Nonresponding ADC...help? |
Posted: Sun Nov 23, 2008 3:37 pm |
|
|
I have drafted and tested the firmware for a color-fading cube toy that will change R, G and B duty cycles based on the input from an analog accelerometer to the ADC. In summary, Timer1 interrupts are responsible for slowly fading the duty cycles to the accelerometer values. Timer0 is in charge of setting the ADC channel and reading off values. The main function is in charge of PWM on the three LEDs. I have the AD interrupt commented out, but I was attempting something clever there: interrupt on completion of ADC conversion, read value, set channel, start next conversion, end interrupt. I would like to use the AD interrupt, but right now the LEDs do not respond even with the simpler scheme, and I'm at a loss. Please, if somebody with more know-how has an idea, I could use some help.
compiler version: 4.038
target mc: 16f684
Standard run mode
Voltage is ~3.3
Oscillator is at 4Mhz
Code: |
#include "C:\Program Files\PICC\Projects\tiltycubecolors.h"
#define RED PIN_A0
#define GREEN PIN_A1
#define BLUE PIN_A2
#define X PIN_C0
#define Y PIN_C1
#define Z PIN_C2
unsigned int Rduty, Gduty, Bduty, speed, counter;
unsigned int Racc, Gacc, Bacc;
unsigned int channel;
#int_TIMER1
void TIMER1_isr(void)
{
if(Racc>Rduty&& Rduty < 128)
Rduty++;
else
Rduty--;
if (Bacc>Bduty && Bduty < 128)
Bduty++;
else
Bduty--;
if (Gacc>Gduty&& Gduty < 128)
Gduty++;
else
Gduty--;
}
#int_TIMER2
void TIMER2_isr(void)
{
}
#int_TIMER0
void TIMER0_isr(void)
{
set_adc_channel(4);
delay_us(10);
Bacc = read_adc();
set_adc_channel(5);
delay_us(10);
Racc=read_adc();
set_adc_channel(6);
delay_us(10);
Gacc = read_adc();
}
#int_AD
void AD_isr(void)
{
/*
int temp;
temp = read_adc(adc_read_only);
temp = temp/2;
// if (channel == 4)
Racc = temp;
else if (channel == 5)
Bacc = temp;
else
Gacc = temp;
// if (channel == 6)
channel = 4;
// else
// channel++;
set_adc_channel(0);
delay_us(10);
read_adc(adc_start_only);
*/
}
void main()
{
enable_interrupts(INT_AD);
setup_adc_ports(setup_adc_ports(sAN4|sAN5|sAN6|VSS_VDD););
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_wdt(WDT_576MS);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
// setup_timer_2(T2_DIV_BY_16,0,1);
// setup_comparator(NC_NC_NC_NC);
// setup_vref(FALSE);
enable_interrupts(INT_TIMER1);
// enable_interrupts(INT_TIMER2);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_oscillator(OSC_4MHZ);
// TODO: USER CODE!!
channel = 4;
while(1){
counter++;
if (counter<Gduty)
output_high(GREEN);
else
output_low(GREEN);
if (counter<Rduty)
output_high(RED);
else
output_low(RED);
if (counter<Bduty)
output_high(BLUE);
else
output_low(BLUE);
if (counter > 128)
counter = 0;
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Nov 23, 2008 3:50 pm |
|
|
1. Post your #include, #fuses, and #use delay() statements.
2. Post if this is from a voltage regulator.
3. Can you make the PIC do anything ? Can you make it blink an LED ? |
|
|
Ttelmah Guest
|
|
Posted: Sun Nov 23, 2008 4:07 pm |
|
|
First, get rid of int_ad, and enabling this.
Interrupts cannot be called inside one another. You are performing the AD conversions inside an interrupt already.
Do a search here, only a very few days ago, and several times in the past, I have posted why you don't want to use int_ad.
It actually takes _longer_ to get into and out of an ADC interrupt, than it does to handle it outside. The only reasons to ever use the ADC interrupt, are, first as a method of waking from sleep, when performing the ADC conversion with the processor suspended, and secondly, if you are triggering the ADC, using a CCP timer.
This latter could be used by you, but with difficulty, because of wanting to read multiple channels.
If you try to use the ADC interrupt as you show, you will never get out of the interrupt. The ADC will have finished conversion, before you return to the main code, and wll be called again...
Second comment, don't use ADC_CLOCK_INTERNAL.
Note4, Table9.1 in the data sheet.
For your clock speed, use the /8 divider.
Third comment. Use less interrupts. Just have one heartbeat timer. Have this at a frequency you can support. At present, you have too many things going on. Timer0, is interrupting every 256 instructions. It takes probably something over 180 instruction times to be called, execute, and return. Not much time for anything else.
Get rid off all the interrupts except Timer0. Halve it's frequency. Then have it run a state machine. On the first call, it selects the first ADC channel, and exits. On the second call, it starts the ADC conversion. On the third, it reads the first value, and selects the second ADC channel. On the fourth call it starts the conversion for the second channel. On the fifth call, it reads the second value, and selects the third channel. Have this go through all the channels required. On each call, you only perform either a reading, and a channel selection, or a trigger for the next channel. When you have completed the whole sequence, write the values to the PWM, and start the sequence again.
By selecting the channel in one call, the settling time needed is provided by the interval to the next. Then similarly, triggering the conversion, on the next call the conversion has finished, and the value is ready for you to read. Let the hardware work _for_ you, performing jobs while your main code does other things.
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|