Здравствуйте! Есть гусеничный робот. Спереди на нем стоят два фотодиода. Есть черная линия по которой он должен ездить и поворачивать с помощью ШИМа. У правляющий порт - С. Комбинация PORTC |= 0x82U; заставляет его ехать вперед. Вроде бы ничего сложного, но уже несколько дней не могу понять в чем накосячил. Стоит на месте и не едет. При этому, если без ШИМа подать на ножки напряжения, то начинает ехать прямо как ему и положено.
Я не прошу разбирать весь код (но и не откажусь ), но не могли бы вы окинуть свежий взгяд на листинг программы ? Вдруг увидите что-нибудь. Спасибо!
Раздел: AVR
Я не прошу разбирать весь код (но и не откажусь ), но не могли бы вы окинуть свежий взгяд на листинг программы ? Вдруг увидите что-нибудь. Спасибо!
#include <mega32.h>
#include <delay.h>
unsigned char x = 0, y = 0;
unsigned char K = 0;
/////////////////////////////////////////////////////////////////////////////////////////
////////////////////// Объявленияе функций //////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
//Заставляем робот ехать вперед (настройка портов)
//-----------------------------------------------------------------------------------------
void start();
//Настройка АЦП
//-----------------------------------------------------------------------------------------
void init_adc();
//Чтение из АЦП
//-----------------------------------------------------------------------------------------
unsigned int read_adc(unsigned char Pin_ADC);
//Настройка таймера 0 и 2
//-----------------------------------------------------------------------------------------
void init_timer02();
//Настройка таймера 0 и 2
//-----------------------------------------------------------------------------------------
void init_timer1();
// Вызов прерывания
//-----------------------------------------------------------------------------------------
interrupt [TIM1_OVF] void workplease(void);
/////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// Функция main //////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
void main()
{
init_adc();
init_adc();
init_timer02();
init_timer1();
start();
#asm("sei") // Разрешение прерывания
while(1)
{
}
}
/////////////////////////////////////////////////////////////////////////////////////////
////////////////////// Описание функций /////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// Установка АЦП
//-----------------------------------------------------------------------------------------
void init_adc()
{
ADMUX = 0x40U; //выбираем источник питания АЦП 5v
ADCSRA |= 0x07U; // устанавливаем предделитель 128 (ADPS2, ADPS1, ADPS0), он нужен из-за того, что ацп занимает много тактов
ADCSRA |= 0x80U; // Включаем АЦП (ADEN)
}
// Чтение из АЦП
unsigned int read_adc(unsigned char Pin_ADC)
{
ADMUX |= Pin_ADC & 0x07U; // Разрешаем менять только 3 последний бита
delay_us(10); // Задержка на 10 микросек по даташиту
ADCSRA |= 0x40U; // Выставлем бит ADIF для запуска преобразования
while((ADCSRA & 0x10) == 0); // Ждем пока оно совершится
return ADCW; // Возвращем сразу значение старшего и младшего бита АЦП
}
// Порты
//-----------------------------------------------------------------------------------------
void start()
{
DDRD |= 0x80U;
DDRB |= 0x08U;
DDRC |= 0x82U;
PORTC |= 0x82U;
}
// Таймеры 0 и 2
//-----------------------------------------------------------------------------------------
void init_timer02()
{
// Указываем явным образом начальное значение регистра счета
TCNT0 = 0x00U;
TCNT2 = 0x00U;
// Укахываем начальное значение регистра сравнения
// Впоследствии оно будет меняться ШИМом
OCR0 = 0x3F;
OCR2 = 0x3F;
// Регистр настройки
TCCR0 = 0x48U; // Fast PWM
TCCR0 |= 0x20U; // Сброс в 0 при прямом счете
TCCR0 |= 0x01U; // Считаем ипульсы кварцевого генератора без предделителя
TCCR2 = 0x48U; // Fast PWM
TCCR2 |= 0x20U; // Сброс в 0 при прямом счете
TCCR2 |= 0x01U; // Считаем ипульсы кварцевого генератора без предделителя
}
// Таймера 1
//-----------------------------------------------------------------------------------------
void init_timer1()
{
TCCR1B |= 0x04U; // устанавливаем режим СТС (сброс по совпадению
TIMSK |= 0x10U; // устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
OCR1AH = 0b00000111; // определяем число сравнения. Определяем как часто делать прерывания
OCR1AL = 0b00000000;
TCCR1B |= 0x01U; //запуск таймера без предделителя
}
// Прерывание
//-----------------------------------------------------------------------------------------
interrupt [TIM1_OVF] void workplease(void)
{
x = read_adc(0x00); // Значение с ножки А0
y = read_adc(0x01); // Значение с ножки А1
K = x - y; // Модуль разности
if (x < y)
OCR0 = OCR0 - K * 10;
else
OCR2 = OCR2 - K * 10;
}
Раздел: AVR