Необходим совет по работе с AVR и proteus

Есть следующая задача — нужен коммутатор UART (1 ком порт раскидать на 11 портов).
Использую Atmega16 + max232 (1 на входе и 6 на выходе).
Выбрал atmega16 потому, что необходимо 24 пина под I/O — 2 пина (RX TX ком порта) и 22 пина (11-RX и 11-TX ) для подключения периферии (сервера с консолью по ком порту).
Итак цель — получить возможность коммутировать один COM порт на 11 COM потребителей.
Первое что пришло в голову — просто соединить передающие пины с принимающими портами. По i2c приходит команда переключить порт
и вызывается макрос который в зависимости от состояния пина ставит требуемый порт. Библиотека для работы с i2c — сторонняя (Pascal Stang — Copyright (C) 2002-2003).

Исходник мастера — получает команды по UART от windows и передает команду по I2c на коммутатор

#include <string.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#include "i2c.h"
#include "uart.h"

void uartInit();
unsigned char data[] = {0,0};//буфер для адреса и комманды
int i=0;
int main(void)
{
    //разрешить прерывания 
	sei(); 
	//инициализировать UART
	uartInit();
	  //инициализировать i2c
	i2cInit(); 
	
//отправить на ББ сообщение что инициализация прошла успешно
	writelnToUart("BAT v.6 24->12 is ready");
	while(1){}

ISR(SIG_UART_RECV)
{
		data[i++] =receiveByte();
		if (i == 2) {
			i2cMasterSendByte(data[0], data[1]);
			i=0;
		}		
}


Исходник слэйва — он же коммутатор UART

#include <string.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <avr/interrupt.h>

#include "i2c.h"
#include "uart.h"

#define LOCAL_ADDR 0x40 //адрес слэйва
unsigned char buff[40];
#define  portToPin(port, po_num, pin, pi_num) {\
					if((pin) >> (pi_num)) {\
				    	    (port)|=(1 << (po_num));\
					}\
					else {\
				     	    (port)&=~(1 << po_num);\
					}\
					}
unsigned char command = 0;

//Объявление функции обратного вызова
void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData) 
{ 
   command = (unsigned char)(*receiveData);
} 

void main(void)
{
	 uartInit();
	_delay_ms(1000);
	writelnToUart("RS-232 module");
	// инициализация ш2с
  	i2cInit(); 
  	// установка адреса устройства
  	i2cSetLocalDeviceAddr(LOCAL_ADDR, TRUE); 
        //привязка функции обратного вызова ( так как обработчки прерывания от i2с команд находится в другом С файле)
	i2cSetSlaveReceiveHandler( i2cSlaveReceiveService ); 

        //тут будем коммутировать порты
	while(1)
	{
		switch(command) 
		{
    		           case 0x41:		
					 portToPin(PORTA, PA0, PIND, PD6);//RX1=Rx0
    				         portToPin(PORTD, PD7, PINC, PC1);//Tx0=Tx1
					 break;
			   case 0x42:
					 portToPin(PORTA, PA1, PIND, PD6);//Rx2 = Rx0;
					 portToPin(PORTD, PD7, PINC, PC2);//Tx0 = Tx2;
					 break;
			   case 0x43:
					 portToPin(PORTA, PA2, PIND, PD6);//Rx3 = Rx0;
					 portToPin(PORTD, PD7, PINC, PC4);//Tx0 = Tx3;
					 break;
			   case 0x44:
					 portToPin(PORTA, PA3, PIND, PD6);//Rx4 = Rx0;
					 portToPin(PORTD, PD7, PINC, PC5);//Tx0 = Tx4;
					 break;
			   case 0x45:
					 portToPin(PORTA, PA4, PIND, PD6);//Rx5 = Rx0;
					 portToPin(PORTD, PD7, PINC, PC6);//Tx0 = Tx5;
				         break;
			   case 0x46:
					 portToPin(PORTA, PA5, PIND, PD6);// Rx6 = Rx0;
					 portToPin(PORTD, PD7, PINC, PC7);//Tx0 = Tx6;
					 break;
			   case 0x47:
					 portToPin(PORTA, PA6, PIND, PD6);//Rx7 = Rx0;
					 portToPin(PORTD, PD7, PIND, PD2);//Tx0 = Tx7;
					 break;
			   case 0x48:
					 portToPin(PORTA, PA7, PIND, PD6);//Rx8 = Rx0;
					 portToPin(PORTD, PD7, PIND, PD3);//Tx0 = Tx8;
					 break;
			   case 0x49:
					 portToPin(PORTB, PB0, PIND, PD6);//Rx9 = Rx0;
					 portToPin(PORTD, PD7, PIND, PD4);//Tx0 = Tx9;
					 break;
			   case 0x4A:
					 portToPin(PORTB, PB1, PIND, PD6);//Rx10 = Rx0;
					 portToPin(PORTD, PD7, PIND, PD5);//Tx0 = Tx10;
					 break;
			   case 0x4B:
					 portToPin(PORTB, PB2, PIND, PD6);//Rx11 = Rx0;
					 portToPin(PORTD, PD7, PIND, PD6);//Tx0 = Tx11;
					 break;
			   case 0x4C:
					portToPin(PORTD, PD7, PIND, PD6);//loopback
					break;
			}
	}
} 

