alexval2007 | Дата: Четверг, 18.11.2010, 17:26 | Сообщение # 1 |
Электро воспламенитель
Группа: Администраторы
Сообщений: 659
Статус: 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; } В дальнейшем я прокомментирую весь код возможно чтото адаптирую под себя может добавлю какието новые функции и результаты сыоих тестов вобщем ждите продолжение следует.
|
|
| |