Необходимо при переключении кнопкой с помощью оператора switch включать мигание светодиода с различной частотой на каком либо выводе.при использовании конструкции (для примера): PORTB |= (1<<PB0); _delay_ms(100); PORTB&= ~(1<<PB0); _delay_ms(100); необходимо зациклить ее в теле case,но невозможно переключить switch в следующий case.Просто невозможно выйти из бесконечного цикла. Я использовал while(),может быть есть какой либо способ решить эту проблему, я начал изучать программирование МК недавно и до сложных кодов еще мне очень далеко. Надеюсь на помощь. Спасибо.
для реальной помощи положено приводить исходный код и схему. а также нужно подробно и четко описать, что тебе надо и как это должно работать. при предоставленном минимуме информации могут помочь только гадалки и экстрасенсы.
_________________ Мудрость приходит вместе с импотенцией... Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
#include <avr/io.h> #define F_CPU 8000000UL #include <util/delay.h> #define time 300 //attiny2313,8Mhz,ДЕЛИТЕЛЬ НА 8 ОТКЛЮЧЕН
void pause (unsigned long a)//Использую вместо стандартной задержки { unsigned long counter ; for(counter=a;counter>0;counter--) asm("nop"); } int main(void) { uint8_t i=0; DDRD = 0xFF; PORTD=0x00; DDRA = 0x00; PORTA|=(1<<PA0); while(1) { if (~PINA&(1<<PA0)) { if (i<3) { i++; } else { i=0; } } switch(i) { case 1: PORTD|=(1<<PD0); pause (10000L*time); PORTD&=~(1<<PD0); pause (10000L*time); break;
case 2: PORTD|=(1<<PD0); pause (5000L*time); PORTD&=~(1<<PD0); pause (5000L*time); break;
case 3: PORTD|=(1<<PD0); pause (1000L*time); PORTD&=~(1<<PD0); pause (1000L*time); break;
} _delay_ms(300); } }
При симуляции в Proteus зацикливается в первом case , т.е. не переключается в следующий .На макетной плате после первого нажатия кнопки светодиод горит постоянно примерно 5 сек(pause (10000L*time) и потом гаснет ,дальнейшие манипуляции кнопкой просто повторяют эту картину(нет мигания светодиода). Что касается студента - я вышел на пенсию и для поддержания здоровья занялся программированием МК, база у меня есть(физфак БГУ) и пока голова работает хочу нагружать ее насколько это возможно. В марте мне будет 71. Спасибо за Ваши комментарии, надеюсь на Вашу помощь.
Качественное и безопасное устройство, работающее от аккумулятора, должно учитывать его физические и химические свойства, профили заряда и разряда, их изменение во времени и под влиянием различных условий, таких как температура и ток нагрузки. Мы расскажем о литий-ионных аккумуляторных батареях EVE и нескольких решениях от различных китайских компаний, рекомендуемых для разработок приложений с использованием этих АКБ. Представленные в статье китайские аналоги помогут заменить продукцию западных брендов с оптимизацией цены без потери качества.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Да, еще на AVR же вроде int 16-ти битный, значит нужно при умножении приведение к uint32_t использовать... Наверно эффективнее сразу перемноженное хранить:
Код:
uint32_t arr[] = { 10000 * time, 5000 * time, 1000 * time };
while(1) { if (~PINA & (1<<PA0)) { if(++i >= 3) i = 0; }
Опять же, это примерный код, я его не проверял потому что с AVR уже давно дела не имею, мелкие правки нужно самому делать. Например, если массив 32-х битный, то time должен быть задефайнен как 32-х битное значение.
Последний раз редактировалось Reflector Вт окт 12, 2021 12:19:07, всего редактировалось 2 раз(а).
Заголовок сообщения: Re: Как поместить цикл в case оператора switch
Добавлено: Вт окт 12, 2021 12:19:02
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52 Сообщений: 4470 Откуда: Главный Улей России (Moscow)
Рейтинг сообщения:0
Как уже сказали, switch у Вас реагирует только на значения i=1, 2 или 3, а переменная i принимает значения 0..2 Соответсвенно, case 3 у Вас никогда не сработает. Ну и пока кнопка нажата, у Вас переменная i будет постоянно меняться, пока Вы ее не отпустите. Как я понял, вы хотите мигать светодиодом с переключаемой с помощью кнопки задержкой. Вам нужно после фиксации факта нажатия кнопки ожидать ее отпускание и уже после отпускания инкрементировать переменную i. Вам еще нужно изучить такой эффект как "дребезг контактов" и методы борьбы с ним. Ибо в Протеусе дребезга нет, а в реальной кнопке он есть.
И чтение лучше явно проверять:
Код:
if( (PINA & (1<<PA0)) == 0) // Бит, соответсвующий выводу PA0 равен нулю (прижали подтянутую ногу к минусу) { // Делаем то, что надо }
Мало того, пока протекают задержки, весь цикл заморожен и даже кнопка не опрашивается. Для решения таких проблем используют неблокирующие задержки на "системном таймере", программу разбивают на модули и реализуют их в виде конечных автоматов, которые меняют свои состояния в зависимости от различных событий и делают различные действия в зависимости от своего состояния.
_________________ I am DX168B and this is my favourite forum on internet!
Последний раз редактировалось DX168B Вт окт 12, 2021 12:29:28, всего редактировалось 1 раз.
Ну и пока кнопка нажата, у Вас переменная i будет постоянно меняться, пока Вы ее не отпустите.
Там в конце задержка 300ms, если кнопку быстро нажимать, то для проверки сойдет, а дальше если еще и с антидребезгом делать, то это уже продвинутый уровень
Вариантов решения много. Задержки лучше бы не использовать, или использовать по минимуму. Для организации задержек идеально подходят таймеры чипа плюс флаги. 1) заводим таймер на срабатывание прерывания с частотой, например в 10 мс. 2) в обработчике прерывания просто инкрементируем переменную-счетчик (не забыть сделать ее при определении как volatile) 3) в начале main обнуляем переменную-счетчик и задаем переменную - максимум (например, через настройку индекса массива на его начало, как вам уже предлагали) 4) главный цикл: 4.1) читаем состояние кнопки (кнопок) 4.2) каскад проверок: Если переменная - счетчик достигла значения переменной - максимум, обнуляем счетчик и инвертируем выход светодиода. Например, если время свечения / паузы светодиода должно быть полсекунды, переменная - максимум должна быть равна 50. Если была нажата кнопка, переопределям переменную - максимум (например, через приращение индекса массива, как вам уже предлагали)
Вроде всё. В протеусе должно взлететь, я думаю. В реальной схеме нужно будет добавить обработку дребезга контактов кнопки.
Заголовок сообщения: Re: Как поместить цикл в case оператора switch
Добавлено: Пт окт 15, 2021 16:19:30
Друг Кота
Карма: 25
Рейтинг сообщений: 99
Зарегистрирован: Вс янв 24, 2010 19:19:52 Сообщений: 4470 Откуда: Главный Улей России (Moscow)
Рейтинг сообщения:0
Рады, что смогли чем-то помочь.
Вообще, можете взять за правило. Пишите один раз код, реализующий задержки на таймере и каждый раз, когда создаете проект, копируете туда этот код и налаживаете его работу. Задержки на таймере позволяют организовать асинхронные задержки, а таких задержек можно организовать великое множество. Саму же программу реализовать можно в виде конечного автомата, который будет состоять из множества состояний для различных действий. Главный цикл постоянно проходится по автомату и выполняет действия, согласно текущему состоянию и переключается в другие состояния по каким-то событиям, значениям в переменных или флажках. Благодаря такому подходу легко можно реализовать нечто, вроде "мигать светодиодом в течении 10 секунд. Если за это время нажали кнопку, зажечь светодиод, а иначе потушить." Есть по этим вещам множество статей в блоге easyelectronics.
Вот пример того, как выглядит один из конечных автоматов в одном из моих проектов: СпойлерТут язык C++, но это не суть. Эта функция постоянно вызывается из главного цикла. Она реализует опрос клавиатуры и антидребезг. Состояния автомата определяются перечислительным типом enum KbProcState (это такой удобный способ дать числам названия) и хранятся переменной state Тут же используются и задержки с таймером.
Все разбито на определенный порядок действий. Состояния физических кнопок читаются постоянно, функцией CheckPressedKey() А дальше автомат:
1 состояние (оно же и начальное): Проверяется, нажато ли вообще что-то. Если нет, то остаемся в этом же состоянии. Если нажалось что-то, значит запускаем таймер антидребезга и меняем состояние автомата (переход во второе состояние)
2: Проверка, не поменялся ли номер нажатой кнопки при очередном опросе. Если в течении задержки антидребезга номер не менялся, значит кнопка в стабильном состоянии, происходит переключение в следующее состояние. Если же номер изменялся (контакт еще нестабилен), то автомат переключается в начальное состояние и все начинается заново.
Последующие состояния уже детектируют короткое или длинное нажатие и выставляют событие (коротко/длинно нажата такая-то кнопка). Это событие уже используется другими конечными автоматами, реализованными в программе.
Код:
/////////////////////////////////////////////////////////////////////// // Keyboard process void CKeyboard::Process() { // Detect pressed key KbKeys pressedKey = CheckPressedKey(); // Keyboard process state machine switch (state) { // Initial state case KbProcState::INITIAL: if(pressedKey != KbKeys::KEY_NONE) { prevKey = pressedKey; kbTim.SetTimer(KEYBOARD_DEBOUNCE_DELAY);// begin debounce timer state = KbProcState::KEY_PRESS_DEBOUNCE; } break;
Возникла проблема. Хочу написать код для переключения кнопками(например три кнопки) трех выходов. С помощью методики "конечных автоматов" попробовал сделать программу. Но получился трехканальный переключатель без фиксации ,т.е. включение и выключение любого канала происходит независимо от состояния других каналов. Мне нужно превратить этот переключатель в переключатель с фиксацией. Т.е. при нажатии на любую кнопку остальные выходы обнуляются(неважно что на них было - 0v,+5v или blink для светодиода) и на выходе канала с этой включенной кнопкой появляется нужный сигнал +5v или blink.Причем выключить этот канал можно включением другого("переключение с фиксацией") или просто повторным нажатием на кнопку включенного канала. Проблема в том, что я не смог добиться отключения активного канала включением любого другого. Перепробовал различные приемы выключения других выходов при включении нужного мне канала. Помещал код типа PORTB&=~(1<<PB3); в switch для blink_click,пробовал в button_ KA после строки поднятия флага fclk: if(fclk =1){PORTB&=~(1<<PB3)}.Номера портов здесь условные. Я понимаю, что мне не хватает опыта для использования таких тонкостей. Поэтому и прошу помощи. Спасибо. В архиве код и протеус https://drive.google.com/file/d/1kOjc23 ... sp=sharing
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 39
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения