Не могу понять поведение таймера.
- Войдите на сайт для отправки комментариев
Здравствуйте, пытаюсь наладить работу пьезодинамика с микроконтроллером. Сейчас работаю в Ардуино и по некоторым причинам пробую сделать это в обход библиотеки tone(на самом деле пробовал и брать код из tone.cpp, и писать свой, и постоянно терплю фиаско). Написал простой тестовый код с использованием 8-битного t2 таймера:
#include <avr/interrupt.h>
#include <avr/io.h>
#define F_CPU 16000000L
#define buzzer 6
unsigned long tcount = 0;
char ocr = 100;
ISR(TIMER2_COMPA_vect) //раз в 100*(1/16 000 000) секунд
{
if (tcount > 1000) //раз в 0,006 25с
{
PORTD ^= (1 << PD6); //за 0,0125с ножка дергается внизвверх
tcount = 0; //в секунду ножка дергается внизвверх 80 раз
}
tcount++; //тикает раз в 0,000 006 25с
}
void setup()
{
pinMode(buzzer, OUTPUT);
digitalWrite(buzzer, LOW);
TCCR2A |= (1 << WGM21); //СТС режим
TCCR2B |= (1 << CS20); //без предделителя
OCR2A = ocr;
TIMSK2 |= (1 << OCIE2A);
}
void loop()
{
delay(5);
}
По замыслу таймер должен отсчитывать мелкие шажки, и с помощью них создавать период дерганью ножкой.
По эффективности и правильности вопросов нет - это только проверка таймера и пьезодинамика.
А вот проблема в том, что в результате кроме постоянного пищания динамика получается примерно 4 секунды писка и столько же тишины и по кругу. Возможно я упускаю что-то очевидное или не очень, но никак не могу понять откуда берется еще и такой цикл. На сбои не похоже, периодичность - на слух постоянная. Пьезодинамик подключен через транзистор для согласования по току на выходе.
Подскажите в чем может быть дело, или если я совершил какую-нибудь глупую ошибку, укажите на нее, пожалуйста.
В строках №№ 24-27 замените |= на присваивания.
Таймер уже настроен средой ардуино (прескэйлер и много чего), а Вы сохраняете все их биты, взводя только свои. Вам же нужно установить все биты как Вам надо - какие-то взвести, а какие-то сбросить.
P.S. Зачем делать так сложно мне непонятно, но работать-то, конечно, должно.
Действительно, спасибо. Я добавил перед взводом регистров их обнуление, еще в loop вставил: delay(500); TIMSK2 ^=(1 << OCIE2A); и здесь нарвался на старую свою проблему с пьезодинамиком и таймерами.
По идее ведь это должно раз в пол секунды запрещать и разрешать прерывания по переполнению, следовательно код в функции ISR выполняться не должен, но время от времени (примерно 50 на 50) после первых 500мс нормальной частоты, когда прерывания запрещены, динамик продолжает пищать с постоянной намного более высокой частотой следующие 500мс. В данном случае тоже не могу понять откуда берется эта высокая частота, если прерывания вообще не должны обрабатываться?
Такое поведение уже я замечал и на отдельной atmega328 с ардуиновскими фьюзами и кварцем 16МГц.
Так первая проблема решилась? Мы переходим ко второй? Правильно?
Nimrok94, не очень понятно зачем заставлять срабатывать прерывания в 1000 раз чаще, чем нужно. Вот то-же самое, но элегантнее:
#define buzzer 6 char ocr = 100; ISR(TIMER2_COMPA_vect){ static uint8_t n; if (n <77) {PORTD ^= (1 << PD6);} n<128? n++ : n=0; } void setup() { pinMode(buzzer, OUTPUT); TCCR2A = (1 << WGM21); //СТС режим TCCR2B = (1 << CS20)|(1 << CS21)|(1 << CS22); //div1024 OCR2A = ocr; TIMSK2 = (1 << OCIE2A); } void loop() {}Без участия лупа получаются прерывистые гудки.
Да, так и есть. Нужно создать новую тему? Не будет ли это подобием спама? Я раньше не писал на специализированных форумах, слышал тут довольно строгие правила.
Первая проблема действительно решилась. Но я неожиданно понял, что новая имеет для меня более важное значение, так как она давно мешается. Как-то мне нужно было сделать звуковое сопровождение на устройстве, которое общалось пакетами в ~30 байт по uart (rs 232, rs485). На Ардуино столкнулся с тем, что функция tone просто переставала работать после получения одного сообщения по Serial, тогда перешел на си и появилось это: после отработки нужных частот динамик время от времени начинал высоко пищать, когда обработка прерываний была уже отключена и должна была быть мертвая тишина. Пищать он так может до следующего срабатывания нужных частот и, в дальнейшем, до бесконечности.
Я все это отложил на длительный срок, а сейчас, столкнувшись с проблемой, не выдержал и, наконец, написал сюда :)
1. Посмотрите, что Вам написал dimax, он оказался менее ленивым, чем я. Я то ограничился замечанием, что не понимаю зачем такие сложности.
Теперь о второй проблеме
Регистры таймера (кроме OCR2A и OCR2B) не имеют двойной буферизации, потому, возможно, Вы просто невовремя в них пишете и всё идёт вразнос. Попробуйте
1. запретить прерывания на время выполнения очистки бита в TIMSK2.
2. Одновременно с очисткой бита, сбрасывайте бит запроса прерывания OCF2A
3. Если не поможет, заодно обнуляйте TCNT2 там же.
Но, если есть такая возможность, я бы просто останавливал таймер - это "неэстетично, зато дешево, надёжно и практично".
Первым делом, как проснулся, попробовал код dimax'а - по таймингу, конечно, работает, но вот переход в писк, когда должен молчать, динамик продолжает. Получается нечто такое: /(звук)(писк)\-/(звук)(тишина)\-/(звук)(писк)\-/(звук)(тишина)\-
Пробовал также cli(), sei(), отключать таймер занулением CS2 битов вместе со всем регистром TCCR2B и другие регистры обнулял. Что-то изменил только cli() на первую половину периода - писка нет, только постоянный звук без пауз.
Может быть проблема аппаратная, но в некоторых примерах динамик соединяют с мк вообще без обвязки и никаких сбоев не ловят.
Простите, если Вы спец, то не обижайтесь, но тут у нас такое бывает ... Что у Вас за динамик? Не активный случаем? Дайте-ка ссылочку, пожалуйста (хотя китайцы могут и наврать - нарывался), но всё равно, дайте-ка.
Спец это точно не про меня)
Пьезодинамик вроде самый обыкновенный:
Подключен вот по такой схеме:
VCC брал как внешние 12В, так и 5В со стабилизатора ардуины. И ведь функция tone работает хорошо, а как пытаюсь руками все настроить так пищит. Но у tone была своя проблема, как писал выше. Я думал может кто-то сталкивался с таким и сейчас опишет свой опыт) Единственное, что во всех случаях я работал с atmega328 на 16МГц с ардуиновским бутлоадером и набором фьюзов, может это решает. В любом случае буду пробовать дальше. Спасибо вам за помощь)
Попробуйте подать на него просто 5В, соблюдая полярность. Никаких tone, никаких шимов - вообще ничего, просто 5В подайте питание, соблюдая нарисованную полярность..
Если запищит, то это активный динамик, а судя по наклейке (её плохо видно, но всё же) - это так и есть.
Если активный, то все Ваши проблемы имеют простые объяснения. Проверьте и скажите. И если он от простых 5В запищит, то я смогу полностью объяснить его поведение, во всех описанных Вами случаях.
Трудно передать словами, что я почувствовал, когда подал на него напряжение) Я даже не помню где покупал этот черный цилиндр с двумя ножками и вот оказалось, что это вполне самодостаточная пищалка! И даже в голову не пришло при таких симптомах провести самую простую проверку..
Еще раз спасибо за ваш свежий взгляд)
Пьезодинамик
Это - сразу в перлы.
Вы уж что ли Википедию бы почитали, что такое громкоговоритель
https://ru.wikipedia.org/wiki/%D0%93%D1%80%D0%BE%D0%BC%D0%BA%D0%BE%D0%B3...
и каких видов они бывают
https://ru.wikipedia.org/wiki/%D0%9F%D1%8C%D0%B5%D0%B7%D0%BE%D1%8D%D0%BB%D0%B5%D0%BA%D1%82%D1%80%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D0%B8%D0%B7%D0%BB%D1%83%D1%87%D0%B0%D1%82%D0%B5%D0%BB%D1%8C
https://ru.wikipedia.org/wiki/%D0%AD%D0%BB%D0%B5%D0%BA%D1%82%D1%80%D0%BE...
Кстати, действительно столкнулся с вопросом - как называть эту пищащую штуку, и в дальнейшем запросы в интернете слова пьезодинамик давали свои результаты) Вот например- http://wiki.amperka.ru/%D0%BA%D0%BE%D0%BD%D1%81%D0%BF%D0%B5%D0%BA%D1%82-arduino:%D0%BF%D1%8C%D0%B5%D0%B7%D0%BE%D0%B4%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D0%BA
Просто мне не с кем обсуждать эту тему и вполне возможны и другие перлы в моем исполнении, уж извините)
Ну, значит, это не Ваш перл.
Хотя, надо отметить, техника развивается быстрее, чем успевает устаканиться терминология. Например, использованный глубокоуважаемым Евгением термин "активный динамик" уже занят совершанно другим устройством.