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; } } }
В нем реализована сработка некоего двигателя с частотой, которая задается в переменной pause в зависимости от значения ADC3. Величина pause сравнивается с переменной timer, и когда timer становится >= pause, происходит сработка. Причем , если пришло время сработки, а переменная light (зависит от ADC2) = false, то сработки не будет. Весь этот алгоритм находится внутри прерывания по переполнению таймера 0, т.е. по моим настройкам примерно 1 раз в 16 секунд. Все остальное время целесообразно спать. Проблема: из режима IDLE контроллер по прерыванию то ли не выходит, толи выходит не полностью. ADC3 и ADC2 не реагируют на изменение напряжения. Как только закомментирую строчки перевода в спячку - все работает идеально. Кстати, внешнее прерывание в любом случае отрабатывает прекрасно! Ничего не понимаю. Помогите, кто чем может. Пожалуйста
Спасибо всем, кто не остался в стороне, Ответом на мои вопросы является фраза: "Не фиг в прерывании вызывать функции". Нужно перерабатывать алгоритм. Тему можно закрывать.
Добавлено after 2 minutes 36 seconds: я наоборот стараюсь всё в прерывания засунуть и, тем самым, например, избавиться от конструкций типа _delay_ms (xxx).
Добавлено after 3 minutes 24 seconds: так, по прерыванию "системного" таймера удобно разом и семисегментник крутить и кнопки (со встроенным антидребезгом и определением длительности и кратности нажатия) и прочую периферию разквартировать, чтобы у них дружная "коммуналка" получилась... и функции применяю - полёт нормальный.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Это при условии, что время выполнения функции гарантировано меньше периода таймера. Иначе результат непредсказуем. СпойлерПомню, в оочень старом проекте на оооочень медленном старом ( выпускаемом ло сих пор ) МК довольно большое вычисление распиливал на части, и пока АЦП наполнял 64 точки первого буфера, МК без особой спешки просчитывал второй. А delay - действительно зло. Таймерные прерывания нужно наполнять полезной работой - с учетом вышесказанного. Это мое мнение, и я так думаю Блин, юбилейный 4000-й пост! Пойду хлебну валерьянки
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
if (timer >= pause) { if (light<=100) { movie(); } else { _delay_us(1); }
} set_sleep_mode(SLEEP_MODE_IDLE); //при комментировании sleep_enable(); // этих строчек sleep_cpu(); // все работает sleep_disable(); // нормально 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; } } }
ADC3 вообще не считывается! ADC2 считывается с ошибкой, т.е. не то, что должно быть. В чем подвох? В чем ошибка? Где собака зарыта? В протеусе работает идеально. Если IDLE убрать - тоже прекрасно работает.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Случилось чудо!! Наконец-то получилось! Ответ нашелся в datasheet`e Attiny13 на стр.82, пункт 14.3, 3 абзац (перевод с помощью онлайн переводчика): АЦП включен по настройка АЦП включить бит aden в ADCSRA. Опорное напряжение и входных каналов не вступят в силу пока Аден установлен. АЦП не потребляет мощность, когда Аден очищается, поэтому рекомендуется отключить перед входом АЦП мощности сохранение режима сна. как-то так... Итог: в первом варианте перед переходом в IDLE устанавливаю ADEN в 0. И перед запуском конвертации устанавливаю ADEN в 1. Все работает прекрасно. Может кому-нибудь мой опыт пригодится
как ни странно, но мне, примерно через месяц эта инфа скорее всего и пригодится тиньки 13 придут, полюбому чего нибудь из них наделаю.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 46
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения