Генератор с регулируемоей частотой на ардуино.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

iarick пишет:

Добрый день, помогите начинающему. Хочу собрать данный генератор. Он мне нужен в первую очередь для отладки УМЗЧ.

Как я понимаю, у генератора будет синусойда смещена верх (постоянная составляющая)..

Просьба подсказать реально хорошую схему буферного усилителя которая:

1. Убирала постоянную составляющую

2. Позволяла бы регулировать амплитуду до 5-7 в...

Заранее признателен.

П.С. отсмотрел много (хотя по факту их мало ;)  ) всяких схем и запутался окончательно, прошу помощи гуру.

если решил заняться усилителями ищи на Авито ГЗ-118, он для этого годится

Piton
Offline
Зарегистрирован: 18.01.2022

iarick, на 13-й странице я выкладывал схему смещения и усилителя. Всё прекрасно работает. Но в последней версии я отказался от регулировки смещения во втором каскаде, сделал как в авторской(верхняя схема), иначе будет зависимость выходного напряжения от нагрузки. Смещение выставляется в первом каскаде один раз подстроечником. Можно при желании и им регулировать, но будет не симметрично. Если нагрузка высокоомная, то можно оставить и так. В этом варианте вам придётся коммутатор делать на реле, или, как в моём случае, на adg604, или ставить смещение и усилитель после коммутатора, подключая его в режиме синуса. Конечно, это не ГЗ-118, но до 20кГц вполне приличный синус и вполне сойдёт для настройки усилителей.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Насчет "вполне приличного синуса" есть некоторые сомнения. Особенно на высоких частотах.

Следовательно, в сигнале будет довольно много гармоник. Уменьшить их количество можно при помощи ФНЧ. Например, типа такого:

Piton
Offline
Зарегистрирован: 18.01.2022

А что нужно начинающему аудиофилу для настройки усилителя?-посмотреть искажения типа "ступенька",   равномерность частотного  диапазона, выходную мощность, плюс есть ешё и прямоугольник для дополнительных испытаний. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Piton пишет:

А что нужно начинающему аудиофилу для настройки усилителя?-посмотреть искажения типа "ступенька",   равномерность частотного  диапазона, выходную мощность, плюс есть ешё и прямоугольник для дополнительных испытаний. 

а это хороший вопрос, вгонял усилители в параметры  по неравномерности, коэффициенту гармоник ...а ведь  я еще даже не начинающий...генератор, осциллограф и измеритель нелинейных искажений были стандартным набором...

Piton
Offline
Зарегистрирован: 18.01.2022

Ну, если "вгонять", то тогда да. Осциллограф по умолчанию должен быть. А вот измеритель нелинейных искажений с этим генератором, разумеется, будет лишним. Для большинства "даже не начинающих", достаточно будет этого генератора и осциллографа. Это, конечно, моё личное мнение.

iarick
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

iarick пишет:

Просьба подсказать реально хорошую схему буферного усилителя которая:

1. Убирала постоянную составляющую

2. Позволяла бы регулировать амплитуду до 5-7 в...

1. Конденсатор.

2. Потенциометр + ОУ с коэффициентом усиления ~3.

 

Вот тут то и загвоздка....

1. Емкости. Какой номинал предлагаете? Просто в разных схемах от 1 мкф до 100 пик предлагают ставить... Понимаю, что 1 Мкф много... но самому сделать расчет, да так чтоб еще и прямоугольник не валился по фронтам, не умею пока.... Какое значение емкости предлагаете?

2. Какой ОУ предлагаете ? (желательно конкретную модель), понимаю, что для этого генератора верхняя граничная частота должна быть не менее 50 мгц... или я ошибаюсь?

Заранее признателен за помощь...

iarick
Offline
Зарегистрирован: 24.12.2020

andriano пишет:

iarick пишет:

Просьба подсказать реально хорошую схему буферного усилителя которая:

1. Убирала постоянную составляющую

2. Позволяла бы регулировать амплитуду до 5-7 в...

1. Конденсатор.

2. Потенциометр + ОУ с коэффициентом усиления ~3.

 

Вот тут то и загвоздка....

1. Емкости. Какой номинал предлагаете? Просто в разных схемах от 1 мкф до 100 пик предлагают ставить... Понимаю, что 1 Мкф много... но самому сделать расчет, да так чтоб еще и прямоугольник не валился по фронтам, не умею пока.... Какое значение емкости предлагаете?

2. Какой ОУ предлагаете ? (желательно конкретную модель), понимаю, что для этого генератора верхняя граничная частота должна быть не менее 50 мгц... или я ошибаюсь?

Заранее признателен за помощь...

iarick
Offline
Зарегистрирован: 24.12.2020

Piton пишет:

А что нужно начинающему аудиофилу для настройки усилителя?-посмотреть искажения типа "ступенька",   равномерность частотного  диапазона, выходную мощность, плюс есть ешё и прямоугольник для дополнительных испытаний. 

 

В десятку!!!!. ;) ну, еще б правда хотелось, ШИМ иметь, как запас на будущее ;)

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

iarick пишет:

1. Емкости. Какой номинал предлагаете? Просто в разных схемах от 1 мкф до 100 пик предлагают ставить... Понимаю, что 1 Мкф много... но самому сделать расчет, да так чтоб еще и прямоугольник не валился по фронтам, не умею пока.... Какое значение емкости предлагаете?

2. Какой ОУ предлагаете ? (желательно конкретную модель), понимаю, что для этого генератора верхняя граничная частота должна быть не менее 50 мгц... или я ошибаюсь?

Заранее признателен за помощь...

1. Вы мне предлагаете потыкать пальцем в небо, указывая, какова величина емкости должна быть для неизвестной схемы? Номинал нужно считать для конкретной схемы.

2. Вам нужно для усилителя звуковой частоты? Тогда достаточная полоса пропускания - произведение верхней рабочей частоты (20 кГц?) на коэффициент усиления. Откуда там 50 МГц?

У меня к Вам встречный вопрос, Вы всерьез собираетесь заниматься настройкой высококачественного усилителя, не умея даже просчитать простейшую схему? Думаю, у Вас ничего не получится.

Посоветую прочитать:

- Хоровиц, Хилл, Искусство схемотехники*,

- Титце, Шенк, Полупроводниковая схемотехника*.

Обе прочитать от корки до корки и не менее двух раз.

* писал по памяти, если где ошибся, в теме "Новичок, прочти" есть точные ссылки с указанием инициалов.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

DIMAX! Такой вопрос, аддон Кларка под IDE версии 1.8.19 не пробовал адаптировать?

MAG-N
MAG-N аватар
Offline
Зарегистрирован: 05.06.2017

А зачем адаптировать? Под 1.8.19 вроде и так работает.

Под 2.0.3 тоже

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Да пытаюсь дисплей ST7789 прикрутить, по привычке библиотеки у меня лежат /portable/sketchbook/libraries а аддон в /portable/packages  ...что-то не выходит каменный цветок...

MAG-N
MAG-N аватар
Offline
Зарегистрирован: 05.06.2017

Так может все дело в библиотеке для 7789, а АДДОН не виноват?

Далеко не все библиотеки дружат с СТМ32

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

MAG-N пишет:

Далеко не все библиотеки дружат с СТМ32

интересно девки пляшут, вот как так, ST7735 работает, а ST7789 - белый экран, подкидываю ST7735 на прошивке с ST7789 - показывает, хоть и с лагами, библиотеки от Adafruit

termak
Offline
Зарегистрирован: 11.09.2020

Уже устал бороться с этим генератором. V.3.5

Прошиваю прошивками с этого сайта ST-Link и ничего кроме подсветки не работает.

Брал и разные платы и уже купил второй индикатор... (думал может индикатор не работает).

Однако не могу запустить ничего.

 

apeks1
apeks1 аватар
Offline
Зарегистрирован: 19.05.2016

2 варианта

1 чтото вы неправильно с перемычками загрузчика делаете

2 возможно в схеме с разводкой намутили

UEF
Offline
Зарегистрирован: 27.01.2018

Добрый день,

Кто использует версию 3.5 без SI5351? Стабильно работает? У меня запускется через раз и иногда не адекватно работает энкодер, Когда не запускается , то просто пустой экран, после нажатия, несколько раз на сборо , может запустится. 

postal2201
Offline
Зарегистрирован: 05.01.2017

Добрый день! Подскажите, возможно ли на ардуино сделать меандр с частотой 3.58MHz и 4.43MHz при установленном кварце на 16MHz ? Или хотя-бы с заменой кварца, но так чтобы его частота была не ниже 16MHz, и можно было использовать 1 кварц для обеих частот.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Нет

240265
240265 аватар
Offline
Зарегистрирован: 12.08.2015

 postal2201   Проще 2 генератора на инверторах собрать.

Dushev
Offline
Зарегистрирован: 29.04.2018

[quote=UEF]

Добрый день,

Кто использует версию 3.5 без SI5351? Стабильно работает? У меня запускется через раз и иногда не адекватно работает энкодер, Когда не запускается , то просто пустой экран, после нажатия, несколько раз на сборо , может запустится. 

