- Code: Select all
Hardware Notes:
* PIC used:
* PIC24FV32KA302 operating at 8MHz)
* I/O ports used and hardware attached
* Outputs:
* RB10, RB11, RB2, RB3, RB8, RB9 connected to SN754410NE
* RB5 and RB6 connected to left and right LEDs
* Inputs:
* RB15 is an analog input connected to the potentiometer
* RB12 is an analog input connected to the left sensor
* RB4 is an analog input connected to the right sensor
*
********************************************************************/
/*******************************************************************
Include Files
********************************************************************/
#include "p24FV32KA302.h"
#include "configBits.h"
#include "delay.h"
/*******************************************************************
Symbolic Constants used by main()
********************************************************************/
//leave blank for now
/*******************************************************************
Local Function Prototypes
********************************************************************/
void initialize();
void get_Inputs(void);
void decide(void);
void refresh_PWM(void);
void delayMs(unsigned int ms);
void line(void);
/*** Global Variable Declarations *********************************************/
unsigned int potValue; // Raw Potentiometer setting
unsigned int leftOpto; // Left Opto Sensor Signal
unsigned int rightOpto; // Right Opto Sensor Signal
unsigned int counter = 0; //Counter for when both Sensor senses black
/*** main() Function **********************************************************/
int main(void) {
initialize();
//infinite loop
while (1) {
get_Inputs();
decide();
refresh_PWM();
delayMs(100);
}
}
/*******************************************************************************
* Function: void initialize(void)
*
* Overview: Initializes the microcontroller, the peripherals
* used in the application and any global variables
* used by multiple functions.
*
* Note: None
******************************************************************************/
void initialize(void) {
//TRISB = 0x0000;
//LATB = 0x0000; // digital outputs
TRISB = 0x9010; //Initialize RB15(Potentiometer),
//RB12(Left Sensor) and RB4(Right Sensor) as inputs
ANSB = 0x9010; //Initialize RB15(Potentiometer),
//RB12(Left Sensor) and RB4(Right Sensor) as analog inputs
LATBbits.LATB5 = 0; //initialize output port RB5
LATBbits.LATB6 = 0; //initialize output port RB6
// Initialize "3-4EN" PWM control output (RB10/OC3)
TRISBbits.TRISB10 = 0; // Make RB10 digital O/P
LATBbits.LATB10 = 0; // initialize the pin0 voltage level
// Initialize Output Compare 3 (OC3) to drive Motor A PWM signal to "3-4EN"
// We want to create 61.04Hz PWM frequency @ 1024 bits resolution
OC3CON1bits.OCM = 0b000; // Disable the OC module
OC3R = potValue; // Write the duty cycle for the 1st PWM pulse
OC3CON1bits.OCTSEL = 0; // Select Timer 2 as the OC time base
OC3CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)
// Initialize "1-2EN" PWM control output (RB11/OC2)
TRISBbits.TRISB11 = 0; // Make RB11 digital O/P
LATBbits.LATB11 = 0; // initialize the pin voltage level
// Initialize Output Compare 2 (OC2) to drive Motor B PWM signal to "1-2EN"
// We want to create 61.04Hz PWM frequency @ 1024 bits resolution
OC2CON1bits.OCM = 0b000; // Disable the OC module
OC2R = potValue; // Write the duty cycle for the 1st PWM pulse
OC2CON1bits.OCTSEL = 0; // Select Timer 2 as the OC time base
OC2CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)
// Initialize and enable Timer 2 to create a 61.04Hz PWM frequency for both
//PWM channels
T2CONbits.TON = 0; // Disable Timer
T2CONbits.TCS = 0; // Select internal instruction clock (Fosc/2)
// which results in 8MHz/2 = 4MHz
T2CONbits.TGATE = 0; // Disable Gated Timer Mode
T2CONbits.TCKPS = 0b10; // Select 1:64 prescale (4MHz/64 = 62.5kHz)
TMR2 = 0x00; // Clear timer register
PR2 = 1024; /* Load the period register with 1024
* This represents the highest value that can be
* loaded from the pot (10-bit converted value)
* This forces you to choose a higher prescale.
* Using Fosc/2 setting = 4MHz clock
* choose a 1:64 prescale = 62.5kHz = .016ms period
* Loading the PR2 register with 1024
* results in a 61.04Hz control signal
* since 1024 * .000016s period = 16.384ms
* f = 1/16.384ms = 61.04Hz */
IFS0bits.T2IF = 0; // Clear Timer 2 interrupt flag
T2CONbits.TON = 1; // Start timer (starts PWMs)
AD1CON1bits.ADON = 1; // Turn on ADC
/***********************SERVO CONTROL*************************************/
/* Initialize Output Compare 1 (OC1) to drive Servo motor using PWM signal
* We want to create a 50Hz PWM frequency (20ms period)
* The servo is limited from 0 to 180 degrees rotation.
* The pulse width for this servo ranges from .75ms to 2.25ms.
* Two Servo positions could be:
* 0 degrees: 3.75% duty cycle (.75ms) * 10,000 = 375
* 90 degrees: 7.5% duty cycle (1.5ms) * 10,000 = 750 */
OC1CON1bits.OCM = 0b000; // Disable the OC module
OC1R = 375; // Write the duty cycle for the
// 1st PWM pulse at 0 degrees
OC1CON1bits.OCTSEL = 0b001; // Select Timer 3 as the OC time base
OC1CON1bits.OCM = 0b110; // Select the OC mode (Edge PWM)
OC1CON2bits.SYNCSEL = 0b01101; // Synchronize OC1 to Timer3
// Initialize and enable Timer 3 to create a 50Hz PWM frequency
// for PWM channel
T3CONbits.TON = 0; // Disable Timer
T3CONbits.TCS = 0; // Select internal instruction clock (Fosc/2)
// which results in 8MHz/2 = 4MHz
T3CONbits.TGATE = 0; // Disable Gated Timer Mode
T3CONbits.TCKPS = 0b01; // Select 1:8 prescale (4MHz/8 = 500kHz)
TMR3 = 0x00; // Clear timer register
PR3 = 10000; /* Load the period register needed for
* for 50Hz (20ms) control signal.
* Using Fosc/2 setting = 4MHz clock
* snd 1:8 prescale = 500kHz = 0.02ms period
* 10,000 clock cycles needed (20ms/0.02ms) */
IFS0bits.T3IF = 0; // Clear Timer 3 interrupt flag
T3CONbits.TON = 1; // Start timer (starts PWMs)
}
/*******************************************************************************
* Function: void get_Inputs(void)
*
* Overview: Obtains any input information either on-chip
* (from internal registers, etc...) or off-chip
* (pin voltage levels). Uses this information to modify
* or update special data structures used in the control
* function "decide()"
*
* Note: None
******************************************************************************/
void get_Inputs(void) {
// Sample/convert/save Opto Sensor and Pot Levels
// Left
AD1CHS = 0x000C; // Connect AN15(RB4) as CH0 input
AD1CON1bits.SAMP = 1; // Sample potentiometer value
delayMs(5); // after 5mS start conversion
AD1CON1bits.SAMP = 0; // Convert potentiometer value
while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
leftOpto = ADC1BUF0; // yes, then save ADC value
// Right
AD1CHS = 0x000F; // Connect AN12(RB12) as CH0 input
AD1CON1bits.SAMP = 1; // Sample potentiometer value
delayMs(5); // after 5mS start conversion
AD1CON1bits.SAMP = 0; // Convert potentiometer value
while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
rightOpto = ADC1BUF0; // yes, then save ADC value
// Sample/save potentiometer connected to RA0/AN0
AD1CHS = 0x0009; // Connect ANSB15(RB15) as CH0 input
AD1CON1bits.SAMP = 1; // Sample potentiometer value
delayMs(1); // after 1mS start conversion
AD1CON1bits.SAMP = 0; // Convert potentiometer value
while (!AD1CON1bits.DONE); // conversion done? (takes 12*Tad)
potValue = ADC1BUF0; // yes, then save ADC value
}
/*******************************************************************************
* Function: void decide(void)
* Overview: Makes decisions based on the input information
* gathered in get_Inputs() function to manipulate
* global output control variables.
*
* Note: None
******************************************************************************/
void decide(void) {
if (leftOpto < 145) { //Left sensor senses black, turns left
LATBbits.LATB5 = 1;
PORTBbits.RB2 = 0;
}
else
{
LATBbits.LATB5 = 0;
PORTBbits.RB2 = 1;
}
if (rightOpto < 145) //Right sensor sense black, turns right
{
LATBbits.LATB6 = 1;
PORTBbits.RB8 = 0;
} else
{
LATBbits.LATB6 = 0;
PORTBbits.RB8 = 1;
}
if (leftOpto < 145 && rightOpto < 145) {
counter++;
line();
}
}
/*******************************************************************************
* Function: void refresh_PWM(void)
* Overview: Based on the decisions made in the previous function,
* this function updates the speed of the motors
*
* Note: None
******************************************************************************/
void refresh_PWM(void) {
// Update PWM duty cycle registers (motor speed/torque) for both motors
OC3R = potValue;
OC2R = potValue;
}
/*******************************************************************************
* Function: void delayMs(unsigned int ms)
*
* PreCondition: Requires Tcyc=250nS (8 MHz Fosc)
*
* Input: delay in milliseconds (1-65535)
*
* Output: None
*
* Side Effects: Blocking Delay (CPU is blocked from doing other tasks)
* Non-portable (Uses PIC24 Assembly language instructions)
*
* Overview: This function implements an in-line delay of up to 65535ms
*
* Note: None
******************************************************************************/
void delayMs(unsigned int ms) {
while (ms--) {
asm("repeat #4000"); // 4000 instruction cycles @ 250nS ea. = 1mS
asm("nop"); // instruction to be repeated 4000x
}
}
void line(void) {
if (counter == 0)
{
refresh_PWM();
PORTBbits.RB2 = 1; //Ignore the first time both sensor senses black and
//keep going
PORTBbits.RB8 = 1;
delayMs(500);
counter++;
}
else if (counter == 4) {
PORTBbits.RB2 = 0;//Ignore the second time both sensor senses black and
//keep going
PORTBbits.RB8 = 0;
}
else
{
PORTBbits.RB2 = 0;//Stop and turn the servo
PORTBbits.RB9 = 0;
OC1R = 1125;
// the code below is supposed to turn the robot but it doesnt. the robot keeps turning and doesnt follow the line back
// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// delayMs(2000);
// do
// {
// PORTBbits.RB2 = 0;//Turn around
// PORTBbits.RB9 = 0;
// decide();
// }
// while(leftOpto < 145 || rightOpto < 145);
// do
// {
// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// }
// while(leftOpto > 145 && rightOpto > 145);
//
//
//
// do{
// PORTBbits.RB2 = 0;//Turn around
// PORTBbits.RB9 = 0;
// decide();
// }
// while(leftOpto < 145 || rightOpto < 145);
// while (1)
// {
// if(leftOpto > 145 && rightOpto > 145)
// {
// PORTBbits.RB2 = 1;//Turn around
// PORTBbits.RB9 = 1;
// }
// else
// break;
// }
// decide();
// }
}
}