Например TDA7294

Форум РадиоКот :: Просмотр темы - Генератор на ATMega328p
Форум РадиоКот
https://radiokot.ru/forum/

Генератор на ATMega328p
https://radiokot.ru/forum/viewtopic.php?f=57&t=135440
Страница 1 из 1

Автор:  Hel [ Сб сен 10, 2016 09:07:07 ]
Заголовок сообщения:  Генератор на ATMega328p

Доброго времени суток.

Понадобился генератор прямоугольных импульсов с независимой регулировкой частоты и скважности.

Диапазон 0,1 - 1000 Гц, шаг регулировки 0,1 Гц. Длительность импульсов от 10 мкс, шаг регулировки 10 мкс. Частота и длительность выводятся на дисплей, в герцах и миллисекундах. Макс. скважность 50%.

Хотел все реализовать в Atmega328, поскольку она все равно есть в устройстве, хотя и до этого я никогда не программировал вообще.

Все, что я смог придумать - это сделать предделитель таймера на 1, установить прерывание по совпадению на 16 (отсчитали 1 микросекунду) и в прерывании изменять переменную х+1. Соответственно сравнивая с двумя другими переменными - подавать 1 или 0 на ножку МК.

Вроде бы худо-бедно работает, но при этом дисплей жутко тупит - секунд по 5 выводятся данные. Если вызывать прерывание по совпадению на 126 (160-34 цикла) - тогда все приемлемо, но длительность импульса конечно будет меняться с шагом 100 мкс. а не 10. Режим СТС не подходит, да и шаг изменения будет 16000000\256= 62500; 1\62500=0,000016 мкс., а хочется кратно10-ти.

Собственно, вопрос: как реализовать такой генератор на МК? Поможет ли ускорить работу МК такие ухищрения как собственный кварц для таймера, или подключение дисплея напрямую без регистра сдвига?



Гуглится очень много подобных тем, но решения вопроса нет ни в одной.

Вот кусочек моего индусского кода:

void WorkOn() {
OCR0A=126; // Количество импульсов соответствующих 10 микросекундам. 16 МГц /(160 - 34)
TIMSK0=(1<<OCIE0A);
TCCR0B=0x01; //Предделитель тактовой частоты - 1.
UpdateFrequency();//обновление переменных

}

ISR (TIMER0_COMPA_vect){ // Генератор импульсов.
TCNT0=0;//обнуляем регистр TCNT1
Timer0Count=Timer0Count+1; // Счетчик таймера, 1 ед. = 10 Микросекунд.
if (Timer0Count == DelayTime){ // Если счетчик таймера соответствует паузе между импульсами.
PORTB |= 1<<3; // Начало импульса.}
if (Timer0Count == PeriodTime){ // Если счетчик таймера соответствует периоду.
PORTB &= ~(1<<3); }// Конец импульса.
Timer0Count=0;} // Сброс счетчика.

}

void UpdateFrequency() {
PeriodTime = 1000000/Frequency; // Период = 1000000 микросек./частота(Гц)*10
PulseTimeMax = PeriodTime/2; // Максимальная скважность - 50%.
if (PulseTime > PulseTimeMax) // Если была увеличена частота и скважность стала более 50%
{PulseTime = PulseTimeMax;}
DelayTime=PeriodTime-PulseTime;
}

Автор:  Z_h_e [ Сб сен 10, 2016 11:17:10 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Конечно такие вещи лучше всего делать на периферии, чтобы на тратить ресурсы ядра. AVR конечно в плане периферии, уже устарела.

Я Вам предложу идею, но возможность ее осуществления проверьте сами, не хочу считать и читать.

16 битный таймер подключаете на выход. Он будет задавать частоту. Этот таймер тактируется от ядра. Т.к. таймер 16 битный. С помощью предделителя и регистров сравнения можно будет задавать частоту в широком диапазоне и хорошей дискретностью.

8 битный таймер тактируется с внешнего пина. Выход 16битного таймера соединен с входом 8 битного. На 8 битном настраиваете скважность и подключаете его тоже на выход. Это уже будет полезный выход.

Все это будет работать без участия программы, кроме моментов изменения режима. А вот возможность установки частот и скважностей посчитайте сами, может получится.

Автор:  Hel [ Сб сен 10, 2016 12:11:26 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Z_h_e писал(а):
8 битный таймер тактируется с внешнего пина. Выход 16битного таймера соединен с входом 8 битного. На 8 битном настраиваете скважность и подключаете его тоже на выход. Это уже будет полезный выход.

Все это будет работать без участия программы, кроме моментов изменения режима. А вот возможность установки частот и скважностей посчитайте сами, может получится.

Впринципе, тоже думал о таком, жаль программирование начал осваивать с 0 всего неделю назад.
Понадобится ещё 1 кварц и куча расчетов. Но надеюсь, осилю такой апгрейд прошивки.
Спасибо за совет!
Смотрел характеристики stm32, выглядят прельстиво, но увы нет таких подробных примеров и исходников какими завален гугл для avr.

Автор:  Z_h_e [ Сб сен 10, 2016 12:15:57 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

STM32 уже тоже довльно широко описан, хотя не так конечно. У STM32 счетчики кончено та еще тема, в плане возможностей.

Кварц для проверки моего алгоритма не нужен, его (алгоритм) вообще чисто математически проверить можно.
Hel писал(а):
жаль программирование начал осваивать с 0 всего неделю назад.
Тут люди кичаться о 200 летнем опыте программирования и такую чушь пишут, а у Вас 0 через неделю уже работает.

Автор:  uk8amk [ Сб сен 10, 2016 14:03:56 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Достаточно одного 16-разрядного таймера.
Режим PWM TOP=OCR1A или ICR1.
Через предделитель и TOP задаём период/частоту, через OCR скважность.
Ровно 10мкс может не получится - виноват делитель на 8, но близко к этому значению вполне реально.
Это чисто аппаратный вариант.

Программный вариант.
Рассчитываем число периодов(переполнений) таймера, на последнем включаем PWM или CTC с управлением выводом по сравнению(если неполный период), вывод устанавливается в 1. Ждём сколько-то переполнений и часть периода таймера до окончания периода синтезируемого колебания, вывод устанавливается в 0. Повторяем цикл снова.
Недостаток - джиттер в небольших пределах и надо уделять внимание тем случаям когда сравнение происходит близко к вершине таймера TOP.

Автор:  Z_h_e [ Сб сен 10, 2016 15:12:40 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

uk8amk писал(а):
Достаточно одного 16-разрядного таймера.
Режим PWM TOP=OCR1A или ICR1.
Тогда чем больше будет частота, тем грубее будет установка скважности.

Автор:  Hel [ Сб сен 10, 2016 16:37:11 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Z_h_e писал(а):
uk8amk писал(а):
Достаточно одного 16-разрядного таймера.
Режим PWM TOP=OCR1A или ICR1.
Тогда чем больше будет частота, тем грубее будет установка скважности.

Меня больше волнует случай 0,1 герц с длительностью импульса 10 микросекунд. Внутреннее чутье подсказывает, что и 16-битного таймера не хватит.

Автор:  uk8amk [ Сб сен 10, 2016 18:58:15 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

А там и до ПЛИСов не далеко. Или на обычной логике собирать. Или как советовали другой контроллер с хорошим и быстрым таймером ставить.
Шаг по 10мкс - это чтоб просто так было или реальные потребности какого-то процесса?

Автор:  Z_h_e [ Сб сен 10, 2016 19:08:24 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Все зависит от задачи.
Пускай частота ядра 16МГц.
Предделитель на 1024. Частота тактирования счетчика будет 15625Гц.
16 битны счетчик будет переполняться с частотой 0,25Гц.

Понижаете частоту тактирования в два раза. Где то вроде Ваша частота.
Но это частота 16 битного счетчика. Делите ее еще на 256, 8битного, будет еще меньше.

Вариаций много. Не утверждаю МК способен выполнить Вашу задачу. но весьма вероятно.

Автор:  Hel [ Вс сен 11, 2016 07:25:01 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

uk8amk писал(а):
А там и до ПЛИСов не далеко. Или на обычной логике собирать. Или как советовали другой контроллер с хорошим и быстрым таймером ставить.
Шаг по 10мкс - это чтоб просто так было или реальные потребности какого-то процесса?

Если другой это stm то боюсь не осилю.
Шаг именно 10 мкс. Уже работает на моем индусском коде с шагом в 100 мкс и не хватает точности, потому сюда и написал. Пусть нижний предел будет 100 мкс и 0,5 гц, но шаг изменения именно такой, даже если максимальная частота станет ниже, до 50гц а не 1 кгц.

Автор:  Z_h_e [ Вс сен 11, 2016 09:05:43 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Hel писал(а):
Вроде бы худо-бедно работает, но при этом дисплей жутко тупит - секунд по 5 выводятся данные
Может получится оптимизировать Ваш алгоритм и будет работать приемлемо.
Вам нужно минимизировать время выполнения обработчика прерывания ISR (TIMER0_COMPA_vect).
1. Используйте режим СТС. Счетчик будет сам сбрасываться при совпадении.
2. Переключайте порт записью 1 в регистр PIN. Отпадет необходимость использовать |=. PINB = 1<<3;
3. Попробуйте разные уровни оптимизации при компиляции.
4. Возможно у Вас неудачный тип данных для переменных, измените.
5. Разместите эти переменные в регистрах, а не в памяти. Но к сожалению это кажется можно только для локальной переменной. Тогда плохой это совет. Надо будет уточнить.
6. Переписать весь код на ассемблере.
7. Тактировать МК на максимальной частоте.

Тут у Вас вроде как фигурная скобка лишняя
Код:
PORTB &= ~(1<<3); }// Конец импульса.

Автор:  uk8amk [ Вс сен 11, 2016 18:02:07 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

FCPU=16000000
FTIM0=FCPU
Режим CTC для TIM0, TOP=OCRA.
OCR0A=160-1;
Получим интервал сравнений и вызова прерываний ровно 10мкс.
В обработчике COMPA:
Timer0Count=Timer0Count+1;
если (Timer0Count == (DelayTime-1)) разрешаем вывод OCR0A как SET on compare match.
если (Timer0Count == (DelayTime)) PORTB |= 1<<3; Normal port operation, OC0A disconnected.
если (Timer0Count == (PeriodTime-1)) разрешаем вывод OCR0A как CLEAR on compare match.
если (Timer0Count == PeriodTime) PORTB &= ~(1<<3);Timer0Count=0;Normal port operation, OC0A disconnected.

Таким образом, управление выводом в нужные моменты производится аппаратно, без джиттера.
160 тактов(10мкс) должно хватить на обработчик(я так думаю).
С тормозами фоновых процессов придётся смириться потому что программный DDS пожирает много ресурсов. Или повышать FCPU.

Вместо PB3 поставить PD6.

Автор:  akl [ Пн сен 12, 2016 06:35:37 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Можно сгенерировать длительность 10мкс таймером 0 в режиме CTC и всю временную диаграмму привязать в этому интервалу.
Вложение:
TEST_GEN328.rar [1.09 KiB]
Скачиваний: 202

Автор:  B@R5uk [ Вт сен 13, 2016 22:19:17 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Одиночную генерацию импульса заданной длительности можно реализовать с помощью недокументированной возможности таймеров AVR в PWM режиме. Здесь подробное описание: https://wp.josh.com/2015/03/12/avr-time ... explained/ Удачно выбрав кварц и предделитель изменение длительности импульса на 10 мкс будет делаться изменением содержимого регистра счётчика на единицу. Сам такое пробовал — работает.

Правда запускается всё это дело программно. Чтобы не было джиттера запускать следует в прерывании от другого таймера, отлавливая длительность задержки входа в прерывание. Это вполне реально реализовать, я даже где-то здесь на форуме встречал синтез видеосигнала для телевизора на какой-то меге. Надеюсь знатоки подскажут. Там джиттер приводит к прыганию строк вправо-влево на один-два пикселя. Но с помощью специальной последовательности команд задержку можно сделать фиксированной. К сожалению сам не пробовал и подробностей не помню. Точно могу сказать, что там нужен ассемблер, на си не факт что можно сделать.

Если джиттер не страшен, то вообще никаких проблем.

Автор:  Z_h_e [ Ср сен 14, 2016 21:12:35 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Сегодня посидел над Вашей задачей. Сделал генератор полностью аппаратный, но от 1.6Гц. Ниже можно будет тоже, но надо будет несколько поизвращаться с подсчетом переполнений таймера1.

МК - мега328
Тактовая частота- 8МГц
На выходе PD5 100кГц. Ее задает таймер0, эта же нога вход тактирования для таймера 1.
На выходе PB2 частота от 1.6Гц до 50кГц.
Спойлер
Код:
/*
 * GccApplication1.c
 *
 * Created: 14.09.2016 20:51:50
 *  Author: ZHE
 */
#define F_CPU 8000000UL
#define F_Timer 100000UL*10
#define TOP OCR1A
#define SourseTimer 7


#include <avr/io.h>
#include <util/delay.h>

//*******************************************************************************************

void Set_Freq (uint16_t Freq, uint32_t Dlina_Imp_us){ //Freq=1 => 0,1 Гц
   TCCR1B&=0xF8;//остановить счетчик
   
   TOP=(F_Timer/Freq-1);
   OCR1B=(uint16_t)(Dlina_Imp_us/10-1);
   
   TCCR1B|=SourseTimer;//запустить счетчик
}
//*******************************************************************************************
int main(void)
{
   DDRB=1<<PB2;//выход генератора
   
   DDRD=1<<PD5; //выход счетчик T0 и он же вход T1
   
   //настройка таймера 0 для тактирования T1 100кГц
   TCCR0B=(1<<WGM02)+1;
   TCCR0A=(1<<WGM01)+(1<<WGM00)+(1<<COM0B1)+(1<<COM0B0);
   OCR0A=79;
   OCR0B=40;
   
   //настройка таймера 1
   
   TCCR1A=(1<<COM1B1)+(0<<COM1B0)+(1<<WGM11)+(1<<WGM10);
   TCCR1B=(1<<WGM13)+(1<<WGM12)+SourseTimer;//
   //TOP=0x2-1;//10;
   //OCR1B=0x1-1;
   //Set_Freq(100,50);
   
   
    while(1)
    {
   
     Set_Freq(1000,5000); //100 Гц 5000 мкс
      _delay_ms(2500); 
      
      Set_Freq(2000,2500);//200 Гц 2500 мкс
      _delay_ms(2500);
      
      Set_Freq(10000,500);//1000 Гц 500 мкс
      _delay_ms(2500);
    
      Set_Freq(16,250000);//1,6 Гц 250 мc
      _delay_ms(10000);
    }
}

Автор:  Hel [ Ср сен 21, 2016 21:24:35 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Огромное спасибо всем, кто откликнулся, сам укатил в небольшую командировку на неделю и потому молчал.
Уважаемый uk8amk, можно мне как новичку-гуманитарию пояснить пару строчек?
Как они должны правильно выглядеть на си?
uk8amk писал(а):
if (Timer0Count == (DelayTime-1)) разрешаем вывод OCR0A как SET on compare match.

if (Timer0Count == (PeriodTime-1)) разрешаем вывод OCR0A как CLEAR on compare match.
.

Как я вас понял:
void WorkOn() {
OCR0A=159; //Количество импульсов соответствующих 10 микросекундам. 16 МГц /160 - 1 (число циклов потраченных на выполнение комманд)
TIMSK0=(1<<OCIE0A);
TCNT0 = 0;
TCCR0B |= (1<<WGM00)|(0<<WGM01)|(0<<CS02)|(1<<CS01)|(1<<CS00); //Предделитель тактовой частоты - 1. режим СТС.
UpdateF();
}
ISR (TIMER0_COMPA_vect) // Генератор импульсов.
{
Timer0Count=Timer0Count+1;

if (Timer0Count == (DelayTime-1)){
TCCR0A |= (1<<COM0A0)|(1<<COM0A1);
}


if (Timer0Count == (DelayTime)) {PIND = 1<<6;}

if (Timer0Count == (PeriodTime-1)){
TCCR0A |= (1<<COM0A0)|(0<<COM0A1);
}


if (Timer0Count == PeriodTime){PIND = 0<<6;}

Timer0Count=0; // Сброс счетчика.
}

UPD проверил, не работает :( на выходе при запуске появляется +5 в и больше ничего. не снимается даже когда PORTD &= ~(1<<6);
Видимо, я где-то напортачил в коде или же не так понял идею.


Z_h_e спасибо, тоже хорошая идея, единственное, что может серьезно помешать - нижний предел 1,6 гц. Эх, не была бы нужна низкая частота - был бы, пожалуй, лучший вариант.

Автор:  akl [ Чт сен 22, 2016 02:11:24 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Не нравится эта строчка
Код:
TCCR0B |= (1<<WGM00)|(0<<WGM01)|(0<<CS02)|(1<<CS01)|(1<<CS00); //Предделитель тактовой частоты - 1. режим СТС.
По мне должно быть что-то типа такого. Не понимаю в этих кыржиках-писал по аналогии
Код:
TCCR0A |= (1<<WGM01) //режим СТС.
TCCR0B |= (1<<CS00); //Предделитель тактовой частоты - 1.

Автор:  Z_h_e [ Чт сен 22, 2016 06:08:46 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Hel писал(а):
единственное, что может серьезно помешать - нижний предел 1,6 гц.
Z_h_e писал(а):
Ниже можно будет тоже, но надо будет несколько поизвращаться с подсчетом переполнений таймера1


А если вдруг на низкой частоте длительность импульса может быть больше, то тогда достаточно понизить частоту с таймера 0.

Автор:  uk8amk [ Чт сен 22, 2016 10:08:50 ]
Заголовок сообщения:  Re: Генератор на ATMega328p

Код:
if (Timer0Count == (DelayTime-1)){
TCCR0A |= (1<<COM0A0)|(1<<COM0A1);
}
if (Timer0Count == (PeriodTime-1)){
TCCR0A |= (1<<COM0A0)|(0<<COM0A1);
}

Это значит что в итоге всегда будет COM0A0=1, COM0A1=1(Set OC0A on Compare Match).

Перед тем как делать
{PIND = 1<<6;}
Надо линию порта переключить с альтернативной функции на GPIO(опять же через COM0A0, COM0A1).

Строка
if (Timer0Count == PeriodTime){PIND = 0<<6;}
Не имеет смысла потому что
Цитата:
14.2.2 Toggling the Pin
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI
instruction can be used to toggle one single bit in a port.

Иными словами смена состояния возможна только при записи 1.
И применять данную функцию вам надо с осторожностью, поскольку результат зависит от предыдущего состояния линии порта.

Страница 1 из 1 Часовой пояс: UTC + 3 часа
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/