Код: Выделить всё
#define F_CPU 16000UL
#define fwd PORTB |=(1<<PB2); PORTB &=~(1<<PB0); // fwd - вперед
#define bwd PORTB |=(1<<PB0); PORTB &=~(1<<PB2); // bwd - назад
#define stp PORTB &=~(1<<PB0); PORTB &=~(1<<PB2); // stp - стоп
#define pause1 4 // 6ч - 1350
#define pause2 3 // 3ч - 675
#define pause3 2 // 90мин - 330
#define pause4 1 // 45 мин - 165
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
// - Varriable -//
unsigned int timer=0; // счетчик таймера (увеличивается в прерывании каждые 16 сек)
void movie ()
{
fwd // включаем двигатель вперед
_delay_ms(600); // пауза 0,5 секунды
stp
_delay_ms(100);
bwd
_delay_ms(300);
stp
timer = 0;
}
unsigned int pause () // время между сработками (pause*16.25)секунд
{
ADMUX = (0<<REFS0)| // Bit 6 – Источник опорного напряжения (0 - VCC, как источник опорного напряжения, 1 - Встроенный источник опорного напряжения)
(1<<ADLAR)|
(1<<MUX1)| // Bit 1 – Analog Channel and Gain Selection Bits (Выбор канала ADC (см. datasheet)) в данном случае выбираем ADC2
(0<<MUX0); // Bit 0 – Analog Channel and Gain Selection Bits (Выбор канала ADC (см. datasheet))
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA & (1 << ADIF)) == 0); // Ждем флага окончания преобразования
ADCSRA|=(1<<ADIF);
if (ADCH <= 53) // в зависимости от АЦП изменяем величину переменной pause
{
return (pause4);
}
if ((ADCH <= 89) && (ADCH >= 54))
{
return (pause3);
}
if ((ADCH <= 125) && (ADCH >= 90))
{
return (pause2);
}
return (pause1);
}
bool light ()
{
ADMUX = (0<<REFS0)| // Bit 6 – Источник опорного напряжения (0 - VCC, как источник опорного напряжения, 1 - Встроенный источник опорного напряжения)
(1<<ADLAR)|
(1<<MUX1)| // Bit 1 – Analog Channel and Gain Selection Bits (Выбор канала ADC (см. datasheet)) в данном случае выбираем ADC2
(1<<MUX0); // Bit 0 – Analog Channel and Gain Selection Bits (Выбор канала ADC (см. datasheet))
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
ADCSRA|=(1<<ADIF);
if ((ADCH <= 176)) // в зависимости от АЦП изменяем light
{
return false;
}
else
{
return true;
}
}
ISR (TIM0_OVF_vect)
{
timer++; //Увеличение timer на 1 каждые 16 секунд
if (timer >= pause()) // если timer больше полученного значения pause
{
if (light()) // и "светло"
{
movie(); // срабатываем
timer = 0; // обнуляем timer
}
else // а если timer больше полученного значения pause и "темно"
{
asm volatile ("nop");
}
}
}
ISR (INT0_vect)
{
movie();
timer = 0;
}
int main(void)
{
DDRB = 0b00101; //0 - Назад (выход), 1 - Кнопка (вход), 2 - вперед (выход), 3 - датчик света (вход), 4 - датчик режима(вход)
PORTB = 0b00010;
TCCR0A |=(0<<COM0A0) //Инициализация таймера
|(0<<COM0A1)
|(0<<COM0B0)
|(0<<COM0B1)
|(0<<WGM01)
|(0<<WGM00);
TCCR0B |=(0<<FOC0A)
|(0<<FOC0B)
|(0<<WGM02)
|(1<<CS02)
|(0<<CS01)
|(1<<CS00);
TCNT0 =0;
ADMUX = (0<<REFS0)| // Bit 6 – Источник опорного напряжения (0 - VCC, как источник опорного напряжения, 1 - Встроенный источник опорного напряжения)
(1<<ADLAR); // Bit 5 – ADC Left Adjust Result (1 - левое выравнивание результата; 0 - правое выравнивание результата измерения)
ADCSRA = (1<<ADEN)| // Bit 7 – ADC включатель (1- включен, 0 - выключен)
(0<<ADATE)| // Bit 5 – ADC постоянное преобразование (1 - включено, 0 - выключено)
(1<<ADPS2)| // Bit 2 – ADC Prescaler Select Bits Выбор частоты преобразования (см. datasheet)
(1<<ADPS1)| // Bit 1 – ADC Prescaler Select Bits Выбор частоты преобразования (см. datasheet)
(1<<ADPS0); // Bit 0 – ADC Prescaler Select Bits Выбор частоты преобразования (см. datasheet)
TIMSK0 |=(1<<TOIE0); // Разрешение прерывания по переполнению таймера 0
GIMSK |=(1<<INT0); // включение внешних прерываний
sei(); // Общее разрешение прерываний
while (1)
{
set_sleep_mode(SLEEP_MODE_IDLE); //Закомментировав
sleep_enable(); // эти строчки
sleep_cpu(); // все работает так как надо!
if (timer >= 5000)
{
cli(); // общий запрет прерываний
TIMSK0 &=~(1<<TOIE0); // отключение прерываний по таймеру (1 раз в 16 секунд)
sei(); // общее разрешение прерываний
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // установка "летаргического сна"
sleep_enable(); // разрешение спящего режима
sleep_cpu(); // сон
sleep_disable(); // запрет сна
cli(); // общий запрет прерываний
TIMSK0 |=(1<<TOIE0); // включение прерываний по переполнению таймера (1 раз в 16 секунд)
sei(); // общее разрешение прерываний
TCNT0 =0; // сброс счетчика
timer = 0;
}
}
}Все остальное время целесообразно спать.
Проблема: из режима IDLE контроллер по прерыванию то ли не выходит, толи выходит не полностью. ADC3 и ADC2 не реагируют на изменение напряжения. Как только закомментирую строчки перевода в спячку - все работает идеально. Кстати, внешнее прерывание в любом случае отрабатывает прекрасно! Ничего не понимаю. Помогите, кто чем может. Пожалуйста



