// Использование таймера в режиме захвата. Измерение ширины, // скважности импульса и частоты сигнала #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> unsigned char OVF_counter, zamer_1, zamer_T, zamer_t, duty; unsigned long t, T, f; unsigned int rising_1, rising_2, falling; // Прерывание по переполнению Таймера/счетчика 1 ISR(TIMER1_OVF_vect) { OVF_counter++; // Увеличиваем счетчик переполнений } // Прерывание по захвату Таймера/счетчика 1 ISR(TIMER1_CAPT_vect) { switch(zamer_1) { case 0: // Вычисляем ширину импульса switch(zamer_t) { case 0: rising_1 = ICR1; // Запоминаем значениие счётчика TCCR1B &= ~(1 << ICES1); // Устанавливаем прерывание по спадающему фронту импульса OVF_counter = 0; // Обнуляем количество переполнений счётчика zamer_t = 1; // Переходим к следующему вычислению break; case 1: falling = ICR1; // Запоминаем значение счётчика TCCR1B |= (1 << ICES1); // Устанавливаем прерывание по нарастающему фронту импульса // Приводим все переменные к одному типу и вычисляем длительность импульса t = (unsigned long)falling - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536); zamer_t = 0; zamer_1 = 1; // Переходим к следующему вычислению break; } break; case 1: // Вычисляем период импульса switch(zamer_T) { case 0: rising_1 = ICR1; // Запоминаем значение счётчика OVF_counter = 0; // Обнуляем количество переполнений счётчика zamer_T = 1; // Переходим к следующему вычислению break; case 1: rising_2 = ICR1; // Запоминаем значение счётчика // Приводим все переменные к одному типу и вычисляем период импульса T = (unsigned long)rising_2 - (unsigned long)rising_1 + ((unsigned long)OVF_counter * 65536); zamer_T = 0; zamer_1 = 2; // Переходим к следующему вычислению break; } break; case 2: f = 1000000/T; // Вычисляем частоту сигнала в Гц duty = (t*100)/T; // Вычисляем скважность импульса в процентах zamer_1 = 0; // Переходим к следующему вычислению break; } } // Функции работы с LCD #define RS PD0 #define EN PD2 // Функция установки курсора в указанную точку #define lcd_gotoxy(x, y) lcd_com(0x80|(x)+((y)*0x40)) // Функция передачи команды void lcd_com(unsigned char p) { PORTD &= ~(1 << RS); // RS = 0 (запись команд) PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция передачи данных void lcd_data(unsigned char p) { PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD) PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл _delay_us(100); PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD) _delay_us(100); } // Функция вывода строки на LCD void lcd_string(char *string) { lcd_com(0x0C); while(*string != '\0') { lcd_data(*string); string++; } } // Функция вывода переменной void lcd_num_to_str(unsigned long value, char nDigit) { switch(nDigit) { case 6: lcd_data(((value/100000)%10)+'0'); case 5: lcd_data(((value/10000)%10)+'0'); case 4: lcd_data(((value/1000)%10)+'0'); case 3: lcd_data(((value/100)%10)+'0'); case 2: lcd_data(((value/10)%10)+'0'); case 1: lcd_data((value%10)+'0'); } } // Функция инициализации LCD void lcd_init(void){
/* PD0 - RS PD2 - E
PD4-PD7 - D4-D7
PB0 - input
*/ PORTD = 0x00; DDRD = 0xFF; _delay_ms(50); // Ожидание готовности ЖК-модуля // Конфигурирование четырехразрядного режима PORTD |= (1 << PD5); PORTD &= ~(1 << PD4); // Активизация четырехразрядного режима PORTD |= (1 << EN); PORTD &= ~(1 << EN); _delay_ms(5); lcd_com(0x28); // шина 4 бит, LCD - 2 строки lcd_com(0x08); // полное выключение дисплея lcd_com(0x01); // очистка дисплея _delay_us(100); lcd_com(0x06); // сдвиг курсора вправо lcd_com(0x0C); // включение дисплея, курсор не видим } int main(void) { TCCR1B |= (1 << ICNC1)|(1 << CS11); // Активируем входной подавитель шума, предделитель на 8 TIMSK |= (1 << TICIE1)|(1 << TOIE1); // Разрешаем прерывание по захвату и переполнению lcd_init(); // Инициализация дисплея _delay_ms(50); lcd_gotoxy(0, 0); lcd_string("F= Hz DUTY"); lcd_gotoxy(0, 1); lcd_string("t= us %"); sei(); // Глобально разрешаем прерывания while (1) { lcd_gotoxy(2, 0); lcd_num_to_str(f, 6); // Выводим частоту сигнала на экран lcd_gotoxy(2, 1); lcd_num_to_str(t, 6); // Выводим ширину импульса на экран lcd_gotoxy(12, 1); lcd_num_to_str(duty, 3); // Выводим скважность импульса на экран _delay_ms(250); } }