Для связи портов с пинами использовал макрос и поместил вызов макроса для каждого требуемого порта в switch в коде коммутатора.
В итоге проиходит странная вещь — если я не использую макрос, а просто вывожу в каком-нибудь кейсе сообщение в дебаговый UART — то все в порядяке… команды от i2c приходят, принимаются слэйвом и выводятся в дебаг. Но если я добавляю в свитч установку портов (не важно каким способом — напрямую ставлю порты, исопльзую макрос или инлайн) — всё, после этого сообщения в UART (те которые внутри свитча)перестают ходить ну и разумеется выходной порты не дублирует пины при попытке что-то передать(или принять).
Прошу помощи или альтернативного решения проблемы.
Примерно такой же код на BASCOM работает нормально.

p.s. В режиме дебага в студии проверял как ставятся порты — все ставилось. Но когда переношу в Proteus — Увы
Компилирую в AS6, gcc.
Простой вариант схемы в Proteus 7.10: (один пин на один порт).

Прощу особо не пинать:) с AVR сталкиваюсь очень редко, и то обычно использую готовые схемы.
UPDATE

Решил в качестве коммутатора задействовать 4052.
Один из модулей 11-портовго коммутатора. Всего модулей будет 3 + управляющий контроллер.


Ну и немного ЛУТа (не самый удачный, но вполне сносно)


Файлы в топике: rs-232.ZIP, RS232_dipTrace.zip

Комментарии (34)

RSS свернуть / развернуть
Зачем Вам такое количество UART-ов? Что за чудное НЛО?
0
  • avatar
  • kalik
  • 23 октября 2013, 01:31
Тестовый стенд. Необходимо без участия человека гонять тестовые сценария на 11 серверах:)… помимо 11 уартов в стенде еще 24 входных USB порта и 12 выходных… но для начала надо UART сдлать )
0
Ужас=)) А у братьев Китайцев подобного решения, для примера, Вам не попадалось? Они шустрые… все может быть…
0
Китайцы если и есть — то все равно надо будет допиливать под себя. По крайней мере в таком количестве портом, за разумные деньги, девайсов не видел
0
В общем я маленько не понял Вашу реализацию… На если я понял правильно задачу, то почему бы не заюзать какой-то аналоговый мультиплексор под все это дело?
+1
Да я смотрел некоторые микросхемы — типа ADG726 — только там обратный функционал — слить в один несколько входных портов, и судя по даташиту развернуть его для демультиплексора не получитася. Также рассматривался вариант сборки дешифратора 5-32 ( из двух 74hc154 или несколькоих меньших), но так как общее управление планируется по i2c — то все равно на него придется вешать контроллер — так что решил пусть все будет в контроллере, если есть такая возможность.
0
Все равно немного не понял. Аналоговый мультиплексор тупо соединяет вход с выходом. А что и в какую сторону ему все равно. И можно вообще обойтись без контроллера — дергать линии COM порта. но если хочется, можно и с простеньким контроллером.
0
слэйвы — это готовые устройства? (в смысле — они ужЕ есть, или только на стадии разработки?) и еще — плата коммутатора, как я понимаю, только в разработке??
0
Слэйвы тоже в проекте — но там задачи попроще — просто выставить определенные порты на которые будут повешены КМОП ключи (коммутатор питания, коммутатора входныех USB разъемов по питанияю, коммутатора выходных USB рахъемов). С ними проблем нет.
Да, весь стенд пока в стадии разработки — предыдущие варианты стенда ( 16 USB входных, 2 выходных USB портов и 1 COM порт ) были реализованы на FT232 + 74HC154 — там хватало ресурсов и без контроллера.


