Завершающий на ближайшее время пост про генераторы на Ардуино. В комментариях ко второй версии некто MozgiNaStene91 написал что есть готовый проект до до 8 МГц. Я конечно открыл, посмотрел. В общем, приспособил скетч под автономный вариант с выводом на I2C дисплей. Проверка частот показала, что никаких 8 МГц нет, только до 4-х. Из недостатков — отвратительная регулировка энкодером на высоких частотах, перескоки на сотни кГц. На малых частотах нормально. Долго экспериментировать не стал, возможно пайка кондеров до 0.1 мкф на каждую ногу энкодеров поможет, но не уверен что на всем диапазоне частот.



.
Выбор как всегда за вами.
Скетч в комментах.
Комментарии 9
подскажите для чего это? спидометр крутить?
Должен быть в хозяйстве каждого драйвовчанина! Наличие повышает карму на +1.
по поводу энкодера, вот что пишет автор "Теперь всё делает энкодер. Из-за особенностей обработчика нужно что-бы энкодер выдавал на один щелчок один или два полных импульса. Классический энкодер ардуинщиков ky-040 выдаёт половинку импульса, поэтому крайне не рекомендуется. Он работать будет, но срабатывать станет через щелчок." возможно вы про это, это написано для стм, но может он и тут так же сделал
Я не использовал Ку-040 с его пропусками. Был другой энкодер, который использовал и автор.
Скажите, а где использовать генератор. Смотрю постоянно их лепят, думал себе слепить, но на кой он мне в машине так и не определился
Если свистит (гудит…) вентилятор, то можно попробовать запитывать его через мосфет с регулировкой генератором. Звуковой сигнал подключить и настроить, регулятор поворотов соорудить и т.п.
Что делать с шим отдельно я понимаю. Для чего нужен этот генератор импульсов?
Новый год на носу, пусть работает с гирляндой :).
#include <wire.h> //…
#include <liquidcrystal_I2C.h> //библиотека для экрана с I2C модулем
LiquidCrystal_I2C lcd(0x3F, 16, 2); //для шины I2C с другой кодировкой надо заменить адрес 0х3F на ваш
#define set_duty() { OCR1A=(uint32_t)ICR1*duty/100; }
uint8_t duty = 50;
float freq;
void setup() {
lcd.init(); //инициализация экрана
lcd.backlight(); //включение подсветки экрана
lcd.print("GENERATOR ver.3"); //заставка
delay(3000);
lcd.clear();
lcd.print("Frequency Duty");
pinMode (9, OUTPUT); // выход генератора PB2
pinMode(A0, INPUT); // PC0 вывод энкодера "частота"
pinMode(A1, INPUT); // PC1 вывод энкодера "частота"
pinMode(A2, INPUT_PULLUP); // PC2 кнопка энкодера
pinMode(8, INPUT); // PB0 вывод энкодера "скважность"
pinMode(10, INPUT); // PB2 вывод энкодера "скважность"
PCICR = (1 << PCIE1) | (1 << PCIE0); //разрешить прерывания PCINT 0, 1
PCMSK1 = 1 << PCINT9; // По сигналу на А1 создавать прерывание (устновка частоты)
PCMSK0 = 1 << PCINT0; // По сигналу на pin8 создавать прерывание (скважность)
TCCR1A = 1 << COM1A1; //подключить выход OC1A первого таймера
TCCR1B = 0; //
}
ISR (PCINT1_vect) {
static boolean gen_mode = 0; //флаг режима управления
static uint32_t enc = 1; //переменная счёта энкодера
uint32_t icr = ICR1;
uint16_t divider = 1; //переменная коэфф. деления прескалера
byte n = PINC & 3; //считать значение энкодера частоты
boolean knopka = PINC & (1 << 2); // 0-кнопка нажата, 1-кнопка НЕ нажата.
if (freq < 2848) gen_mode = 0; //переключение режима управления по частоте
if (freq >= 2848) gen_mode = 1; //переключение режима управления по OCR
// Если увеличение частоты
if (n == 3 || n == 0) {
if (gen_mode) {
if (knopka) {
if (icr > 2) {
icr--;
}
} else {
if (icr > 12)icr -= 10;
}
}
else knopka ? enc++ : enc += 100; // в нч режиме
} //end GetUP
// Если уменьшение частоты
if (n == 2 || n == 1) {
if (gen_mode) {
if (knopka) {
if (icr < 65535) {
icr++;
}
} else {
if (icr <= 65525)icr += 10;
}
}
else {
if (knopka) {
if (enc >= 2)enc--;
} else {
if (enc > 100) enc -= 100;
}
}
} //end GetDown
if (gen_mode) {
ICR1 = icr;
set_duty();
freq = (float)F_CPU / 2 / ICR1;
}
else { //расчёт прескалера и ICR по нужной частоте
divider = 1; icr = F_CPU / enc / 2 / divider;
if (icr > 65536) {
divider = 8; icr = F_CPU / enc / 2 / divider;
if (icr > 65536) {
divider = 64; icr = F_CPU / enc / 2 / divider;
if (icr > 65536) {
divider = 256; icr = F_CPU / enc / 2 / divider;
if (icr > 65536) {
divider = 1024; icr = F_CPU / enc / 2 / divider;
if (icr > 65536) {
icr = 65536;
}
}
}
}
} ICR1 = icr — 1; set_duty();
//запись в регистр прескалера
switch (divider) {
case 1: TCCR1B = 1 | (1 << WGM13); break;
case 8: TCCR1B = 2 | (1 << WGM13); break;
case 64: TCCR1B = 3 | (1 << WGM13); break;
case 256: TCCR1B = 4 | (1 << WGM13); break;
case 1024: TCCR1B = 5 | (1 << WGM13); break;
}
freq = (float) F_CPU / 2 / (ICR1 + 1) / divider;
} //конец "если работа в НЧ режиме"
}
ISR (PCINT0_vect) { //обработчик энкодера "скважность"
byte m = PINB & B00000101; //считать значение энкодера2
if (m == 0 || m == 5) {
if (duty < 100) {
duty++;
}
}
if (m == 1 || m == 4) {
if (duty > 0) {
duty--;
}
}
set_duty();
}
void loop() {
if (freq < 1000) {
lcd.setCursor(0, 1);
lcd.print(freq, 0);
lcd.print(" Hz ");
}
if (freq >= 1000) {
lcd.setCursor(0, 1);
lcd.print(freq / 1000, 3);
lcd.print(" kHz ");
}
if (freq >= 1000000) {
lcd.setCursor(0, 1);
lcd.print(freq / 1000000, 3);
lcd.print(" MHz ");
}
lcd.setCursor(12, 1);
lcd.print(duty);
lcd.print("%");
delay(1000);
}