View previous topic :: View next topic |
Author |
Message |
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
Help needed on using analog values. |
Posted: Tue Oct 09, 2007 4:02 am |
|
|
I wrote the folowing code and it worked fine until i started using analog channel 3. I am using a small joystic that has an analog input for left and right and forward reverse. I need the forward reverse to stop working if the stick is pushed left and right. The pwm output rb1 and rb2 works fine but indication led RB3 stops working when the part that reeds an input from analog 3 is included in the program. What am i doing wrong?
Code: |
setup_adc_ports(all_analog);
//setup_adc_ports(sAN2);
//setup_adc_ports(sAN3);
setup_adc( ADC_CLOCK_INTERNAL );
#define P1C PIN_B1
#define P1b PIN_B2
setup_timer_2(T2_DIV_BY_4, 124, 1); // 1000 Hz
output_low(P1C);
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
while(1){
set_adc_channel(1);
value = read_adc();
set_adc_channel(2);
value1 = read_adc();
set_adc_channel(3);
weapon = read_adc();
if(weapon > 230){
output_high(pin_b4);
}
if(weapon > 30 && weapon <230){
output_low(pin_b4);
}
if(weapon <30){
output_high(pin_b4);
}
//////////////////////////////////////right//////////////////////////////////////////////
if(value1 > 245 ){
set_pwm1_duty(80);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_B);
output_high(pin_A4);
output_low(pin_b5);
output_low(pin_b3);
}
if(value1 > 210 && value1 < 245 ){
//set_pwm1_duty(0);
setup_ccp1(CCP_OFF);
output_low(pin_A4);
output_low(pin_b5);
output_low(pin_b3);
}
///////////////////////////////////////////left////////////////////////////////////////////
if(value1 > 10 && value1 < 90 ){
//set_pwm1_duty(0);
setup_ccp1(CCP_OFF);
output_low(pin_A5);
output_low(pin_b5);
output_low(pin_b3);
}
if(value1 < 10 ){
set_pwm1_duty(80);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_B);
output_high(pin_A5);
output_low(pin_b5);
output_low(pin_b3);
}
//////////////////////////////forwardreverse//////////////////////////////////////
if(value1 > 90 && value1 <210){
output_low(pin_A4);
output_low(pin_A5);
if(value > 110 && value < 115 ) {
set_pwm1_duty(25);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_C);
output_high(pin_b3);
}
if(value > 115 && value < 160 ) {
set_pwm1_duty(0);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_C);
output_low(pin_b5);
output_low(pin_b3);
}
if(value > 160 && value < 180 ) {
set_pwm1_duty(25);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_C);
output_high(pin_b5);
}
}
} | } |
|
|
Ttelmah Guest
|
|
Posted: Tue Oct 09, 2007 7:50 am |
|
|
First thing. You must pause after selecting a channel, befoe reading it. The internal ADC, is electrically a capacitor, and there is significant resistance present in the input parts of the chip. It therefore takes time for the capacitor to charge to the input voltage. Typically at least 10uSec are needed, and almost certainly more, from a joystick, which will itself usually have a fairly high resistance. I'd suspect this is the actual problem. If the voltage on input 3, is significantly different from the other values, the capacitor will charge to this voltage, and never get 'back' to the right sort of levels fo the other channels.
A couple of other comments.
In general, don't use 'ADC_CLOCK_INTERNAL'. The problem with this, is that the sampling is then asynchronous to the other stuff going on in the chip. Hence there is a tendency to more noise variation between samples. Normally the data sheet will have a 'caveat', saying not to use this above perhaps 1MHz, unless the chip is put to sleep for the sample. However some latter chips are OK with this, provided you are running off the internal oscillator.
Then there is a 'weakness', in the logic of the 'weapon' test. What happens if the value _is_ 30, or '230'?.
Best Wishes |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Tue Oct 09, 2007 8:24 am |
|
|
Quote: | What happens if the value _is_ 30, or '230'?. |
Ahhhh, I remember when this type of thing bit me in the rear.
What Ttelmah is talking about is:
You are comparing values from your ADC. If the value is > 230 and if it is < 230. If the value is exactly 230 there is nothing that will be true in your evaluation. You'll need to change one of them so 230 (and 30 and 245 and so forth) will cause an evaluation to be true. Try:
Code: | if(weapon > 229){ // this will be true if value is 230
output_high(pin_b4);
}
if(weapon > 30 && weapon <230){ // this will be true if value is 229 or less
output_low(pin_b4);
} |
It's the little things that can cause the most grief.
Ronald |
|
|
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
|
Posted: Tue Oct 09, 2007 8:37 am |
|
|
Thanks for the help.
Just one thing> If i do not use the "ADC_CLOCK_INTERNAL" what would be the better option as i am using an external oscilator of 4mhz?
I see those holes and will sort them out to see if that wil work.
Code: | #define ADC_CLOCK_DIV_2 0x100
#define ADC_CLOCK_DIV_8 0x40
#define ADC_CLOCK_DIV_32 0x80
#define ADC_CLOCK_INTERNAL 0xc0 |
Am i correct in saying that if i use one of the following the reading time would be connected to the external oscilator_div_x so it would have less interference? |
|
|
Ttelmah Guest
|
|
Posted: Tue Oct 09, 2007 9:47 am |
|
|
There is a table in the data sheet....
However you generally need more than 2uSec/cycle (some latter chips less). This represents 8 cycles of your clock.
Check the data sheet for your chip (you have not told us which chip it actually is...).
Best Wishes |
|
|
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
|
Posted: Tue Oct 09, 2007 11:36 am |
|
|
Thanks. Its a 16f886 and i see in the datasheet it should be div_8.
Seems like most of the hickups are sorted out i just need to sort the pwm switching on and off but shouldn't be a problem.
Thanks for the help. |
|
|
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
|
Posted: Tue Oct 09, 2007 11:58 am |
|
|
I thought i would be able to sort it out but i must be missing something??
In the code if i move the stick to the front and back the pwm on pin c switches correctly between the duty cycles but if i move it left and right as well as front and back the pwm on both B and C doesnt want to switch off when i return the stick to between the levels where i set ccp_off. Is there a software problem or can anyone see what i did wrong?
Code: | set_tris_a(TRISA | 0b00001110);
set_tris_a(TRISA & 0b11001111);
set_tris_b(trisb & 0b11000001);
output_low(PIN_A4);
output_low(PIN_A5);
output_low(PIN_B1);
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B4);
setup_adc_ports(sAN1);
setup_adc_ports(sAN2);
setup_adc_ports(sAN3);
setup_adc( ADC_CLOCK_DIV_8 );
#define P1C PIN_B1
#define P1b PIN_B2
setup_timer_2(T2_DIV_BY_4, 124, 1); // 1000 Hz
output_low(P1C);
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
while(1){
///part were weapon is actvated
//xxxxxxxxxxxxxxxxxxxxxxxxxxx
//////////////////////////////////////Joystick pushed right ////////////////////////////////////////
set_adc_channel(2);
delay_us(20);
value1 = read_adc();
if(value1 > 245 ){
setup_ccp1(CCP_OFF);
output_high(pin_A4);
output_low(pin_b5);
output_low(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x1A);
}
else if(value1 > 210 && value1 < 246 ){
set_pwm1_duty(0);
setup_ccp1(CCP_OFF); ////switch off ccp1(pwm)
output_low(pin_A4);
output_low(pin_b5);
output_low(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x1B);
}
///////////////////////////////////////////Joystick pushed left////////////////////////////////////////////
if(value1 > 10 && value1 < 90 ){
//set_pwm1_duty(0);
setup_ccp1(CCP_OFF); ////switch off ccp1(pwm)
output_low(pin_A5);
output_low(pin_b5);
output_low(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x2A);
}
else if(value1 < 11 ){
set_pwm1_duty(80);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_B);
output_high(pin_A5);
output_low(pin_b5);
output_low(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x2B);
}
//////////////////////////////joystic pushed forward /////////////////////////////////////////////////
if(value1 > 90 && value1 <211){
output_low(pin_A4);
output_low(pin_A5);
set_adc_channel(1);
delay_us(20);
value = read_adc();
if(value > 110 && value < 116 ) {
set_pwm1_duty(25);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_C);
output_high(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x3E);
}
//////////////Joystic in the middle////////
else if(value > 115 && value < 161 ) {
setup_ccp1(CCP_OFF); ////switch off ccp1(pwm)
output_low(pin_b5);
output_low(pin_b3);
PutCC1000(PREAMBLE);
PutCC1000(0x4A);
}
/////////////////joystick pushed back////////////
else if(value > 160 && value < 181 ) {
set_pwm1_duty(25);
setup_ccp1(CCP_PWM_H_H | CCP_PULSE_STEERING_C);
output_high(pin_b5);
PutCC1000(PREAMBLE);
PutCC1000(0x5A);
}
}
} |
|
|
|
Gerhard
Joined: 30 Aug 2007 Posts: 144 Location: South Africa
|
|
Posted: Tue Oct 09, 2007 2:12 pm |
|
|
If anyone has a better way of doing it also please your input would be apreciated. The reason i am not using the analog values directly is because the position of the joystick is sent via rf to another pic to actually control the car but if there is a better way please let me know. |
|
|
|