[Timer] [Ethenet]

- Timer
  ㄴ 타이머 구조 개선
  ㄴ 타이머 인터럽트 내 로직 제거, 플래그 삽입 (시리얼통신 등 제거를 위해)
- Ethernet
  ㄴ 이더넷 통신을 위한 독립 스케치 생성
- 기타
  ㄴ 통신관련 모듈에서 CR LF (\r \n) 프로토콜 삽입
main
Changwoo Park 2 years ago
parent 06967ceb60
commit 320d2cee1a

@ -0,0 +1,100 @@
//
void Ethernet_setup(){
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x00 };
IPAddress ip(192, 168, 20, 177);
IPAddress gateway(192, 168, 20, 1);
IPAddress subnet(255, 255, 255, 0);
// Mac as unique value by change last byte from ip last value.
mac[5] = ip[3] & 0xFF;
// initialize the ethernet device
Ethernet.begin(mac, ip, gateway, subnet);
// start listening for clients
server.begin();
web.begin();
// Report address
Serial.print("MAC>>");
for (int i = 0; i < 6; i++) {
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
if (i < 5) {
Serial.print(":");
}
}
Serial.println();
Serial.print("IP >>");
Serial.println(Ethernet.localIP());
}
void webReponse(){
EthernetClient webClient = web.available();
if (webClient) {
Serial.println("Web client connected");
while (webClient.connected()) {
if (webClient.available()) {
// 웹 브라우저에서 요청이 도착한 경우
String request = webClient.readStringUntil('\r');
//Serial.println(request);
webClient.flush();
// 웹 브라우저에 출력할 문구 작성
String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: text/html\r\n\r\n";
response += "<html><body>";
response += Prcss_AI();
//response += "<h1>Hello, World!</h1>";
response += "</body></html>";
// 문구를 웹 브라우저로 전송
webClient.print(response);
delay(1);
// 클라이언트 연결 종료
webClient.stop();
}
}
}
}
String demuxCMD(String command, String* rightPart) {
// "::"를 기준으로 문자열을 분리
int separatorIndex = command.indexOf("::");
String leftPart = command.substring(0, separatorIndex);
*rightPart = command.substring(separatorIndex + 2);
leftPart.replace(" ", "");
return leftPart;
}
int demuxNum(String rightPart, unsigned int data[]) {
// 우측의 16진수 배열을 분리하여 추출
const char* delimiter = ",";
int startIndex = 0;
int endIndex = rightPart.indexOf(delimiter);
int index = 0;
while (endIndex >= 0) {
String hexValue = rightPart.substring(startIndex, endIndex);
// 16진수 문자열을 16진수 숫자로 변환하여 data 배열에 저장
data[index] = strtoul(hexValue.c_str(), NULL, 16);
index++;
startIndex = endIndex + 1;
endIndex = rightPart.indexOf(delimiter, startIndex);
}
// 남은 마지막 16진수 배열 원소 처리
String hexValue = rightPart.substring(startIndex);
data[index] = strtoul(hexValue.c_str(), NULL, 16);
index++;
// 왼쪽 부분인 "ABC"을 반환
return index;
}

@ -10,39 +10,47 @@
#define RcvErr "ER\r\n"
#define MODE_DEBUG false
String demuxCMD(String command, String* rightPart);
int demuxNum(String rightPart, unsigned int data[]);
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network.
// gateway and subnet are optional:
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x00 };
IPAddress ip(192, 168, 20, 177);
IPAddress gateway(192, 168, 20, 1);
IPAddress subnet(255, 255, 255, 0);
// ========== ========== Periodic Flags
bool T_10ms = false;
bool T_20ms = false;
bool T_50ms = false;
bool T_100ms = false;
bool T_200ms = false;
bool T_500ms = false;
bool T_500ms_2 = false;
bool T_1000ms = false;
// ========== ========== Communication
// ---------- Ethernet
// Ethernet Client
EthernetClient client;
// SCPI defaults to port 5025
EthernetServer server(5025);
EthernetClient client;
// HTTP defaults to port 5025
EthernetServer web(80);
unsigned long lastDataReceivedTime;
unsigned long timeoutPeriod = 5000; // 타임아웃 시간 (5초)
bool busy = false;
bool connection = false;
char buffer[1024];
bool State_eth = false;
// ---------- 485
String Buf_485;
bool Wait_485;
int Wait_485_cnt;
// ========== ========== Processing
// Read Datas
int Size_AI = 16;
int Values_AI[16];
int Size_PV = 8;
int Values_PV[8];
String Buf_485;
bool Wait_485;
int Wait_485_cnt;
int msCnt = 0;
unsigned long timer = 0;
@ -52,98 +60,85 @@ void setup() {
Serial.begin(9600);
Serial.println("Start!");
TCPIP_setup(mac, ip, gateway, subnet);
// scitech korea Library
// modules setup (init.)
Ethernet_setup();
GPIO_setup();
MC9_setup();
// Timer set
MsTimer2::set(10, periodic_10ms);
MsTimer2::set(10, timer_10ms);
MsTimer2::start();
// Report address
Serial.print("MAC>>");
for (int i = 0; i < 6; i++) {
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
if (i < 5) {
Serial.print(":");
}
}
Serial.println();
Serial.print("IP >>");
Serial.println(Ethernet.localIP());
}
void loop() {
// wait for a new client:
// wait for a new client:
webReponse();
client = server.available();
//Prcss_SV();
//delay(100);
if (client) {
String Buf_eth;
String message;
String cmd;
String cmdData;
unsigned int data[32];
int dataSize;
// check if client is connected
Serial.println("Client Connected!!!");
// Do What Message Command
while(client.connected()){
int buffCnt = 0;
// check for command byte
// read data check
if(client.available() > 0) {
char c;
bool cr = false;
char c ;//= client.read();
String command;
String cmd;
unsigned int data[32];
String message;
int dataSize;
busy = true;
// Read message by byte
while((c = client.read())) {
// Read data until CR or LF
if((c != 13) && (c != 10)){
command += c;
}else{
//If endwith CRLF
if((c == 10) && (Buf_eth.endsWith("\r"))){
Buf_eth.remove(Buf_eth.length() - 1); //remove CR
message = Buf_eth;
Buf_eth = "";
break;
}else{
Buf_eth += c;
}
}
// 데이터를 수신했으므로 타임아웃 타이머 초기화
lastDataReceivedTime = millis();
}
// -------------------- Process CMD -------------------- //
cmd = demuxCMD(command, &message);
// If data read
if(message != ""){
cmd = demuxCMD(message, &cmdData);
message = "";
if(cmd=="AI"){
client.print(Prcss_AI());
}else if(cmd=="AO"){
dataSize = demuxNum(message, data);
dataSize = demuxNum(cmdData, data);
client.print(Prcss_AO(data, dataSize));
}else if(cmd=="PV"){
client.print(Prcss_PV());
}else if(cmd=="SV"){
client.print(Prcss_SV());
dataSize = demuxNum(cmdData, data);
client.print(Prcss_SV(data, dataSize));
}else if(cmd=="RS"){
client.print(Prcss_RS(message));
client.print(Prcss_RS(cmdData));
}//else if(cmd==""){
//}
else{
client.print(cmd + " " + RcvErr);
}
message = "";
}
// Debug
if(MODE_DEBUG){
@ -151,35 +146,20 @@ void loop() {
//Serial.println(command);
}
busy = false;
// 데이터를 수신했으므로 타임아웃 타이머 초기화
lastDataReceivedTime = millis();
}// if end, client.available()
//Serial.println("end client available");
// 타임아웃 확인
// check Timeout
if (millis() - lastDataReceivedTime > timeoutPeriod) {
Serial.println("Client Disconnected... (Timeout)");
client.stop();
}
Periodic_run();
}
Serial.println("Client Disconnected...");
}
Periodic_run();
}
void TCPIP_setup(byte mac[], IPAddress ip, IPAddress gateway, IPAddress subnet){
mac[5] = ip[3] & 0xFF;
// initialize the ethernet device
Ethernet.begin(mac, ip, gateway, subnet);
// start listening for clients
server.begin();
web.begin();
}
void AnalogIn_Print(){
@ -192,33 +172,3 @@ void AnalogIn_Print(){
void webReponse(){
EthernetClient webClient = web.available();
if (webClient) {
Serial.println("Web client connected");
while (webClient.connected()) {
if (webClient.available()) {
// 웹 브라우저에서 요청이 도착한 경우
String request = webClient.readStringUntil('\r');
//Serial.println(request);
webClient.flush();
// 웹 브라우저에 출력할 문구 작성
String response = "HTTP/1.1 200 OK\r\n";
response += "Content-Type: text/html\r\n\r\n";
response += "<html><body>";
response += Prcss_AI();
//response += "<h1>Hello, World!</h1>";
response += "</body></html>";
// 문구를 웹 브라우저로 전송
webClient.print(response);
delay(1);
// 클라이언트 연결 종료
webClient.stop();
}
}
}
}

@ -11,15 +11,18 @@ void MC9_setup(){
digitalWrite(RS485_OE_1, Rcv_485);
}
void read_mc9_req(){
void read_mc9_req(String address){
if(!Wait_485){
String command = "10DRS,03,0011C7\r\n";
String command = "";
command += address;
command += "DRS,03,0011C7\r\n";
// Send request to return pv data
digitalWrite(RS485_OE_1, Snd_485); delay(5);
Serial1.print(command);
Serial1.flush();
digitalWrite(RS485_OE_1, Rcv_485); delay(5);
Wait_485 = true;
Wait_485_cnt = 0;
}
@ -32,7 +35,7 @@ void read_mc9(int arr[], int size){
// Timeout code
if(Wait_485){
Wait_485_cnt++;
if(Wait_485_cnt > 200){ // Timeout = periodic(10ms) x 200 = 2sec
if(Wait_485_cnt > 10){ // Timeout = periodic(10ms) x 10 = 10 msec
Wait_485 = false;
Wait_485_cnt = 0;
}
@ -40,26 +43,31 @@ void read_mc9(int arr[], int size){
// Receive pv data
while(Wait_485 && (Serial1.available() > 0)) {
c = Serial1.read();
Buf_485 += c;
Serial.print(c, HEX);
Serial.print(" ");
if(c == '\n'){
if((c == '\n') && (Buf_485.endsWith("\r"))){
Buf_485.remove(Buf_485.length() - 1); //remove CR
message = Buf_485;
Buf_485 = "";
Wait_485 = false;
Wait_485_cnt = 0;
}
else{
Buf_485 += c;
}
}
// save pv
if(message != ""){
Serial.println(message);
for(int i = 0 ; i < size ; i++){
//arr[i] = ???;
}
}
}
void write_mc9(int arr[], int size){
cli();//stop interrupts
Serial1.print("485 Write^^"); //Serial Write ADC_Value to RS-485 Bus
sei();//allow interrupts
digitalWrite(RS485_OE_1, Snd_485); delay(5);
Serial1.print("485 Write^^\r\n"); //Serial Write ADC_Value to RS-485 Bus
Serial1.flush();
digitalWrite(RS485_OE_1, Rcv_485); delay(5);
}

@ -1,11 +1,11 @@
//
String Prcss_AI(){
String str = "";
for (int i = 0; i < Size_AI; i++) {
char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자
sprintf(formattedNumber, "%04X", Values_AI[i]); // 4자리로 고정된 형식의 문자열 생성
str += formattedNumber; // 형식화된 문자열 추가
//str += String(AI_VALUES[i]);
str += ',';
}
@ -29,18 +29,23 @@ String Prcss_RS(String message){
}
String Prcss_PV(){
String str = "";
for (int i = 0; i < Size_PV; i++) {
char formattedNumber[5]; // 4자리 숫자 + 널 종료 문자
sprintf(formattedNumber, "%04X", Values_PV[i]); // 4자리로 고정된 형식의 문자열 생성
str += formattedNumber; // 형식화된 문자열 추가
str += ',';
}
String str = "PV ";
digitalWrite(RS485_OE_1, Snd_485);
Serial1.print("485 Read!!"); //Serial Write ADC_Value to RS-485 Bus
str += RcvOK;
return str;
}
String Prcss_SV(){
String Prcss_SV(unsigned int data[], int dataSize){
String str = "SV ";
write_mc9(data, dataSize);
str += RcvOK;
return str;

@ -1,38 +0,0 @@
String demuxCMD(String command, String* rightPart) {
// "::"를 기준으로 문자열을 분리
int separatorIndex = command.indexOf("::");
String leftPart = command.substring(0, separatorIndex);
*rightPart = command.substring(separatorIndex + 2);
leftPart.replace(" ", "");
return leftPart;
}
int demuxNum(String rightPart, unsigned int data[]) {
// 우측의 16진수 배열을 분리하여 추출
const char* delimiter = ",";
int startIndex = 0;
int endIndex = rightPart.indexOf(delimiter);
int index = 0;
while (endIndex >= 0) {
String hexValue = rightPart.substring(startIndex, endIndex);
// 16진수 문자열을 16진수 숫자로 변환하여 data 배열에 저장
data[index] = strtoul(hexValue.c_str(), NULL, 16);
index++;
startIndex = endIndex + 1;
endIndex = rightPart.indexOf(delimiter, startIndex);
}
// 남은 마지막 16진수 배열 원소 처리
String hexValue = rightPart.substring(startIndex);
data[index] = strtoul(hexValue.c_str(), NULL, 16);
index++;
// 왼쪽 부분인 "ABC"을 반환
return index;
}

@ -1,34 +1,64 @@
void periodic_10ms(){
msCnt += 10;
if(!busy){
// Call a function every 10ms
//
void Periodic_run(){
if(T_10ms){
read_analog(Values_AI, Size_AI);
read_mc9(Values_PV, Size_PV);
T_10ms = false;
}
if(T_20ms){
// Call a function every 50ms
if (msCnt % 20 == 0){
T_20ms = false;
}
if(T_50ms){
T_50ms = false;
}
if(T_100ms){
// Call a function every 50ms
if (msCnt % 50 == 0){
T_100ms = false;
}
if(T_200ms){
T_200ms = false;
}
if(T_500ms){
read_mc9_req("10");
T_500ms = false;
}
if(T_500ms_2){
read_mc9_req("11");
T_500ms_2 = false;
}
if(T_1000ms){
AnalogIn_Print();
T_1000ms = false;
}
}
void timer_10ms(){
msCnt += 10;
// Call a function every 100ms
T_10ms = true;
if (msCnt % 20 == 0){
T_20ms = true;
}
if (msCnt % 50 == 0){
T_50ms = true;
}
if (msCnt % 100 == 0){
T_100ms = true;
}
if (msCnt % 200 == 0){
T_200ms = true;
}
// Call a function every 500ms
if (msCnt % 500 == 0){
read_mc9_req();
T_500ms = true;
}
if ((msCnt+250) % 500 == 0){
T_500ms_2 = true;
}
// Call a function every 1000ms
if (msCnt > 1000){
T_1000ms = true;
msCnt = 0;
}
}
}

Loading…
Cancel
Save