I have spent 2 1/2 hours trying to figure this out...
I have an ultrasonic sensor mounted on a servo and I am trying to write a function that scans from right to left, then when it is called again from left to right. Pretty easy right? Sure if the code ran how it should. For some reason when it scans from right to left the for loop does not stop.
for (counter=0;counter<15;counter++)It continues to count forever. Here is the whole code. The function is near the bottom.
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <math.h>
#include <avr/interrupt.h>
#include "hardware.h"
void init_hardware (void);
void USART_Transmit( unsigned char data );
uint16_t a2d_10( uint8_t Channel );
uint16_t ultra_sonic (void);
uint16_t get_ultra_sonic (void);
void debug (char *str);
void us_servo (int8_t deg);
void scan (void);
uint8_t learn_motor (void);
volatile uint16_t interrupt_timer=0;
uint8_t motor_f=0, motor_r=0;
uint16_t log_scan[10][17];
int8_t current_deg=0;
char text[20];
//volatile int8_t current_deg=0;
ISR (TIMER2_OVF_vect)
{
++interrupt_timer;
}
void init_hardware (void)
{
PORTA=0;
DDRA=0;
PORTB=YELLOW_LED_MASK;
DDRB=YELLOW_LED_MASK;
PORTC=0;
DDRC=0;
PORTD=0;
DDRD=0;
PORTE=0;
DDRE=MOTOR_MASK|SERVO_WHEEL_MASK|SERVO_IR_MASK;
PORTF=0;
DDRF=0;
PORTG=BLUE_LED_MASK|RED_LED_MASK;
DDRG=BLUE_LED_MASK|RED_LED_MASK;
TCCR3A=0b10101010;
TCCR3B=0b00011010;
ICR3=40000;
OCR3A=US_SERVO_CENTER;
OCR3B=3000;
OCR3C=3000;
TCCR1A=0;
TCCR1B=2;
TCCR2=3;
TIMSK=64;
sei();
ADCSR = (( 1 << ADEN ) | ( 1 << ADSC ) | ADC_PRESCALAR_128 );
ADMUX = (( 0 << REFS1 ) | ( 1 << REFS0 ));
if (((( 1 << ADEN ) | ( 1 << ADSC ) | ADC_PRESCALAR_128 ) & ADCSR ) != 0 )
{
// Wait for the initial conversion to complete. This initializes
// the ADC.
while (ADCSR & ( 1 << ADSC) )
;
}
UBRR0H = UBRR0_INIT >> 8;
UBRR0L = UBRR0_INIT & 0xFF;
UCSR0A = UCSR0A_INIT;
UCSR0B = UCSR0B_INIT;
UCSR0C = UCSR0C_INIT;
}
void USART_Transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */
UDR0 = data;
}
void debug (char *str)
{
uint8_t x=0;
while (str[x]!=0)
{
USART_Transmit(str[x++]);
}
}
uint16_t a2d_10( uint8_t Channel )
{
// Select the channel in a manner which leaves REFS0 and REFS1 un touched.
ADMUX = ( ADMUX & (( 1 << REFS1 ) | ( 1 << REFS0 ))) | Channel;
// Start the conversion
ADCSR = ADCSR | ( 1 << ADSC );
// Wait for it to complete
while ( ADCSR & ( 1 << ADSC ));
return ADC;
} // a2d_10
uint16_t get_ultra_sonic (void)
{
uint16_t fcap=0,scap=0,dist=0;//fcap stores first capture, scap stores second
ULTRA_SONIC_OUT;//set pin to output
ULTRA_SONIC_SET;//set pin to high
_delay_us (10);//delay for a pulse
ULTRA_SONIC_RESET;//set pin low
ULTRA_SONIC_IN;//set pin to input
Clear_ICF1;//clear the capture flag
TCNT1=0;//set timer 1 to 0 to prevent overflow
ULTRA_SONIC_CAP_RISING;//capture the rising edge of the pulse
while (ICF1_Empty)//wait for capture
{
if (TCNT1>50000) return 0xFFFF;
}
Clear_ICF1;//clear the capture flag
fcap=ICR1;//save the captured value
ULTRA_SONIC_CAP_FALLING;//capture the falling edge of the pulse
while (ICF1_Empty)//wait for capture
{
if (TCNT1>50000) return 0xFFFF;
}
Clear_ICF1;//clear the capture flag
scap=ICR1;//save the captured value
dist=scap-fcap;//subtract the timer values to find the pulse lenght
dist*=0.0850725;//convert to mm
return dist;
}
uint16_t ultra_sonic (void)
{
uint16_t dist;
dist=0xFFFF;
while (dist==0xFFFF)
{
dist=get_ultra_sonic();
_delay_ms(10);
}
return dist;
}
void us_servo (int8_t deg)
{
int16_t change;
current_deg=deg;
change=deg*22.22;
change=US_SERVO_CENTER+change;
if (change<US_SERVO_MIN)change=US_SERVO_MIN;
if (change>US_SERVO_MAX)change=US_SERVO_MAX;
sprintf(text,"%i %i %i\n\r",change, US_SERVO_MAX,US_SERVO_MIN);
debug(text);
OCR3A=change;
}
void turn (int8_t deg)
{
int16_t change;
change=deg*15;
change+=300;//offset for the motor to speed up and the servos to move
OCR3C=2800;
if (change>0){
OCR3B=TURN_SERVO_MAX;
for (;change>0;--change)
{
_delay_ms(1);
}
}
else
{
OCR3B=TURN_SERVO_MIN;
for (;change<0;++change)
{
_delay_ms(1);
}
}
OCR3B=TURN_SERVO_CENTER;
OCR3C=3000;
}
void scan (void)
{
int8_t counter=0,countert=0;
debug("scanning\n\r");
for (counter=0;counter<9;++counter)
{
for (countert=0;countert<17;++countert)
{
log_scan[counter][countert]=log_scan[counter+1][countert];
}
}
/*if ((current_deg!=-80)||(current_deg!=80))
{
us_servo(-80);
_delay_ms(500);
}*/
if (current_deg==(-70))
{
for (counter=0;counter<15;counter++) <========This works fine?!?
{
us_servo((-70)+(10*counter));
_delay_ms(1000);
log_scan[9][counter]=ultra_sonic();
sprintf(text,"%i\n\r",current_deg);
debug(text);
}
}
else
{
for (counter=0;counter<15;counter++) //<============================================Problem occurs here!
{
us_servo(70-(10*counter)); //commenting this line out makes it work
_delay_ms(1000);
log_scan[9][16-counter]=ultra_sonic(); //same thing for this line
sprintf(text,"%i %i\n\r",current_deg, counter);
debug(text);
}
}
}
uint8_t learn_motor (void)
{
uint16_t ultra_base=0, tmr1_base=0;
us_servo(0);
OCR3C=3000;
_delay_ms(1000);
ultra_base=ultra_sonic(); //get the base reading
interrupt_timer=0;
LED_ON(YELLOW);
OCR3C=2800;
tmr1_base=interrupt_timer;
while (ultra_sonic()>(ultra_base-100));
motor_f=interrupt_timer-tmr1_base;
OCR3C=3000;
_delay_ms(1000);
LED_ON(BLUE);
interrupt_timer=0;
OCR3C=3200;
tmr1_base=interrupt_timer;
while (ultra_sonic()<ultra_base);
motor_r=interrupt_timer-tmr1_base;
OCR3C=3000;
_delay_ms(1000);
return 1;
}
int main (void)
{
init_hardware();
_delay_ms(50); //allow things to settle
while (1)
{
scan();
_delay_ms(1000);
}
}
Commenting either of those two lines makes the for loop work properly. Also making the loop start at 2 (or higher) instead of 0 works too. I am stumped. I even tried a while loop and got the same problem. It seems that if ct is used in the loop is messes it up because log_scan[9][0]=ultra_sonic(); works.
I really appreciate any help. I am completely confused.
This code is for an ATmega128.