Вход

Регистрация
Главная
 

 

Пиротехнические пульты, пиротехническое оборудование
и пиротехника
Pyro Alex RF 48
Open Pyro SFX 8 D
Open Pyro SFX 10/120
Pyro Man 200 M
Spets 150
Приём заказов на изготовление пиротехнических пультов
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
Пиропульты - Электроника Форум » Электроника » Микроконтроллеры и ПЛИС » Arduino и сеть RS485
Arduino и сеть RS485
alexval2007Дата: Четверг, 18.11.2010, 17:26 | Сообщение # 1
Электро воспламенитель
Группа: Администраторы
Сообщений: 662
Награды: 7
Репутация: 7
Статус: Offline
Arduino и сеть RS485.

Статья переведена с оригинала на английском
Автор Igor Real Технический перевод и комментарии alexval2007

RS485 - стандартный последовательный протокол с шинной топологией сети, где ты можешь соединить несколько устройств очень легко. Здесь я расскажу, как создать сеть между микроконтроллерами с использованием всего 2х проводов. Это базируется в дифференциале несколько проводов, с которыми мы можем получить полу-дуплексный коммуникационный канал. У драйвера есть конфигурационный вывод, который предоставляет нам возможность настроить наш приемопередатчик как передатчик или приёмник.

Аппаратные средства для формирования RS485.
* MAX485
* SN75176(более дешевый)

Для чего это нужно? Это - преобразователь уровня напряжения, чтобы использовать наш UART в качестве интерфейса RS485.

Хорошо, теперь мы готовы начать. RS485 находится в физическом уровне, основанном на Модели OSI, таким образом, это только говорит нам о напряжениях, физические параметры....

Рекомендуемые ссылки:
rs-485.pdf

http://www.maxim-ic.com]

rs485-d810.neo

RS485 Снимки экрана осциллографа
Мы нуждаемся в протоколе обмена по сети чтобы отправить нашу информацию. В качестве протокола мы выбираем уже готовый , созданный компанией Фуджи в её промышленных проектах.

Взгляните на: FUJI_RS485_COMM_for_FRENIC-Mini

Давайте посмотрим на конфигурацию протокола:

* Byte 1: Start Byte ( 0 hexadecimal ).
* Byte 2-3: ASCII Arduino's address.
* Byte 4: Byte ENQ, ACK or NAK (0x05h, 0x06h y 0x15h) .
* Byte 5: ASCII Requested command.
* Byte 6 y 7: ASCII Function number.
* Byte 8: Sign byte (Positive 0x20h y Negative 2D)
* Byte 9-12: ASCII of data bytes (0x00h-0xFFFFh)
* Byte 13: Byte EOT (End of Text) (0x03h)
* Byte 14-15: Checksum (addition from 2nd byte to 13th byte)

С этим протоколом мы имеем
* 1 байт, указывающий на Функциональное Число (Function Number)
* 2 байта, указывающие на под функциональное Число (sub-function Number)
Так вообразите возможные комбинации!!!

Например:
A01 запрос имеющий значение на Аналоговом входе 1
P01 запрос конфигурации PWM 1 с данными установки в байтах данных
И так далее!!!! Разве не замечательно?

Заметьте: - Команды - Кодированный ASCII - Служебные байты не Кодированный ASCII Это - хорошая функция из-за, в случае, если мы получаем 0x00 (думающий, что это - байт запуска), программа поймет, что это - запускающийся фрейм вместо как 0 значений, потому что в этом случае, это должно быть отправлено как ASCII (0x30). Взгляните на Таблицу ASCII, еще лучше распечатайте её.

Посмотрим пример: Предположим, что мы нуждаемся в arduino (мастер сети), который решает включить или выключить отдаленные светодиоды. Тогда, он должен послать команду по нашей сети RS485, и затем другой arduino (слейв) будет интерпретировать команду и выполнит её. Мастер будет следить за состоянием кнопок, a и как необходимый, мастер пошлет команду вкл/выкл слейву, с адресом 01. Функция будет вызвана D и номер 0. (ты можешь настроить это как тебе необходимо). Так, мастер посылает: слейв (01) - функция выполнения Запроса (D)-SubFunction (0) 0x00 0x30 0x31 0x05 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEE слейв отвечает: AKNOWLEDGE (ACK). 0x00 0x30 0x31 0x06 0x44 0x30 0x30 0x20 0x30 0x30 0x30 0x31 0x03 0x01 0xEF The salve's ACK frame has the following configuration(take a look at Byte 4 due to here is specified ACK) У ведомого фрейма ACK есть следующая конфигурация (смотрите на Байт 4 из-за, вот определенный ACK), Еще лучше смотрите следующий видеофильм:


Жаль, но переключатель только несколько проводов, идущих от VCC до GND! Чтобы видеть, что фреймы идут по сети, Вы нуждаетесь только в USB <----> RS232 как FTDI232 или MAX232+MAX485... Если у Вас есть PCB Arduino, заметьте, что Вы можете удалить uC из его сокета, и у Вас будет USB <----> Rs232 преобразователь!

Если Вы хотите наблюдать что происходит в сети, Вы можете использовать Гипер терминал, или любое ПО, которые включают некоторые полезные функции как вывод формата, сохраняя опции.... например:

RealTerm
FREE SERIAL TERMINAL MONITOR
Действительно удобный, если Вы хотите отправлять и принимать фреймы по RS232 Но тут я с автором не соглашусь у нас есть свои средства гораздо удобней.
Программа Terminal RS232является монитором COM порта
COM Port Toolkit
у этой программы есть много полезных функций самая нужная это функция прослушки порта без вмешательства в поток данных. В этом примере у нас есть 3 соединенные arduinos. У ведущего устройства есть 2 переключателя, используемые, чтобы переключиться вкл/выкл светодиоды соединенный с каждым из ведомых устройств.


Теперь... КОД!
ВАЖНО: Контрольная сумма сделана непосредственно в шестнадцатеричном формате вместо преобразования его в ASCII. Изменения, которое моглИ быть необходимо, чтобы не сделать, есть проблемы. Эта запись - бумага с практическими рекомендациями, чтобы показать Вам, как RS485 работает, но отлажено не на 100 %.

MASTER

Code

//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------
byte data[12];
unsigned long previous_time;
unsigned long previous_time2;
byte times_repeat=5;
byte times_repeat2=5;

byte state=0;
byte state2=0;

#define pinCONTROL 02
#define myaddress 01

void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(13,HIGH);
digitalWrite(12,LOW);
pinMode(8,INPUT);
pinMode(9,INPUT);
digitalWrite(pinCONTROL,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
state=0;
state2=0;
}

void loop(){
if (digitalRead(8)==state){
state=!state;
times_repeat=0;
}
if (digitalRead(9)==state2){
state2=!state2;
times_repeat2=0;
}

if (times_repeat<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(8)==HIGH){
sendMSG(48,49,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,49,68,48,48,32,48,48,48,48);
}
times_repeat=times_repeat+1;

previous_time=millis();
while (((millis()-previous_time)<500) && (Serial.available()!=15)){
;;
}

if (Serial.available()>=15){
if (receiveMSG()==1){
Serial.println("Trama correcta");
if (data[0]==48 && data[1]==49 && data[2]==6){
//ACK
times_repeat=5;
Serial.println("ACK recibido");
}
}
}
}

if (times_repeat2<4){
Serial.flush();
//(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4)
if (digitalRead(9)==HIGH){
sendMSG(48,50,68,48,48,32,48,48,48,49);
}else {
sendMSG(48,50,68,48,48,32,48,48,48,48);
}
times_repeat2=times_repeat2+1;

previous_time2=millis();
while (((millis()-previous_time2)<500) && (Serial.available()!=15)){
;;
}

if (Serial.available()>=15){
if (receiveMSG()==1){
//Serial.println("Trama correcta");
if (data[0]==48 && data[1]==50 && data[2]==6){
//ACK
times_repeat2=5;
//Serial.println("ACK recibido");
}
}
}
}
}

//------------------------
//Функции
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;

unsigned int checksum;
unsigned int checksum_trace;

while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}

void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){

unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;

UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);

}

void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){

unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}

void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){

unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}

byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}

SLAVES:
(Вы должны изменить myaddress на 01 или 02)

Code

//----------------------------------
//RS 485
//By Igor Real
//24-06-09
//----------------------------------

byte data[12];
byte address;
byte function;
byte function_code;
unsigned int data_received;
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;
#define pinCONTROL 02
#define myaddress 02

void setup() {
pinMode(13,OUTPUT);
pinMode(pinCONTROL,OUTPUT);
digitalWrite(2,LOW);
Serial.begin(9600);
Serial.println("Empezamos");
}

void loop(){
while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
//Serial.println("Se ha recibido byte Start");
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
address=0;
data_received=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
//Serial.print("Primer Byte Checksum");
//Serial.print(checksum_trace,HEX);
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
//Serial.println(byte_receive,HEX);
//Serial.println("Recibida trama");
//Serial.print("Checksum Trace= ");
//Serial.println(checksum_trace,HEX);
//Serial.print("Checksum= ");
//Serial.println(checksum,HEX);
//Serial.println(checksum,DEC);
//Serial.println("Trama= ");
//Serial.print(data[0]);
//Serial.print(data[1]);
//Serial.print(data[2]);
//Serial.print(data[3]);
//Serial.print(data[4]);
//Serial.print(data[5]);
//Serial.print(data[6]);
//Serial.print(data[7]);
//Serial.print(data[8]);
//Serial.print(data[9]);
//Serial.print(data[10]);
//Serial.println(data[11]);

if (checksum_trace==checksum){
trace_OK=1;
address=(hex2num(data[0])<<4)+(hex2num(data[1]));
function=data[3];
function_code=(hex2num(data[4])<<4)+(hex2num(data[5]));
data_received=(hex2num(data[7])<<12)+(hex2num(data[8])<<8)+(hex2num(data[9])<<4)+(hex2num(data[10]));

//Serial.println("TRAZA CORRECTA");
//Serial.println(address,DEC);
//Serial.println(data_received);
if (address==myaddress){
if ((function=='D') && (function_code==0) && data[2]==5){
if (data_received==1){
digitalWrite(13,HIGH);
//Serial.println(data_received,DEC);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}else if (data_received==0){
digitalWrite(13,LOW);
sendACK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}else{
//Serial.println("TRAZA INCORRECTA");
sendNAK(data[0],data[1],data[3],data[4],data[5],data[6],data[7],data[8],data[9],data[10]);
}
}
}
}

//------------------------
//Функции
//------------------------
byte receiveMSG(){
byte byte_receive;
byte state=0;
byte cont1=1;
byte trace_OK=0;
unsigned int checksum;
unsigned int checksum_trace;

while (Serial.available() > 0){
byte_receive=Serial.read();
if (byte_receive==00){
state=1;
checksum_trace=0;
checksum=0;
trace_OK=0;
cont1=1;
}else if (state==1 && cont1<=12){
data[cont1-1]=byte_receive;
checksum=checksum+byte_receive;
cont1=cont1+1;
}else if (state==1 && cont1==13){
checksum_trace=byte_receive<<8;
cont1=cont1+1;
}else if (state==1 && cont1==14){
checksum_trace=checksum_trace+byte_receive;
cont1=cont1+1;
state=0;
if (checksum_trace==checksum){
trace_OK=1;
}else{
trace_OK=0;
}
break;
}
}
return trace_OK;
}

void sendMSG(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){
unsigned int checksum_ACK;
checksum_ACK=address1+address2+5+data_type+code1+code2+Sign+data1+data2+data3+data4+3;
UCSR0A=UCSR0A |(1 << TXC0);
digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(5,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)& 255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);

}

void sendACK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){

unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;

UCSR0A=UCSR0A |(1 << TXC0);

digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(6,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}

void sendNAK(byte address1,byte address2,byte data_type,byte code1,byte code2,byte Sign,byte data1,byte data2,byte data3,byte data4){

unsigned int checksum_ACK;
checksum_ACK=address1+address2+6+data_type+code1+code2+Sign+data1+data2+data3+data4+3;

UCSR0A=UCSR0A |(1 << TXC0);

digitalWrite(pinCONTROL,HIGH);
delay(1);

Serial.print(0,BYTE);
Serial.print(address1,BYTE);
Serial.print(address2,BYTE);
Serial.print(15,BYTE);
Serial.print(data_type,BYTE);
Serial.print(code1,BYTE);
Serial.print(code2,BYTE);
Serial.print(Sign,BYTE);
Serial.print(data1,BYTE);
Serial.print(data2,BYTE);
Serial.print(data3,BYTE);
Serial.print(data4,BYTE);
Serial.print(3,BYTE);
Serial.print(((checksum_ACK>>8)&255),BYTE);
Serial.print(((checksum_ACK)&255),BYTE);
while (!(UCSR0A & (1 << TXC0)));
digitalWrite(pinCONTROL,LOW);
}

byte hex2num(byte x){
byte result;
if (x>=48 && x<=57){
result=x-48;
}else if (x>=65 && x<=70){
switch(x){
case 65:
result=10;
break;
case 66:
result=11;
break;
case 67:
result=12;
break;
case 68:
result=13;
break;
case 69:
result=14;
break;
case 70:
result=15;
break;
}
}
return result;
}

В дальнейшем я прокомментирую весь код возможно чтото адаптирую под себя может добавлю какието новые функции и результаты сыоих тестов вобщем ждите продолжение следует. wink
 
YugДата: Воскресенье, 19.12.2010, 22:02 | Сообщение # 2
Рядовой
Группа: Проверенные
Сообщений: 2
Награды: 0
Репутация: 0
Статус: Offline
RS485 - это конечно хорошо, но есть ограничения: если подключаешь более 64 устройств, то начинает глючить. А вообще нужно использовать совместно с RS485 радиомодули. Это позволит подключить большое количество устройств для шикарного пирошоу под музыку. Есть даже система на 1000 включений. У меня smile
 
Open_PyroДата: Понедельник, 20.12.2010, 06:48 | Сообщение # 3
Генерал-майор
Группа: Администраторы
Сообщений: 395
Награды: 3
Репутация: 6
Статус: Offline
Нам бы хотя бы 10 сделать, больше любительский бюджет по фейерверку и не потянет)))
Более чем 64 устройств можно подключить и без радиоканала просто воспользуйтесь репетиром RS485.

А у вас радиоканал на 1000 каналов ?

 
alexval2007Дата: Понедельник, 20.12.2010, 20:31 | Сообщение # 4
Электро воспламенитель
Группа: Администраторы
Сообщений: 662
Награды: 7
Репутация: 7
Статус: Offline
в промышленности 32 модуля потом репитер и еще 32 так на одном порту до 256 устройств можно
 
sergomanovДата: Среда, 20.08.2014, 12:51 | Сообщение # 5
Рядовой
Группа: Пользователи
Сообщений: 1
Награды: 0
Репутация: 0
Статус: Offline

Вот понятная инструкция по подключению RS485 модуля к arduino.
http://adatum.ru/podklyuchenie-konvertera-rs-485-v-ttl-k-arduino.html
Прикрепления: 0485004.jpg(123Kb)


Сообщение отредактировал sergomanov - Среда, 20.08.2014, 12:52
 
alexval2007Дата: Вторник, 30.09.2014, 19:47 | Сообщение # 6
Электро воспламенитель
Группа: Администраторы
Сообщений: 662
Награды: 7
Репутация: 7
Статус: Offline
Хорошая статья спасибо я сейчас разбираюсь с протоколом модбас по 485 интерфейсу на ардуинках получается неплохо как доделаю выложу на форум статью
 
Пиропульты - Электроника Форум » Электроника » Микроконтроллеры и ПЛИС » Arduino и сеть RS485
Страница 1 из 11
Поиск:


Rambler's Top100 Пиротехника, салюты, фейерверки. Яндекс цитирования
www.alexval2007.ucoz.ru © 2008