Понадобился мне частотомер – решил его сделать на Ардуино. Порыскав в интернете понял, что все, в основном, используют библиотеку <FreqCount.h>. Однако посмотрев их скетчи, пришёл к выводу, что написана программа крайне нехорошо. Придётся писать свою и правильно.
В общем частотомер строится по такому принципу: получить переменный сигнал, сформировать из него импульсы. Эти импульсы посчитать за определённый интервал времени и отсюда уже выходит принятая частота в Гц/кГц/МГц. Далее всё выводится на какое-нибудь индикаторное устройство.
Вроде всё понятно и просто, но в реальности получается не всё так, как бы того хотелось. В интернете у людей их самодельные частотомеры измеряют аж до 200 МГц с высокочастотными делителями и до 20-50 МГц без делителей.
Реальность же показывает, что программа, основанная на библиотеке <FreqCount.h> не способна измерять частоту входного сигнала выше 6 МГц.
Так же на работоспособность сильно влияют формирователь импульсов, его частотные характеристики. Влияет и быстроходность делителя частоты.
Схема
Пришлось разрабатывать свою схему частотомера.
Вначале перепробовал разные схемы формирователей. Оказалось, что простая схема наиболее эффективна. На входе стоит усилитель на транзисторе 2SD2144 (fгр.=390 МГц). Сигнал с коллектора поступает на триггер Шмитта, выполненный на микросхеме DD1 КР1533ЛА3 (во второй схеме предполагается использовать 74AC14). Дале сформированные импульсы из входного сигнала поступают на делитель частоты.
Делитель частоты позволяет расширить диапазон входных сигналов, так как выяснил, что без делителя входной частоты программа не в состоянии измерять выше 6 МГц. Пришлось искать подходящие микросхемы счётчиков. У меня нашлась микросхема КР531ИЕ17. Она может делить входной сигнал на 2, 4, 8, 16. Первая схема разработана под эту микросхему. Попутно купил микросхему SN74LS90N (Это наш 555ИЕ2) и оказалось, что эта микросхема быстреее переключается чем КР531ИЕ17. Если же смотреть характеристики на микросхемы, то вроде у КР531ИЕ17 максимальная тактовая частота составляет примерно 65 МГц. Реальный же экземпляр работает медленнее. Максимальная частота SN74LS90N должна составлять 42 МГц. У меня три разных партии этой микросхемы и из них выбрал наиболее быстроходный.
На основе SN74LS90N построил вторую схему. SN74LS90N может делить на 2 и 10. Вторая схема использует ещё прямой входной сигнал, т.е. коэффициент деления 1:1.
После делителя частоты сигнал поступает на ключи на микросхеме DD3 К561КТ3, которые использую как мультиплексор. Переключение ключей происходит программно по нажатию на кнопку [RANGE].
Кнопка [TIME] позволяет выбрать время счёта 0,1с; 1с; 10с; или режим счёта импульсов Counter.
Для счётчика импульсов собран свой формирователь с оптронной развязкой на U1. Работает от 5 до 110 В, сигнал может быть любой полярности.
Кнопка [LIGHT] управляет подсветкой дисплея. Вначале использовал дисплей LCD Nokia 5110. В окончательном варианте использую дисплей LCD1602, он более подходит для частотомера. В программе применена условная компиляция и можно задать вывод на любой из этих дисплеев.
Pic 1. Схема электрическая принципиальная Вариант 1
Триггер Шмитта можно использовать на КР1533ЛА3 или на специализированной микросхеме 74AC14, что более предпочтительно.
Pic 2. Схема электрическая принципиальная Вариант 2
Триггер Шмитта на специализированной микросхеме 74AC14.
Pic 3. Схема электрическая принципиальная Вариант 3
Генератор для проверки работы частотомера собран на микросхеме К555ЛА3. Подставляя разные кварцы, была проверена работа частотомера от 1МГц до 27МГц.
Все программы, которые смотрел у других, оказывались неоптимально написаны. Пришлось писать свою программу. Для быстрого переключения разных компонентов – использую условную компиляцию, что даёт лёгкость настройки всей программы под имеющееся оборудование и компоненты.
Библиотека <FreqCount.h> использует 8-битный Timer0 на CHANNEL_B – вывод D5 (PD5). Реально измерить напрямую частоту выше 4-6 МГц невозможно. Для этого приходится делить входную частоту, чтобы счётчик микроконтроллера смог посчитать периоды входного сигнала. Поэтому, если кто-то указывает, что его программа без делителя измеряет 20 МГц – это заблуждение.
Дисплей сейчас использую LCD1602 (16 символов в 2 строки). Он достаточно удобен для частотомера. У меня данный дисплей подключен по I2C, если же использовать без I2C, то в строчках 047-054 закомментирован альтернативный вариант. Можно его раскомментировать, а строчки 038 и 041 закомментировать.
Управление частотомером осущестляется тремя кнопками: [RANGE], [TIME], [LIGHT], что соответственно позволяет изменять делители входной частоты, изменять временной интервал счёта и включать/отключать подсветку экрана дисплея. Выводы кнопок подтянуты к питанию и при нажатии на кнопки с них подаётся низкий уровень. Дребезг кнопок устраняется подпрограммой fnDebounce().
В строках 312-320 реализован автоматический выбор делителя. Если сигнал не определён, то выставляется максимальный делитель. Заметил, особенно на делителе КР531ИЕ17, что счётчик не может посчитать входной высокочастотный сигнал и выдает на дисплей 0, хотя входной сигнал и присутствует. При переключении на больший делитель программа успевает посчитать периоды входного сигнала и выдаёт на дисплей уже реальную частоту. Автоматическое переключение делителя – удобство пользования. Всегда можно выбрать другой делитель в ручном управлении через кнопку [RANGE].
Кнопкой [TIME] можно установить режим подсчёта входных импульсов. Для этого задействован вывод D2 Ардуино. Чтобы обнулить значение счётчика входных импульсов – нажмите на кнопку [RANGE]. Для чего нужен такой режим? К примеру, можно подсчитывать количество витков, при намотке катушки индуктивности или обмотки трансформатора.
Далее можно по кнопке посмотреть код скетча частотомера... Сам файл смотрите в Приложении.
/***********************************************************************
https://rutube.ru/video/3da1255eaece3b90d465582a6995d928/
Частотомер на Arduino Uno c входным делителем частоты
2026-03-17 Mr.ALB Повторим оригинал... на дисплее 5110
2026-03-26 Mr.ALB Переделка, добавление счётчика импульсов
по входу 2.
2026-04-05 Mr.ALB Добавление дисплея LCD_1602 + делитель на счётчике
КР531ИЕ17, делит на 2, 4, 8, 16.
+ Автовыбор делителя.
2026-04-11 Mr.ALB Делитель на SN74LS90N, делит на 1, 2, 10
2026-04-21 Mr.ALB v1.4 Прдключение дисплея OLED SSD1306 0.96'
Примечание: устойчиво измеряет частоту до 4МГц,
на 8МГЦ сильно врёт! Генератор на К155ЛА3
Нужен делитель входного сигнала на 10
на микросхеме 74LS90 - соответственно переделать программу...
...Использовавл счётчик КР531ИЕ17
Условная компиляция под разные делители.
Примечание: Программа сигнал частотой выше 4-6 МГц не измеряет!
Поэтому для расширения диапазона обязательно требуется
делители входной частоты.
***********************************************************************/
// Библиотека для частотомера
// https://github.com/PaulStoffregen/FreqCount/archive/master.zip#include<FreqCount.h>// Библиотека для частотомера#define SERIAL_ON // Включение вывода в порт для отладки// Ниже в двух строках выбор дисплея#define LCD_1602 // Вывод на дисплей LCD_1602//#define LCD_5110 // Вывод на дисплей Nokia LCD5110//#define SSD1306 // Вывод на дисплей SSD1306 128x64//*********************SSD1306*****************************#ifdef SSD1306
// Дисплей SSD1306 с I2C#include<GyverOLED.h>// Библиотека от ГайвераGyverOLED<SSD1306_128x64,OLED_NO_BUFFER> oled; // Создание объектаconstuint8_t SCREEN_W = 128,// Ширина экрана в пикселях
SCREEN_H = 64,// Высота экрана в пикселях
h = 8,// Высота буквы size 1
w = 6; // Ширина буквы size 1#endif// endif of SSD1306****************************************//********************LCD_1602*****************************#ifdef LCD_1602
// Дисплей с I2C#include<Wire.h>#include<LiquidCrystal_I2C.h>// set the LCD address to 0x27 for a 16 chars and 2 line display// установите адрес на ЖК-дисплее 0x27 для отображения 16 символов и 2 строкLiquidCrystal_I2C lcd(0x27, 16, 2);
// Дисплей без I2C----------------------------------------//#include <LiquidCrystal.h> // Библиотека для индикатора// Определение выводов//#define LCD_RS 14 // A0//#define LCD_E 15 // A1//#define LCD_D4 16 // A2//#define LCD_D5 17 // A3//#define LCD_D6 18 // A4//#define LCD_D7 19 // A5// Создание объекта дисплея//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);#endif// endif of LCD_1602***************************************//********************LCD_5110*****************************#ifdef LCD_5110
#include<SPI.h>#include<Adafruit_GFX.h>#include<Adafruit_PCD8544.h>// Дисплей NOKIA red 1#define LCD_RST 3
#define LCD_CS 4
#define LCD_DC 10
#define LCD_DIN 11
#define LCD_CLK 13
#define LCD_BL 9 // Подсветка на pin~ через резистор 2R2
Adafruit_PCD8544 lcd = Adafruit_PCD8544(LCD_DC, LCD_CS, LCD_RST);
constuint8_t SCREEN_W = 84,// Ширина экрана в пикселях
SCREEN_H = 48,// Высота экрана в пикселях
h = 8,// Высота буквы size 1
w = 6; // Ширина буквы size 1#define LCD_BL 9 // Подсветка на pin~ через резистор 2R2 #endif// endif of LCD_5110***************************************// Определения выводов// Вход частотомера 5/D5 (PD5/T1 - ножка 9 микросхемы// QFP32 ATMega48/88/168/328)#define BTN_LIGHT 6 // Кнопка Время измерения#define BTN_TIME 8 // Кнопка Время измерения#define BTN_RANGE 12 // Кнопка Диапазон// Массив для заставкиconstchar* stitle[] =
{
"Freq&Counter",// 0"v1.4",// 1"Mr.ALB",// 2"2026-04-21",// 3
};
#define COUNT_IN 2 // Вход счётчика#define INDEBOUNCE 120 // Время на антидребезг счётчика#define TMDEBOUNCE 60 // Время на антидребезг кнопкиenum// Перечисление для времени измерения
{
IMP,// 0
T01S,// 1
T10S,// 2
T1S,// 3
};
// Массив каналов для управления делителямиconstbyte divPin[] =
{
A0,
A1,
A2,
A3
};
// Определяем делитель// без DIV10 - КР531ИЕ17// DIV10 - SN74LS90N (К555ИЕ2)#define DIV10
constbyte divider[] =
{
#ifdef DIV10 // Для SN74LS90N
1,
2,
10
#else// Для КР531ИЕ17
2,
4,
8,
16
#endif
};
uint32_t f; // Отсчёты частоты при измерении таймера1float f0; // Частота на выводbyte n = T1S, r; // Переменные время измерения, точностьbyte nn = 0; // Делительbool btn, bl;
bool flag =false; // Флаг смены настройкиbool btn_flag =false; // Флаг кнопкиbool flag_debounce =false; // Флаг антидребезгаuint32_t time_debounce = 0; // Переменная времени антидреезгаuint32_t time_out = 0; // Переменная для автомат.выбора делителя#define TIMEOUT 10000 // Время ожидания автоматической регулировки// Прототипы функцийvoid fnSetTimeMeasure(void);
//void fnPrintSpace(byte x = 2);/****************************************** Функция настройки *****************************************/voidsetup()
{
#ifdef SERIAL_ON
Serial.begin(9600);
delay(300);
#endif// Конфигурация кнопок управления#ifndef SSD1306
pinMode(BTN_LIGHT,INPUT_PULLUP); // Кнопка подсветки#endifpinMode(BTN_TIME,INPUT_PULLUP); // Кнопка Время измеренияpinMode(BTN_RANGE,INPUT_PULLUP); // Кнопка Диапазон#ifdef SSD1306
oled.init();
if (1) // Поворот экрана на 180° - если нужно, иначе ставьте 0
{
oled.flipV(OLED_FLIP_V); // Отражение вертикально
oled.flipH(OLED_FLIP_H); // Отражение горизонтально
}
fnZastavka(); // Заставка#endif#ifdef LCD_1602
lcd.init();
lcd.begin(16, 2); // LCD 16X2// Проверка подсветки
lcd.backlight(); // Включить подсветку
fnZastavka(); // Заставка
lcd.noBacklight(); // Отключить подсветку#endif// end of LCD_1602#ifdef LCD_5110
lcd.begin(52); // LCD Nokia, Контраст 52
lcd.clearDisplay(); // Очистить дисплей
lcd.setTextColor(BLACK); // Цвет текста
lcd.setCursor(0, 0); // Позиция вывода левый-верх в px
lcd.clearDisplay();
pinMode(LCD_BL,OUTPUT); // Подсветка дисплея// Проверка подсветкиdigitalWrite(LCD_BL,HIGH); // Включить подсветкуdelay(500);
fnZastavka(); // ЗаставкаdigitalWrite(LCD_BL,LOW); // Отключить подсветку#endif// end of LCD_5110pinMode(COUNT_IN,INPUT_PULLUP); // Вход счётчика// Выход на ключи мультиплексораfor (byte i = 0; i < 4; i++)
{
pinMode(divPin[i],OUTPUT);
}
fnSetTimeMeasure(); // Установка времени измерения
fnTitle(); // Вывод заголовка
nn = 1; // Делитель 1:2
fnSetRange(); // Коэф.деления#ifdef SSD1306
oled.update();
#endif#ifdef LCD_1602
lcd.display();
#endif#ifdef LCD_5110
lcd.display();
#endif
time_out =millis(); // Время для автом. установки делителя
}
// end of setup()/****************************************** Основная функция *****************************************/voidloop()
{
time_debounce =millis(); // Обновляем время антидребезга//**************************************// Если нажата кнопка времени измерения
btn =!digitalRead(BTN_TIME);
if (btn ==true&& btn_flag ==false)
{
btn_flag =true;
fnDebounce(TMDEBOUNCE); // Антидребезг
n++;
if (n > 3)
{
n = 0;
delay(TMDEBOUNCE);
}
flag =true;
}
//**************************************// Если нажата кнопка диапазона измерения
btn =!digitalRead(BTN_RANGE);
if (btn ==true&& btn_flag ==false)
{
btn_flag =true;
fnDebounce(TMDEBOUNCE); // Антидребезг
nn++;
if (nn ==sizeof(divider))
{
nn = 0;
delay(TMDEBOUNCE);
}
flag =true;
}
#ifndef SSD1306
//******************************// Если нажата кнопка подсветки
btn =!digitalRead(BTN_LIGHT);
if (btn ==true&& btn_flag ==false)
{
btn_flag =true;
fnDebounce(TMDEBOUNCE); // Антидребезг
bl =!bl; // Инверсия значения#ifdef LCD_1602
if (bl)
lcd.backlight();
else
lcd.noBacklight();
#endif#ifdef LCD_5110
digitalWrite(LCD_BL, bl); // Вкл./Откл. подсветки#endif
}
#endif//******************************// Вход счётчика
btn =!digitalRead(COUNT_IN);
if (btn ==true&& btn_flag ==false)
{
btn_flag =true;
fnDebounce(INDEBOUNCE); // Антидребезг
f++;
#ifdef SERIAL_ON
Serial.print("f=");
Serial.println(f);
//Serial.println(sizeof(divider));#endif
}
// Смена параметров настройкиif (flag)
{
flag =!flag; // Сброс флага#ifdef SSD1306
oled.clear();
#endif#ifdef LCD_1602
lcd.clear();
#endif#ifdef LCD_5110
lcd.clearDisplay();
#endif
fnTitle();
fnSetTimeMeasure(); // Установка времени измеренияif (n != 0)
fnSetRange(); // Установка делителей
}
if (n != 0) // Не счётчик импульсов
{
// Если есть значение fif (FreqCount.available())
{
f =FreqCount.read(); // Измерение частоты
f *= divider[nn]; // Умножаем на делитель// Автоматический выбор делителя****************************if (f == 0 && ((millis() - time_out) > TIMEOUT))
{
if (nn < (sizeof(divider) - 1))
nn =sizeof(divider) - 1;
fnSetRange();
time_out =millis();// Время для автом.установки делителя
}
//**********************************************************#ifdef SSD1306
oled.setCursor(w * 16, 0);
oled.setScale(1);
oled.print("*"); // Выводим * - символ измерения частоты
oled.update();
#endif#ifdef LCD_1602
lcd.setCursor(14, 0);
lcd.print("*"); // Выводим * - символ измерения частоты#endif#ifdef LCD_5110
lcd.setCursor(w * 12, 0);
lcd.setTextSize(1);
lcd.print("*"); // Выводим * - символ измерения частоты
lcd.display();
#endif
}
#ifdef SSD1306
// Стираем предыдущее показание частоты
oled.setScale(2);
oled.setCursor(4, 2);// Позиционирование вывода частоты#endif#ifdef LCD_1602
lcd.setCursor(2, 0);// Позиционирование вывода частоты
lcd.print(0, 8);
lcd.setCursor(2, 0);// Позиционирование вывода частоты#endif#ifdef LCD_5110
// Стираем предыдущее показание частоты
lcd.fillRect(0, h * 2, 84, 16,WHITE);
lcd.setTextSize(2);
lcd.setCursor(0, h * 2);// Позиционирование вывода частоты#endifif (f >= 1000000 && n == 3)
{
f0 = f / 1000000.0;
fnPrintF0(f0, 5 + r);
fnPrintMes("MHz"); // Вывод размерности
}
if (f < 1000000 && n == 3)
{
f0 = f / 1000.0;
fnPrintF0(f0, 3 + r);
fnPrintMes("kHz"); // Вывод размерности
}
if (f >= 100000 && n == 1)
{
f0 = f / 100000.0;
fnPrintF0(f0, 5 + r);
fnPrintMes("MHz"); // Вывод размерности
}
if (f < 100000 && n == 1)
{
f0 = f / 100.0;
fnPrintF0(f0, 3 + r);
fnPrintMes("kHz"); // Вывод размерности
}
if (f >= 10000000 && n == 2)
{
f0 = f / 10000000.0;
fnPrintF0(f0, 5 + r);
fnPrintMes("MHz"); // Вывод размерности
}
if (f < 10000000 && n == 2)
{
f0 = f / 10000.0;
fnPrintF0(f0, 3 + r);
fnPrintMes("kHz"); // Вывод размерности
}
delay(300);
#ifdef SERIAL_ON
Serial.print("n=");
Serial.print(n);
Serial.print("\tnn=");
Serial.print(nn);
Serial.print("\t");
Serial.println(f);
#endif#ifdef SSD1306
// Стирание звёздочки - знака измерения
oled.setCursor(w * 16, 0);
oled.print(" ");
#endif#ifdef LCD_1602
// Стирание звёздочки - знака измерения
lcd.setCursor(14, 0);
lcd.print(" ");
#endif#ifdef LCD_5110
// Стирание звёздочки - знака измерения
lcd.fillRect(w * 12, 0, w, h,WHITE); // Стираем [*]#endif
}
else
{
#ifdef SSD1306
oled.setScale(2);
oled.setCursor(4, 2); // Позиционирование вывода счётчика
oled.print(f);
#endif#ifdef LCD_1602
lcd.setCursor(0, 1); // Позиционирование вывода счётчика#endif#ifdef LCD_5110
// Стираем предыдущее показание
lcd.fillRect(0, h * 2, 84, 16,WHITE);
lcd.setTextSize(2);
lcd.setCursor(0, h * 2);// Позиционирование вывода счётчика#endif#ifndef SSD1306
lcd.print(f);
#endif
fnPrintMes("Imp"); // Вывод размерности
}
#ifdef SSD1306
oled.update();
#endif#ifdef LCD_5110
lcd.display();
#endif// Сброс флага нажатия кнопкиif (btn ==false&& btn_flag ==true)
btn_flag =false;
delay(100);
}
// end of loop()/********************************** ***** ПОДПРОГРАММЫ ***** *********************************//******************************** Функция: Антидребезг кнопки *******************************/void fnDebounce(uint16_t t)
{
// Антидребезгwhile ((millis() - time_debounce) < t);
}
// end of fnDebounce()/************************************ Функция: Заставка ***********************************/void fnZastavka()
{
#ifdef SSD1306
oled.clear();
oled.setScale(1);
byte j = 0;
for (byte i = 0; i < (sizeof(stitle) /sizeof(stitle[0])); i++)
{
oled.setCursor((SCREEN_W - w *strlen(stitle[i])) / 2, j);
j += 2;
oled.print(stitle[i]);
}
oled.update();
#endif#ifdef LCD_1602
lcd.setCursor(2, 0);
lcd.print(stitle[0]);
lcd.setCursor(0, 1);
lcd.print(stitle[1]);
lcd.print(" ");
lcd.print(stitle[3]);
#endif#ifdef LCD_5110
for (byte i = 0; i < (sizeof(stitle) /sizeof(stitle[0])); i++)
{
byte j = 0;
if (i > 1)j = h;
lcd.setCursor((SCREEN_W - w *strlen(stitle[i])) / 2, h * i + j);
lcd.print(stitle[i]);
}
lcd.display();
#endifdelay(5000); // Пауза#ifdef SSD1306
oled.clear(); // Очистить дисплей#endif#ifdef LCD_1602
lcd.clear(); // Очистить дисплей#endif#ifdef LCD_5110
lcd.clearDisplay();
#endif
}
// end of fnZastavka()/************************************************* Функция: Установка позиции вывода размерности ************************************************/void fnPrintMes(String s)
{
#ifdef SSD1306
oled.setScale(1);
oled.setCursor(w * 16, 6);
oled.print(s);
#endif#ifdef LCD_1602
lcd.setCursor(12, 1);
lcd.print(s);
#endif#ifdef LCD_5110
lcd.setTextSize(1);
lcd.setCursor(w * 10, h * 5);
lcd.fillRect(w * 10, h * 5, w * 3, h,WHITE);
lcd.setCursor(w * 10, h * 5);
lcd.print(s);
#endif
}
// end of fnPrintMes()/************************************ Функция: Вывод заголовка ***********************************/void fnTitle()
{
#ifdef SSD1306
oled.setScale(1); // Установка размера шрифта
oled.setCursor(4, 0);
#endif#ifdef LCD_1602
lcd.setCursor(0, 0);
#endif#ifdef LCD_5110
lcd.setTextSize(1); // Установка размера шрифта
lcd.setCursor(0, 0);
#endifif (n != 0)
{
#ifdef SSD1306
oled.print("Freq.Meter");
#endif#ifdef LCD_1602
lcd.print("F=");
#endif#ifdef LCD_5110
lcd.print("Freq.Meter");
#endif
}
else
{
#ifdef SSD1306
oled.print("Counter");
#else
lcd.print("Counter");
#endif
}
}
// end of fnTitle()/**************************************** Функция: Установка времени измерения ***************************************/void fnSetTimeMeasure()
{
#ifdef SSD1306
oled.setCursor(4, 6);
#endif#ifdef LCD_1602
lcd.setCursor(0, 1);
#endif#ifdef LCD_5110
lcd.setTextSize(1);
lcd.setCursor(0, h * 5);
#endif
f = 0; // При смене времени обнуляем частотуswitch (n)
{
case IMP:FreqCount.end();
break;
case T01S:FreqCount.begin(100);
#ifdef SSD1306
r = 0;
oled.print("0.1s");
#endif#ifdef LCD_1602
r = 0;
lcd.print("0.1s");
#endif#ifdef LCD_5110
r =-1;
lcd.print("0.1s");
#endifbreak;
case T10S:FreqCount.begin(10000);
#ifdef SSD1306
r = 2;
oled.print("10s");
#endif#ifdef LCD_1602
r = 2;
lcd.print("10s");
#endif#ifdef LCD_5110
r = 0;
lcd.print("10s");
#endifbreak;
case T1S:FreqCount.begin(1000);
#ifdef SSD1306
r = 1;
oled.print("1s");
#endif#ifdef LCD_1602
r = 1;
lcd.print("1s");
#endif#ifdef LCD_5110
r = 0;
lcd.print("1s");
#endif
}
// end of switch
}
// end of fnSetTimeMeasure()/**************************************** Функция: Коэффициент деления ***************************************/void fnSetRange()
{
#ifdef SSD1306
oled.setScale(1);
oled.setCursor(w * 8, 6);
oled.print("1:");
oled.print(divider[nn]);
#endif#ifdef LCD_1602
lcd.setCursor(6, 1);
#endif#ifdef LCD_5110
lcd.setTextSize(1);
lcd.setCursor(w * 6, h * 5);
lcd.fillRect(w * 6, h * 5, w * 2, h,WHITE);
#endif#ifndef SSD1306
lcd.print("1:");
lcd.print(divider[nn]);
#endif// Включение мультиплексора на выбранный канал
fnSetDIV(nn);
#ifdef SERIAL_ON
Serial.print("divPin[");
Serial.print(nn);
Serial.print("]=");
Serial.println(divPin[nn]);
#endifdelay(1000);
}
// end of fnSetRange()/**************************************** Функция: Включение канала деления ***************************************/void fnSetDIV(byte x)
{
for (byte i = 0; i < 4; i++)
digitalWrite(divPin[i],LOW); // Отключим всеdigitalWrite(divPin[x],HIGH); // Включим нужный
}
// end of fnSetDIV()/******************************************** Функция: Вывод измеренной частоты *******************************************/void fnPrintF0(float ff,byte rr)
{
#ifdef SSD1306
oled.print(ff, rr);
oled.print(" ");
#else
lcd.print(ff, rr);
lcd.print(" ");
#endif
}
// end of fnPrintF0
Конструкция
Так как это новая разработка, то законченной конструкции пока нет, требуется ещё довести до финального состояния схему (когда пришлют необходимые микросхемы). Возможно что-то изменится. Пока всё собирается на бредбордах.
Pic 5. Макетирование схемы
Проверка работоспособности проводилась с помощью генератора на К555ЛА3. Кварцы от в диапазоне от 1.000 МГц до 30.000 МГц. Всего 16 шт.
Pic 6. Линейка кварцевых резонаторовPic 7. Испытательный генератор на К555ЛА3
Ниже на экране дисплея выводится: в верхней строке – частота, в правой части верхней строки – символ [*], указывающий на приход подсчитанных периодов входной частоты (не попал в кадр). В нижней строке выводится: слева – интервал времени измерения, в середине – выбранный делитель, справа – размерность [кГц/МГц]. В режиме счётчика (Counter) размерность [Imp]. В данном случае происходит измерение частоты в 1 МГц. Погрешность составляет 190 Гц, что -0,019%. Очень даже хорошо. Замечу, что генератор можно было бы подстраивать под каждый кварц поточнее, но я просто их перетыкивал, возможно что сам генератор выдаёт не точно 1 МГц. Расхождение в 190 Гц на частоте 1000000 Гц для самодельного частотомера достаточно приемлемо. На других частотах погрешность примерно такая же, но не более 0,05%. На частоте 30 МГц погрешность несколько больше – около 0,16%.
Pic 8. Экран дисплея LCD1602
Ниже на экране дисплея выводится: в верхней строке – режим счётчика (Counter) размерность [Imp]. Насчитано 16 импульсов.
Pic 9. Экран дисплея LCD1602
Добавил возможность подключать дисплей OLED SSD1306. Он хоть и маленький, но довольно информативноёмкий, гораздо лучше чем Nokia LCD5110.
Pic 10. Экран дисплея SDD1306
Проект в стадии разработки, возможны какие-то изменения и доработки...
Приложение
Все, что необходимо для повторения конструкции, можно скачать по ссылкам: