View previous topic :: View next topic |
Author |
Message |
elasticman
Joined: 26 May 2009 Posts: 8
|
2 general questions about using a PIC processor |
Posted: Tue May 26, 2009 12:17 pm |
|
|
Hello all, I'm pretty new to all of this so I hope my questions don't sound too stupid:)
I'm working on my final project for my first degree in mechanical engineering and I have designed and built a robot.
I'm going to mount IR sensors to it and am using the PIC18F4431.
I wanted to make sure of one thing first : when I want the PIC to operate the motors (I'm using 3 DC gear motors) in accordance to the voltage thats coming from the IR sensors do I control the VOLTAGE to the motors via the programming or is it done by the electronics (the driver)??
And second : what type of data do I get from the A/D converter - analog data gets in and digital data gets out. But what exactly do I get? a number? or what exactly??
thank you very much in advance |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 26, 2009 1:03 pm |
|
|
If you bought the board with the IR sensors and motor driver on it,
post a link to the webpage for the board. If you're building it yourself
then post the manufacturer and part numbers of the IR sensors and
motor driver components. Also post links to the data sheets.
The A/D converter will return a number from 0 to 255. This number
corresponds in a linear manner to the input voltage at the A/D pin. For a
PIC running at +5v, the input voltage can be from 0 to +5v, and the
output of the A/D will be 0 to 255.
The A/D can also run in 10-bit mode, in which case the output values
will be 0-1023 over the 0-5v input voltage range. |
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Tue May 26, 2009 2:01 pm |
|
|
PCM programmer wrote: | If you bought the board with the IR sensors and motor driver on it,
post a link to the webpage for the board. If you're building it yourself
then post the manufacturer and part numbers of the IR sensors and
motor driver components. Also post links to the data sheets.
The A/D converter will return a number from 0 to 255. This number
corresponds in a linear manner to the input voltage at the A/D pin. For a
PIC running at +5v, the input voltage can be from 0 to +5v, and the
output of the A/D will be 0 to 255.
The A/D can also run in 10-bit mode, in which case the output values
will be 0-1023 over the 0-5v input voltage range. |
thank you
i bought the PIC and im using it in an OLIMEX PIC-P40-USB
i don't know which drivers yet (that is something that im going to get tomorrow from the electrician in the lab)
where can i find the exact linearity of the output values and the corresponding voltage?
also,if i understand correctly , i use control the motors through my programming as in , i either tell it to send a pulse or not (on or off) and then the driver takes care of the voltage to the motor....is that true? (isnt it a global thing with drivers?) |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Thu May 28, 2009 12:28 am |
|
|
Thank you PCM programmer.
I wanna make sure I get something, if I have 3 IR sensors, I connect them to AN0, AN1, AN2...
then I have my pic do the A/D conversion on the AN0, delay then read, convert AN1, delay then read, convert AN3 , delay then read.
Right?
and I'm going to use a 20 microsecond delay for each read (my OLIMEX board has a 20MHz clock). |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu May 28, 2009 8:04 am |
|
|
You want to
1) select AN0
2) delay
3) convert AN0
4) select AN1
5) delay
6) convert AN1
7) select AN2
8) delay
9) convert AN2
The delay needs to be between switching the A/D mux and running the conversion. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Thu May 28, 2009 8:12 am |
|
|
SherpaDoug wrote: | You want to
1) select AN0
2) delay
3) convert AN0
4) select AN1
5) delay
6) convert AN1
7) select AN2
8) delay
9) convert AN2
The delay needs to be between switching the A/D mux and running the conversion. |
Something like this :
Code: |
set_adc_channel(front_sensor);
delay_us(20);
data_from_front_sensor = READ_ADC();
set_adc_channel(right_sensor);
delay_us(20);
data_from_right_sensor = READ_ADC();
set_adc_channel(left_sensor);
delay_us(20);
data_from_left_sensor = READ_ADC();
|
??? |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Thu May 28, 2009 12:31 pm |
|
|
Yes, that is the sequence. I would have to look at your chip to see if 20us is the right time length. Usually I do math and storage on the reading I just got and the math takes more time than the required A/D delay. I end by re-selecting the first channel so it is ready for the next cycle of readings. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Fri May 29, 2009 3:13 am |
|
|
SherpaDoug wrote: | Yes, that is the sequence. I would have to look at your chip to see if 20us is the right time length. Usually I do math and storage on the reading I just got and the math takes more time than the required A/D delay. I end by re-selecting the first channel so it is ready for the next cycle of readings. |
Well, from the link given to me up here, in this thread by PCM programmer
http://ww1.microchip.com/downloads/en/DeviceDoc/31023a.pdf
If I understand correctly it takes about 20 us for the A/D.
I'm using the PIC18F4431 processor.
Thanks for the help and the idea for the idea on how to end the function.
btw : Does what I wrote mean that it takes continuous readings?
I would appreciate it if you check and tell me if the 20us is enough:) |
|
|
SherpaDoug
Joined: 07 Sep 2003 Posts: 1640 Location: Cape Cod Mass USA
|
|
Posted: Sun May 31, 2009 3:47 pm |
|
|
As long as your source resistance is under 10k and your temperature is reasonable, it looks to me like 20us acquisition time is enough.
this code Code: |
set_adc_channel(front_sensor);
delay_us(20);
data_from_front_sensor = READ_ADC();
set_adc_channel(right_sensor);
delay_us(20);
data_from_right_sensor = READ_ADC();
set_adc_channel(left_sensor);
delay_us(20);
data_from_left_sensor = READ_ADC(); |
will get a set of reading each time it is run. To get continuous readings you must run the code continuously. _________________ The search for better is endless. Instead simply find very good and get the job done. |
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Mon Jun 08, 2009 3:27 am |
|
|
I'm having problems with my program and I'm in dire need for help.
This is my program :
Code: | #include <18F4431.H>
#device ADC=10
//#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#fuses HS, NOLVP
#use delay(clock = 20000000)
#define PWM_PIN0 PIN_B0 //for the driver board - enable always H for all motors
#define PWM_PIN1 PIN_B1 // motor1 - I1
#define PWM_PIN2 PIN_B2 // motor1 - I2
#define PWM_PIN3 PIN_B3 // motor2 - I3
#define PWM_PIN4 PIN_B4 // motor2 - I4
#define PWM_PIN5 PIN_D6 // motor3 - I1
#define PWM_PIN6 PIN_D7 // motor3 - I2
#define FRONT_SENSOR 6
#define RIGHT_SENSOR 7
#define LEFT_SENSOR 8
#define NUMBER_EQUATING_1_METER 0.65
int first_run_flag = 0;
long temp_data_from_front_sensor,temp_data_from_right_sensor,temp_data_from_left_sensor;
float distance_from_front_sensor,distance_from_right_sensor,distance_from_left_sensor;
//-------------------------------
void initialize_adc(void);
void activate_motors_1_and_2_to_move_forward(void);
void deactivate_motors_1_and_2(void);
void activate_all_motors_to_rotate_right(void);
void activate_all_motors_to_rotate_left(void);
void deactivate_all_motors(void);
void decide_what_to_do();
void read_sensors(void);
//====================================
void initialize_adc(void)
{
setup_adc_ports( ALL_ANALOG ); //defines all pins to be analog
setup_adc (ADC_CLOCK_INTERNAL); // the adc uses the same clock speed as the board
}
void activate_motors_1_and_2_to_move_forward(void)
{
output_high(PWM_PIN1);
output_low(PWM_PIN2);
output_low(PWM_PIN3);
output_high(PWM_PIN4);
}
void deactivate_motors_1_and_2(void)
{
output_low(PWM_PIN1);
output_low(PWM_PIN2);
output_low(PWM_PIN3);
output_low(PWM_PIN4);
}
void activate_all_motors_to_rotate_right(void)
{
output_high(PWM_PIN1);
output_low(PWM_PIN2);
output_high(PWM_PIN3);
output_low(PWM_PIN4);
output_high(PWM_PIN5);
output_low(PWM_PIN6);
}
void activate_all_motors_to_rotate_left(void)
{
output_low(PWM_PIN1);
output_high(PWM_PIN2);
output_low(PWM_PIN3);
output_high(PWM_PIN4);
output_low(PWM_PIN5);
output_high(PWM_PIN6);
}
void deactivate_all_motors(void)
{
output_low(PWM_PIN1);
output_low(PWM_PIN2);
output_low(PWM_PIN3);
output_low(PWM_PIN4);
output_low(PWM_PIN5);
output_low(PWM_PIN6);
}
void decide_what_to_do()
{
if ( distance_from_front_sensor>=NUMBER_EQUATING_1_METER ) // this is
{ // for the initial operation
first_run_flag = 1; // scan first
} // to find the object
while (first_run_flag == 0 ) // then keep on
{ // following it
activate_all_motors_to_rotate_right(); //
delay_ms(60); //
deactivate_all_motors(); //
delay_ms(60); //
read_sensors(); //
if ( distance_from_front_sensor>=NUMBER_EQUATING_1_METER )//
{ //
first_run_flag = 1; //
} //
}
if ( distance_from_front_sensor<NUMBER_EQUATING_1_METER ) //voltage is lower for farther object
{
while ( distance_from_front_sensor<NUMBER_EQUATING_1_METER )
{
activate_motors_1_and_2_to_move_forward();
delay_ms(60);
deactivate_motors_1_and_2();
delay_ms(60);
read_sensors();
}
}
if ( distance_from_right_sensor!= 0 )
{
while ( distance_from_right_sensor!= 0 )
{
activate_all_motors_to_rotate_right();
delay_ms(60);
deactivate_all_motors();
delay_ms(60);
read_sensors();
}
}
if ( distance_from_left_sensor!= 0 )
{
while ( distance_from_left_sensor!= 0 )
{
activate_all_motors_to_rotate_left();
delay_ms(60);
deactivate_all_motors();
delay_ms(60);
read_sensors();
}
}
}
void read_sensors(void)
{
set_adc_channel(front_sensor);
delay_us(20);
temp_data_from_front_sensor = READ_ADC( ADC_START_AND_READ );
distance_from_front_sensor = temp_data_from_front_sensor*5/1023;
set_adc_channel(right_sensor);
delay_us(20);
temp_data_from_right_sensor = READ_ADC( ADC_START_AND_READ );
distance_from_right_sensor = temp_data_from_right_sensor*5/1023;
set_adc_channel(left_sensor);
delay_us(20);
temp_data_from_left_sensor = READ_ADC( ADC_START_AND_READ );
distance_from_left_sensor = temp_data_from_left_sensor*5/1023;
}
void main()
{
initialize_adc();
output_high(PWM_PIN0); //for the driver board - always have the "enabled" pin set to H ,for all motors
do
{
read_sensors();
decide_what_to_do();
} while (TRUE);
} |
if anybody sees whats wrong...please do tell |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 08, 2009 11:39 am |
|
|
There is a recent discussion here, about how get the correct result
from a math expression when some of the terms are integers and
some are floating point:
http://www.ccsinfo.com/forum/viewtopic.php?t=39140
To trouble-shoot a problem, you need to use printf statements to
display intermediate values in your program. This will tell you
where the problem may be. If the values are not as expected,
then look closely at the code that does your calculations.
For example, you are assuming that this line has a full floating
point result as the output. But does it ?
Quote: | distance_from_front_sensor = temp_data_from_front_sensor*5/1023; |
Suppose the numerator is 512. Then the result should be:
Quote: | (512 * 5)/1023 = 2.50 |
But, if we run the test program shown below, we get:
It's truncating the result to an integer. (Though it's still put
into the floating point variable).
You can read that link about math calculations. It tells you
what needs to be changed in the expression so it will give
the correct output of 2.50.
Code: | #include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
long temp_data_from_front_sensor,temp_data_from_right_sensor,temp_data_from_left_sensor;
float distance_from_front_sensor,distance_from_right_sensor,distance_from_left_sensor;
//======================================
void main()
{
temp_data_from_front_sensor = 512;
distance_from_front_sensor = temp_data_from_front_sensor*5/1023;
printf("result = %7.3f", distance_from_front_sensor);
while(1);
} |
There may be other problems with your code, but this was one of them.
If you want more help, you need to provide a link to the motor driver
board schematic or webpage (and the part number). Also provide info
on the motors. |
|
|
mkuang
Joined: 14 Dec 2007 Posts: 257
|
|
Posted: Mon Jun 08, 2009 2:24 pm |
|
|
Regarding this line of code:
Code: |
temp_data_from_front_sensor = READ_ADC( ADC_START_AND_READ );
|
Isn't the read_adc function void?
Shouldn't it just be:
Code: |
temp_data_from_front_sensor = READ_ADC( );
|
In addition, if you have something like this:
Code: |
distance_from_front_sensor = temp_data_from_front_sensor*5/1023;
|
You are probably going to get an integer back, either 0, 1, 2, 3, 4, or 5. You declared temp_data_from_front_sensor as an integer and you are mulitiplying it by 5, an integer, then dividing it back 1023, again an integer. I think what you want to do is something like:
Code: |
distance_from_front_sensor = (long)temp_data_from_front_sensor*5.0/1023
|
Last edited by mkuang on Mon Jun 08, 2009 2:33 pm; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 08, 2009 2:27 pm |
|
|
It's the same thing. From the manual:
Quote: | read_adc( )
Syntax: value = read_adc ([mode])
ADC_START_AND_READ (continually takes readings, this is the default) |
But you're right, normally, we just use read_adc(). |
|
|
elasticman
Joined: 26 May 2009 Posts: 8
|
|
Posted: Tue Jun 09, 2009 12:26 am |
|
|
Thanks a lot guys.
We have managed to get it to work.
Somebody helped us and actually changed some of the stuff you are talking about before seeing what you wrote....
and the logic of the program seemed to work:)
Next week we will be connecting EVERYTHING and giving it a go:)
Thanks a LOT PCM Programmer and SherpaDoug , you guys are a great help! |
|
|
|