Появилась идея как использовать прерывание со входа - сразу засчитать нажатие, но игнорировать повторное нажатие этой же кнопки определённое время. Ну и конденсаторы конечно, тут без них плохо будет.
Но теперь, если у меня будет 16 кнопок, то в прерывании задержусь на 1600тактов, плюс, допустим, 400 тактов на всякую другую фигню.
Если у вас 16 кнопок, для их считывания ставьте соответствующую микросхему, например, ТМ1638. Она вроде как может работать с 24 кнопками, да ещё и выводить информацию на семисегментный дисплей (не помню, вроде 10 разрядов). Управляется по SPI. На чём сейчас пишу, одна простая команда считывания с ТМ1638, есть даже с учётом дребезга, всё банально. В ЧипДипе ТМ1638 стоит 18 рублей, это мелочь.
Да ведь это несложно сделать в конечном автомате. Кнопка или концевик - штука очень медленная, достаточно опрашивать 1 раз в миллисекунду (понятно, что если концевик можно "проскочить", то придется задействовать прерывание, но во всех остальных случаях это не нужно). Каждой кнопке заводим структуру: предыдущее состояние, нонешнее состояние, время последней смены состояния. Если еще счетчик нажатий ввести, можно и несколько нажатий подряд детектировать (а по прошествии определенного времени сбрасывать в нуль). Заодно и "антидребезг" программный. У меня обычно новая смена состояния допускается не раньше, чем через 50-80мс после предыдущей. Вот такой простой код.
Тоже интересное решение. Спасибо!
А вообще вариантов появляется намного больше, чем успеваю реализовать. Так я буду делать 1000 + 1 реализацию обработки кнопок, наверное нужно решать проблемы по мере появления.
А то уже количество строк кода для обработки нажатия приближается к 500 (правда вместе с комментариями и дефайнами). А в итоге при самых простых настройках, дают всего 20 строк ассембелернрого кода. Но правда если включить все опции(долгое нажатие, автосброс неиспользуемых нажатий и т.п.), то ассемблерный код разрастается до почти 100 строк, но при этом в нормальном состоянии из-за условных переходов отработает за несколько тактов.
... А вообще вариантов появляется намного больше, чем успеваю реализовать ...
Вчерашняя установка: нужно было портировать программный код с ARM (48 MHz) на PIC (внурт. 4 MHz -> /4 = клок 1 MHz) (для управления устройством, сигналы в областью x1..x10 μs). В рабочем коде возникали большие непредсказуемые паузы, пришлось полностью переработать вычислительную часть (битовые операции, сдвиг и т. д.). А на ARM код работает без всяких условий, со временем вообще не думал об оптимизации, напр. в отношении количества инструкций).
Так что пусть будут варианты решения, через некоторое время вспомните, что уже тестировали другие методы/способы, и быстро их примените .
P.P.S. Если можно подскажите на сколько в норме можно занимать прерывание в тактах или в миллисекундах в условиях когда в других прерываниях нет ничего важного и в условиях когда что-то есть. Желательно с конкретными примерами - например если используется UART на скорости 19200, то не больше столько-то. … А то уже количество строк кода для обработки нажатия приближается к 500 (правда вместе с комментариями и дефайнами).
В прерываниях предпочитаю только необходимый минимум, десяток, другой ассемблерных команд. Остальная обработка – в основной программе. Это избавляет от ряда проблем. Иногда можно вообще не прыгать в прерывания, а работать по аппаратному флагу прерывания. Часто опрос кнопок можно делать в основном круге вообще без прерывания, это проще. Прямой связи со скоростью UART нет, всё зависит от построения программы. Для такой простой задачи 500 строк – это ужас. Наверно, у вас пройдёт простой вариант, на основном круге в свободном окне делать опрос кнопок с учётом дребезга. Спецы критикуют, но очень просто и надёжно.
Вообще-то, 2к инструкций при 20М даст время 0.1 мс. За две страницы не смогли этого вычислить. Что такое 0.1 мс в прерывании (с отсутствием приоритетного арбитража)? При отсутствии DMA это означает отказ работы при приеме длины двух символов. Т.е. 19200+ это гарантированный сбой приема. Если устройство живет не на 2400-9600, что никто ставить не будет, то сие "плоскостопие" означает полный черный ящик с веревочками - внешние интерфейсы невозможны.
if (btn_is_clicked(hi_btn_info.state)) { on_hi_click(); btn_reset(&hi_btn_info); } else if (btn_is_long_clicked(hi_btn_info.state)) { on_hi_press(); btn_reset(&hi_btn_info); } clock_compare_incr_fegi(compare, BTN_LOOP_STEPS_OF_CLOCK); }
И всё это крутится вне прерывания в основном цикле (естественно не каждый раз, а раз в 10ms). До нормального кода клавиатуры(который не стыдно было бы показать) руки так и не дошли, пока только наброски.
Вообще-то, 2к инструкций при 20М даст время 0.1 мс. За две страницы не смогли этого вычислить. Что такое 0.1 мс в прерывании (с отсутствием приоритетного арбитража)? При отсутствии DMA это означает отказ работы при приеме длины двух символов. Т.е. 19200+ это гарантированный сбой приема. Если устройство живет не на 2400-9600, что никто ставить не будет, то сие "плоскостопие" означает полный черный ящик с веревочками - внешние интерфейсы невозможны.
Пару байтов не принять, гарантируемый сбой, внешние интерфейсы невозможны – какой-то у вас всё сильно проблематично. Для многих задач подойдёт простой метод: в основном круге по установившемуся флагу прерывания USART (например, от компьютера) перейти на программу связи через USART и провести связь. Здесь всё просто, скорость USART не важна, принять можно и пару байт, и пару сотен, и пару килобайт, DMA не нужен. Конечно, есть специфика задачи.
Simon.S Вы писали на ассемблере, а тут вроде как СИ. СИ для меня замороченный язык. На современном ассемблере строчек, пожалуй, поменьше будет и читаемость лучше.
На вкус и цвет, как говорится... Для меня ассемблер замороченный. Не скажу, что совсем тёмный лес, просто смысла в нём особого не вижу. Пока ни разу в жизни не пригодился, даже когда работал разработчиком. Для души конечно интересно - померяться у кого код, меньше и быстрее. Меня поэтому MCU и привлекают, я С понял только тогда, когда начал разрабатывать под AVR. Но каждому своё - кого-то и ардуино устраивает, а я такого вынести не могу
Добавлено after 2 minutes 9 seconds: Для меня самая большая проблема придумать проект, который я не смогу купить быстрее и дешевле, чем самому разработать. Вроде почти всё уже придумали. Поэтому больше экспериментирую, чем реально что-то делаю.
Штаааа????!!!!1111 Ничего глупее придумать не могли? Весь смысл языков высокого уровня - это управление сложностью кода. Что собственно становится возможным именно благодаря высокой читабельности кода. В отличии от ассемблера. Вы просто не знаете ЯВУ. Поэтому и пишите всякую чушь. ЗЫ. Для определенности. Не нужно приводить код автора темы в качестве примера "замороченности". Это точно НЕ референс.
В фирме, где я первый раз устроился на работу говорили, что железо стоит дешевле, чем работа программиста. Я до сих пор согласен с этим утверждением. Но, как уже писал, MCU нравится именно сложностью - ограниченные ресурсы, да и много чего вспомнить пришлось, что во время учебы, не особо воспринималось.
Добавлено after 3 minutes 50 seconds: А соответственно и лучше понять. Я вообще СИ освоил после школьного Паскаля - писал, писал код на Делфи, а потом понял, что пишу почти на чистом WinAPI(стандартные формы, меня соответственно не устраивали). Когда понял, за день перешёл на СИ, но ещё долго вникал в тонкости.
Штаааа????!!!!1111 Ничего глупее придумать не могли? Весь смысл языков высокого уровня - это управление сложностью кода. Что собственно становится возможным именно благодаря высокой читабельности кода. В отличии от ассемблера. Вы просто не знаете ЯВУ. Поэтому и пишите всякую чушь.
Я пишу про условно названный современным ассемблер. В нём встроены элементы ЯВУ, это сильно упрощает разработку. Например, в основном круге опрос пары кнопок (Start и Stop) можно сделать таким: Key_Read If Keys = Key_Start Then Goto L_0 If Keys = Key_Stop Then Goto L_ 1 Встроенная команда Key_Read три раза с заданным интервалом читает порт до тех пор, когда данные отсчёты совпадут, это защита от дребезга. Результат – в регистре Keys. Key_Start и Key_Stop – числа, соответствующие нажатой кнопке. Далее обработка нажатой кнопки Start, ожидание отпускания кнопки: L_0: Key_Read If Keys <> 0 Then Goto L_ 0 …… Немного упростил для читаемости. Этого языка вы не знаете, но, наверно, и так всё понятно. Писать просто, читаемость хорошая, даже комментарии не нужны, 6 простеньких строчек. Можете сравнить с СИ. Правда, при таком опросе программа задержится на опросе кнопок, но в большинстве случаев это несущественно. Если нужно определить длительное и короткое нажатие, можно запустить таймер. Если фиксированное время основного круга, наверно, можно обойтись без таймера. 500 строк у ТС для такой простой задачи шокировали.
Например, в основном круге опрос пары кнопок (Start и Stop) можно сделать таким: Key_Read If Keys = Key_Start Then Goto L_0 If Keys = Key_Stop Then Goto L_ 1.
Называть это "читабельным" - бред сивой кобылы. Спорить о вкусе устриц нужно с теми, кто их ел... (с) Сначала хотя бы ознакомьтесь с Си, а потом пытайтесь оценить "читабельность".
КРАМ Этот «бред сивой кобылы» неплохо работает, а время написания – минуты. Насчёт читабельности. Интересно, какие у вас затруднение возникли при чтении этих команд, что непонятного. На мой взгляд, это совсем простые строки. Насчёт СИ. Изучишь СИ, а он окажется хуже, впустую потрачено время.
Этот «бред сивой кобылы» неплохо работает, а время написания – минуты.
Это зависит от сложности алгоритма. Помигать LED-ом или прочитать клаву - это суперпримитивные задачи. Макросы АСМа - это беспонтовый костыль. Чисто листинг сократить.
Насчёт читабельности. Интересно, какие у вас затруднение возникли при чтении этих команд, что непонятного. На мой взгляд, это совсем простые строки.
В том и дело, что простые. Текст понятен до уровня его исполнения. Алгоритм в нем вообще не читается. А под читабельностью понимается не код, а алгоритм.
Встроенная команда Key_Read три раза с заданным интервалом читает порт до тех пор, когда данные отсчёты совпадут, это защита от дребезга. Результат – в регистре Keys. Key_Start и Key_Stop – числа, соответствующие нажатой кнопке.
В догон. Во первых, уже обсуждали как выглядит защита от дребезга. "Читать три раза подряд с заданным интервалом" - совершенно пустое мероприятие. Мало того, оно еще и блокирующее или требует специально выделенного таймера. Во вторых, кнопки могут висеть на разных портах и все "числа соответствующие данной нажатой кнопке" идут попесдэ лесом и болотами... В третьих, AVR является RISC машиной, то есть вся математика возможна только с РОНами. А это значит, что регистр Keys - это РОН. Со всеми вытекающими последствиями для остального кода и его читабельности. ЗЫ. Штобтызнал. Вот так выглядит функция подсчета CRC16 на Си. Абсолютно для любого контроллера любой разрядности.
for (i=0;i<len;i++) { crc^=data[i]; for (k=0;k<8;k++) if((crc&0x1)!=0) crc=(crc>>1)^POLINOM; else crc=crc>>1; } return ~crc; }
Эта функция не зависит от вызываемого ее кода. То есть может работать с любыми разными исходными массивами программы. Транслируется для 32-битного ARM так (оптимизация о3):
ГЫММ.... А как, к примеру, на СИ будет выглядеть типичный для ассемблера приём условного возврата из прерывания подстановкой адреса возврата в стеке? Т. Е. Прерывание: Загрузить в стек адрес перехода к обслуживаемых программе, которая завершается по RET И выполнить стандартное для прерывания RETI Далее программа прыгает на "длинный обработчик" при разрешённых прерываниях. По завершении того "длинного обработчика" происходит возврат на предшествовавший прерывания участок основной программы.
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения