Pull to refresh

Comments 43

нехватает фотографий, которые хорошо иллюстрируют
Ну-у, заголовочек я втулил. А вообще сделаю в понедельник фотку того самого коммутатора — монстр еще тот!
Немного подправил оформление топика в шапке.
«8канальное АЦП» :)
Вроде бы АЦП всегда был мужского рода?

PS: А за «моё день рожденье» вообще убивать готов. Grammar Nazi
Про деньрожденье — это не к автору претензия, сорри. Просто по поводу моего др меня сегодня с утра уже задолбали этим и я злой :)
А-а, а то я начал судорожно искать в тексте — вроде ж ничего не было такого…
Упс, извиянюсь! Благодарю, исправил!
Просто у меня с институтских времен было сокращение в конспекте АЦП — аналогово-цифровое преобразование. Посему ОНО…
«ДециМиллиСекунда» — это скорее 10 мс, чем 0.1, если уж быть точным :) Обычно эту величину называют «тиком» (SystemTick), в современных ARM-ах даже есть специальный аппаратный таймер под эту задачу. Как правило, помимо инкремента переменной в этом прерывании выполняется еще перепланирование задач в случае использования ОС.
«ДециМиллиСекунда» — это скорее 10 мс, чем 0.1
Нет уж, извините :-)Р! Секунда — 1 сек. Миллисекунда — 1e-3 сек. «Деци» — 1e-1 (как дециметр). Посему получаем 1e-4.
По поводу тика — да, в Windows тоже явно оперируют тиками. Только тик там 1 мсек, если не ошибаюсь (т. к. функция GetTickCount() переполняется за 49 суток, если не ошибаюсь)
Да, действительно, ошибся :) Хотел сумничать и малость облажался :) Тик — условная величина, может быть равна чему угодно. Я обычно использую от 0.1 мс до 10 мс в зависимости от задачи.
Точность 1 мкс на интервале 5 суток вы никак не получите — намного раньше упретесь в точность кварцевого генератора.
Да, об этом я думал написать тоже… Хорошо, что напомнили — ща добавлю информацию.
UFO just landed and posted this here
Да ничего не мешает. Просто все зависит от конкретной реализации — у автора она упрощенная, а это важно для микроконтроллеров, так как у них нет лишних ресурсов ни по коду, ни по памяти, ни по быстродействию.

Кстати, ИМХО, глобальный счетчик времени лучше делать не микросекундным, а миллисекундным. Для пользовательского интерфейса (мигания, опросов кнопок, клавиатуры, отсчета выдержек времени и т. п.) этого часто вполне достаточно, и уменьшается нагрузка на ядро микроконтроллера. В специальных случаях можно сделать счетчик более точным.
Ну-у, вначале я и хотел делать миллисекундным, но с моим контроллером и моим кварцем оптимальным получился как раз 0.1 миллисекундный. Им я в основном и пользуюсь — однажды, впрочем, пригодилось значение таймера
Ну-у, вначале я и хотел делать миллисекундным, но с моим контроллером и моим кварцем оптимальным получился как раз 0.1 миллисекундный. Им я в основном и пользуюсь — однажды, впрочем, пригодилось значение таймера
Что легче сравнить на предмет «что больше?» — одну числовую переменную или структуру?
UFO just landed and posted this here
память в 256-4096 байт, в основном :)
А можно поподробнее про то, что такое «Коммутатор фехтовальных ситуаций»? Что этот девайс делает?
UFO just landed and posted this here
Вы серьезно? А что там коммутировать-то?
UFO just landed and posted this here
Дело не в этом. В фехтовании (к слову, не только шпага — там еще рапира и сабля) наличествует 2 цепи наконечника в клинке, цепь электропроводящей куртки и цепь дорожки. Соответственно, распознаются ситуации укола в непроводящую поверхность, в куртку, в дорожку и в клинок (точнее, в гарду). Все эти ситуации — их всевозможные комбинации, длительность нажатия/касания (от 0.7 мсек в сабле до 15мсек в рапире) — надо анализировать. Скажем, скользящий укол в гарду, с которого перепрыгивает на куртку, а противник в это время уколол в гарду. И все это надо закоммутировать и убедиться, что все отрабатывается корректно.
обязательно счетчик меняемый в прерывание пометьте как
volatile dword dmsec;
а то может возникнуть ситуация когда оптимизатор ее проигнорирует например в такой ситуации
while(1){
  if(dmsec == 0)  fun();
}
Согласен. Исправил
И еще использование оператора goto ведет к непредсказуемым ошибкам, да и выглядит как то не профессионально :)
А вот с этим можно поспорить. У меня опыт программирования 20 лет и в С++ у меня еще не было ситуации, когда подходил ТОЛЬКО goto. В С тоже, в общем-то, всегда можно было выкрутиться.
НО в микроконтроллерах он иногда здорово облегчает жизнь! Потому что дает более простой код.
А вообще — какая разница, на самом-то деле? Главное, чтобы было читаемо и работало как надо. «Читаемо» — категория субъективная. «Работает как надо» — тут не важно, goto или while ().
IMHO :-)
в том то и дело что не читаемое я долго выискивал куда же оно ведет это goto а хотя пример очень маленький и я еще не одну ситуацию не видел где goto облегчал что либо.
Просто нужно проектировать структуру более обдумано и при это забыть, что такой оператор существует :)
Вместо самодельного dword используйте стандартный uint32_t.
У меня в CodeVisionAVR такой тип не поддерживается.
Я могу его сделать typedef, но лично мне читабельней byte/word/dword/qword/real.
А в CodeVisionAVR есть stdint.h? Тип uint32_t и остальные определены там.
Нет такого файла.
Понятное дело, его не сложно скопировать ;-)
А вы не думали, что таймер у вас в синхронном режиме и пользовательские прерывания (по нажатию кнопок или завершения преобразования АЦП и т.д.) будут нарушать работу таймера?
Для тех целей, что вы преследуете все давным давно придумано и называется это асинхронный режим работы таймера.
Честно говоря, это В МОЕМ СЛУЧАЕ не шибко важно — я не делаю хронометр. И задачи у меня не хронометрические.
А вот если мне надо будет очень и очень четко отмерять время, я буду пользоваться внешними устройствами, несвязанные с логикой работы программы.
А вы меня нарочно запутать решили, но начнем с исходных данных
Часто при работе микроконтроллерного устройства есть необходимость отсчитывать «антропоморфное» время – сколько долей секунды светиться светодиоду, максимальный промежуток времени double-click


Для того, чтобы отсчитывать время в устройствах на AVR делают примерно так.
Вешают внешний часовой кварц на 32768Hz для запуска асинхронного таймера и пишут примерно такой код для настройки таймера.
В данном случае делитель 256, значит прерывание по таймеру возникает с частотой 32768/256=128Hz
А в регистр счетчика TCNT2 записано значение 0xC0, следовательно до переполнения произойдет 256-192=64 тактов что соответствует времени 0.5 секунды.
/* -------------------------------------------------------------------------- */
//TIMER2 initialize - prescale:256
// WGM: Normal
// desired value: .5Sec
// actual value:  0,500Sec (0,0%)
void timer2_init(void)
{
 TCCR2 = 0x00; //stop
 ASSR  = 0x08; //set async mode
 TCNT2 = 0xC0; //setup
 OCR2  = 0x40;
 TCCR2 = 0x06; //start
}
/* -------------------------------------------------------------------------- */


А потом обработчик прерывания вызываемый каждые пол секунды.
#pragma interrupt_handler timer2_ovf_isr:5
void timer2_ovf_isr(void)
{
 TCNT2 = 0xC0; //reload counter value
 TCCR2 = 0x06; //start 

  //тут полезный код
     
}
/* -------------------------------------------------------------------------- */


И всё! Все ваши измерения времени теперь не зависят от остальной части программы и от прерываний, а точность измерения временных промежутков выше примерно в 360 раз.
А зачем вешать часовой кварц, когда такая точность просто не нужна?

Если делать высокоточный секундомер или часы — то это будет оправданно.
Но если необходимо просто отмерять различные отрезки времени, незавязанные на реальное время — то какой в этом смысл?

Считаю что в заголовке слово точность будет логичнее заменить на слово шаг.
Согласен. Заменил
Можно ли для этого использовать таймер не на 32768, а, скажем, как у меня, 12 MHz?
Часовой кварц ставится не вместо, а вместе с основным.
МК тактируется от 12MHz, а таймер — от 32,768 KHz.
Хм… А как влияет на точность изменение счетчика в прерывании? Или все делается с расчетом на то, что это выполнится до следущего такта таймера?

Не проще поставить предделитель на 64, тогда счетчик сам по себе будет переполняться ровно 2 раза в секунду?
Вы имеете в виду изменение программного счетчика dmsec? Операция сложения занимает совсем немного времени.
Что касается периода таймера, то меня 1) интересовала точность в пределах 1 мсек, 2) хотелось занять 8-ми битный таймер, а не 16-ти битный.
Рядом с комментарием есть стрелочка вверх. Комментарий был обращен к Zak по поводу кода асинхронного таймера.

Как видно, он настроен на прерывание не при совпадении, а при переполнении. Притом каждое прерывание счетчик таймера вручную устанавливается на фиксированное значение. А значит есть вероятность того, что действие установки счетчика будет выполнено при ненулевом его значении, что приведет к ошибкам измерения времени.
В данном конкретном случае (128Hz при тактовой 12MHz, 1 прерывание, 2 строчки кода) — этого явно не произойдет. Но не всегда все так просто.
Sign up to leave a comment.

Articles

Change theme settings