На микроконтроллере ATtiny2313 можно собрать очень простой частотомер, в качестве индикатора частотомера используется модуль TM1637 который представляет собой 4-х разрядный семисегментный дисплей на базе драйвера TM1637. Дисплей имеет десятичные точки в разрядах.
Частотомер может изменять частоту сигнала уровня TTL от единиц герц до 5,5 МГц. Так как индикатор частотомера имеет всего четыре разряда, то частота выводится в кГц, при этом положение запятой автоматически меняется в зависимости от поданной частоты.
Перед загрузкой скетча рекомендую ознакомится со статьей — ATtiny2313 + Arduino IDE
// tm1637 PB0 === CLK // tm1637 PB1 === DIO volatile byte x; unsigned long f; int f_ind; void setup() { delay(100); DDRB &= ~(1 << 0)|(1 << 1); DDRD &= ~(1 << 5); // весь порт D как вход PORTD |= (1 << 5); // подтягивающий резистор на PD5 (вход T1) cli(); TCCR1A = 0; TCCR1B = 0; TCCR1B = (1 << CS12)|(1 << CS11)|(1 << CS10); //Внешний тактовый источник на выводе T1. Тактирование по фронту TIMSK |= (1 << TOIE1); // бит TOIE1 в регистре TIMSK взывает прерывание когда таймер переполняется sei(); } void loop() { x = 0; // обнулить переменную х TCNT1 = 0; // обнулить счетный регистр TCCR1B = (1 << CS12)|(1 << CS11)|(1 << CS10); // запускаем таймер delay(996);delayMicroseconds(150); // ждем 1 секунду пока таймер считает импульсы TCCR1B &= ~(1 << CS12)|(1 << CS11)|(1 << CS10); // останавливаем таймер f = ((x*65535) + TCNT1); // подсчет частоты // вывод частоты на индикатор if(f>=10000&&f<100000){f_ind = f/10;print_time(f_ind, 2, 7);} if(f>=100000&&f<1000000){f_ind = f/100;print_time(f_ind, 1, 7);} if(f>=1000000){f_ind = f/1000;print_time(f_ind, 0, 7);} if(f<10000){f_ind=f;print_time(f_ind, 3, 7);} } void tm_dec(byte dig){ for(int i = 0; i < 8; i++) { DDRB |= (1 << 0);del(); if (dig & 0x01) DDRB &= ~(1 << 1); else DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); dig = dig >> 1; } DDRB |= (1 << 0); DDRB &= ~(1 << 1);del(); DDRB &= ~(1 << 0);del(); if (((PINB >> 1) & 1) == 0) DDRB |= (1 << 1);del(); DDRB |= (1 << 0);del(); } void tm_stop(){ DDRB |= (1 << 1);del(); DDRB &= ~(1 << 0);del(); DDRB &= ~(1 << 1);del(); } void tm_start(){ DDRB |= (1 << 1);del(); } void print_time(int t, byte pd_t, int br){ tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start(); tm_dec(0x40);tm_stop();tm_start(); int data0 = t / 1000; int data1 = t / 100 % 10; int data2 = t / 10 % 10; int data3 = t % 10; for(byte n = 0; n < 4; n++){ int data; switch(n){ case 0: data = data0;break; case 1: data = data1;break; case 2: data = data2;break; case 3: data = data3;break; } switch(data){ // XGFEDCBA case 0: data = 0b00111111;break; // 0 case 1: data = 0b00000110;break; // 1 case 2: data = 0b01011011;break; // 2 case 3: data = 0b01001111;break; // 3 case 4: data = 0b01100110;break; // 4 case 5: data = 0b01101101;break; // 5 case 6: data = 0b01111101;break; // 6 case 7: data = 0b00000111;break; // 7 case 8: data = 0b01111111;break; // 8 case 9: data = 0b01101111;break; // 9 } if(n == 0){data0 = data;} if(n == 1){data1 = data;} if(n == 2){data2 = data;} if(n == 3){data3 = data;} } switch(pd_t){ case 1 : data2 = data2+0b10000000;break; case 2 : data1 = data1+0b10000000;break; case 3 : data0 = data0+0b10000000;break; } tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop(); } void del(){delayMicroseconds(200);} ISR (TIMER1_OVF_vect){x++;}// при переполнении увеличить переменную х на 1
Скетч использует 1316 байт (64%) памяти устройства. Всего доступно 2048 байт.
Глобальные переменные используют 41 байт (32%) динамической памяти, оставляя 87 байт для локальных переменных. Максимум: 128 байт.Arduino IDE 1.8.9 | Плата для прошивки версии 1.2.5 (выбрать в менеджере плат)
Погрешность измеряемой частоты напрямую зависит от точности кварцевого резонатора, в моем случае частотомер имел небольшую погрешность, для ее устранения можно подобрать время счета при измерении частоты.
delay(996);delayMicroseconds(150); // ждем 1 секунду пока таймер считает импульсы
При наличии точного генератора можно очень точно подобрать время счета.
Результаты измерений