Контроллер антенного переключателя на 8 антенн… v1.2

…без этой вашей адурины!

Внимание! 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

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *