Hello i want to drive a RGB led with three PWM pulses, i use 3 potentiometers to control the PWM duty cycle, timer0 is used to trigger an A2D conversion and when the interrupt arrives i save the result into a buffer and configure the next channel for a conversion. I write the following code and the led is blinking... there is an error but i am unable to find it.
unsigned char t0_reload_value = 0x05; unsigned char d2a_output = 0xff; typedef enum SCH {ch0 = 0x00,ch1,ch2} A2DCHANNEL; A2DCHANNEL channel = ch0; data volatile unsigned char a2d[3]; void init_pca(void) { CMOD = 0x00; //cps1=0,cps0=0 (fosc/12),ecf=0 CH = 0x00; //clear PCA timer CH_CL CL = 0x00; CCAPM0 = 0x42; //mode 8bit PWM CCAPM1 = 0x42; //mode 8bit PWM CCAPM2 = 0x42; //mode 8bit PWM CCAP0H = d2a_output; //0.4% PWM Duty Cycle=(256-ccap2h)/256 CCAP1H = d2a_output; //0.4% PWM Duty Cycle=(256-ccap2h)/256 CCAP2H = d2a_output; //0.4% PWM Duty Cycle=(256-ccap2h)/256 CR = 1; // Turn PCA timer on } void init_timer0(void) { TMOD &= 0xF0; /* Timer 0 mode 2 with software gate */ TMOD |= 0x02; /* GATE0=0; C/T0#=0; M10=1; M00=0; */ TL0 = t0_reload_value; /* init values */ TH0 = t0_reload_value; /* reload value */ ET0=1; /* enable timer0 interrupt */ EA=1; /* enable interrupts */ TR0=1; /* timer0 run */ } void init_adc() { unsigned char i; //Configure P1[0.2] as analog channels ADCF = 0x07; /* Configure ADC clock Fadc=Fclk/4*PRS, PRS=5 Fclk=12Mhz then Fadc=600Khz and tconv=11/600=18.33usec */ ADCLK = 0x05; ADCON = MSK_ADCON_ADEN; //ADC enable (bit ADEN ) ADCON &= ~MSK_ADCON_SCH; //Clear the channel field adcon[2:0] ADCON |= channel; //Select channel0 to convert ADCON &= ~MSK_ADCON_PSIDLE; //Standard mode (Disables PSIDLE) EADC = 1; //Enable adc interrupt EA = 1; //Enable interrupts IPH1 = 0x00; IPL1 = 0x02; //Set interrupt level priority at state 1 ADCON &= ~MSK_ADCON_ADEOC; //Clear the End of conversion flag for(i=0;i<3;++i) a2d[i] = 0x00; //clean array } void main() { unsigned char r,g,b; init_pca(); init_adc(); init_timer0(); while(1) { r = a2d[ch0]; //get a copy of most recent value g = a2d[ch1]; //get a copy of most recent value b = a2d[ch2]; //get a copy of most recent value CCAP0H = r; CCAP1H = g; CCAP2H = b; } } void irq_t0_overflow(void) interrupt 1 using 1 { ADCON |= MSK_ADCON_ADSST; //start A2D conversion } void irq_a2d() interrupt 8 using 2 { a2d[channel]= ADDH; ++channel; if(channel == 0x03) channel = 0x00; ADCON &= ~MSK_ADCON_SCH; //clear the channel field ADCON[2:0] ADCON |= channel; //Select next channel for convertion ADCON &= ~MSK_ADCON_ADEOC; //clear the End of conversion flag }
Any ideas? Thanks
C B,
I hope your problem was fixed with your new code rendition. I like it better than the first code: ISR driven.
A point about your source: don't use tabs. Use space-fill instead. It makes the code cleaner when changing editors.
Also, the enumeration should be more explicit:
#define CHAN0 0x00 // selects channel 0 in the ADCON register #define CHAN1 0x01 // selects channel 1 in the ADCON register #define CHAN3 0x02 // selects channel 2 in the ADCON register typedef enum SCH { ch0 = CHAN0, ch1 = CHAN1, ch2 = CHAN2 } A2DCHANNEL; A2DCHANNEL channel = ch0;
Since you use 'channel' to OR in to the SFR to convert the next channel, be careful that those values are compatible with the SFR specs and the ability to simply increment the ++channel value. The SFR can have different bit-values than what the compiler assigns the enum values.
I'd suggest you separate the channel selection enum values from the switch( case ) and incrementing just to de-link the SFR channel assignment from the 'portable' "C" code.
void irq_a2d() interrupt 8 { static unsigned char chan = 0; // or use a 'global' for syncing to rest of code a2d[ chan ] = ADDH; // Get converted ADC value /*--------------------------------------------------------------. ; Transfer the ADC values into the PWM registers ; '--------------------------------------------------------------*/ switch( chan ) { case 0: CCAP0H = a2d[ chan ]; // Transfer ADC to PWM 0 break; case 1: CCAP1H = a2d[ chan ]; // Transfer ADC to PWM 1 break; case 2: CCAP2H = a2d[ chan ]; // Transfer ADC to PWM 2 break; default: chan = 2; // force an error to become the last channel CCAP2H = a2d[ chan ]; break; } /*--------------------------------------------------------------. ; Manage index ; '--------------------------------------------------------------*/ chan++; if( chan > 2 ) // safer than an '==' in case chan gets a random value { chan = 0; } /*--------------------------------------------------------------. ; Update the ADC conversion for next iteration ; '--------------------------------------------------------------*/ channel++; // bump the enum value ADCON &= ~MSK_ADCON_SCH; // clear the channel field ADCON[2:0] ADCON |= channel; // Select next channel for conversion ADCON &= ~MSK_ADCON_ADEOC; // clear the End of conversion flag ADCON |= MSK_ADCON_ADSST; // start conversion once again }
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA