набросал тест "помограть" с "кнопкой" - синий св.диод моргает ~ 1Гц - зеленый св.диод - меняет состояние по нажатию на кнопку
есть непонимание: код чтения пина кнопки "тормозит", точнее - если код "чтения" заремить - то син.св.диод переключается "правильно", прим. 1Гц - если код "включить", то син.св.диод переключается прим. в 2 раза медленнее
GPIO_Mode_AIN — аналоговый вход; GPIO_Mode_IN_FLOATING — вход без подтяжки, болтающийся (англ. float) в воздухе GPIO_Mode_IPD — вход с подтяжкой к земле (англ. Pull-down) GPIO_Mode_IPU — вход с подтяжкой к питанию (англ. Pull-up) GPIO_Mode_Out_OD — выход с открытым стоком (англ. Open Drain) GPIO_Mode_Out_PP — выход двумя состояниями (англ. Push-Pull — туда-сюда) GPIO_Mode_AF_OD — выход с открытым стоком для альтернативных функций (англ. Alternate Function). Используется в случаях, когда выводом должна управлять периферия, прикрепленная к данному разряду порта (например, вывод Tx USART и т.п.) GPIO_Mode_AF_PP — то же самое, но с двумя состояниями */
// // 2 LED pin's // GPIOC_init_params.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; // Blue LED PC[8], Green LED PC[9] GPIOC_init_params.GPIO_Speed = GPIO_Speed_10MHz; GPIOC_init_params.GPIO_Mode = GPIO_Mode_Out_PP; // Push-pull output GPIO_Init (GPIOC, &GPIOC_init_params);
// // Button // GPIOC_init_params.GPIO_Pin = GPIO_Pin_0; // user button PA0 GPIOC_init_params.GPIO_Speed = GPIO_Speed_10MHz; // 10-50 по барабану GPIOC_init_params.GPIO_Mode = GPIO_Mode_IPD; // GPIO_Mode_IPD - PD connect GND GPIO_Init (GPIOA, &GPIOC_init_params); // } //////////////////////////////////////////////////////////////////////////////// int main(void) //////////////////////////////////////////////////////////////////////////////// { int cnt = TIMER_CNT; int flag_time = 0; int flag_btn = 0;
Так.... окей. Я понимаю, что это тест, но... Попробуйте иначе.
Код:
#define TIMER_CNT 0xFFFFE / 100
<...> int main (void) { int loop_10ms = 0; int flag_time = 0; int flag_btn = 0; int is_button_pressed = 0; // Добавочный флаг, позволяющий создать из переменной flag_btn триггер
<...>
// Тикает 100 раз в секунду while (1) { if (!(cnt--)) { cnt = TIMER_CNT; loop_10ms++; // Читаем состояние пина. if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) { // Если высокое И ЕСЛИ добавочный флаг НЕ взведён, if (!is_button_pressed) { // Взводим оба флага - добавочный и сам триггер. is_button_pressed = 1; flag_btn = 1; }; } else { // Если кнопка отпущена И ЕСЛИ был взведён дополнительный флаг if (is_button_pressed) { // Сбрасываем его. flag_btn не изменяется, потому что он уже в состоянии "0" из-за кода ниже. is_button_pressed = 0; }; }; }; if (loop_10ms >= 100) { // 1 секунда loop_10ms = 0; flag_time = 1; // Тикнула секунда }; };
if (flag_time) { flag_time = 0; // Сбрасываем флаг if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_8)) { LED_B_CLR; } // invert Blue Led else { LED_B_SET; } }; if (flag_btn) { flag_btn = 0; if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9)) { LED_G_CLR; } // invert Green Led else { LED_G_SET; } }; };
Собственно, что я сделал. Опрос кнопки производится в одном месте, совместно с часто работающим таймером (каждые 10 мс). Таким образом основной цикл, в отличии от кода в Вашем примере, срабатывает чаще. Кстати, в *HDL логике подобный код опроса работал бы, ибо там всё максимально параллельно из-за того, что это аппаратная логика. Но вернёмся к коду. Так как основной цикл крутится уже 100 раз в секунду, требуются дополнительные счётчики, которые будут делить его тики на более редкие. В частности, секундный флаг вызывается каждые 100 итераций (не могу достоверно сказать что прямо так точно, но счётчкики на переменных имеют место быть). При этом, пока флаг секунды не взведён - код, проверяющий этот флаг ниже, не заходит в ветку мигания зелёным диодом. Опрос кнопки так же работает чаще и взводит уже два флага. Первый - для себя, второй - для кода после. Если не использовать два флага, то флаг "кнопка нажата" будет постоянно выставляться в каждом цикле (100 раз в секунду!) и диод будет так же часто менять своё состояние. Второй флаг - позволяет дождаться перехода логического состояния "1 -> 0" и только после этого позволит поднять флаг кнопки вновь. Как бы, всё.
Всё остальное поведение спрятано в прерывании таймера и методах (функциях, если без плюсов) объектов кнопок и диодов. Иначе 99% времени будете проводить над вопросом "чего это оно работает не так как я хочу".
Так.... окей. Я понимаю, что это тест, но... Попробуйте иначе.
а вы мой кот точно смотрели?! пишу с патифона, ваш код еще не щюпал, но по описанию - все тоже самое :о) и что сразу бросается в глаза > основной цикл крутится уже 100 раз в секунду надеюсь, понятно о чем?!
> А чего в этом удивительного? т.е. вас не смущает что "оператор" чтения пина "тормозит" практически пустой while в 2 раза, что реально отражается на прим 100% задержке по сравнению с "пустым циклом задержки"?!
оч. давно, когда разбирался с "avr-мандариной" и работой с портами, набросал примерно такой-же код... и, на ск. я помню, таких проблем не было (если память не изменяет, давно было)
ладушки, доберусь до большой машинки, посмотрим что там да чаво
зы >А их количество и влияние друг на друга неописуенным? если вы про "флаги" то это надо быть безмозглым старым пердуно-котом, что-бы запутаться в структурах-флагов и в том, кто их поднимает а кто их обробатывает и сбрасывает
_________________ Енот - это кот, только инкогнито! p.s. держитесь обоими руками, а то прорвет...
Не смущает. Все флаги и счётчик легли в регистры процессора. Работать с ними легко и быстро. А пин надо вычитать из порта GPIO и наложить маску. Вполне соизмеримо по времени.
Или, например, счётчик перестал помещаться в регистрах и переехал в стек и доступ к нему стал сильно дольше.
а вы мой кот точно смотрели?! пишу с патифона, ваш код еще не щюпал, но по описанию - все тоже самое :о) и что сразу бросается в глаза
У вас основной цикл работает так (псевдокод): while (1) { ЗАДЕРЖКА(0xFFFFE); - Калькулятор говорит, что это около 1 миллиона циклов декремента - проверки - повтора. Грубо говоря, ПАУЗА в 1с. Если (Флаг_ВРЕМЯ) то <...> Если (ПИН==1) то <...> };
В итоге, пока задержка не пройдёт, процесс выполнения не сможет добраться до кода после неё. Значит, нажатие на кнопку обрабатываться только 1 раз в секунду.
Мой код: while (1) { ЗАДЕРЖКА (10мс); Счётчик_МС ++; Если (Счётчик_МС >= 100) то { Счётчик_МС = 0, Флаг_ВРЕМЯ = 1 }; Если (ПИН == 1) то {ФЛАГ_ПИН = 1, ФЛАГ_Триггер = 1};
Если (Флаг_ПИН == 1) то {Флаг_ПИН = 0, Пин = НЕ пин}; Если (Флаг_ВРЕМЯ == 1) то { Флаг_ВРЕМЯ = 0, ДИОД = НЕ ДИОД}; };
Я исползую дополнительные флаги и короткие кванты времени. Согласен, код не сильно отличается, но работает по-разному. В итоге получается примитивный автомат состояний. У вас проблема в коде в задержке, которая просто молотит такты процессора, но не выполняет полезных действий. На самом деле, решить это можно и таймерами и на прерываниях. Но если делать без прерываний, то работать будет приблизительно так как я сделал.
AlanDrakes, вы неправильно поняли как там задержка работает. Он считает количество полных циклов, длительность которых зависит от фазы луны. В этом и проблема.
> нажатие на кнопку обрабатываться только 1 раз в секунду. уточнение - переключение св.д от нажатия !!! синхронизируется !!! с морганием 1го св.диода, т.е. это так и задумано :о)
_________________ Енот - это кот, только инкогнито! p.s. держитесь обоими руками, а то прорвет...
AlanDrakes, вы неправильно поняли как там задержка работает. Он считает количество полных циклов, длительность которых зависит от фазы луны. В этом и проблема.
Оу щи~ Действительно. Тогда я что-то не могу найти в коде примера задержку. =]
sunjob писал(а):
уточнение - переключение св.д от нажатия !!! синхронизируется !!! с морганием 1го св.диода, т.е. это так и задумано :о)
Тогда опишите логику более подробно, ибо теперь стало ещё менее понятно, чего вы хотите добиться. Можете нарисовать диаграмму состояний.
да в коде все-же понятно :о) это был тестовый код, хотел проверить "отладочную" плату, набросал тест, залил и... обнаружил что "чтение" пина занимает "львинную" долю... хотя, до этого, (давно - давно) подобные тестовые скетчи делал в авр-ках, ПРОБЛЕМ НЕ БЫЛО ЗАМЕЧЕНО (ну давно было, не помню тонкости, но вроде как ни чего не "сквозило") :о)
ну вот, поэтому решил у знатоков поинтересоваться
если надо, то, конечно, обьясню "логику мыслей"... но, вроде и так все понятно... просто с патифона не очень удобно шкрябать когТями... а до большого компа пока не добрался, не успеваю :о)
спасибо, парни, за помидоры :о) но все равно не понятно, как так?!
_________________ Енот - это кот, только инкогнито! p.s. держитесь обоими руками, а то прорвет...
сократил текст просто для наглядности. но большие задержки методом cnt-- это как отмерять периоды в несколько месяцев посредством распилки н-ного количества бревен, типа если нужно отмерить 32,25 месяца, значит нужно не останавливаясь распилить 3млн. бревен. для stm32 такой подход - дичь, ведь достаточно просто включить таймер. а по вопросу - как было сказано - надо смотреть листинг.
> Архитектура. Листинги смотри, там всё видно. лааап моих бы не было-бы на форуме, если бы чего... :о) а то я так тоже могу, бороду отрастить, очки напялить потолще (у хозяина стащить еще и трубку)... и умные слова глаголить налево направо :о)
спасибо за умные роковождения :о) надеюсь без обид?! :о) было бы лучше, все таки более развернутый ответ, типа ...опа, а у нас тут мыши...
мур...
_________________ Енот - это кот, только инкогнито! p.s. держитесь обоими руками, а то прорвет...
чтение ножки, наверняка, не причем. более вероятно - в одном случае cnt ячейка памяти, в другом регистр. вот cnt-- и дает существенно разные тайминги Владислав об этом писал. только чего гадать-то, если можно все увидеть в листинге.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 31
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения