나미/아두이노

modbus RTU

규남 2021. 5. 27. 10:59
반응형

/*==============================================================================================/
 *
 *  Copyright (C) 2021 ******** Software Corp Reaserch Institute
 *  All rights reserved.
 *
 *  Author : Lee Kyu Nam (nasanx2001@naver.com)
 *  Descrition : L2버전
 *               
 *               
 *
 *==============================================================================================*/
#include <time.h>
#include <Crc16.h>
#include <EEPROM.h>

#define u8                        unsigned char
#define u16                       unsigned short

#define _bit_buff_size            128
#define _write_buff_size          256

#define codesys_addr              0x01
#define pureun_addr               0x01
#define systemid                  "100003"

/*
 * timer 
 */
extern volatile unsigned long timer0_millis;

int polling_time = 0;
int old_time = 0;

u16 YYYY = 0;
u8 MM = 0;
u8 DD = 0;
u8 hh = 0;
u8 mm = 0;
u8 ss = 0;

u8 old_mm = 0;


/*
 * codesys
 */
u8 codesys_bit_buff[_bit_buff_size] = {0,};
u8 codesys_write_buff[_write_buff_size] = {0,};

u16 codesys_read_point = 0;                // serial read point
u16 codesys_last_point = 0;                // codesys buff last point
u16 codesys_start_point = 0;               // codesys buff start point
u16 codesys_write_point = 0;               // codesys write buff point

bool codesys_process = false;


/*
 * memory mapping
 */
u16 a_mem[500] = {0,};
u16 b_mem[500] = {0,};
u16 r_mem[500] = {0,};


/*
 * digital mapping I/O
 */
// DI
#define WATER_HI                28
#define WATER_LO                29
#define RETURN_WATER_HI         30
#define RETURN_WATER_LO         31

// DO
#define WATER_MAIN_PIN          38
#define WATER_PIN               39
#define RETURN_WATER_PIN        40
#define UV_LAMP_PIN             41
#define PH_PUMP_PIN             42
#define EC_PUMP_PIN             43


/*
 * crc
 */

Crc16 crc;
u8 codesys_crc_buff[2];
u8 pureun_crc_buff[2];

/*
 * etc
 */
u8 bit_addr[] = {1,2,4,8,16,32,64,128};

u8 uv_flag = 0;
u8 uv_day = 0;

unsigned int ec_time = 0;
u8 ec_flag = 0;

unsigned int ph_time = 0;
u8 ph_flag = 0;




//===================================================================================
void setup(){
  u8 i;
  
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1);        // codesys
  Serial2.begin(115200, SERIAL_8N1);        // rasp

  for(i=22; i<34; i++){ 
    pinMode(i, INPUT); 
  }
  for(i=34; i<52; i++){ 
    pinMode(i, OUTPUT); 
  }

  Serial.println("============= Start controll process ==============");
  
}

void loop(){
  unsigned long MillisTime = millis();

  /*
   * 1 sec time check
   */
  if(millis() - (MillisTime >= 1000)){
    polling_time = millis()/1000;
    if(polling_time != old_time){
      timer();
      digitalWrite(51, !digitalRead(51));     
      old_time = polling_time;
    }
  }


  /*
   * 1 min time check
   */
  if(mm != old_mm){
    digitalWrite(50, HIGH);
    
    // system get info -> raspberry pi -> get cmd(g)
    Serial2.write("g");
    
    digitalWrite(50, LOW);
    old_mm = mm;
  }
  

  /*
   * codesys process (rs232)
   */
  codesys_getData();
  
  if(codesys_process == true){
    codesys_modbus_process();
  }
  else{
    codesys_process = codesys_getData_frame_check();
  }
  
   /*
   * raspberry process
   */
  rasp_getData();

}
//===================================================================================


/*
 * function list
 */



/*****************************************************************
 *                  codesys modbus function                      *
 *                                                               * 
 * **************************************************************/

//===============================================================
//  codesys getData
//===============================================================
void codesys_getData(){
  if(Serial1.available() > 0){    
    codesys_bit_buff[codesys_read_point++] = Serial1.read();
    codesys_last_point = codesys_read_point-1;
    //Serial.print(codesys_bit_buff[codesys_last_point], HEX);
  }
}


//===============================================================
//  codesys modbus data frame check
//===============================================================
bool codesys_getData_frame_check(){
  int i;
  u8 Hi, Lo;
  
  // 1. codesys read data -> codesys_id find
  if((codesys_bit_buff[codesys_start_point] != codesys_addr) && (codesys_bit_buff[codesys_start_point] != 0)){
    codesys_start_point += 1;
    return false;
  }
  else if(codesys_bit_buff[codesys_start_point] == codesys_addr){
    if((codesys_last_point - codesys_start_point) > 5){
      codesys_Crc16(codesys_bit_buff, codesys_start_point, codesys_last_point-1);

      Hi = codesys_bit_buff[codesys_last_point-1];
      Lo = codesys_bit_buff[codesys_last_point];

      if((Hi == codesys_crc_buff[1]) && (Lo == codesys_crc_buff[0])){
        return true;
      }
      else{
        return false;
      }
    }
    else{
      return false;
    }
  }
  else{
    return false;
  }
}


//===============================================================
//  codesys modbus crc check
//===============================================================
void codesys_Crc16(u8 *buff, u16 start_point, u16 last_point){
  u16 crc_value, i;

  memset(codesys_crc_buff, 0x00, 2);

  crc_value = crc.Modbus(buff, start_point, last_point);
  codesys_crc_buff[0] = crc_value >> 8;
  codesys_crc_buff[1] = crc_value;
}


//===============================================================
//  codesys move point
//===============================================================
void codesys_move_point(){
  codesys_start_point = codesys_last_point+1;
  codesys_process = false;
  
  memset(codesys_write_buff, 0x00, sizeof(codesys_write_buff));
  codesys_write_point = 0;

  // read buff data -> last check -> buff clear
  if((codesys_start_point == codesys_read_point) && (codesys_start_point != 0)){
    Serial.println("============= codesys last data ==============");
    codesys_clear();
  }
}


//===============================================================
//  codesys buff clear
//===============================================================
void codesys_clear(){
  memset(codesys_bit_buff, 0x00, sizeof(codesys_bit_buff));
  memset(codesys_write_buff, 0x00, sizeof(codesys_write_buff));
  
  codesys_read_point = 0;                
  codesys_last_point = 0;                
  codesys_start_point = 0;
  codesys_write_point = 0;               

  codesys_process = false;
}


//===============================================================
//  codesys put byte
//===============================================================
void codesys_putByte(u8 data){
  Serial1.write(data);
  codesys_write_buff[codesys_write_point++] = data;
}


//===============================================================
//  codesys put word
//===============================================================
void codesys_putWord(u16 data){
  u8 Hi, Lo;
  Serial1.write(data >> 8);
  Serial1.write(data);
  codesys_write_buff[codesys_write_point++] = (data >> 8);
  codesys_write_buff[codesys_write_point++] = data;  
}


//===============================================================
//  codesys get word
//===============================================================
u16 codesys_getWord(u16 num){
  u8 wh, wl;
  wh = codesys_bit_buff[num];
  wl = codesys_bit_buff[num+1];
  return (wh<<8)+wl;
}


//===============================================================
//  codesys read memory -> make bit -> send codesys
//===============================================================
u8 codesys_bit_mem(u16 addr, u16 len)
{
  u8 i, j, k=0, val=0;
  u16 pin;
  for(i=0; i<len; i++){
    pin = r_mem[addr];
    if(pin == 1){
      if(i > 0){
        val += (1 << i);
      }  
      if(i == 0){
        k = 1;     
      }
    }
    addr++;
  }
  return (val+k);
}


//===============================================================
//  codesys modbus process
//===============================================================
void codesys_modbus_process(){
  u8 i, num=0;
  u8 slave_addr, fc;

  slave_addr = codesys_bit_buff[num++];
  fc = codesys_bit_buff[num++];

  switch(fc){
    case 1:
    case 2:
      codesys_read_bit();
      break;
    case 3:
      codesys_read_word();
      break;
    case 5:
      codesys_write_bit_single();
      break;
    case 6:
      codesys_write_word_single();
      break;
    case 15:
      codesys_write_bit_multiple();
      break;
    case 16:
      codesys_write_word_multiple();
      break;
    default:
      break;
  }

  Serial.print("codesys read Data : ");
  for(i=codesys_start_point; i<=codesys_last_point; i++){
    Serial.print(codesys_bit_buff[i], HEX);
    Serial.print(" ");
  }
  Serial.println();

  codesys_move_point();
}


//===============================================================
//  codesys modbus function code 1,2
//===============================================================
void codesys_read_bit(){
  u8 i, j=0, fc, blen, pin=0;
  u16 len, addr;

  fc = codesys_bit_buff[1];
  addr = codesys_getWord(2);          
  len = codesys_getWord(4);           

  //return data
  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  blen = len >> 3;
  if (len & 7) blen++;
  codesys_putByte(blen);
  for(i=0; i<blen; i++){
    j = codesys_bit_mem(addr, len);
    digital_read_mapping(addr);
    codesys_putByte(j);
    addr += 8;
    len -= 8; 
  }

  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);

  
/*
  Serial.print("codesys write data : ");
  for(int k=0; k<codesys_write_point; k++){
    Serial.print(codesys_write_buff[k] ,HEX);
    Serial.print(" ");
  }
  Serial.println();
*/
  memset(codesys_write_buff, 0x00, sizeof(codesys_write_buff));
  codesys_write_point = 0;
}


//===============================================================
//  codesys modbus function code 3
//===============================================================
void codesys_read_word(){
  u8 i, k, fc, count=0;
  u16 addr, addr_save, len, j, val; 
  u16 crc_value; 

  fc = codesys_bit_buff[1];
  addr = codesys_getWord(2);          
  len = codesys_getWord(4);

  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  k = len << 1;
  codesys_putByte(k);

  for(j=0; j<len; j++){
    val = a_mem[addr];
    codesys_putWord(val);
    addr++;
  }      

  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);
/*
  Serial.print("codesys write Data : ");
  for(i=0; i<codesys_write_point; i++){
    Serial.print(codesys_write_buff[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
*/
  memset(codesys_write_buff, 0x00, sizeof(codesys_write_buff));
  codesys_write_point = 0;
}


//===============================================================
//  codesys modbus function code 5
//===============================================================
void codesys_write_bit_single(){
  u8 i, fc;
  u16 val, addr, addr_save, pin_num;

  fc = codesys_bit_buff[1];
  addr_save = addr = codesys_getWord(2);
  val = codesys_getWord(4);
  
  addr = codesys_stick_controll(addr, val);

  if(addr <= 500){
    digitalWrite(addr, (val>>8) & 0xFF ? HIGH : LOW);
  }
  Serial.println(addr, DEC);

  digital_read_mapping(addr);
  
  //return data
  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  codesys_putWord(addr_save);
  codesys_putWord(val);
  
  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);
}


//===============================================================
//  codesys modbus function code 6
//===============================================================
void codesys_write_word_single(){
  u8 i, fc;
  u16 addr, val;

  fc = codesys_bit_buff[1];
  addr = codesys_getWord(2);
  val = codesys_getWord(4);

  codesys_word_input(addr, val);

  //return data
  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  codesys_putWord(addr);
  codesys_putWord(val);

  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);
 
}


//===============================================================
//  codesys modbus function code 15
//===============================================================
void codesys_write_bit_multiple(){
  u8 i, j, fc, cnt;
  u16 addr, addr_save, len, len_save;

  fc = codesys_bit_buff[1];
  addr_save = addr = codesys_getWord(2);
  len_save = len = codesys_getWord(4);
  cnt = codesys_bit_buff[6];

  for(i=0; i<cnt; i++){
    j = codesys_bit_buff[7];
    arduino_writebits(addr, j, len, codesys_bit_buff);
    addr += 8;
    len -= 8;
  }

  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  codesys_putByte(addr_save);
  codesys_putByte(len_save);

  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);
}


//===============================================================
//  codesys modbus function code 16
//===============================================================
void codesys_write_word_multiple(){
  u8 fc, cnt;
  u16 addr, addr_save, len, val, i, num;

  fc = codesys_bit_buff[1];
  addr_save = addr = codesys_getWord(2);
  len = codesys_getWord(4);
  cnt = codesys_bit_buff[6];

  for(i=0; i<len; i++){
    num = 7+(i*2);
    val = codesys_getWord(num);
    a_mem[addr] = val;
    addr++;
  }

  codesys_putByte(codesys_addr);
  codesys_putByte(fc);
  codesys_putByte(addr_save);
  codesys_putByte(len);

  codesys_Crc16(codesys_write_buff, 0, codesys_write_point);
  codesys_putByte(codesys_crc_buff[1]);
  codesys_putByte(codesys_crc_buff[0]);
}


//===============================================================
//  codesys digital read mapping (D/O)
//===============================================================
void digital_read_mapping(u16 addr){
  u16 val;
  
  switch(addr){
    case UV_LAMP_PIN:
      val = digitalRead(UV_LAMP_PIN);
      r_mem[73] = val;
      break;
    case EC_PUMP_PIN:
      val = digitalRead(EC_PUMP_PIN);
      r_mem[75] = val;
      break;
    case PH_PUMP_PIN:
      val = digitalRead(PH_PUMP_PIN);
      r_mem[76] = val;
      break;
    case WATER_MAIN_PIN:
      val = digitalRead(WATER_MAIN_PIN);
      r_mem[85] = val;
      break;
    case WATER_PIN:
      val = digitalRead(WATER_PIN);
      r_mem[101] = val;
      break;
    case RETURN_WATER_PIN:
      val = digitalRead(RETURN_WATER_PIN);
      r_mem[111] = val;
      break;
    default:
      break;
  }
}


