[RS485] [Ethernet] [Timer]

- RS485
  ㄴ MC9 Address 10 기준 PV? SV? 처리
  ㄴ MC9 response time 150~250ms
  ㄴ 시간 감안하여 현재 PV every 1sec, SV every 5sec
  ㄴ 마지막 request 저장하여 수신시 데이터 처리 (수신데이터에 데이터 종류 없는 문제 방지)
- Ethernet
  ㄴ 현 명령어 AI? AO! PV? SV? SV! 작성
  ㄴ SV! 인 경우 485 send buff 앞에 저장하여 최우선순위 결정
main
Changwoo Park 2 years ago
parent 320d2cee1a
commit 8429349d1b

Binary file not shown.

@ -44,7 +44,7 @@ void webReponse(){
String response = "HTTP/1.1 200 OK\r\n"; String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: text/html\r\n\r\n"; response += "Content-Type: text/html\r\n\r\n";
response += "<html><body>"; response += "<html><body>";
response += Prcss_AI(); response += Prcss_AI_Read();
//response += "<h1>Hello, World!</h1>"; //response += "<h1>Hello, World!</h1>";
response += "</body></html>"; response += "</body></html>";
@ -62,8 +62,8 @@ void webReponse(){
String demuxCMD(String command, String* rightPart) { String demuxCMD(String command, String* rightPart) {
// "::"를 기준으로 문자열을 분리 // ":"를 기준으로 문자열을 분리
int separatorIndex = command.indexOf("::"); int separatorIndex = command.indexOf(":");
String leftPart = command.substring(0, separatorIndex); String leftPart = command.substring(0, separatorIndex);
*rightPart = command.substring(separatorIndex + 2); *rightPart = command.substring(separatorIndex + 2);

@ -10,7 +10,13 @@
#define RcvErr "ER\r\n" #define RcvErr "ER\r\n"
#define MODE_DEBUG false #define MODE_DEBUG false
const int BUFF_SIZE = 512;
char Buff_Eth_Rd[BUFF_SIZE] = {0};
char Buff_485_Wr[BUFF_SIZE] = {0};
char Buff_485_Rd[BUFF_SIZE] = {0};
String latest_sent_msg;
int numOf485 = 0;
int returnTime = 0;
// ========== ========== Periodic Flags // ========== ========== Periodic Flags
bool T_10ms = false; bool T_10ms = false;
bool T_20ms = false; bool T_20ms = false;
@ -18,9 +24,9 @@ bool T_50ms = false;
bool T_100ms = false; bool T_100ms = false;
bool T_200ms = false; bool T_200ms = false;
bool T_500ms = false; bool T_500ms = false;
bool T_500ms_2 = false;
bool T_1000ms = false; bool T_1000ms = false;
bool T_2000ms = false;
bool T_5000ms = false;
// ========== ========== Communication // ========== ========== Communication
// ---------- Ethernet // ---------- Ethernet
@ -49,8 +55,9 @@ int Wait_485_cnt;
int Size_AI = 16; int Size_AI = 16;
int Values_AI[16]; int Values_AI[16];
int Size_PV = 8; int Size_PV = 8;
int Values_PV[8]; int Values_10_PV[8];
int Size_SV = 8;
int Values_10_SV[8];
int msCnt = 0; int msCnt = 0;
unsigned long timer = 0; unsigned long timer = 0;
@ -63,7 +70,8 @@ void setup() {
// modules setup (init.) // modules setup (init.)
Ethernet_setup(); Ethernet_setup();
GPIO_setup(); GPIO_setup();
MC9_setup(); //MC9_setup();
RS485_setup();
// Timer set // Timer set
MsTimer2::set(10, timer_10ms); MsTimer2::set(10, timer_10ms);
@ -73,7 +81,7 @@ void setup() {
void loop() { void loop() {
// wait for a new client: // wait for a new client:
webReponse(); //webReponse();
client = server.available(); client = server.available();
if (client) { if (client) {
@ -95,6 +103,15 @@ void loop() {
char c ;//= client.read(); char c ;//= client.read();
while((c = client.read())) { while((c = client.read())) {
if((c == '\n') && (Buff_Eth_Rd[strlen(Buff_Eth_Rd)-1] == '\r')){
write_buff_c(Buff_Eth_Rd, c);
break;
}else{
write_buff_c(Buff_Eth_Rd, c);
}
/*
//If endwith CRLF //If endwith CRLF
if((c == 10) && (Buf_eth.endsWith("\r"))){ if((c == 10) && (Buf_eth.endsWith("\r"))){
Buf_eth.remove(Buf_eth.length() - 1); //remove CR Buf_eth.remove(Buf_eth.length() - 1); //remove CR
@ -104,32 +121,33 @@ void loop() {
}else{ }else{
Buf_eth += c; Buf_eth += c;
} }
*/
} }
// 데이터를 수신했으므로 타임아웃 타이머 초기화 // 데이터를 수신했으므로 타임아웃 타이머 초기화
lastDataReceivedTime = millis(); lastDataReceivedTime = millis();
} }
message = read_buff(Buff_Eth_Rd);
// If data read // If data read
if(message != ""){ if(message != ""){
cmd = demuxCMD(message, &cmdData); cmd = demuxCMD(message, &cmdData);
message = ""; message = "";
if(cmd=="AI"){ if(cmd=="AI?"){
client.print(Prcss_AI()); client.print(Prcss_AI_Read());
}else if(cmd=="AO"){ }else if(cmd=="AO!"){
dataSize = demuxNum(cmdData, data); dataSize = demuxNum(cmdData, data);
client.print(Prcss_AO(data, dataSize)); client.print(Prcss_AO(data, dataSize));
}else if(cmd=="PV"){ }else if(cmd=="PV?"){
client.print(Prcss_PV()); client.print(Prcss_PV_Read());
}else if(cmd=="SV"){ }else if(cmd=="SV?"){
dataSize = demuxNum(cmdData, data); client.print(Prcss_SV_Read());
client.print(Prcss_SV(data, dataSize));
}else if(cmd=="RS"){ }else if(cmd=="SV!"){
client.print(Prcss_RS(cmdData)); dataSize = demuxNum(cmdData, data);
client.print(Prcss_SV_Write(data, dataSize));
}//else if(cmd==""){ }//else if(cmd==""){

@ -1,14 +1,14 @@
int aipin[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15}; const int aipin[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15};
void GPIO_setup(){ void GPIO_setup(){
} }
void read_analog(int arr[], int size){ void read_analog(){
int i = 0; int i = 0;
for(i = 0 ; i < size ; i++){ for(i = 0 ; i < Size_AI ; i++){
arr[i] = analogRead(aipin[i]); Values_AI[i] = analogRead(aipin[i]);
} }
} }

@ -1,16 +1,5 @@
// Sample communication Code for RS 485 Shield with Arduino Mega 2560
#define RS485_OE_1 22 //RS485 CH#1 Output Enable => pin 22 for CH#1
#define Snd_485 HIGH
#define Rcv_485 LOW
void MC9_setup(){
Serial1.setTimeout(300);
Serial1.begin(9600);
pinMode(RS485_OE_1, OUTPUT);
delay(10);
digitalWrite(RS485_OE_1, Rcv_485);
}
/*
void read_mc9_req(String address){ void read_mc9_req(String address){
if(!Wait_485){ if(!Wait_485){
String command = ""; String command = "";
@ -71,3 +60,4 @@ void write_mc9(int arr[], int size){
Serial1.flush(); Serial1.flush();
digitalWrite(RS485_OE_1, Rcv_485); delay(5); digitalWrite(RS485_OE_1, Rcv_485); delay(5);
} }
*/

@ -1,6 +1,6 @@
// //
String Prcss_AI(){ String Prcss_AI_Read(){
String str = ""; String str = "AI?:";
for (int i = 0; i < Size_AI; i++) { for (int i = 0; i < Size_AI; i++) {
char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자 char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자
@ -14,7 +14,7 @@ String Prcss_AI(){
} }
String Prcss_AO(unsigned int data[], int dataSize){ String Prcss_AO(unsigned int data[], int dataSize){
String str = ""; String str = "AO!:";
for(int i=0 ; i<dataSize ; i++){ for(int i=0 ; i<dataSize ; i++){
str += String(data[i]); str += String(data[i]);
str += "\t"; str += "\t";
@ -23,17 +23,12 @@ String Prcss_AO(unsigned int data[], int dataSize){
return RcvOK; return RcvOK;
} }
String Prcss_RS(String message){ String Prcss_PV_Read(){
Serial.println(message); String str = "PV10?:";
return RcvOK;
}
String Prcss_PV(){
String str = "";
for (int i = 0; i < Size_PV; i++) { for (int i = 0; i < Size_PV; i++) {
char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자 char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자
sprintf(formattedNumber, "%04X", Values_PV[i]); // 4자리로 고정된 형식의 문자열 생성 sprintf(formattedNumber, "%04X", Values_10_PV[i]); // 4자리로 고정된 형식의 문자열 생성
str += formattedNumber; // 형식화된 문자열 추가 str += formattedNumber; // 형식화된 문자열 추가
str += ','; str += ',';
} }
@ -42,12 +37,28 @@ String Prcss_PV(){
return str; return str;
} }
String Prcss_SV(unsigned int data[], int dataSize){ String Prcss_SV_Read(){
String str = "SV10?:";
String str = "SV "; for (int i = 0; i < Size_SV; i++) {
write_mc9(data, dataSize); char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자
sprintf(formattedNumber, "%04X", Values_10_SV[i]); // 4자리로 고정된 형식의 문자열 생성
str += formattedNumber; // 형식화된 문자열 추가
str += ',';
}
str += RcvOK; str += RcvOK;
return str; return str;
} }
String Prcss_SV_Write(unsigned int data[], int dataSize){
String str = "SV!:";
for(int i=0 ; i<dataSize ; i++){
str += String(data[i]);
str += "\t";
}
//write_buff_first(Buff_485_Wr, String str)
Serial.println(str);
return RcvOK;
}

@ -0,0 +1,122 @@
// Sample communication Code for RS 485 Shield with Arduino Mega 2560
#define RS485_OE_1 22 //RS485 CH#1 Output Enable => pin 22 for CH#1
#define Snd_485 HIGH
#define Rcv_485 LOW
#define MC9_10_PV "10DRS,08,0001CB"
#define MC9_10_SV "10DRS,08,0011CC"
void RS485_setup(){
Serial1.setTimeout(300);
Serial1.begin(9600);
pinMode(RS485_OE_1, OUTPUT);
delay(10);
digitalWrite(RS485_OE_1, Rcv_485);
}
void send_485(){
if(!Wait_485){
String message = read_buff(Buff_485_Wr);
// Send request to return pv data
//Serial.println(Buff_485_Wr);
//Serial.print(message);
//Serial.print(" : ");
if(message != ""){
latest_sent_msg = message;
message += "\r\n";
digitalWrite(RS485_OE_1, Snd_485); delay(5);
Serial1.print(message);
returnTime = millis();
Serial1.flush();
digitalWrite(RS485_OE_1, Rcv_485); delay(5);
Wait_485 = true;
Wait_485_cnt = 0;
}
else{
//Serial.println("Free");
}
}
}
int read_485(){
// Timeout code
if(Wait_485){
Wait_485_cnt++;
if(Wait_485_cnt > 200){ // Timeout = periodic(100ms) x 200 = 2 sec
Serial.println("485 not responced... (Timeout)");
latest_sent_msg = "";
Wait_485 = false;
Wait_485_cnt = 0;
numOf485--;
return 0;
}
}
// Receive pv data
while(Wait_485 && (Serial1.available() > 0)) {
char c = Serial1.read();
write_buff_c(Buff_485_Rd, c);
}
String message = read_buff(Buff_485_Rd);
if(message != ""){
int addr;
String mode;
int data[8];
int crc;
numOf485--;
//message.replace("\r\n","");
//Serial.println(message);
if (parseMessage(message, addr, mode, data, crc)) {
if(latest_sent_msg == MC9_10_PV){
for(int i = 0 ; i < Size_PV ; i++){
Values_10_PV[i] = data[i];
}
}
if(latest_sent_msg == MC9_10_SV){
for(int i = 0 ; i < Size_SV ; i++){
Values_10_SV[i] = data[i];
}
}
} else {
// OK가 아닌 경우 또는 파싱 오류가 발생한 경우
Serial.println("error 485 read");
}
Wait_485 = false;
Wait_485_cnt = 0;
}
return 1;
}
int parseMessage(const String& message, int& addr, String& mode, int data[8], int& crc) {
char addrC[3], modeC[4], statusC[3];
int dataC[8], crcC;
if (message[0] == '\x02') {
message = message.substring(1);
}
int ret = sscanf(message.c_str(), "%2s%3s,%2s,%4x,%4x,%4x,%4x,%4x,%4x,%4x,%4x%2x",
addrC, modeC, statusC, &dataC[0], &dataC[1], &dataC[2], &dataC[3], &dataC[4], &dataC[5], &dataC[6], &dataC[7], &crcC);
if (strcmp(statusC, "OK") != 0 || ret != 12) {
// 오류 처리
return 0;
}
// 복사
addr = atoi(addrC);
mode = String(modeC);
for (int i = 0; i < 8; i++) {
data[i] = dataC[i];
}
crc = crcC;
return 1;
}

@ -0,0 +1,54 @@
int write_buff_c(char* buff, char c) {
size_t len = strlen(buff);
if (len + 1 < BUFF_SIZE) {
buff[len] = c;
buff[len + 1] = '\0'; // 문자열의 끝을 나타내는 null 문자를 추가해야 합니다.
return 1;
} else {
Serial.println("Not enough space in buffer! (write c)");
return 0;
}
}
int write_buff(char* buff, String str) {
const char* cstr = str.c_str();
size_t len = strlen(cstr);
if (strlen(buff) + len < BUFF_SIZE) {
strcat(buff, cstr);
numOf485++;
return 1;
} else {
Serial.println("Not enough space in buffer! (write)");
return 0;
}
}
int write_buff_first(char* buff, String str) {
const char* cstr = str.c_str();
size_t len = strlen(cstr);
if (strlen(buff) + len < BUFF_SIZE) {
char temp[BUFF_SIZE];
strcpy(temp, buff); // copy existing content to temp buffer
strcpy(buff, cstr); // copy new string to buffer
strcat(buff, temp); // append old content to buffer
numOf485++;
return 1;
} else {
Serial.println("Not enough space in buffer! (prepend)");
return 0;
}
}
String read_buff(char* buff) {
char* pos = strstr(buff, "\r\n");
String output = "";
if (pos != nullptr) {
size_t len = pos - buff;
output = String(buff).substring(0, len);
// Shift remaining string to the start
memmove(buff, pos + 2, strlen(pos + 2) + 1);
}
return output;
}

@ -1,12 +1,12 @@
// //
void Periodic_run(){ void Periodic_run(){
if(T_10ms){ if(T_10ms){
read_analog(Values_AI, Size_AI); read_analog();
read_mc9(Values_PV, Size_PV);
T_10ms = false; T_10ms = false;
} }
if(T_20ms){ if(T_20ms){
read_485();
send_485();
T_20ms = false; T_20ms = false;
} }
if(T_50ms){ if(T_50ms){
@ -22,17 +22,21 @@ void Periodic_run(){
T_200ms = false; T_200ms = false;
} }
if(T_500ms){ if(T_500ms){
read_mc9_req("10");
T_500ms = false; T_500ms = false;
} }
if(T_500ms_2){
read_mc9_req("11");
T_500ms_2 = false;
}
if(T_1000ms){ if(T_1000ms){
AnalogIn_Print(); write_buff(Buff_485_Wr, MC9_10_PV); // 10 DRS num 8 from ch1 PV
T_1000ms = false; T_1000ms = false;
} }
if(T_2000ms){
Serial.print("----- remain 485 buff : ");
Serial.println(numOf485);
T_2000ms = false;
}
if(T_5000ms){
write_buff(Buff_485_Wr, MC9_10_SV); // 10 DRS num 8 from ch1 SV
T_5000ms = false;
}
} }
void timer_10ms(){ void timer_10ms(){
msCnt += 10; msCnt += 10;
@ -53,11 +57,14 @@ void timer_10ms(){
if (msCnt % 500 == 0){ if (msCnt % 500 == 0){
T_500ms = true; T_500ms = true;
} }
if ((msCnt+250) % 500 == 0){ if (msCnt % 1000 == 0){
T_500ms_2 = true;
}
if (msCnt > 1000){
T_1000ms = true; T_1000ms = true;
}
if (msCnt % 2000 == 0){
T_2000ms = true;
}
if (msCnt > 5000){
T_5000ms = true;
msCnt = 0; msCnt = 0;
} }

Loading…
Cancel
Save