В текущем проекте получается 4 независимых платы каждая со своим контроллером (что бы не тянуть горы проводов от управляющего). И один мастер контроллер для общения с ПК и раздачи команда по i2c слэйвам.
0
я к тому, что может лучше вместо i2c заюзать второй uart? у 16-й меги его, конечно, нет, но он есть у, например, меги164, pin-to-pin совместимой с мегой16. uart по-любому попроще будет. или надо далеко тащить провода до слэйвов?
0
Да нет провода тянуть недалеко — все это планируется в корпус типа серверного для вставки в стойку. Но проблем с i2с вроде нет — есть проблема именно со связываеним портов — небуферизированная передача сигналов с пинов на некоторый порт. Допустима ли вообще такая работа? Без использования таймера. Прием уарт сигналов на произвольный порт, считывания с пина этого порта состояния и выставление соответсвующего порта.
0
Прием уарт сигналов на произвольный порт, считывания с пина этого порта состояния и выставление соответсвующего порта

а, вон надо как:) не понял сначала. тогда да, и с уартом всё не так просто будет:)
0
Есть конечно еще вариант взять готовую реализцию софтварного уарта — и просто в нем менять выходные порты. Этот вариант тоже как запсной оставил.
0
Я бы применил что-то из этого — www.gaw.ru/html.cgi/txt/ic/Maxim/switches/index2.htm
На крайний случай — полевики, в SOT-23, что-то вроде IRML. Дешево и сердито
0
Ну видимо если с контроллером не совладаю — буду использовать любой из подобных вараинтов — прадва достать микросхемы коммутаторв у нас сложнее чем контроллеры. Но хотелось бы все таки разобраться — по идее вполнле реализуемо средствами AVR
0
А почему бы не использовать для этого например вместо МК ПЛИС? Такая вот MAXII с 100 ногами без проблем с этим справится…
0
  • avatar
  • wowa
  • 23 октября 2013, 10:41
Можно разумеется… но увы сроки не позволят разбираться еще и с плисами. Опыт работы с ними минимальный — да и то только в режиме эмуляции в MAx Plus.
0
В таком случае — на Вашем месте я бы делал это на аналоговых мультиплексорах — они пропускают сигнал в обе стороны. Хотя не уведены скорость передачи по серийному порту… Если там под 9600 кбод то я думаю что можно будет сделать на все ноги прерывание по изменению и дальше смотреть какой выбран — тот переслать дальше на выходной порт. Думаю так даже и дуплекс будет работать :) Но будет внесёт ощютимый джитер в сигнал — тут нужно пробовать… Ну и ещё — у 16 атмеги нет прерывания от всех ног… нужно брать 164 или похожую подходящую по ногам…
+2
Скорость будет фиксированная — 38400. Касаемо прерываний — я ведь опрашиваю пины в общем цикле… с частотой процессора… и с такой же частотой выплевываю их содержимое в порты вывода. Или такой вариант работать не будет?
0
Зачем? Когда можно ждать на прерывание? Прерывание сделает только то что надо — остальное будет игнорировать… Хотя и маленький луп — тоже думаю будет работать… Нужно пробовать :)
0
В случае с прерываниеми прийдется брать контроллер у которого хотя бы 12 прерываний заведены на ноги… по идее так. ну или по таймеру опрашивать текущий пин
0
Проблема в том что по таймеру можно и прозевать короткий импульс. А вот по прерыванию уже не так просто. Написать короткий обработчик на АСМ. А почему просто не перевести всю шину на нечто что умеет много устройст на шине? Например на CAN? Один раз перевести на UART<->CAN и всё остальное делать уже на CAN.
0
Проблема в том что по таймеру можно и прозевать короткий импульс.
И хрен с ним. Интерфейс задан — UART, 38400. Это значит, что любой импульс короче 26мс — мусор. Достаточно обеспечить частоту опроса раз в 8 выше битрейта и о пропусках можно не беспокоиться.
0
А зачем в устройстве два МК? Нельзя разве команды с ПК принимать сразу в «коммутаторе»?
И вообще, я бы применил 4051-4053. Это аналоговые мультиплексоры, 1х1:8, 2х1:4, 3х1:2 (не помню, кто есть кто). На трех штуках 2х1:4 (это, ЕМНИП, 4052, и вроде оно же — 74HC4052) вполне можно собрать двухканальный коммутатор 1:12. Дешевые и распространенные, есть отечественные аналоги серии К561.
+1
  • avatar
  • Vga
  • 23 октября 2013, 11:13
Просто таких устройств несколько — и есть мастер который получается команды. А потом уже по i2c раздает их. Если бы можно было на уарт повесить несколько устройств — было бы хорошо. Так что либо свой протокол придумывать или тянуть кучу линий для параллельной передачи сигналов. либо использовать i2c, 1wire или что нибудь подобное с возможность адресации устройств
0
Наверно расмотрю идею с каким нибудь небольшим контроллером на котором есть TWI и внешним демультиплексором. Получается нужно минимум 7 пинов I/O — два для TWI и 5 для передачи команды на демультиплексор.
0
В принципе, повесить на UART несколько устройств параллельно вполне можно, надо только проработать протокол, чтобы они не начали одновременно отвечать мастеру. Ну и различали, кому та или иная посылка предназначена. Например, посылать по UART байт, где 4 бита адрес слейва, 4 — номер выбираемого канала, в ответ — какой-нить ACK от устройства, чей адрес совпадает с указанным в команде. Остальные молчат. Еще есть MPCM (Multi Processor Communication Mode), который тут уже где-то описывался.
И потом, если использовать аналоговые коммутаторы, вполне можно повесить все каналы на один контроллер. Или разные слейвы нужно разнести в пространстве на значительное расстояние? Но в принципе, на каждый модуль с аналоговыми коммутаторами придется тянуть всего 4 линии управления.
0
Все слэйвы находятся в одном корпусе — типа серверного, для вставки его в стойку. Поэтому расстояние максимум 20-30 см между платами.
0
Разве проблема в таких условиях протянуть шлейфик в пять проводов (земля и 4 адресных линии) от контроллера к каждому коммутатору?
0
А почему было не взять MM74C150 и 74154? Чуток дороже зато никаких проблем с программированием.
0
дрыгать ногами по i2c можно и без МК, да и не только по i2c.
достаточно спросить у гугла про i2c io expander, у nxp, ti, maxim их кучи.
мультиплексор с двухполярным питанием можно прямо на rs232 поставить без преобразования туда обратно в TTL, например ad5206, но можно и кучу max232 и cd74hc4067
+1
  • avatar
  • _pv
  • 23 октября 2013, 13:04
с другой стороны у китайцев 10 портовые usb хабы от 5$, то есть по 0.5$ за порт. а 4х портовые вообще по полбакса, но гирлянда сильно уж большая получится.
usb->serial переходники от 1.5$, то есть заплатив 2$ за порт можно размножить rs232 через usb без мультиплексирования вообще и на готовых покупных устройствах.
0
Может как-то так:

и на выходы 3 штуки MAX238(208)
+1
Почему то в протосе 4067 показало себя как односторонний демукс — если тоесть ТХ я смогу коммутировать, а RX — получается нет. ВОзможно это загоны протоса — я в итоге сваял схему на 4052.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.