Собирал на днях подобное, для экспериментов. Но я потенциометры повесил на АЦП. Один задаёт скважность, второй меняет коэффициент деления. Естественно, плавной регулировки частоты не получилось, думаю как реализовать..
Потенциометр без АЦП конечно работать не будет. Я не упомянул его, потому что он подразумевается по умолчанию. Я вижу это так: 1) На одном канале АЦП снимаем показания с потенциометра и задаем уровень для сравнения (число для регистра OCRх) по 1-му таймеру в режиме СТС - это для скважности. 2) С другого канала АЦП снимаем уровень сравнения для 2-го таймера в режиме СТС - это для частоты (формирует период). 3) Число из 1 пункта не может быть больше числа из 2 пункта. Ну или может... только это уже не имеет смысла. Если брать период (время работы 2-го таймера) за 100%, то не может 4) По прерыванию 2-го таймера сбрасываем оба счетчика, включаем высокий уровень на сигнальной ноге и счет начинается сначала (стартуют оба счетчика). 5) По прерыванию 1-го таймера на сигнальной ноге формируется низкий уровень и 1-й таймер останавливается.
Kalisnik, в АТмега8 у таймера1 есть режим ШИМ номер 8 и режим номер 14, где период задается регистром ICR1. поэтому максимальное число равно 65535 (0xFFFF), и частоту можно изменять относительно плавно, изменяя число в этом регистре через 1. а скважность можно задавать по каналу А в регистре OCR1A.
_________________ Мудрость приходит вместе с импотенцией... Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Какой ещё протез? Софт для МК надо отлаживать на МК.
_________________ ВНИМАНИЕ! Я часто редактирую свои сообщения, поэтому перед ответом мне советую обновить страницу. За перенос модераторами в МЯВУ тем с моими сообщениями я ответственности не несу.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
Карма: 3
Рейтинг сообщений: 0
Зарегистрирован: Вт сен 27, 2011 07:28:44 Сообщений: 46 Откуда: Москва
Рейтинг сообщения:0
Господа коты, а можно ли как-то заставить таймер (в данном случае ATtiny13) аппаратно генерировать частоту (режимы CTC с переключением выхода или один из режимов PWM с переключением выхода), но при этом воспользоваться прерыванием по переполнению, для отсчета интервалов и задержек? Проблема еще заключается в том, что мне нужно менять генерируемую частоту по ходу пьесы, соответственно содержимое регистра OCR0A в процессе меняется. И получается, что привязаться вообще не к чему. Т.е. получается таймер в режимах CTC, PWM не считает по кругу, а считает до "отметки" в регистрах OCR0A и OCR0B, причем в последнем значение должно быть меньше чем в первом. Я многого хочу и нужен второй таймер? (менять МК, например на ATtiny25)
_________________ ИзвЕните от слова - веник, ИзвИните от слова - вина.
нет, напрямую не получится, т.к. период таймера нестабилен, но можно сделать немного по другому — использовать прерывание сравнения с оср1а , в котором к 16, 24 или 32 битному аккумулятору прибаввлять значение оср1а+1 и, затем сравнивать с определяющей период величиной, в случае превышения - тикать часами и вычитать из аккумулятора значение этой величины. конечно, будет небольшой джиттер, но общий ход часов сбиваться не будет
Добавлено after 2 minutes 48 seconds: ну, и важное замечание - мк должен всё это успевать сделать (например при делителе 1 и значении в оср1а 1 он полюбому не успеет....
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Ну, для отсчёта интервалов и задержек в таком случае можно использовать и сторожевой таймер… и по его прерыванию производить отсчёт… минимальное время у тини13 это 16 мс, а максимальное 8,2 сек. Так что вполне удобно при необходимости…
Карма: 3
Рейтинг сообщений: 0
Зарегистрирован: Вт сен 27, 2011 07:28:44 Сообщений: 46 Откуда: Москва
Рейтинг сообщения:0
Ivanoff-iv, спасибо за идею, но что-то я не соображу как это сделать. Не хватает опыта... Вот у меня настройки сейчас такие:
Код:
TCCR0A |=(1<<COM0A0)|(1<<WGM00); // режим Phase Correct PWM с переключением выхода OCR0A (PB0 должен быть настроен как выход) TCCR0B |=(1<<CS01)|(1<<WGM02); // запуск таймера с соотв. делителем на 8 (1200000/8=150000) OCR0A = 15; // начальное значение
Значение регистра OCR0A в процессе меняется не сильно от 12 до 20. Чаще всего работа идет на значении 15. Что надо сделать? Надо включить прерывание по регистру сравнения А.
Код:
TIMSK0 |= (1<<OCIE0A);
Добавить глобальную переменную
Код:
uint32_t accum = 0 ;
И добавить обработчик:
Код:
ISR(TIM0_COMPA_vect) { accum += (OCR0A +1); if (accum >= 5) // допустим 5 действие accum -= 5; }
Добавлено after 14 minutes 57 seconds: VNS, спасибо за идею, я пробовал. Но словил некоторые глюки. Судя по ДШ, мне нужно было включить только бит WDTIE, который разрешает просто прерывание без ресета. Возьмем минимальный интервал 16мс, поэтому делитель оставляем по нулям. Собственно это все, чтобы оно заработало, ну описать обработчик еще в самом коде. В обработчике инкрементирую глобальную переменную. Проверяю в главном цикле когда натикает, натикало - сбрасываю эту переменную и "делаю дело". Но при этом Таимер0 (основной) у меня генерирует некоторую частоту в режиме Phase Correct PWM и вот когда наступает прерывание от WDT появляется какой-то джиттер. Если в обработчик помимо инкремента засунуть что-то еще, становится еще заметнее. Работаю на частоте 1,2МГц. Это первый глюк. Второй глюк, что бывает после сброса наступает циклический сброс, но не всегда, а как повезет. Видимо я что-то не учитываю с этим WDT.
_________________ ИзвЕните от слова - веник, ИзвИните от слова - вина.
1) частоту я бы поднял, 12х8=96 тактов, конечно, тут хватит, но ведь тиня ещё чтото делает... 2) код правильный, но я бы цифру 5 задефайнил, чтобы при сравнении и при вычитании числа всегда совпадали. 3) 5 для этого места катастрофически мало, т.к. при каждом вызове прерывания в накопитель складывается от 13 до 21. я бы использовал числа, кратные 256, так если оптимизатор хороший, то он оптимизирует (уберёт) операции с младшим разрядом. (например число 5*256 даст интервал в 5 полных 0—ff оборотов таймера, т.е. 10240 тактов = 117 Гц) переменную для накопителя не стоит брать с избытком (большей разрядности чем величина с которой он сравнивается), в вашем случае достаточно 16 бит. ————— у сторожевого таймера нужно после каждой сработки вновь взводить режим прерывания, иначе вторая и последующие сработки вызовут уже не прерывание, а перезагрузку.
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Карма: 3
Рейтинг сообщений: 0
Зарегистрирован: Вт сен 27, 2011 07:28:44 Сообщений: 46 Откуда: Москва
Рейтинг сообщения:0
Да, что-то я совсем запутался. Когда на асме писал, я там такты высчитывал, а когда на Си перешел, что-то все внимание переключилось на сам язык. 1) Что за цифра 96, можно подробнее? 2) Само собой, я тоже не люблю "магические" числа. 3) Допустим я поднимаю частоту МК до 4800000, соотв. для генерации таких же частот у меня вместо 15, в регистре будет 60. Размерность переменной само собой потом приведу к минимально необходимому значению, когда разберусь. Было: 1200000/8=150000/15=10000/2/2=2500Гц Станет: 4800000/8=600000/60=10000/2/2=2500Гц Вернемся к алгоритму. Диапазон значений в регистре сравнения у меня получается теперь такой 48-80, вместо 12-20. Если частоту сделать 9600000, то я уже не влезаю в нижний предел по генерируемой частоте, т.к. 320 > 256... Так какое же число мне выбрать? Все равно кратно 2 не получается.
_________________ ИзвЕните от слова - веник, ИзвИните от слова - вина.
Судя по ДШ, мне нужно было включить только бит WDTIE, который разрешает просто прерывание без ресета. Возьмем минимальный интервал 16мс, поэтому делитель оставляем по нулям.
Включить таймер и разрешить прерывание (1 -> WDTIE), а так же разрешить глобальные прерывания (1 -> I)… далее чтобы не происходило сброса МК в прерывании по таймеру (WDT) каждый раз выполняете процедуру (1 -> WDTIE) - разрешить прерывание, а так же взводите флаг отслеживания данного прерывания… затем выходите из данного прерывания… в основном цикле программы отслеживаете данный флаг и производите отсчёт интервала с последующим сбросом этого флага… тем самым не будет никаких глюков при подсчёте необходимого времени…
Вот как пример (прошивка)… тактовая (1,2 МГц)… на выводах РВ3 и РВ4 светодиоды… РВ3 – показывает цикличность отсчёта таймера (в данном примере 496 мс), а РВ4 – загорается при сбросе (перезагрузки) МК… вывод РВ1 – ШИМ… который изменяется периодично (при каждом отсчёте таймера)… и никто некому не мешает…
int main(void) { ACSR |=(1<<ACD); // отключение компаратора DDRB |=(1<<PB3)|(1<<PB4); // эти порты на выход PORTB |=(1<<PB4); // включаем зеленый _delay_ms(10); PORTB &=~(1<<PB4); // выключаем зеленый WDTCR |=(1<<WDTIE)|(1<<WDP1)|(1<<WDP2); // разрешаем прерывание от WDT и выставляем делитель на 1 сек. sei(); // глобальное разрешение прерываний /* Replace with your application code */ while (1) { if (wdt_flag&(1<<FLAG)) { wdt_flag &=~(1<<FLAG); PORTB ^=(1<<PB3); } } // end while(1) } // end main
UPD: Забыл добавить ШИМ, только он у меня не совсем ШИМ, а генератор.
Код:
TCCR0A |=(1<<COM0A0)|(1<<WGM00); // режим Phase Correct PWM с переключением выхода OCR0A (PB0 должен быть настроен как выход) TCCR0B |=(1<<CS01)|(1<<WGM02); // запуск таймера с соотв. делителем на 8 OCR0A = 15; // начальное значение регистра сравнения
В общем работает нормально, как и на Вашей прошивке.
_________________ ИзвЕните от слова - веник, ИзвИните от слова - вина.
1) делитель таймера =8, значит за 1 такт таймера проходит 8 тактов АЛУ, минимальное значение OCR1A =12, значит между прерываниями, генерируемыми таймером может быть всего 13 тактов таймера, перемножаем, получаем 104... т.е. основная программа может прерываться каждые 104 такта АЛУ (извиняюсь 96 — это я посчитал неправильно) и к этому надо быть готовым - надо успеть зайти в прерывание, сохранить регистры в стек, выполнить тело прерывания, вернуть регистры из стека, вернутьсф на прежнее место выполнения программы и чтото ещё в ней успеть сделать...
нужно увеличить скорость работы АЛУ и при этом не сбить частоту генерации (выходной), —> надо замедлить генерацию отностиельно тактирования АЛУ и поднять частоту самого АЛУ. Есть 2 варианта - увеличение значения ОCR1A (ты это делал и видишь плюсы, минусы и ограничения), можно увеличить делитель (дш под рукой нет, не помню там шаг 2 или 8....) увеличиваем тактирование кристалла до 9,6МГц (1,2 х 8), а делитель ставим 64 (8 х 8), больше ничего не меняем и получаем ту-же частоту на выходе но 64х13=832 такта АЛУ между прерываниями
Добавлено after 2 hours 38 minutes 16 seconds: вариант с тактированием 4,8 МГц тоже хорош (около 400 тактов) да + ещё выходную частоту можно более точно выставлять
_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Понадобилось сделать переключатель switch на atmega328 для переключения между генераторами меандра (на различные частоты). Генератор на таймере Т0 в режиме СТС, разница между подключаемыми генераторами только в численном значении OCR0A. При первом нажатии на кнопку после подачи питания зажигается светодиод(case1). Затем при последовательном нажатии кнопки происходит вызов функций генераторов (case2, case3, case4). Проблема в том что вызвать функцию генератора можно, но вернуть ее назад (если так можно сказать) при следующем нажатии кнопки (например case5) не получается. Я попробовал просто отключать выход OC0А (в моем случае это DDRD&=~(1<<PD6)) но после возвращения из case5 в case1 светодиод не горит (т.к. в предыдущем case5 было отключение ОС0А (DDRD&=~(1<<PD6)). Если ввести еще один case6 для включения ОС0А (DDRD|=(1<<PD6)) то получается что генератор из case4 (последний по списку) вновь получил возможность подавать меандр на теперь подключенный ОС0А (и подключение ОС0А в case6).Поэтому после первого прохождения прохождении case1...case6 при последующем переключении в case1 получаем работающий на выход ОС0А генератор из case4. Возможно применение отключения выхода ОС0А это моя ошибка. Я еще начинающий, хоть и не молодой. Пробовал вводить переменную (типа флаг) и использовать оператор if() который в зависимости ит наличия установленного или сброшенного флага включал бы или отключал бы генератор в кейсах switch.К сожалению не помогло. Прошу помощи у опытных форумчан. Спасибо за терпение.
Добавлено after 4 hours 29 minutes 19 seconds: файлы
Добавлено after 2 hours 32 minutes 51 second: veso74 Для таймера Т0 все работает. Но я попытался переделать код для таймера Т1 потерпел неудачу. Вроде сделал все точно но не работает. Во вложении файлы для Т0 и Т1. Спасибо
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения