|
|
View previous topic :: View next topic |
Author |
Message |
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Wed May 30, 2012 10:00 pm |
|
|
Small Update:
I have all 3 A/D and PWM working and updating. I am now able to manually adjust 4096 different colors. I am now going to start to clean up the code make it run more efficient and start slowly adding some features. For the pot adjustments. What is a good efficient way to check each channel for changes. Could I just use an if x1 != x2 update pwm or is there a better way?
I am also reading the CCS manual to create a function that will generate random PWM with a calculated seed. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Thu May 31, 2012 2:09 am |
|
|
What do you mean by this?
Quote: | What is a good efficient way to check each channel for changes. Could I just use an if x1 != x2 update pwm or is there a better way?
| Are you wanting a neat way to:-
(1) update the PWMs?
OR
(2) have a human speed readable monitor?
Mike |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu May 31, 2012 3:03 am |
|
|
Just to go back to an earlier question:
Quote: |
Its seems as the data sheet over complicates how to configure this or I am just not capable of understanding what it is trying to say. It is frustrating non the less.
From the Data Sheet: Where is the 2048 coming from? Could that be 10bit*2?
|
The data sheet shows example calculations. You could go through the same for your hardware, but generally its not required unless your source impedance is higher than recommended (which on many examples posted here it often is...).
The datasheet says:
Quote: |
To calculate the minimum acquisition time,
Equation 23-1 can be used. This equation assumes
that 1/2 LSb error is used (1,024 steps for the A/D). The
1/2 LSb error is the maximum error allowed for the A/D
to meet its specified resolution.
|
That is where the 1/2048 comes from, its half the LSB for a ten bit convertor. It would be 1/8192 for 12 bit convertors, and only 1/512 for 8 bit accuracy. Basically, the hold capacitor has to charge to within half a bit of the actualy value for maximum conversion accuracy. Tacq as calculated is the minimum time needed to do this if the input voltage is at the other end of the input range from its previous value (which is usually very unlikely) and the temperature is at its worst case (probably hottest for the PIC). Normally the hold cap voltage will settle well inside this time. If you don't want full 10 bit accuracy then you can use a shorter Tacq time. Generally I find it simpler to set the acq time to anything equal or longer than the calculated Tacq time, unless its something really time critical in which I will carefully review Tacq and set the bare minimum.
Once you've decided on a Tacq then you have to implement it by some sort of wait between selecting an adc channel and tirggering a conversion. Many newer pics have hardware to do that for us. That's set by TAD_MUL_x in setup_adc(). You should select the TAD_MUL setting that's just longer than the minimum Tacq that you want.
TAD_MUL makes the hardware implimented Tacq a multiple of the ADC clock. Microchip clearly use their own "standard" ADC blocks in all their chips. The commonest one is the 10 bit version, though newer 18series PICs have a revised 12 bitter. The 10bit appears to be basically designed to work off a 1.25MHz clock. This makes Tad = 0.8us. Some are a bit faster, some a bit slower. The older 8 bit version seen in many 16 series PICs ran at a nominal 1MHz, or 1us. In all cases that I've seen, the data sheet gives recommended TAD settings for various PIC clock rates. In the case of the PIC18F26K80 that's Table 23-1. If I remember rightly the internal clock is a nominal 1MHz on all PICs, though I could well be wrong as I rarely use it. As with Tacq, select the setting that gives TAD greater than or equal to the minimum time.
All the convertors appear to be of the successive approximation type and require at east one more clock than the number of bits, so a 10 bit conversion with hardware Tacq takes 10+1+TAD_MUL+ maybe one or two addtional TAD clock periods.
RF Developer. |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Sun Jun 03, 2012 5:20 pm |
|
|
@Mike, I was looking for an if statement to check if the value has changed vs constantly updating the pwm duty cycle. Since the adc values have some variation a simple if statement will not work. If the acd value is 122 it could be 121 122 or 123. I figure it does not hurt to let the pwm update the duty cycle over and over.
RF Developer, Thank You very much for making that more clear to me. It is very easy to follow with the way that you explained in detail.
I will look more into the details to make sure I am using the best acquisition times.
If the sum of adcR+adcG+adcB > 255 the program goes into random_color mode. Why does that happen?
Current working version.
Code: |
#include <18F26K80.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#FUSES NOPUT
#use delay(int=4000000)
#define LED PIN_C4
#define DELAY 1000
#define RAND_MAX 621
#include <stdlib.h>
int8 adcR;
int8 adcG;
int8 adcB;
int16 pwmR;
int16 pwmG;
int16 pwmB;
int16 randR;
int16 randG;
int16 randB;
int random_flag;
void set_init()
{
setup_adc_ports(sAN0|sAN1|sAN2);
setup_adc(ADC_CLOCK_DIV_4|ADC_TAD_MUL_4);
setup_timer_2(T2_DIV_BY_16,155,1); //2.4 ms overflow, 2.4 ms interrupt
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
setup_ccp4(CCP_PWM);
set_pwm2_duty((int16)0);
set_pwm3_duty((int16)0);
set_pwm4_duty((int16)0);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
output_high(LED);// Power ON LED
}
void check_adc()
{
set_adc_channel(0);// AN0 reading
delay_us(10);// 10us delay
adcR=read_adc();
set_adc_channel(1);// AN1 reading
delay_us(10);// 10us delay
adcG=read_adc();
set_adc_channel(2);// AN2 reading
delay_us(10);// 10us delay
adcB=read_adc();
}
void set_pwm()
{
if (random_flag==0)
{
pwmR=adcR*2.43;
pwmG=adcG*2.43;
pwmB=adcB*2.43;
}
set_pwm2_duty(pwmR);
set_pwm3_duty(pwmG);
set_pwm4_duty(pwmB);
}
void random_colors()
{
delay_us(rand());
while(adcR+adcG+adcB < 5)
{
srand((pwmR+pwmG+pwmB)/3);
randR=rand(); //range 0-621
randG=rand(); //range 0-621
randB=rand(); //range 0-621
while(pwmR!=randR && pwmG!=randG && pwmB!=randB)
{
if(pwmR<randR)
pwmR++;
else if(pwmR>randR)
pwmR--;
if(pwmG<randG)
pwmG++;
else if(pwmG>randG)
pwmG--;
if(pwmB<randB)
pwmB++;
else if(pwmB>randB)
pwmB--;
set_pwm();
check_adc();
if (adcR+adcG+adcB>=5)
return;
delay_ms(250);
}
}
}
void main()
{
set_init();
while(true)
{
check_adc();
if (adcR+adcG+adcB < 5)
{
output_low(LED);// Power OFF LED
random_flag=1;
random_colors();
}
else
{
random_flag=0;
output_high(LED);
}
set_pwm();
}
}
|
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Mon Jun 04, 2012 4:23 pm |
|
|
I don't see how this answers my original question. Quote: | @Mike, I was looking for an if statement to check if the value has changed vs constantly updating the pwm duty cycle. Since the adc values have some variation a simple if statement will not work. If the acd value is 122 it could be 121 122 or 123. I figure it does not hurt to let the pwm update the duty cycle over and over. |
Quote: | If the sum of adcR+adcG+adcB > 255 the program goes into random_color mode. Why does that happen? | Because you told it to.
You've declared each of the three variables as int8. If their sum goes just over 255, say 257, the value will be 1. Int8's are 8bit unsigned variables in CCS.
Your test for going random is for the sum to be <5! Nuf said.
Mike |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Mon Jun 04, 2012 5:01 pm |
|
|
Mike Walne wrote: | What do you mean by this?
Quote: | What is a good efficient way to check each channel for changes. Could I just use an if x1 != x2 update pwm or is there a better way?
| Are you wanting a neat way to:-
(1) update the PWMs?
OR
(2) have a human speed readable monitor?
Mike |
I am wanting a neat way to update the PWM.
I will look more into the adc summing issue and see if I can find my mistake. |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Mon Jun 04, 2012 5:21 pm |
|
|
Mike Walne wrote: |
Quote: | If the sum of adcR+adcG+adcB > 255 the program goes into random_color mode. Why does that happen? | Because you told it to.
You've declared each of the three variables as int8. If their sum goes just over 255, say 257, the value will be 1. Int8's are 8bit unsigned variables in CCS.
Your test for going random is for the sum to be <5! Nuf said.
Mike |
I was under the impression that the sum would always be larger than 5 if one of them was set to anything over 5. So the statements that contain variables also use the definition of the variables
Example?
Code: |
int8 x;
int8 y;
int8 z;
if(x+y+z)
do something;
//The if statement can only contain up to 255 numerically summed?
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19591
|
|
Posted: Tue Jun 05, 2012 1:29 am |
|
|
ounvme wrote: | Mike Walne wrote: |
Quote: | If the sum of adcR+adcG+adcB > 255 the program goes into random_color mode. Why does that happen? | Because you told it to.
You've declared each of the three variables as int8. If their sum goes just over 255, say 257, the value will be 1. Int8's are 8bit unsigned variables in CCS.
Your test for going random is for the sum to be <5! Nuf said.
Mike |
I was under the impression that the sum would always be larger than 5 if one of them was set to anything over 5. So the statements that contain variables also use the definition of the variables
Example?
Code: |
int8 x;
int8 y;
int8 z;
if(x+y+z)
do something;
//The if statement can only contain up to 255 numerically summed?
|
|
x=128
y=129
z=1
Add them using int8 arithmetic, and the result is 128+129+1 = 258 -> int8 _2_. So the sum of these three numbers will test as <5.
Arithmetic wraps. Go past the largest value that can be held, and you start again at the bottom.
_You_ have to handle such things. So:
Code: |
int16 result;
result=(int16)x+y+z;
if (result>255) result=255;
|
Adds the three 8bit values, and gets the '258' result, then since this is >255, stores 255 as the 'result'.
Two key things. First is using an int16 value for the result (even if latter you then only use the bottom 8bits of this), and the second is telling the compiler to do the addition using int16 arithmetic, rather than int8. This is done using the 'cast' (int16), which converts the 8bit value into an int16, before the sum is performed. The compiler says 'Value is an int16 type, so arithmetic must use int16 maths'.
Best Wishes |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Jun 05, 2012 3:09 am |
|
|
I asked
Quote: | Are you wanting a neat way to:-
(1) update the PWMs?
OR
(2) have a human speed readable monitor? |
We seem to have our lines crossed.
I often use printf's to a PC, so that I can see what is going on inside a PIC.
I was wanting to know if you were looking for a way of watching the current state of your PWM's without rapidly filling the monitor screen.
You now seem happy with updating the PWMs continuously, I don't see that causing any problems. The PWM system is buffered, any new PWM data is not used until the end of the current PWM cycle. You should not get any glitches by updating the PWM_duty at any time.
Mike |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Tue Jun 05, 2012 7:35 pm |
|
|
Ttelmah wrote: |
x=128
y=129
z=1
Add them using int8 arithmetic, and the result is 128+129+1 = 258 -> int8 _2_. So the sum of these three numbers will test as <5.
Arithmetic wraps. Go past the largest value that can be held, and you start again at the bottom.
_You_ have to handle such things. So:
Code: |
int16 result;
result=(int16)x+y+z;
if (result>255) result=255;
|
Adds the three 8bit values, and gets the '258' result, then since this is >255, stores 255 as the 'result'.
Two key things. First is using an int16 value for the result (even if latter you then only use the bottom 8bits of this), and the second is telling the compiler to do the addition using int16 arithmetic, rather than int8. This is done using the 'cast' (int16), which converts the 8bit value into an int16, before the sum is performed. The compiler says 'Value is an int16 type, so arithmetic must use int16 maths'.
Best Wishes |
I changed the adcR,G,B definitions to int16. The summing problem went away without having to add a variable or the (int16) to the math. It seems that if int16 variables are used in the math the result is an int16.
The results thus far are very pleasing. Especially in random_color mode. The color transitions are very smooth and nice to watch.
Code: |
#include <18F26K80.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
//#FUSES NOPUT
#use delay(int=4000000)
#define LED PIN_C4
#define DELAY 1000
#define RAND_MAX 621
#include <stdlib.h>
int16 adcR;
int16 adcG;
int16 adcB;
int16 pwmR;
int16 pwmG;
int16 pwmB;
int16 randR;
int16 randG;
int16 randB;
int random_flag;
void set_init()
{
setup_adc_ports(sAN0|sAN1|sAN2);
setup_adc(ADC_CLOCK_DIV_4|ADC_TAD_MUL_4);
setup_timer_2(T2_DIV_BY_16,155,1); //2.4 ms overflow, 2.4 ms interrupt
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_ccp2(CCP_PWM);
setup_ccp3(CCP_PWM);
setup_ccp4(CCP_PWM);
set_pwm2_duty((int16)0);
set_pwm3_duty((int16)0);
set_pwm4_duty((int16)0);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
output_high(LED);// Power ON LED
}
void check_adc()
{
set_adc_channel(0);// AN0 reading
delay_us(10);// 10us delay
adcR=read_adc();
set_adc_channel(1);// AN1 reading
delay_us(10);// 10us delay
adcG=read_adc();
set_adc_channel(2);// AN2 reading
delay_us(10);// 10us delay
adcB=read_adc();
}
void set_pwm()
{
if (random_flag==0)
{
pwmR=adcR*2.43;
pwmG=adcG*2.43;
pwmB=adcB*2.43;
}
set_pwm2_duty(pwmR);
set_pwm3_duty(pwmG);
set_pwm4_duty(pwmB);
}
void random_colors()
{
delay_us(rand());
while(adcR+adcG+adcB < 8)
{
srand(get_timer2());
randR=rand(); //range 0-621
randG=rand(); //range 0-621
randB=rand(); //range 0-621
while(pwmR!=randR && pwmG!=randG && pwmB!=randB)
{
if(pwmR<randR)
pwmR++;
else if(pwmR>randR)
pwmR--;
if(pwmG<randG)
pwmG++;
else if(pwmG>randG)
pwmG--;
if(pwmB<randB)
pwmB++;
else if(pwmB>randB)
pwmB--;
set_pwm();
check_adc();
if (adcR+adcG+adcB>=8)
return;
delay_ms(100);
}
}
}
void main()
{
set_init();
while(true)
{
check_adc();
if (adcR+adcG+adcB < 8)
{
output_low(LED);// Power OFF LED
random_flag=1;
random_colors();
}
else
{
random_flag=0;
output_high(LED);
}
set_pwm();
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19591
|
|
Posted: Wed Jun 06, 2012 1:32 am |
|
|
Yes, but you are then using 2bytes to store each number - RAM space is often _critical_ in a PIC, hence being able to store the values in single bytes, and yet still use int16 arithmetic, _may_ be essential, if space is tight.
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
|