--- title: "Простой частотомер на AVR - курсовая работа" categories: ["mcu", "archive"] date: 2015-08-16T00:00:00+03:00 draft: true featured_image: miniature.jpg --- Итак, пришло время время делать курсовые работы. Мне попалась тема "Частотомер с передачей данных по последовательному порту и динамической индикацией". Значит, будем использовать таймер, внешние прерывания и динамическую индикацию. Использовал семисегментный индикатор с четырьмя разрядами и общим анодом. Микроконтроллер выберем Atmega16. Именно с ним я не чувствовал дефицита ножек. Приступим. > :warning: Этот текст – древний стыд. Не нужно принимать его всерьёз. Сейчас бы такой бред не сделал. Работа заключается в следующем: нужно спроектировать схему устройства, развести печатку, а также изготовить корпус для готового устройства. В КОМПАС 3D, разумеется. Для начала нам нужно определиться как именно считать частоту. Я решил использовать таймер, тактированный часовым кварцем и засекать количество внешних прерываний за секунду. Прерывания использовал по нарастающему фронту. Возможно, я не прав, но, во благо, на железе собирать ничего не требуется. Делаем всё в протеусе. Схема получилась такая: ![Схема|786](freq_sch.png) Пишем программу. Микроконтроллер должен считать импульсы в секунду и выводить их на семисегментный индикатор. А также отдавать данные по UART. main.h: ```c #ifndef __MAIN_H_ #define __MAIN_H_ #include #include typedef uint8_t byte; byte buf[16]; uint32_t freq; uint32_t freq_max; uint32_t measure_buf; // порт для сегментов #define SEGMENTS_DDR DDRA #define SEGMENTS_PORT PORTA // порт для разрядов #define DIGITS_DDR DDRC #define DIGITS_PORT PORTC #define SWITCH_TIME 45 // время между переключениями разрядов; чем меньше, тем меньше мерцает #define INPUT 0x00 #define OUTPUT 0xFF #define SYMBOLS_SIZE 11 // количество символов в таблице byte symbols[SYMBOLS_SIZE] = //состояния пинов для символов { 0b00111111, // 0 0b00000110, // 1 0b01011011, // 2 0b01001111, // 3 0b01100110, // 4 0b01101101, // 5 0b01111101, // 6 0b00000111, // 7 0b01111111, // 8 0b01101111, // 9 0b10000000 // . }; int main(void); void switchDigit(byte digit); // показать нужный разряд, остальные погасить; значения от 0 до 3 void showDigit(byte number, bool dot); // вывести символ на разряд, с точкой или без; значения от 0 до SYMBOLS_SIZE void initTimer(); // инициализация таймера (для нас - часового) void initInterrupts(); //инициализация прерываний void initUART(); //инициализация последовательного порта void sendByte(byte b); //отправка байта по UART void sendString(byte *str); //отправка строки по UART #endif //__MAIN_H_ ``` main.c: ```c #include "main.h" #include #include #include #include int main(void) { SEGMENTS_DDR = OUTPUT; // настраиваем порты ввода-вывода DIGITS_DDR = OUTPUT; DIGITS_PORT = 0xFF; initTimer(); initInterrupts(); initUART(); byte i; uint32_t num; sprintf(buf, "? Stabilization...\r\n"); sendString(buf); _delay_ms(100); // ожидаем стабилизации таймера sprintf(buf, "? Init finished!\r\n"); sendString(buf); while (1) { num = freq > 9999 ? 9999 : freq; for (i = 0; i < 4; ++i) { // перебираем все разряды, разбираем частоту на цифры switchDigit(i); switch (i) { case 0: showDigit((byte) ((num / 1000) % 10), false); break; case 1: showDigit((byte) ((num / 100) % 10), false); break; case 2: showDigit((byte) ((num / 10) % 10), false); break; case 3: showDigit(num % 10, false); break; default: break; } _delay_ms(SWITCH_TIME); } } } ISR(TIMER2_OVF_vect) { // прерывание таймера при переполнении freq = measure_buf; if( freq > freq_max) freq_max = freq; measure_buf = 0; sprintf(buf, "> Freq: %dHz, ", freq); // отправляем данные sendString(buf); sprintf(buf, "Max: %dHz\r\n", freq_max); sendString(buf); } ISR(INT0_vect) { //внешнее прерывание measure_buf++; } void showDigit(byte digit, bool dot) { SEGMENTS_PORT = ~symbols[digit > SYMBOLS_SIZE - 1 ? 10 : digit] | (dot ? symbols[10] : 0); } void switchDigit(byte number) { DIGITS_PORT = number < 4 ? (byte) (1 << number) : 0x00; } void initTimer() { ASSR |= _BV(AS2); // асинхронный режим, тактируемся от часового кварца TCCR2 = _BV(CS20) | _BV(CS22); //предделитель 128, одна секунда TIMSK |= _BV(TOIE2); // включаем таймер } void initInterrupts() { MCUCR = (1 << ISC01) | (1 << ISC00); //прерывание по растущему форонту GICR = (1 << INT0); //включаем прерывание на INT0 sei(); // разрешаем прерывания } void initUART() { // выставляем скорость: 9600 при частоте 8МГц // UBRR=8000000/(16*9600)-1=51.0833, округляем = 51 (0x33) UBRRH = 0x00; UBRRL = 0x33; // Разрешаем приём и передачу UCSRB = (1 << RXEN) | (1 << TXEN); UCSRB |= (1 << RXCIE); // устанавливаем формат: 8 бит данных, 2 стоп бита UCSRC = (1 << URSEL) | (1 << USBS) | (3 << UCSZ0); } void sendByte(byte b) { while ( !(UCSRA & (1<