//===============================================================
//  codesys digital stick controll
//===============================================================
u16 codesys_stick_controll(u16 addr, u16 val){
  
  switch(addr){
    case 1073:
      b_mem[addr-1000] = 0;
      addr = UV_LAMP_PIN;
      break;
    case 1075:
      b_mem[addr-1000] = 0;
      addr = EC_PUMP_PIN;
      break;
    case 1076:
      b_mem[addr-1000] = 0;
      addr = PH_PUMP_PIN;
      break;
    case 1101:
      b_mem[addr-1000] = 0;
      addr = WATER_PIN;
      break;
    case 1111:
      b_mem[addr-1000] = 0;
      addr = RETURN_WATER_PIN;
      break;
    default:
      break;
  }
  return addr;
}


//===============================================================
//  codesys analog mapping input
//===============================================================
void codesys_word_input(u16 addr, u16 val){
  u16 addr_save;

  addr_save = (addr - 250);
  a_mem[addr_save] = val;
  a_mem[addr] = 0;

  Serial.print("addr_save, val : ");
  Serial.print(addr_save, DEC);
  Serial.print(", ");
  Serial.println(a_mem[addr_save], DEC);
}




/*****************************************************************
 *                  raspberry pi function                        *
 *                                                               * 
 * **************************************************************/
 

//===============================================================
//  raspberry getData
//===============================================================
void rasp_getData(){
  while(Serial2.available() > 0){
    String str = Serial2.readStringUntil('\n');
    str.toCharArray(rasp_buff, str.length()+1);
    if(rasp_buff[0] == 't'){
      getTime();
    }
    if(rasp_buff[0] == 'g'){
      t_farm_getData();
    }
  }
}







/*****************************************************************
 *                          etc function                         *
 *                                                               *
 * **************************************************************/

//===============================================================
//  arduino wirte bit controll
//===============================================================
void arduino_writebits(u16 addr, u8 val, u8 len, u8 *buff){
  u8 i,m;
  if (len > 7){
    m=8;
  }
  else{
    m=len;   // 15인 경우도 8개씩 나누어서 처리
  }
    
  for (i=0;i<m;i++) { // 8번 (마지막에서는 8번 미만) 돌면서, buffer의 내용을 수정한다.
    if (val & bit_addr[i]){ // (adr에 byte어드레스와 bit어드레스 모두 포함되어 있다.)
      buff[addr >> 3] |= bit_addr[addr & 7];
      digitalWrite(addr, HIGH); 
    }  
    else{
      buff[addr >> 3] &= ~bit_addr[addr & 7];
      digitalWrite(addr, LOW);
    }
    addr++;
  }
}


//===============================================================
//  timer
//===============================================================
void timer(){
  if((ss == 0) && (mm == 0) && (hh == 0)){
    timer0_millis = 0;
    // timer get info -> raspberry pi -> get cmd(t)
    Serial2.write('t');
  }
  
  ss++;
  if(ss >= 60){
    ss = 0;
    ++mm;
    if(mm >= 60){
      mm = 0;
      ++hh;
      if(hh >= 24){
        hh = 0;
      }
    }
  }

  Serial.println();
  Serial.print(hh, DEC);
  Serial.print(":");
  Serial.print(mm, DEC);
  Serial.print(":");
  Serial.print(ss, DEC);
  Serial.println();
      
  a_mem[0] = hh;
  a_mem[1] = mm;
  a_mem[2] = ss;
}



//===============================================================
//  rasp time info get
//===============================================================
void getTime(){
  char *p;
  int i=0;
  String tmp;

  p = strtok(rasp_buff, ", ");
  while(p != NULL)
  {
    if((strcmp(p, "t") != 0))
    {
      i++;
      tmp = p;
      switch(i){
        case 1: YYYY = tmp.toInt(); break;
        case 2: MM = tmp.toInt(); break;
        case 3: DD = tmp.toInt(); break;
        case 4: a_mem[0] = hh = tmp.toInt(); break;
        case 5: a_mem[1] = mm = tmp.toInt(); break;
        case 6: a_mem[2] = ss = tmp.toInt(); break;
      }
    }
    p = strtok(NULL, ", ");
  }

  memset(rasp_buff, 0x00, sizeof(rasp_buff));
}

공개할수 없는 부분들도 있어서 이것저것 바꿔서 올리다보니 안맞는 부분이 많을수도 있다..

코드는 modbus 관련한 부분만 가져다가 수정해서 써보는걸로.. 공부도 될겸

728x90
반응형