Очень простой генератор из ардуины.

poty

★★★★★★✩
19 Фев 2020
3,237
942
@Сузунец, в оригинале частота выставлялась только при получении данных из серийного порта, сейчас - в каждой итерации. Это потенциально может привести к неадекватной работе. Нужно перенести всё в setup.
 

Сузунец

✩✩✩✩✩✩✩
19 Июн 2024
18
8
42
Сузун
@poty,
Частота выставляется 1 раз:
C++:
static uint32_t reqfreq = 350; // Частота 350 Гц
переменная reqfreq static
Static - это ключевое слово в C++, используемое для придания элементу особых характеристик. Для статических элементов выделение памяти происходит только один раз и существуют эти элементы до завершения программы.
 

poty

★★★★★★✩
19 Фев 2020
3,237
942

@Сузунец, указанная Вами строка - присвоение числа переменной. Далее в цикле настраивается таймер после расчётов на базе этой переменной. Расчёты и настройка таймера осуществляются каждый цикл loop.
 

Toyotabod

✩✩✩✩✩✩✩
24 Май 2024
8
1
Померил амплитуду на выходе генератора - 0.7 вольт на постоянке и 0.9 по переменке. Маловато для моих нужд. Надо 5 вольт. Похоже надо добавлять транзистор для усиления. Буду думать.
 

Сузунец

✩✩✩✩✩✩✩
19 Июн 2024
18
8
42
Сузун
@poty, ...а понял про что вы говорили. Переделал и нормально отформатировал код:
C++:
void setup() {
    pinMode(9, OUTPUT); // выход генератора
    TCCR1A = 0;
    TCCR1B = 0;
    static uint32_t reqfreq = 350; // Частота 350 Гц
    uint32_t ocr = OCR1A;
    uint16_t divider = 1;
   
    if (reqfreq == 0 || reqfreq > F_CPU/2) return;
    ocr = (F_CPU/reqfreq/2/divider);
    byte shifts[] = {3, 3, 2, 2};
    for(byte i = 0; i < 4; i++) {
        if (ocr > 65536) {
            divider <<= shifts[i];
            ocr = F_CPU/reqfreq/2/divider;
            }
        else {
            TCCR1B = (i + 1)|(1<<WGM12);
            break;
            }
        } //Mode4 (CTC)
    OCR1A = ocr - 1;
    TCCR1A = 1<<COM1A0;
}

void loop() {

}
 
Изменено:

Toyotabod

✩✩✩✩✩✩✩
24 Май 2024
8
1
Проверил. Этот скетч тоже работает. (по звуку с пищалки работает так же)
 

poty

★★★★★★✩
19 Фев 2020
3,237
942
@Toyotabod, нужно использовать осциллограф или мультиметр, измеряющий амплитуду переменного напряжения. Там можно получить значение 5В.
Некоторые мультиметры могут адекватно измерять среднеквадратичное напряжение переменного тока, но тогда напряжение будет в районе 2,5В (при амплитуде 5В). В режиме DC, как правило, измерения переменного тока недостоверны.
Ваши измерения очень странные, предполагаю, что либо выход сильно нагружен, либо мультиметр при таких условиях измерения врёт.
 

Сузунец

✩✩✩✩✩✩✩
19 Июн 2024
18
8
42
Сузун
Дело было вечером, делать было нечего... короче я немного "прокачал" этого малыша (ну уж очень он мне понравился), немного прибавил в весе конечно, но многое стал уметь:
1. Частота вводиться кнопками +/- с определенным шагом (ненужно каждый раз прошивать или вводить с компа)
2. Вывод частоты на дисплей
3. Запоминает последнюю рабочую частоту
Теперь его (генератор) можно оформить как отдельный прибор, только изредка прошивать когда нужна точная настройка частоты

20240702_230834.jpg
 

Вложения

  • Лойс +1
Реакции: Vijit и Toyotabod

Toyotabod

✩✩✩✩✩✩✩
24 Май 2024
8
1
@Сузунец,
Вот что-то такое тоже хотел сделать, тем более всё для этого есть. Буду пробовать.
 

Jibuzz

✩✩✩✩✩✩✩
23 Авг 2024
5
0
Добрый день!
Подскажите, как изменить код, чтоб повесить гену на А0 пин? Я с таймерами на низком уровне пока не особо дружу, еле с АЦП разобрался. Хочу добавить как опцию в свой проект осциллографического пробника. И какие регистры надо сохранять и восстанавливать, чтоб при выходе из подпрограммы таймеры остались как были до входа? А то у меня там на миллис и делэй все завязано.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@Jibuzz,
Этот генератор работает только на конкретном пине. Изменить нельзя. (Переписать можно только на использование PWM выходов таймеров 1 или 2)
Если допустимо дрожание фронтов, то можно посмотреть функцию tone(), она работает на любом пине, но возможно дрожание.
П.С. полезно разобраться в работе таймеров. Или по даташиту или по урокам (конкретных уроков не подскажу) .
 

Jibuzz

✩✩✩✩✩✩✩
23 Авг 2024
5
0
@Bruzzer,
С таймерами разобраться надо безусловно, но как говориться не все сразу. Про функцию тон() конечно знаю, но это уж совсем детский сад. В общем-то можно чтоб генерил на любом пине PORTC (А0-А5), да хоть на всех сразу. Порты B и D трогать нежелательно, там висит дисплей (от Моторолы ц350, разбираться в коде драйвера которого, нет никакого желания). И совсем нельзя трогать пин PD1, там висит управление питанием.
 

bort707

★★★★★★✩
21 Сен 2020
3,064
912
В общем-то можно чтоб генерил на любом пине PORTC (А0-А5), да хоть на всех сразу.
На порту С нет выходов таймеров, так что не выйдет.
По мне так куда перспективнее попробовать перенести на порт С дисплей ...
 

Jibuzz

✩✩✩✩✩✩✩
23 Авг 2024
5
0
@bort707, это я уже понял, покурил немного даташит. Освободил 3 пин (PD3), вроде таймер 2 туда можно запихнуть, но пока не догоняю как код переделать. Может кто подскажет, а то велосипед изобретаю.
 

bort707

★★★★★★✩
21 Сен 2020
3,064
912
@Jibuzz, лучше освободить пины pb1 или pb2 таймера1- тогда код не надо будет переписывать.
А на таймерах 0 или 2 ваш код сильно потеряет в возможностях - так как они 8битные
 

Jibuzz

✩✩✩✩✩✩✩
23 Авг 2024
5
0
@bort707,
другое освободить проблематично, так как придется девайс собрать заново. :) Вот фото для понимания:
"Найди кот...атмегу." :)
Да и не нужна там точность, это для ремонта всякой унц-унц техники, вроде китайских сабов и прочих балалаек. Для чего-то более серьезного есть нормальные приборы, но их в карман не положишь. Это типа индикаторной отвертки (кстати и эта функция есть).
Вот в работе, если интересно:
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
474
136
@Jibuzz,
Если не разбираться с таймерами, то можно использовать готовые библиотеки.
Хотя в них могут быть ошибки и избыточный функционал. Да и разобраться в чужой библиотеке иногда дольше, чем разобраться в даташите.
Например GyverTimers
Код на основе примера meandr_test из этой библиотеки (GyverTimers)
(ПС Возможно для данной ветки это офтопик, и дальнейшее обсуждение использования библиотек здесь лучше не вести).
C++:
//Пример генерации меандра на таймере 2 , канале B (D3 на Arduino UNO)
#include <GyverTimers.h>

void setup() {
  Serial.begin(115200);
  Serial.println("==START==");
  pinMode(3, OUTPUT);                           // настроить пин как выход
}

void loop() {
  uint32_t reqfreq = 0; //переменная запроса частоты
  if (Serial.available() > 0)
    reqfreq = Serial.parseInt();

  if (reqfreq == 0 || reqfreq > F_CPU / 2)
    return;

  // из-за особенности генерации меандра таймером
  // частоту нужно указывать в два раза больше нужной!
  reqfreq = Timer2.setFrequency(reqfreq * 2); // настроить частоту таймера в Гц
  Serial.println(reqfreq/2);  // Реальная частота
  Timer2.outputEnable(CHANNEL_B, TOGGLE_PIN);   // в момент срабатывания таймера пин будет переключаться
}
 

Jibuzz

✩✩✩✩✩✩✩
23 Авг 2024
5
0
@Bruzzer,
Для шарабайки я уже так и сделал (через библиотеку Алекса, благо у него все отлично расписано, за что ему огромное спасибо). Но хотелось бы самому разобраться как програмить таймеры на низком уровне.