В проводных наушниках? Я может быть отстал от жизни, но под проводными наушниками я по умолчанию подразумеваю устройство из динамиков и проводов к ним. Ни те ни другие ничего буферизовать не умеют :)
Ненавижу писать. После 4-5 строк рукописного текста меня начинает чуть ли не трясти от желания закончить побыстрее, скомкать бумагу и пойти напечатать это на нормальной клавиатуре :)
Каждый раз, как вижу ник статью за авторством этого ника, думаю - "Ну может быть хоть в этот раз он хоть какую-то из своих фантазий попробовал реализовать на практике?". Но нет. Мало того, в этот раз он даже не удосужился изучить имеющийся в инете практический опыт реализации некоторых из своих фантазий :)
Мне кажется, что отреагировать на кнопку в прерывании обработкой каких-то данных - это не самая плохая идея.
Угу. По нажатию кнопки отправляем по RS-485 запрос датчику, дожидаемся от него ответ, обрабатываем полученные данные, выводим результат на экран. И за это время пропускаем пять следующих прерываний. Отличный план, что тут может пойти не так? :)
В фоновой программе работает какой-то процесс, и вдруг в прерывании меняется его состояние... сомнительно тоже.
Поэтому в прерывании меняется состояние не процесса, а флага, который фоновая (хотя строго говоря это как раз не фоновая, а активная) программа проверит когда у нее будет для этого возможность.
посмотрите хотя бы как реализован HAL-драйвер в прерываниях таймеров у STM32
Я Вам уже писал: HAL от ST - это далеко не лучший пример для подражания.
На Ардуине не работал, Куб использую только для "конструирования" начальной инициализации периферии, да и то с большой оглядкой. Ардуина - это вообще отдельный разговор. Но тот же IAR, да и Keil вроде тоже, добавят от себя лишь минимальный стартап-код. И насчет "пусть лежит на всякий случай" - линкеры этим уже давно не занимаются даже с минимальным уровнем оптимизации. Если лежит - значит оно где-то используется.
Меня тоже смущает, поэтому я свое некоторое смущение перевел в свой некоторый стыд :) Но у меня и официально купленного софта много, вы не подумайте :)
Iar (на тот момент хороший компилятор - ужасный редактор кода)
Ну, редактор у него и сейчас все еще не идеал :) А версия 9.30 еще и тормозить начала при переключении между режимами отладки и правки кода :) Но вообще это та среда, на которой я остановился много лет назад и до сих пор не жалею.
Так это вопросы к фреймворку, а не к IDE. Вы как в блокноте можете подключить библиотеки на килобайт для простого мигания светодиодом, так и в IDE уложить в 300-400 байт на регистрах вывод измеренного на входе АЦП значения на семисегментные индикаторы.
регулярное сидение на таких "Мега-IDE"(точно так как и дальнейшее сидение после начального вхождения в Arduino-IDE) сводит Ваш дальнейший профессиональный рост в работе с МК, лишь к навыкам работы в конкретной IDE, а не общего понимания специфики процесса программирования МК как класса железяк.
Непонятно. Понимание специфики программирования МК как класса железяк резко пойдет в гору если исходники писать в блокноте, а собирать проект через командную строку с ручным указанием всех ключей компилятора и линкера?
Ну если с возможностью оценки размера и плотности с допустимой погрешностью я еще могу согласиться, то все остальное - только предположения. Например, по Вашим ссылкам пишут, что расчет температуры "основан на предположении, что планета имеет атмосферу, подобную земной с парниковым эффектом за счет наличия 1 % СО2 и при альбедо 0,3". То есть реальная температура экзопланет на самом деле неизвестна. Состав (а зачастую и само наличие) атмосферы так же неизвестны, можно лишь в редких случаях делать предположения типа "вероятно, она содержит пары воды", да и то не для землеподобных планет. По крайней мере беглое гугление говорит, что на данном этапе технологий мы можем хоть как-то оценивать некоторые характеристики атмосферы лишь для очень больших планет с толстым слоем атмосферы и для молодых планет, которые, по сути, еще и полноценными планетами-то не являются.
Соответственно вся землеподобность сводится к "на ней должна быть похожая гравитация и она получает плюс-минус столько же энергии от своей звезды, сколько и Земля от Солнца" :)
Смотрел и щупал, поэтому не использую его в своих проектах. HAL уже вплотную приблизился к ардуино-стилю :)
Оптимизация всегда будет актуальной для нормальных разработчиков, но повторюсь - речь не об оптимизации, а о правильном программировании. Если Вы в прерывании UART начнете обрабатывать пришедшие данные, а в прерывании таймера выполнять код по нажатию кнопок, то рискуете запросто нарваться на ситуацию когда контроллер не будет вылазить из прерываний даже если у него вагон ресурсов.
Я и имел ввиду, что надо передать данные о нажатии кнопки в фоновую программу.
Честно говоря, из текста это совершенно не очевидно, по крайней мере для меня :)
Концепция предполагает удобство программирования без оглядки на ресурсы контроллера.
Речь ведь не о производительности, а о базовых принципах программирования для микроконтроллера. В прерываниях должен быть код, выполняющийся за минимально возможное время, что в 8-битной Ардуине на 8 МГц, что в 32-битном ARM-е на 400 МГц :)
просто посмотрите, как реализованы некоторые библиотеки Arduino. И почитайте статьи по программированию Arduino в интернете.
Это отдельный вид искусства антипрограммирования, согласен. Значит тем более не нужно прививать начинающим эти антипаттерны :)
Зачем хранить инициализирующие параметры кнопок в структуре в оперативной памяти? Ее как правило не так уж много, а изменения этих параметров в процессе работы программы вроде бы не предполагается.
Структура текущего состояния кнопок мне кажется излишне большой. Ниже приведу свой вариант с пояснениями.
"В обработчике прерывания, вместо вывода в терминал сообщений о нажатии кнопки, вы можете разместить полезный код, который будет реагировать на нажатие кнопки." - ну зачем же учить начинающих плохому? В прерывании код должен быть как можно более коротким. В данном случае - только оценка текущего состояния кнопок и все, никаких реакций на их нажатие, тем более никаких медленных блокирующих выводов в UART. Это очень, очень вредная рекомендация.
Размер структуры текущего состояния кнопки можно сделать более компактным - это опять же сократит использование оперативки, как и размещение инициализирующих данных в константах или дифайнах. Вот пример:
enum
{
KB_FREE, // отсутствие событий у кнопки
KB_WORKED, // последнее событие кнопки было обработано
KB_PREPRESSED, // есть сигнал нажатия, идет выжидание антибребезга
KB_SPRESSED, // подтверждено нажатие кнопки после антидребезга
KB_LPRESSED, // кнопка остается нажатой длительное время
KB_SRELEASED, // кнопка отпущена после короткого времени нажатия
KB_LRELEASED, // кнопка отпущена после долгого нажатия
} KBD_STATES;
typedef struct
{
KBD_STATES state;
uint8_t time;
} KEYBOARD;
Структура имеет размер всего 5 байтов, и этого достаточно для обработки короткого и длинного нажатий, а так же отпускания после короткого и длинного нажатий.
Алгоритм обработки каждой кнопки в цикле в прерывании таймера таков:
for (uint8_t kb = 0; kb < keys_count; kb++)
{
switch (Keys[kb].state) // проверяем текущий статус кнопки
{
// если событие кнопки было обработано и сейчас кнопка отпущена,
// то возвращаем ее статус в свободный
case KB_WORKED:
if (!KeyRead(kb)) // если на входе нет сигнала нажатой кнопки
{
Keys[0].state = KB_FREE;
}
break;
// если кнопка в свободном состоянии, или была отпущена после
// любого нажатия, и в данный момент есть сигнал ее нажатия,
// то начинаем обработку антидребезга
case KB_FREE:
case KB_SRELEASED:
case KB_LRELEASED:
if (KeyRead(kb))
{
Keys[kb].state = KB_PREPRESSED;
Keys[kb].time = 0; // обнуляем счетчик времени
}
break;
// если кнопка в состоянии обработки антидребезга и есть сигнал
// нажатия - инкрементируем счетчик и проверяем не достиг ли он времени
// проверки антидребезга, если достиг, то присваиваем кнопке статус
// короткого нажатия.
// Если сигнала нажатия нет, значит проверка антидребезга не прошла,
// обнуляем счетчик времени и возвращаем статус кнопки в свободный.
case KB_PREPRESSED:
if (KeyRead(kb))
{
if (Keys[kb].time > 6) // время обработки антидребезга вышло
Keys[kb].state = KB_SPRESSED;
else
Keys[kb].time++;
}
else
{
Keys[kb].state = KB_FREE;
Keys[kb].time = 0;
}
break;
// если кнопка в состоянии короткого нажатия и есть сигнал нажатия -
// инкрементируем счетчик времени и проверяем не достиг ли он времени
// долгого нажатия, если достиг, то переводим статус кнопки в долгое
// нажатие.
// Если нет сигнала нажатия - значит кнопка была отпущена, ставим
// ей статус "отпущена после короткого нажатия".
case KB_SPRESSED:
if (KeyRead(kb))
{
if (Keys[kb].time > 150)
{
Keys[kb].state = KB_LPRESSED;
}
else
Keys[kb].time++;
}
else
{
Keys[kb].state = KB_SRELEASED;
Keys[kb].time = 0;
}
break;
// если кнопка в состоянии долгого нажатия и есть сигнал нажатия -
// инкрементируем счетчик времени (это просто для легкой организации
// автоповтора нажатий).
// Если нет сигнала нажатия - значит кнопка была отпущена, ставим
// ей статус "отпущена после долгого нажатия".
case KB_LPRESSED:
if (!KeyRead(kb))
{
Keys[kb].state = KB_LRELEASED;
Keys[kb].time = 0;
}
else
Keys[kb].time++;
break;
}
Этот код позволяет достаточно легко организовать и автоповтор нажатия с заданным интервалом - просто проверять значение счетчика времени при статусе кнопки KB_LPRESSED и если он достиг определенного значения - обнулять его и выполнять действия по очередному "нажатию" автоповтора.
Все реакции на события кнопок необходимо размещать в основной программе, а ни в коем случае не в прерывании. Просто в основном цикле (или где это нужно) проверяется текущий статус нужной кнопки и если он не "свободен" (KB_FREE) и не "обработан" (KB_WORKED), то идем выполнять полезный код, связанный с событием кнопки, после чего выставляем кнопке статус "обработан" (KB_WORKED). Этот статус сам сменится на "свободен" при ближайшем очередном вызове прерывания таймера с обработкой состояний кнопок.
По счетчику времени: нет нужды считать в нем миллисекунды или любые другие реальные временные величины. Достаточно считать вызовы прерывания таймера - они все равно следуют с определенным промежутком времени. Поэтому достаточно 1-байтового счетчика, который посчитает, скажем, 5 вызовов (с периодом 20 миллисекунд) вместо 100 миллисекунд для антидребезга. Или 50 вызовов вместо 1000 миллисекунд для долгого нажатия.
Очевидно же, что пишут про задержки наушников, а не внутренностей синтезатора.
В проводных наушниках? Я может быть отстал от жизни, но под проводными наушниками я по умолчанию подразумеваю устройство из динамиков и проводов к ним. Ни те ни другие ничего буферизовать не умеют :)
А откуда такая дикая задержка у проводных наушников?
Ненавижу писать. После 4-5 строк рукописного текста меня начинает чуть ли не трясти от желания закончить побыстрее, скомкать бумагу и пойти напечатать это на нормальной клавиатуре :)
Каждый раз, как вижу ник статью за авторством этого ника, думаю - "Ну может быть хоть в этот раз он хоть какую-то из своих фантазий попробовал реализовать на практике?". Но нет. Мало того, в этот раз он даже не удосужился изучить имеющийся в инете практический опыт реализации некоторых из своих фантазий :)
Будет кто надо. А эти, вероятно, оказались не совсем кем надо.
Угу. По нажатию кнопки отправляем по RS-485 запрос датчику, дожидаемся от него ответ, обрабатываем полученные данные, выводим результат на экран. И за это время пропускаем пять следующих прерываний. Отличный план, что тут может пойти не так? :)
Поэтому в прерывании меняется состояние не процесса, а флага, который фоновая (хотя строго говоря это как раз не фоновая, а активная) программа проверит когда у нее будет для этого возможность.
Я Вам уже писал: HAL от ST - это далеко не лучший пример для подражания.
На Ардуине не работал, Куб использую только для "конструирования" начальной инициализации периферии, да и то с большой оглядкой. Ардуина - это вообще отдельный разговор. Но тот же IAR, да и Keil вроде тоже, добавят от себя лишь минимальный стартап-код. И насчет "пусть лежит на всякий случай" - линкеры этим уже давно не занимаются даже с минимальным уровнем оптимизации. Если лежит - значит оно где-то используется.
Я бы даже немного сузил рамки интереса - 128-512 КБ ПЗУ и 64-192 КБ ОЗУ.
Меня тоже смущает, поэтому я свое некоторое смущение перевел в свой некоторый стыд :) Но у меня и официально купленного софта много, вы не подумайте :)
Ну, редактор у него и сейчас все еще не идеал :) А версия 9.30 еще и тормозить начала при переключении между режимами отладки и правки кода :) Но вообще это та среда, на которой я остановился много лет назад и до сих пор не жалею.
Так это вопросы к фреймворку, а не к IDE. Вы как в блокноте можете подключить библиотеки на килобайт для простого мигания светодиодом, так и в IDE уложить в 300-400 байт на регистрах вывод измеренного на входе АЦП значения на семисегментные индикаторы.
Непонятно. Понимание специфики программирования МК как класса железяк резко пойдет в гору если исходники писать в блокноте, а собирать проект через командную строку с ручным указанием всех ключей компилятора и линкера?
"Я снова сделаю Твиттер свободным и демократичным!" - говорил он...
И к какому из этих трех основных диапазонов относится, скажем, длина волн, которые передают на наши радиоприемники музыку?
Ну если с возможностью оценки размера и плотности с допустимой погрешностью я еще могу согласиться, то все остальное - только предположения. Например, по Вашим ссылкам пишут, что расчет температуры "основан на предположении, что планета имеет атмосферу, подобную земной с парниковым эффектом за счет наличия 1 % СО2 и при альбедо 0,3". То есть реальная температура экзопланет на самом деле неизвестна. Состав (а зачастую и само наличие) атмосферы так же неизвестны, можно лишь в редких случаях делать предположения типа "вероятно, она содержит пары воды", да и то не для землеподобных планет. По крайней мере беглое гугление говорит, что на данном этапе технологий мы можем хоть как-то оценивать некоторые характеристики атмосферы лишь для очень больших планет с толстым слоем атмосферы и для молодых планет, которые, по сути, еще и полноценными планетами-то не являются.
Соответственно вся землеподобность сводится к "на ней должна быть похожая гравитация и она получает плюс-минус столько же энергии от своей звезды, сколько и Земля от Солнца" :)
Смотрел и щупал, поэтому не использую его в своих проектах. HAL уже вплотную приблизился к ардуино-стилю :)
Оптимизация всегда будет актуальной для нормальных разработчиков, но повторюсь - речь не об оптимизации, а о правильном программировании. Если Вы в прерывании UART начнете обрабатывать пришедшие данные, а в прерывании таймера выполнять код по нажатию кнопок, то рискуете запросто нарваться на ситуацию когда контроллер не будет вылазить из прерываний даже если у него вагон ресурсов.
Честно говоря, из текста это совершенно не очевидно, по крайней мере для меня :)
Речь ведь не о производительности, а о базовых принципах программирования для микроконтроллера. В прерываниях должен быть код, выполняющийся за минимально возможное время, что в 8-битной Ардуине на 8 МГц, что в 32-битном ARM-е на 400 МГц :)
Это отдельный вид искусства антипрограммирования, согласен. Значит тем более не нужно прививать начинающим эти антипаттерны :)
Ну разве что ради любопытства :)
Позволю себе несколько замечаний.
Зачем хранить инициализирующие параметры кнопок в структуре в оперативной памяти? Ее как правило не так уж много, а изменения этих параметров в процессе работы программы вроде бы не предполагается.
Структура текущего состояния кнопок мне кажется излишне большой. Ниже приведу свой вариант с пояснениями.
"В обработчике прерывания, вместо вывода в терминал сообщений о нажатии кнопки, вы можете разместить полезный код, который будет реагировать на нажатие кнопки." - ну зачем же учить начинающих плохому? В прерывании код должен быть как можно более коротким. В данном случае - только оценка текущего состояния кнопок и все, никаких реакций на их нажатие, тем более никаких медленных блокирующих выводов в UART. Это очень, очень вредная рекомендация.
Размер структуры текущего состояния кнопки можно сделать более компактным - это опять же сократит использование оперативки, как и размещение инициализирующих данных в константах или дифайнах. Вот пример:
Структура имеет размер всего 5 байтов, и этого достаточно для обработки короткого и длинного нажатий, а так же отпускания после короткого и длинного нажатий.
Алгоритм обработки каждой кнопки в цикле в прерывании таймера таков:
Этот код позволяет достаточно легко организовать и автоповтор нажатия с заданным интервалом - просто проверять значение счетчика времени при статусе кнопки KB_LPRESSED и если он достиг определенного значения - обнулять его и выполнять действия по очередному "нажатию" автоповтора.
Все реакции на события кнопок необходимо размещать в основной программе, а ни в коем случае не в прерывании. Просто в основном цикле (или где это нужно) проверяется текущий статус нужной кнопки и если он не "свободен" (KB_FREE) и не "обработан" (KB_WORKED), то идем выполнять полезный код, связанный с событием кнопки, после чего выставляем кнопке статус "обработан" (KB_WORKED). Этот статус сам сменится на "свободен" при ближайшем очередном вызове прерывания таймера с обработкой состояний кнопок.
По счетчику времени: нет нужды считать в нем миллисекунды или любые другие реальные временные величины. Достаточно считать вызовы прерывания таймера - они все равно следуют с определенным промежутком времени. Поэтому достаточно 1-байтового счетчика, который посчитает, скажем, 5 вызовов (с периодом 20 миллисекунд) вместо 100 миллисекунд для антидребезга. Или 50 вызовов вместо 1000 миллисекунд для долгого нажатия.