…без этой вашей адурины!
Внимание! Attention! Achtung! Проект на стадии разработки!
Давно возникла необходимость иметь антенный переключатель для КВ антенн, которые хоть и медленно, но начинают появляться. Как правило, антенные переключатели состоят из двух частей: собственно, самого переключателя, и блока управления (контроллера). С первым проблем обычно не возникает, да и со вторым тоже, если бы не одно НО — возможность управления с ПК. Вот тут начинается интересное (кто постоянно читает мой блог — два путя). Первый: сходить на Хабр или на сайт к RW9JD, взять Arduino, всё собрать и прошить, воткнуть разъем от трансивера с Band Data и успокоиться. Ага, щаз..! Во-первых — переключение антенн происходит по команде с трансивера, а не с ПК. Во-вторых — использовать в таком простом проекте эту вашу адурину равносильно доставке единственного мешка картошки (причем рассыпаного по всей площади кузова) на большом грузовике; очень нерациональное использование ресурсов. Поэтому идем по второму пути: берем САПР Proteus, подключаем WinAVR, создаем проект на Attiny2313 и пишем прошивку на чистом Си.
Итак. Реализация контроллера переключателя антенн следующая: к микроконтроллеру Attiny2313 подключено восемь кнопок, управление восемью реле осуществляется через сдвиговый регистр 74HC595, индикация светодиодная (какая ж еще?), связь с ПК по UART либо через преобразователь RS232/UART, либо через преобразователь USB/UART — как в моем случае на микросхеме FT232; скорость соединения 9600 бит/с. Схема устройства ниже.
Прошивка, как уже говорилось, написана на чистом Си для WinAVR. Исходный код первой версии ниже.
/***************************************************** Project : Antenna Switch Version : 1.0 Date : 23.03.2021 Author : R4ADX Company : Unlis Comments: Chip type : ATtiny2313 Clock frequency : 11,059200 MHz Memory model : Tiny External SRAM size : 0 Data Stack size : 32 *****************************************************/ #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define SH PD4 // Тактовый выход 74HC595 #define DS PD3 // Выход данных 74HC595 #define ST PD2 // Синхронизация #define F_CPU 11059200 // Тактовая частота MCU #define baudrate 9600L // Скорость передачи USART #define baud (F_CPU/(16*baudrate)-1) // unsigned char tab[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; // Коды антенных портов unsigned char count; // Счетчик для клавиатуры unsigned char temp; volatile unsigned char antenna; // Активный антенный порт unsigned char buf[2]; // Буфер приема UART unsigned char addr = 0; volatile unsigned char enabled; // Разрешенные антенные порты /* Функция передачи байта по UART */ void USART_Transmit(unsigned char data) { while (!(UCSRA & (1<<UDRE))); UDR = data; } /* Функция записи в EEPROM */ void EEPROM_write(unsigned int uiAddress, unsigned char ucData) { while(EECR & (1<<EEPE)) {}; // Ожидание окончания предыдущей записи EEAR = uiAddress; // Установка регистра адреса EEDR = ucData; // Установка регистра данных EECR |= (1<<EEMPE); // Подготовка к записи EECR |= (1<<EEPE); // Начало записи в EEPROM } /* Функция чтения из EEPROM */ unsigned char EEPROM_read(unsigned int uiAddress) { while(EECR & (1<<EEPE)) {}; // Ожидание окончания предыдущей записи EEAR = uiAddress; // Установка регистра адреса EECR |= (1<<EERE); // Начало чтения из EEPROM return EEDR; // Возврат регистра данных } /* Функция вывода данных в сдвиговый регистр 74HC595 */ void shift_595(antenna) { for (count = 0; count < 8; count++) { PORTD =(antenna & 0x80) ? PORTD | (1<<DS) : PORTD & ~(1<<DS); PORTD |= (1<<SH); _delay_us(2); PORTD &= ~(1<<SH); antenna = antenna <<1; } PORTD |= (1<<ST); _delay_us(2); PORTD &= ~(1<<ST); } /* Отправка переключенной антенны в UART */ void S_to_PC() { USART_Transmit('S'); // Шлем в порт S USART_Transmit(antenna); // Шлем в порт адрес антенны } /* Обработчик приемного буфера */ void from_PC(unsigned char *data) { switch (data[0]) { case 0x49: USART_Transmit('I'); // I - Инициализация коммутатора программой с ПК. Шлем в порт I USART_Transmit(enabled); // Шлем в порт байт разрешенных антенн S_to_PC(); // Вызываем функцию для отсылки адреса антенны break; case 0x53: antenna = data[1]; // S - Переключение антенн с ПК shift_595(antenna); // ...переключили EEPROM_write(0x01, antenna); // ...запомнили break; case 0x57: enabled = data[1]; // W - Запись разрешенных антенн EEPROM_write(0, enabled); break; } } int main(void) { /* Настройка портов */ DDRB = 0x00; // PortB на вход PORTB = 0xFF; // Подтяжка DDRD |= (1<<SH) | (1<<DS) | (1<<ST); // PortD HC595 на выход /* Настройка UART */ UBRRH = (unsigned char)(baud>>8); // Скорость порта UBRRL = (unsigned char)baud; // UCSRB = (1<<RXEN) | (1<<TXEN) | (1<<RXCIE); // Разрешение прием и передачу через USART. Разрешение прерывания по приему UCSRC = (0<<USBS) | (1<<UCSZ0) | (1<<UCSZ1); // Режим UART: 8n1 enabled = EEPROM_read(0x00); // Читаем разрешенные антенные порты antenna = EEPROM_read(0x01); // Последняя включенная антенна shift_595(antenna); // Включаем антенну sei(); while(1) { m1: temp = PINB; for (count = 0; count < 8; count++) { // Цикл сканирования клавиатуры if ((temp&1) == 0) { // Проверка младшего бита _delay_ms(10); // Антидребезг while ( PINB != 0xFF ) {}; // Ждем отпускания кнопок goto m2; } temp >>= 1; // Сдвигаем для проверки следующий бит } goto m1; // Идем в начало сканирования клавиатуры m2: if ((enabled & (1<<count)) != 0 ) { // Проверка разрешено ли включать антенный порт antenna = tab[count]; // Запись значения антенны shift_595(antenna); // Переключаем антенные реле S_to_PC(); // Отправляем в UART EEPROM_write(0x01, antenna); // Запоминаем что включили } } } /* Обработчик вектора прерывания по приему UART */ ISR(USART_RX_vect) { buf[addr] = UDR; // Читаем UART в буфер addr++; // Увеличиваем адрес буфера if (addr == 2) { from_PC(buf); // Если заполнился - вызываем обработчик приемного буфера addr = 0; // Сбрасываем адрес буфера. } }
В начале управляющей программы происходит настройка портов ввода/вывода МК, подготовка USART, загрузка из EEPROM памяти байта разрешенных/запрещенных антенных входов и байта с адресом последней включенной антенной, происходит включение соответствующего антенного входа. Далее выполняется бесконечный цикл опроса клавиатуры, и в этом же цикле — процедура обработки нажатия кнопок, в котором происходит проверка на запрещенный антенный вход, вызов функции записи данных в сдвиговый регистр, сохранение адреса включенной антенны в EEPROM, вызов функции отправки данных о переключении по USART. При приеме байта данных по USART микроконтроллером вызывается прерывание, в котором осуществляется запись принятого байта в кольцевой буфер длиной 2 байта, при заполнении буфера происходит вызов функции его обработчика. Функция обработчика буфера по нулевому байту определяет тип сообщения: при поступлении команды инициализации МК формирует ответ, состоящий из заголовка, байта разрешенных антенн, байта с адресом включенной в данный момент антенны; при поступлении команды переключения антенн байт с адресом антенны записывается в ОЗУ, EEPROM, сдвиговый регистр 74HC595; при поступлении команды записи настроек разрешенных/запрещенных антенных входов происходит запись байта данных в соответствующее место ОЗУ, EEPROM. Формат обмена данными между программой ПК и микроконтроллером представлен в таблице.
Действие | МК => ПК | ПК => МК |
Переключение антенн кнопками блока управления | Заголовок. Байт 0: 0x53 (ASCII символ «S») Данные. Байт 1: адрес антенны |
|
Не передает данные | ||
Инициализация контроллера программой ПК | Заголовок. Байт 0: 0x49 (ASCII символ «I») Данные. Байт 1: Любой, но должен быть передан. |
|
Заголовок. Байт 0: 0x49 (ASCII символ «I») Данные. Байт 1: байт разрешенных/запрещенных антенных входов Данные. Байт 2: 0x53 (ASCII символ «S») Данные. Байт 3: адрес антенны |
||
Разрешение/запрещение антенных входов программой ПК | | Заголовок. Байт 0: 0x57 (ASCII символ «W») Данные. Байт 1: набор бит, соответствующих антенным входам. |
Не передает данные | ||
Переключение антенн программой ПК | | Заголовок. Байт 0: 0x53 (ASCII символ «S») Данные. Байт 1: адрес антенны |
Не передает данные |
Из недостатков стоит отметить отсутствие какого-либо контроля целостности, отсутствие ответа от контроллера об успешном выполнении операций, запись настроек ведется по одному и тому же адресу EEPROM, что при частых переключениях быстро выведет его ячейку из строя.
Программа управления почти написана на C# в среде Visual Studio.
Алгоритм управления следующий. При запуске программы происходит попытка инициализации микроконтроллера путем посылки байта 0x49 (ASCII код — I). При успешной инициализации (первый байт ответа также будет 0x49) отключаются кнопки тех антенн, которые были запрещены настройками, записанными в EEPROM контроллера, а также выбирается кнопка, соответствующая включенной в данный момент антенне. Если инициализация не удалась — все кнопки будут отключены. В статусной строке отображается состояние. При переключении антенн непосредственно с контроллера выбирается RadioButton, соответствующий выбранной антенне; при переключении антенн из программы в микроконтроллер посылается байт управления 0x53 и байт с адресом антенны. При нажатии меню Settings открывается окно, где можно выбрать порт для подключения, переименовать антенны (названия хранятся в ini файле), а также разрешить/запретить антенные входы.
С GitHub у меня отношения не сложились, поэтому продолжение в новой статье…
Ссылка для обсуждения https://forum.cqr4a.ru/index.php/topic,5.0.html