1[quote]<span style="font-family:Verdana, Geneva, Arial, sans-serif;font-size:12px;">
2 
3</span>
Dushev
Offline
Зарегистрирован: 29.04.2018
001/*       Генератор с регулируемой частотой v3.5  (C)Dimax     
004 */
005    #define pwm2_polar 0 //полярность выхода PWM2 (вывод PA7)
006   #define paper        0x000000 // цвет фона экрана
007  #define DDSMAX 1E7 //максимальная частота для генератора DDS (удесятерённая)
008 #define dds_mpl_72 1133.8314742150209378723713167832 //множитель DDS для частоты F_CPU 72МГц
009                  //835.05327478167234049174700635502 - origin !!!
010//для пересчёта множителя необходимо: частоту на экране прибора * текущий множитель и разделить на фактически измеренную частоту
011#define dds_mpl_128 469.7191655978919104715512499704  //множитель DDS для  частоты F_CPU 128Mhz
012#define VrefINT 1209  //внутренее опорное напряжение в милливольтах
013 #define Mn 6.06  //множитель для пересчёта напряжения с учётом резисторного делителя.
014 #include <Adafruit_ST7735.h> // Hardware-specific library
015   #include <SPI.h>
016     #include <Wire.h>
017      #include <libmaple/dac.h>
018       Adafruit_ST7735 tft = Adafruit_ST7735(-1, PB11,PB10); //PB12 освобождён, вывод CS дисплея запаять на землю.
019         boolean  modevolt, infreqpsc; // si5351_found,
020      volatile int enc_tic=0, duty_in=50, mon_flag, divider, modebit=1;
021      volatile int mode=1;//  1-PWM, 2-Duty, 3-impuls , 4..7 DDS, 8-Freqmeter, 9-VoltMeter
022      volatile byte imp_mode=1; //единицы счёта длины импульса  по умолчанию 0-мс, 1-мкс, 2 -такт
023      volatile byte imp_mode_menu=0; //переменная выбора меню в одновибраторе (значение длины/единица времени/шаг)
024      volatile int encstep=10; //шаг изменения частоты по умолчанию (желаемый *10)
025     volatile int32_t freq=10000; //частота по умолчанию (желаемая *10)
026   volatile float duty_out;// переменная счёта скважности
027  float t_hi, t_low; //переменные счёта длины импульсов
028  uint32_t Vcc; //переменная внутреннего измерения напряжения питания МК (милливольты)
029 int Vin_low=0, Vin_hi=15000; //переменные пределов для вольтмера (милливольты)
030uint8_t wave[512]; //массив для DDS синтеза
031uint8_t sine_logo[] __FLASH__ ={25,27,28,30,31,33,34,36,37,38,40,41,42,43,
032 44,45,46,47,48,48,49,49,50,50,50,50,50,50,50,49,49,48,48,47,
033   46,45,44,43,42,41,40,38,37,36,34,33,31,30,28,27,25,23,22,20,
034    19,17,16,14,13,12,10,9,8,7,6,5,4,3,2,2,1,1,0,0,0,0,0,0,0,1,
035     1,2,2,3,4,5,6,7,8,9,10,12,13,14,16,17,19,20,22,23};
036          void setup() {
037          delay(100);// пауза для загрузки дисплея
038          SPI.setModule(2);// выбор SPI2
039        tft.initR(INITR_BLACKTAB);
040       tft.setRotation(3);//дисплей горизонтально, контакты слева
041      tft.fillScreen(paper);//залить цветом по умолчанию
042    tft.setTextWrap(0);//не переносить строки
043 Serial.end();// дефолтовый USBCDC не нужен
044 nvic_irq_disable_all();//отключить все прерывания
045disableDebugPorts();//отключить режим дебага
046systick_disable(); // отключить системный таймер
047RCC_BASE->APB1ENR|= (1<<2)|(1<<1)|(1<<0); //включить тактирование tim-2,3,4
048 RCC_BASE->APB2ENR|= (1<<3)|(1<<11)|(1<<2)|(1<<0)|(1<<4);////включить тактирование port-a-b-c,tim1
049  AFIO_BASE->MAPR|=(1<<8)|(1<<6); //tim 1 && tim 2 Partial remap
050   i2c_master_enable(I2C1, I2C_REMAP); //SDA PB9, SCL PB8
051    Wire.begin();
052  pinMode(PB0,PWM); //buzzer
053  pinMode (PB1,INPUT_ANALOG); // вход АЦП
054   pinMode(PB5,INPUT_PULLUP);//key encoder
055    pinMode(PB3,OUTPUT); //мультиплексор
056     pinMode(PB4,OUTPUT); //мультиплексор
057      pinMode(PB6,INPUT_PULLUP);//encoder
058       pinMode(PB7,INPUT_PULLUP);//encoder
059        mytone(1000,50);//сигнал после старта
060      attachInterrupt(PB5, key_enc_int, RISING);//прерывание кнопки энкодера
061     attachInterrupt(PB6, enc_int, CHANGE); attachInterrupt(PB7, enc_int, CHANGE);//прерывания энкодера
062   adc_enable_single_swstart(ADC1);//запуск АЦП
063   ADC1->regs->CR2 |= ADC_CR2_TSVREFE; // Enable VREFINT conversion
064   ADC1->regs->SMPR1=3<<21;  //ADC (vrefint) Sample time = 28.5 cycles
065 ADC1->regs->SMPR2=3<<27; //ADC (channel 9) Sample time = 28.5 cycles
066if (mode==1){ timer_set(0); }
067} //end setup
068 
069 
070void loop() {
071static int old_mode_loop=-1;
072  //чистить полностью экран только при смене режимов
073  if (mode!=old_mode_loop) { tft.fillScreen(paper); old_mode_loop=mode; mon_flag=1;}
074    comm();//коммутация выходов мультиплексором
075     if (mode==8) {mon_out(); freq_meter();  }
076   if (mode==9) {volt_meter(); mon_out(); }
077   if (mode >2 && mode<8) { mon_out();  dds_set(); } // запуск DDS режимов
078 if (mon_flag) {mon_flag=0; mon_out();} //в остальных ситуациях при наличии флага вывода на дисплей
079}
080   
081 
082void freq_meter(){
083/////////////////////счётчик импульсов
084pinMode(PA15,INPUT_PULLDOWN); // вход частотометра
085 uint32_t imp_long,imp_hi;//переменные измерения длины такта
086   __asm volatile( "cpsid i" );
087   /// Timer2 счёт младших 16 бит
088RCC_BASE->APB1RSTR |=  1<<0; //сброс таймера2
089 RCC_BASE->APB1RSTR &= ~(1<<0); // сброс таймера2
090  TIMER2_BASE->CR2=1<<5; //MMS:010 управление подчинённым в режиме "Update"
091    TIMER2_BASE->SMCR= (1<<14)|(infreqpsc<<13)|(infreqpsc<<12);// режим 2 внешнего тактирования + делитель/8 + разрешение работы от таймера1
092     TIMER2_BASE->ARR=65535; //считать до максимума
093       TIMER2_BASE->EGR=1; //перечитать регистры.
094       TIMER2_BASE->CR1|=(1<<0);//start timer2
095      /// Timer3 счёт старших 16 бит
096RCC_BASE->APB1RSTR |=  1<<1; //сброс таймера3
097 RCC_BASE->APB1RSTR &= ~(1<<1); // запуск таймера 3
098 TIMER3_BASE->SMCR=(1<<2)|(1<<1)|(1<<0)|(1<<4);//SMS:111 && TS:001  такт брать от 2-го таймера 
099  TIMER3_BASE->ARR=65535; //считать до
100   TIMER3_BASE->EGR=1; //перечитать регистры.
101    TIMER3_BASE->CR1|=(1<<0);//start timer3
102    /// настройка времени разрешения на таймере1 для таймера2
103     TIMER1_BASE->CR1=(1<<3)|(1<<2);//один импульс, без прерываний
104      TIMER1_BASE->CNT=0;
105       TIMER1_BASE->CR2=(1<<4);  //MMS:001 сигнал разрешения работы другим таймерам
106        TIMER1_BASE->CCER=0;// отключить выходы таймера на физ ноги
107         TIMER1_BASE->PSC=F_CPU/36000 -1;// 1999; // 72000000/2000= 36000кГц тактовая таймера
108          TIMER1_BASE->ARR=35999;//считать до 36000 (1секунда)
109          TIMER1_BASE->EGR=1; //перечитать регистры.
110         TIMER1_BASE->CR1|=(1<<0);
111       __asm volatile( "cpsie i" );
112      while (TIMER1_BASE->CR1&1) {asm volatile("nop"); if(mon_flag) {return;}  }
113     freq=  TIMER3_BASE->CNT<<16  | TIMER2_BASE->CNT; //частота (не удесятерённая)
114    if (infreqpsc) {freq*=8;}// если включен делитель на 8 то результат умножить на 8
115    if (freq>1E5){freq*=10; t_low=0;t_hi=0; duty_out=0; mon_flag=1; return;} //выйти если freq больше 100кГц
116   // Перенастройка таймера 2 в режии измерения длительности импульса и скважности для частот менее 100 кГц
117 divider=1;                                 
118while ((F_CPU/divider/((freq>0)? freq : 1 )) > 65000) {divider++;}
119 __asm volatile( "cpsid i" );
120RCC_BASE->APB1RSTR |=  1<<0; //сброс таймера2
121 RCC_BASE->APB1RSTR &= ~(1<<0); // запуск таймера 2
122  TIMER2_BASE->CR1=0;//стоп таймер
123    TIMER2_BASE->PSC= divider-1;
124      TIMER2_BASE->SMCR=(1<<4)|(1<<6)|(1<<2);// TS:101 SMS:100  вход TI1FP1  , Режим сброса
125        TIMER2_BASE->CCMR1=(1<<0)|(1<<9);//CC1 input,mapped on TI1, CC2 input,mapped on TI1
126         TIMER2_BASE->CCER=(1<<5)|(1<<0)|(1<<4);//cc1-Hi,cc2-lo
127        TIMER2_BASE->EGR=1; //перечитать регистры.
128   /// настройка таймера1 для счёта  тайм-аута при измерения PWM
129     TIMER1_BASE->CR1=(1<<3);//один импульс, без прерываний
130      TIMER1_BASE->CNT=0; TIMER1_BASE->CR2=0;  TIMER1_BASE->CCER=0;
131         TIMER1_BASE->PSC=F_CPU/15625 -1; // тактовая таймера 15625 Герц
132          TIMER1_BASE->ARR=31250;//считать до 31250 (2 секунды)
133          TIMER1_BASE->EGR=1; //перечитать регистры.
134          timer_attach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT, myint);
135         TIMER1_BASE->CR1|=(1<<0);// старт счёта 2х секунд     
136      __asm volatile( "cpsie i" );
137       TIMER2_BASE->CR1=(1<<0);// старт захвата PWM
138     while( (TIMER2_BASE->SR&0x65F)!=0x65F) {
139      asm volatile("nop"); if(mon_flag) {timer_detach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT); return;} }
140    TIMER2_BASE->CR1=0;// стоп таймер
141   timer_detach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT);
142   imp_long=(uint32_t) ((TIMER2_BASE->CCR1)*divider);
143  imp_hi=(uint32_t)  ((TIMER2_BASE->CCR2)*divider);
144 if (freq <1000){ freq= F_CPU*10 /imp_long ;} //если freq Менее 1кГц то использовать данные второго НЧ-измерения частоты (*10)
145 else {freq*=10; } //иначе просто удесятерить результат для корректного вывода информации.
146duty_out=  (float) imp_hi / (imp_long / 100.0) ;
147if (duty_out > 100 || duty_out < 0) {duty_out=0;} // на всякий случай ограничение
148 t_low= (double)(imp_long-imp_hi) / (F_CPU/1E6) ;
149  t_hi=  (double) imp_hi /(F_CPU/1E6);
150   mon_flag=1;
151   } //END freq meter
152 
153// прерывание тайм-аута при отсутствиии сигнала на входе при измерении PWM
154void myint(){ mon_flag=1; t_low=0; t_hi=0; duty_out=0;  freq=0;
155timer_detach_interrupt(TIMER1, TIMER_UPDATE_INTERRUPT);
156}
157 
158///////////////////////////////////////////////////////////////////////////
159/////////*********** ВЫВОД НА ДИСПЛЕЙ************//////////////////////////
160///////////////////////////////////////////////////////////////////////////
161void mon_out(){
162char mybuf[15];
163//************** Вывод первой строчки*****************************
164  tft.setCursor(0, 0); //  вперёд, вниз
165   tft.setTextColor(ST7735_GREEN, paper);
166    tft.setTextSize(2);
167    switch(mode){
168              
169        case 1: tft.print("  PWM Mode   "); break;
170          case 2: tft.print("  Duty Mode  "); break;
171           case 3: tft.print("  Sine DDS  "); break; //3
172            case 4: tft.print(" Triangle DDS"); break; //4
173           case 5: tft.print("  Saw 1 DDS  "); break; //5
174          case 6: tft.print("  Saw 2 DDS  "); break; //6
175         case 7: tft.print("  Square DDS "); break;
176       case 8: tft.print(" Freq. meter "); break; //7
177      case 9: tft.print(" Volt. meter "); break; //8
178       }
179  
180 //*****************Вывод второй строчки*****************************
181tft.setTextColor(ST7735_WHITE, paper);
182tft.setCursor(0, 19); tft.setTextSize(3); 
183 if (freq>=1E8) {tft.print("         ");   tft.setTextSize(2);tft.setCursor(0, 21);}  
184     if (freq<10) {sprintf(mybuf,"   0,%ld   ", freq );}                //9 -> 0,9
185else if (freq<100){sprintf(mybuf,"   %ld,%ld   ", freq/10, freq%10 );}   //99 -> 9,9               
186else if (freq<1E3){sprintf(mybuf,"   %ld,%ld  ", freq/10, freq%10 );}    //999 -> 99,9          
187else if (freq<1E4){sprintf(mybuf,"  %ld,%ld  ", freq/10, freq%10 );}    //9999 -> 999,9            
188else if (freq<1E5){sprintf(mybuf,"  %ld %03ld  ", freq/10000, (freq/10)%1000 );} //99999 -> 9.999              
189else if (freq<1E6){sprintf(mybuf,"  %ld %03ld ", freq/10000, (freq/10)%1000 );}  //999999 -> 99.999                      
190else if (freq<1E7){sprintf(mybuf," %ld %03ld ", freq/10000, (freq/10)%1000 );} //999999 -> 999.999                      
191else if (freq<1E8){sprintf(mybuf,"%ld %03ld %03ld", freq/10000000, (freq%10000000)/10000, (freq%10000)/10  );} //9999999 -> 9.999.999                      
192else              {sprintf(mybuf,"%3ld %03ld %03ld", freq/10000000, (freq%10000000)/10000, (freq%10000)/10  );} //99999999 -> 99.999.999             
193 
194 
195tft.print(mybuf);    //вывод частоты
196  //********************Вывод третьей строчки*****************************
197               tft.setTextColor(ST7735_RED,paper); //красный цет строки для всех вариантов             
198               
199              if (mode==9){ //если вольтметр
200                tft.setTextSize(3); //крупно
201               tft.setCursor(50, 43);
202                tft.print(" mV"); }             
203 
204              else if (mode==8) { //если частотометр
205               tft.setTextSize(2);
206                tft.setCursor(20, 43);
207                tft.print("Herz ");
208                tft.setCursor(75, 50); tft.setTextSize(1);
209                infreqpsc? tft.print("max 180MHz") : tft.print("max 32MHz ") ;
210                 }
211 
212if (imp_mode_menu == 1) {tft.setTextColor(ST7735_RED,ST7735_WHITE);}  /////   изтрий ако горното е вкл.
213               
214               else if (mode <8) { //если генераторы
215                tft.setTextSize(3);
216                tft.setCursor(50, 43);
217               tft.print("Herz"); 
218                }
219           
220  //********************* "осциллограммы"******************************
221     if (mode!=9){ tft.fillRect(5,90, 100,38,paper); }// зачистка пяточка (вправо, вниз, ширина вправо, длина вниз)
222     tft.drawRect(0,67, 160,61,ST7735_MAGENTA);//рамка: вправо, вниз, ширина вправо, длина вниз
223      if (mode==1 ||mode==2 || mode==8){
224        tft.drawFastVLine(5, 90, 30, ST7735_CYAN); // восход фронта статическая вер линия
225         tft.drawFastHLine(5, 91, (int)duty_out, ST7735_YELLOW);//длина единицы
226          tft.drawFastHLine(5, 90, (int)duty_out, ST7735_YELLOW);//паралельная линия для выделения
227           tft.drawFastVLine((int)duty_out+5, 91, 30, ST7735_YELLOW);// спад
228            tft.drawFastVLine((int)duty_out+4, 90, 30, ST7735_YELLOW);//паралельная линия для выделения
229             tft.drawFastVLine(105, 90, 30, ST7735_YELLOW);//спад конец такта статическая вер. линия
230              tft.drawFastVLine(104, 90, 30, ST7735_YELLOW);//паралельная линия для выделения
231               tft.drawFastHLine((int)duty_out+5, 120, (100-(int)duty_out), ST7735_YELLOW);//линия единицы 2-го такта
232                tft.drawFastHLine((int)duty_out+5, 119, (100-(int)duty_out), ST7735_YELLOW);//паралельная линия для выделения
233                 }
234                        
235                       if (mode==3){ // логотип синуса
236                    for(uint8_t n=0; n<100; n++){tft.drawPixel(5+n, 73+ sine_logo[n],ST7735_YELLOW);
237                    } //END  for
238                 } // END if (mode==3)
239                       else if (mode==4){// логотип треугольника                        
240                      tft.drawLine(5,98,30,73,ST7735_YELLOW);
241                     tft.drawLine(30,73,80,123,ST7735_YELLOW);
242                    tft.drawLine(80,123,105,98,ST7735_YELLOW);
243                  } //END  mode==5
244                         else if (mode==5){ //логотип пилы1
245                           tft.drawLine(5,123,105,73,ST7735_YELLOW);
246                           tft.drawFastVLine(105, 73, 50, ST7735_YELLOW);//спад конец такта статическая вер. линия
247                           } //END  if (mode==5)
248                            else if (mode==6){//логотип пилы2
249                             tft.drawFastVLine(5, 73, 50, ST7735_YELLOW); // восход фронта статическая вер линия
250                             tft.drawLine(5,73,105,123,ST7735_YELLOW);
251                              }// END  if (mode==6)
252                                else if (mode==7 || mode==0){ //логотип меандра
253                                  tft.drawFastVLine(5,73,25,ST7735_YELLOW);
254                                  tft.drawFastHLine(5,73,50,ST7735_YELLOW);
255                                  tft.drawFastVLine(55,73,50,ST7735_YELLOW);
256                                  tft.drawFastHLine(55,123,50,ST7735_YELLOW);
257                                  tft.drawFastVLine(105,98,25,ST7735_YELLOW);
258                                }
259                   //*********************** характеристики сигнала****************************************
260                  tft.setCursor(5, 70); //  вперёд, вниз
261                 tft.setTextColor(ST7735_WHITE, paper);
262                tft.setTextSize(1);
263                 if (mode==1 ||mode==2 || mode==8){ //
264               tft.print("+Width="); if (t_hi<1E3) {tft.print(t_hi); tft.print(" uS  ");} else {tft.print(t_hi/1000); tft.print(" mS  ");} 
265              tft.setCursor(5, 80); //  вперёд, вниз
266            tft.print("-Width="); if (t_low<1E3) {tft.print(t_low); tft.print(" uS  ");} else {tft.print(t_low/1000); tft.print(" mS  ");} 
267           tft.setCursor(114, 70); tft.print("Duty=");
268          tft.setCursor(114, 80); tft.print(duty_out,0);tft.print(" %   ");
269          } //END
270          if (mode < 2 || mode==8)
271   if (mode==9) { tft.print("Vcc=");tft.print(Vcc); tft.print(" mV   ");}
272 
273  if (mode==8){ return;} // в режиме  частотометра выводить на экран больше ничего не нужно.
274           
275  /////////// установка курсора и вывод шага в разных режимах ///////////////  
276   
277                else if (mode<9) { tft.setCursor(114, 95); tft.print("Step="); tft.setCursor(114, 105);}
278                 else if (mode==9)  {tft.print("Step=");} //только в вольтметре
279                 
280                   switch (encstep) {
281                    case 1: tft.print(" 0,1"); break;
282                    case 10: tft.print("   1"); break;
283                    case 100: tft.print("  10"); break;
284                    case 1E3: tft.print(" 100");break;
285                    case 1E4: tft.print(" 1E3");break;
286                    case 1E5:  tft.print(" 1E4");break;
287                    case 1E6:  tft.print(" 1E5");break;
288                    case 1E7:  tft.print(" 1E6");break;
289                    case 1E8:  tft.print(" 1E7");break;
290                   }// END switch case */         
291   // вывод прочей информации
292 
293/// вывод пределов для вольтметра
294if (mode==9) {
295 tft.setCursor(5, 80); //  вперёд, вниз
296    tft.setTextSize(2);
297     tft.setTextColor(modevolt? ST7735_YELLOW : ST7735_WHITE , paper);//выбрать жёлтый цвет если активен
298      sprintf(mybuf,"Low_mv=%5d", Vin_low);//выводить 5 символов
299      tft.print(mybuf);    //вывод нижнего предела
300      tft.setTextColor(modevolt? ST7735_WHITE : ST7735_YELLOW , paper);
301    tft.setCursor(5, 100); //  вперёд, вниз
302  sprintf(mybuf," Hi_mv=%5d", Vin_hi);
303tft.print(mybuf); //вывод верхнего предела
304 }
305 
306}//END mon_out
307 
308//обработчик прерываний энкодера
309void enc_int(){  
310static char EncPrev=0;      //предыдущее состояние энкодера
311 static char EncPrevPrev=0;  //пред-предыдущее состояние энкодера
312  char EncCur = 0;
313   if(!(  GPIOB_BASE->IDR&64  )){EncCur  = 2;} //опрос фазы 1 энкодера
314    if(!(  GPIOB_BASE->IDR&128 )){ EncCur |= 1;} //опрос фазы 2 энкодера
315    if(EncCur != EncPrev)             //если состояние изменилось,
316    {
317    if(EncPrev == 3 &&        //если предыдущее состояние 3
318       EncCur != EncPrevPrev )      //и текущее и пред-предыдущее не равны,
319    {
320      if(EncCur == 2)          //если текущее состояние 2,
321        enc_mode(-1);            //шаг вверх
322      else                          //иначе
323        enc_mode(1);            //шаг вниз
324    }
325    EncPrevPrev = EncPrev;          //сохранение пред-предыдущего состояния
326    EncPrev = EncCur;               //сохранение предыдущего состояния
327  }
328 }// END VOID
329 
330 
331// ФУНКЦИЯ конфигурации режимов
332void enc_mode(int in){
333  modebit= digitalRead(PB5); //состояние кнопки PB5. 0-нажата
334   if (!modebit) {// если сейчас идёт переключение режимов (кнопка нажата)
335   mytone(880,30); //звук переключения режимов
336     mode+=in;
337     if(mode>9){mode=9; modevolt=!modevolt; }
338      else { if(mode<1){mode=1;} }
339     if(mode<1){mode=1;} ///////////////////////////
340       if (mode==1 || mode==2 ){timer_set(0);}
341        if (mode==8) {freq=0;}// сбросить в ноль freq в режиме частотометра
342        if (mode >2 && mode !=8) {if (freq>DDSMAX) {freq=DDSMAX;} }////////////////***********///////////
343         mon_flag=1; enc_step_control();
344         return;
345          } //сюда попадает при изменении частоты (вращение без нажатия)
346         mytone(4400,10); //звук изменения частоты
347       switch(mode){ //если сейчас идёт изменение частоты
348     case 1:   timer_set(in); break;
349     case 2:   duty_in+=in; timer_set(0);  break
350    // case 3:  if (imp_mode_menu==0){ freq+=(encstep*in); if (freq<10) freq=10; if (freq> 500000) {freq=500000;}   }  //переключение длительности импульса
351         //else
352         if (imp_mode_menu==1){ imp_mode++;  if (imp_mode >2){imp_mode=0;} }//переключение 0-мс, 1-мкс, 2 -такт          
353         //else
354         if (imp_mode_menu==2){ encstep*=10; enc_step_control();} //переключение шага
355 
356    case 8:   break; // в частотометре не реагировать на вращение энкодера
357   case 9:   modevolt?  Vin_low+=(encstep/10*in) : Vin_hi+=(encstep/10*in); //регулировка пределов вольтметра
358   if (Vin_low<0||Vin_low>99999 ){Vin_low=0;} if (Vin_hi<0||Vin_hi >99999){Vin_hi=0;} break; //ограничения не менее ноля и не более 4х символов
359  default: freq+=(encstep*in); if (freq>DDSMAX) {freq=DDSMAX;}  //DDS режимы
360 } //end switch case
361 if (freq<0){freq=0;}  
362mon_flag=1;
363}//end enc_mode
364 
365 
366// обработчик кнопки энкодера:
367void key_enc_int(){//сюда должно попадать только при отжимании кнопки (Rising Edge)
368if (digitalRead(PB5)==0) return;// если на пине  ноль значит это дребезг, выходим.
369if(!modebit){ // если до этого менялся режим то выдержать паузу (низкий звук в спикер) и выйти
370     mytone(30,150); //150ms примерно соответсвует времени отпускания кнопки после вращения
371   while( (TIMER2_BASE->SR)==0);//подождать пока пропищит
372  modebit=1; return; //и выйти
373  //сменить режим и выйти если были в duty mode:
374    if (mode==2) { mytone(880,30); mode=1; enc_step_control() ; return;}
375     mytone(160,100); //выдать звук переключения шага
376   while( (TIMER2_BASE->SR)==0);//подождать пока пропищит
377  if (mode==8) {infreqpsc=!infreqpsc; mon_flag=1; return;} //включать/отключать делитель в режиме частотометра                
378  else {encstep*=10;}
379 enc_step_control();
380}//end
381 
382void enc_step_control(){ //ограничение шага в зависимости от режимов и частот
383if ( mode==1  && encstep >1E5) {encstep=1;} //для PWM макс шаг 10 000 Гц
384if (mode>2 && mode<8 && encstep >1E6) {encstep=1;} //для DDS  макс шаг 100 000 Гц
385if (encstep==1 && freq >=10000  ) encstep=10;// менять шаг 0,1 Гц -> 1Гц  на частотах выше 1кГц для всех режимов
386if (mode==9 && (encstep >1E4 || encstep ==1)  ) {encstep=10;} //для вольтметра макс 1000 мв
387mon_flag=1; //флаг вывода на дисплей 
388}
389 
390 
391 
392////////////////НАСТРОЙКА ТАЙМЕРА-ГЕНЕРАТОРА/////////////////////////////////////////////
393void timer_set(int in){ //принимает +1 -1 или 0
394int tim_arr; uint32_t imp_long, imp_hi;
395//общие настройки таймера1
396pinMode(PA7,PWM); pinMode(PA8,PWM);
397 TIMER1_BASE->CR1=0;
398   TIMER1_BASE->CCMR2=0;TIMER1_BASE->PSC=0; TIMER1_BASE->CCR2=0;
399    TIMER1_BASE->CCER=(1<<0)|(1<<2)|(pwm2_polar<<3);//cc1e/cc1ne enable
400     //TIMER1_BASE->BDTR=(1<<15)| 255 ;// dead time sample
401       TIMER1_BASE->CCMR1=(1<<6)|(1<<5)|(1<<3);//PWM mode 1
402         if(freq < 84850){ //изменение частоты таймера по заданной частоте
403          if (in) {freq+=(encstep*in);}//если передавалось изменение частоты, то рассчитать
404           if (freq<1){freq=1;}  if (freq>(F_CPU/2*10)) {freq=F_CPU/2*10;}// ограничение макс. частоты *10
405           tim_arr = F_CPU*10/freq;
406          divider=1; while ( (tim_arr/divider) > 65535) {divider++;}
407         TIMER1_BASE->PSC=divider-1;
408        TIMER1_BASE->ARR=(tim_arr/divider)-1;
409       } //end f (freq < 84850)
410     else { // изменение частоты таймера инкрементом регистра ARR
411    tim_arr=TIMER1_BASE->ARR; //снять тукущее состояния регистра    
412   if (tim_arr<1000 && encstep > 1000) encstep=1000; // уменьшать шаг с ростом частоты
413 if (tim_arr<100 && encstep > 100) encstep=100; // уменьшать шаг с ростом частоты
414if (tim_arr<10 && encstep > 10) encstep=10;   // уменьшать шаг с ростом частоты   
415in*=(encstep/10);
416 tim_arr-=in;
417  if (tim_arr<1) {tim_arr=1;} if (tim_arr>65535) {tim_arr=65535;}
418   TIMER1_BASE->ARR=tim_arr;
419    } // END  изменение частоты таймера инкрементом регистра ARR
420     // установка заданного DUTY
421      if(duty_in>99){duty_in=99;} if(duty_in<1){duty_in=1;}
422       if (mode==1 && TIMER1_BASE->ARR<100){ TIMER1_BASE->CCR1=(TIMER1_BASE->ARR+1)/2 ; duty_in=50;} //сбрасывать duty на 50% на высоких частотах
423        else{TIMER1_BASE->CCR1= (float) (TIMER1_BASE->ARR+1)* duty_in/100.0 ;} //или рассчитать
424         freq= F_CPU*10 /((TIMER1_BASE->ARR+1)*divider);// рассчёт фактической частоты
425          duty_out=  (float) TIMER1_BASE->CCR1 / ((TIMER1_BASE->ARR+1) / 100.0) ; //расчёт фактического duty
426          duty_out= floorf(duty_out); //округление
427         imp_long=(uint32_t) ((TIMER1_BASE->ARR+1)*divider); //длина периода в тактах
428       imp_hi=(uint32_t)  ((TIMER1_BASE->CCR1)*divider); // длина импульса в тактах
429     t_low= (imp_long-imp_hi) /(F_CPU/1E6) ; //время LOW
430   t_hi=  imp_hi /(F_CPU/1E6); //время HI
431 TIMER1_BASE->CR1=1;
432mon_flag=1;
433}//end timer_set
434  
435 
436// КОНФИГУРАЦИЯ DDS РЕЖИМОВ
437void dds_set(){
438 static byte oldmode=255;
439   TIMER1_BASE->CCER=0; //timer output pins disable
440    #if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
441     rcc_clk_enable(RCC_DAC);
442      rcc_reset_dev(RCC_DAC);
443     gpio_set_mode(GPIOA, 4, GPIO_MODE_ANALOG);
444    DAC->regs->CR = DAC_CR_BOFF1 | DAC_CR_EN1 ;
445   #define DDS_OUT DAC->regs->DHR8R1
446  #else
447#define DDS_OUT GPIOA_BASE->ODR
448GPIOA_BASE->CRL = 0x33333333;// pa0-pa7  выход
449  #endif
450     if (oldmode !=mode) {
451      if (mode==3) {for(uint16_t n=0; n<512; n++){wave[n]=255*(sin(TWO_PI*float(n)/512)+1)/2 ;}}// синус
452       else if (mode==4){ for(uint16_t n=0; n<512; n++){if (n<256){ wave[n]=n;} else {wave[n]=(511-n);}}}//треугол
453      else if (mode==5){ for(uint16_t n=0; n<512; n++){ wave[n]=(n>>1);}}                               //пила1
454     else if (mode==6){ for(uint16_t n=0; n<512; n++){ wave[n]=((~n)>>1);}}                            //пила2
455    else if (mode==7){ for(uint16_t n=0; n<512; n++){if (n<256){ wave[n]=0;} else {wave[n]=255;}}}    //меандр
456  oldmode=mode; }
457uint32_t dds_shag= (double)freq/10 * ((F_CPU==72E6)? dds_mpl_72 : dds_mpl_128) ;//  шаг= частота*коэффициент
458asm volatile (
459"mov   R9, %[port];"  "\n\t" // записать в r9 адресс порта "A"-ODR
460 "mov   R8, %[wave];"       "\n\t" //адресс массива положить в r8 
461 "mov   R7, %[shag];"   "\n\t" // значение шага в r7
462  "dds_loop:"                  "\n\t"
463   "add R6, r7;"               "\n\t"  //(1)добавить к аккумулятору шаг
464    "lsrs r2, r6, #23;"         "\n\t"  //(1) положить в R2 сдвинутый на 23 бита аккумулятор
465   "ldrb r2, [r8, r2];"        "\n\t"  //(2)загрузить в R2 выбранный байт из массива
466   "strb  r2, [r9];"           "\n\t"  //(2) запиcать этот байт в PORTA-ODR
467  "ldr  R2, [%[flag]];"       "\n\t"  //(2) подгрузить в  R2 флаг
468 "cmp r2, 1;"                "\n\t"  //(1) сравнить
469"bne dds_loop;"              "\n\t"  //(1) перейти в цикл
470: : [wave]"r" (&wave),[shag]"r"(dds_shag),[port]"r"(&DDS_OUT),[flag]"r"(&mon_flag)
471: "r9","r8","r7","r6","r2"
472);
473  #if defined (STM32_MEDIUM_DENSITY)
474  GPIOA_BASE->CRL=0x44444444;// все пины в Z для резисторного цап
475 #endif
476} //END DDS set()
477 
478  void mytone(int frq, int ms ){
479 uint16_t psc=1; uint32_t tim_arr;
480 // настройка генератора звука на таймере3
481  tim_arr = (F_CPU/2)/frq;
482  while ( (tim_arr/psc) > 65535) {psc++;}
483  __asm volatile( "cpsid i" );
484   TIMER2_BASE->SMCR=0;
485    TIMER3_BASE->CCR3=0; //обнулить регистр соответсвующий используемому выходу
486     TIMER3_BASE->PSC=psc-1;
487      TIMER3_BASE->ARR=(tim_arr/psc)-1;
488       TIMER3_BASE->CCMR2=(1<<5)|(1<<4);// OC3M:011
489        TIMER3_BASE->CCER=1<<8;//cc3e  подключить аппаратную ногу
490         TIMER3_BASE->SMCR=(1<<2)|(1<<0)|(1<<4);//SMS:101 && TS:001  строб от 2-го таймера 
491          TIMER3_BASE->EGR=1; //перечитать регистры.
492           TIMER3_BASE->CR1=1;
493           /// настройка выдержки времени на таймере2
494          psc=1;
495        tim_arr = (F_CPU/1E3) * ms;
496       while ( (tim_arr/psc) > 65536) {psc++;}
497      TIMER2_BASE->CCMR2=0;
498     TIMER2_BASE->CR2=0;
499    TIMER2_BASE->CR1=(1<<3)|(1<<2);//один импульс, без прерываний
500   TIMER2_BASE->CNT=0;
501  TIMER2_BASE->CR2=(1<<4);  //MMS:001 сигнал разрешения работы другим таймерам
502 TIMER2_BASE->PSC=psc-1;
503TIMER2_BASE->ARR=(tim_arr/psc)-1;
504TIMER2_BASE->EGR=1; //перечитать регистры.
505TIMER2_BASE->SR=0;//отчистить флаги
506TIMER2_BASE->CR1|=(1<<0);
507  __asm volatile( "cpsie i" );
508}
509 
510void comm(){ //коммутация выходов через мультиплексор
511if (mode>0 && mode<3 ) {digitalWrite(PB3,LOW); digitalWrite(PB4,LOW);}
512  else  if (mode>2 && mode<8 ) {digitalWrite(PB3,HIGH); digitalWrite(PB4,LOW);}
513 else if (mode==8) {digitalWrite(PB3,HIGH); digitalWrite(PB4,HIGH);}
514}
515 
516void volt_meter() {
517static boolean alarm=0;
518 uint64_t akkum=0;
519 //измерение напряжения питания МК
520  for (int n=0; n<=16383; n++ ) {//собирать 16384 выборок
521    akkum += sq(adc_read(ADC1,17)); } //суммировать квадраты
522     akkum =  (sqrt(akkum>>14));
523        Vcc = (VrefINT <<12) / akkum;
524         //измерение напряжения на входе ADC9(PB1)
525        akkum=0;
526       for (int n=0; n<=16383; n++ ) {//собирать 16384 выборок
527      akkum += sq(adc_read(ADC1,9)); } //суммировать квадраты
528     akkum =  (sqrt(akkum>>14));
529   for (int n=0; n<=65535; n++ ) {asm volatile("nop"); } //Типа delay
530  freq = (double) Mn * ((uint32_t)(akkum * Vcc *10)/4096);
531   // если напряжение не удовлетворяет условиям, и буззер не работает -то включить
532 if      (freq < Vin_low*10) { alarm =1;  if (TIMER2_BASE->SR!=0) {mytone (200, 10000);} }
533  else if (freq >  Vin_hi*10) { alarm =1;  if  (TIMER2_BASE->SR!=0) {mytone (1000, 10000);} }
534   else alarm=0;
535    //если всё ок, а буззер работает, то выключить.
536     if (!alarm && (!TIMER2_BASE->SR) ) {mytone (0, 0);}
537  }

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Для терминальной версии под STM32G431 как дефайны найти, читал даташит, совсем не понял адресацию

nickjust
Offline
Зарегистрирован: 29.04.2021

а можно добавить калибратор 0-20 мв ?

vokovl
Offline
Зарегистрирован: 12.12.2021

Возник такой вопрос, собрал генератор, мне он нужен для работы до 500кгц, работает отлично, но мне нужно что бы в точке, которая на рисунке, включался другой пин на HIGH

 

 

miklin
miklin аватар
Offline
Зарегистрирован: 08.06.2018

Добрый день!!!

Ребята у кого есть Файлы AN619,AN1234 для si5351.

Они закрыты,может кто скинет на почту miklin@mail.ru 

miklin
miklin аватар
Offline
Зарегистрирован: 08.06.2018

Тема видно заглохла,все наделали генераторов.

Тоже сделал генератор давно но без si5351,не было необходимости, хотя подключение

предусмотрел. Решил подключить (v3.5) проц её не видит. Прошиваю другие платы

не работают(ST link),как прошивал  рабочую не помню. Вроде писали что ST перемычки

без разницы. Как выйти в личку на автора или на MAG-N, не знаю. Вроде на этом сайте

нет лички.