⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dev103.c

📁 简单103规约程序示例
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
编写人  :TT(06.2.21于淮钢220变)
装置说明:103规约,9600BD,偶校验,485接口.
程序说明:上送保护信息,定值,软压板,对时.
*****************************************************************************/
#include "Dev103.h"

//接收中断回调函数,用以判断数据帧的结束
static WORD c103_check_packet(const BYTE *p_data, WORD data_len)
{
  if ((data_len == 1) && ((p_data[0] == 0x68) || (p_data[0] == 0x10)))
  {
    return UART_PKT_CON;
  }
  if (data_len < 5)
  {
    return UART_PKT_CON;
  }
  if (p_data[0] == 0x10 && data_len == 5 && p_data[4] == 0x16)
  {
    return UART_PKT_FIN;
  }
  else if (p_data[0] == 0x68 && data_len == p_data[1]+6 && p_data[data_len-1] == 0x16)
  {
    return UART_PKT_FIN;
  }
  return UART_PKT_CON;
}
//===================================================================
//设备初始化
BOOL IED_Initialize()
{
  return DEV_Create_IED(g_ied_list, sizeof(g_ied_list)/sizeof(T_IED));
}
//===================================================================
//校验和
BYTE calc_check_sum(const BYTE *p_data, WORD data_len)
{
  WORD  i;
  BYTE  sum =0;

  for(i=0;i<data_len;i++)
  {
    sum+=p_data[i];
  }
  return sum;
}
//===================================================================
//串口管理
WORD c103_serial_com(T_IED* p_ied,T_C103_FRAME* p_frame,BOOL brx)
{
  WORD wSize,size,i;

  m_c103_fcb[p_ied->dev_id] ^=0x20;//帧记数位取反

  NU_Sleep(20);
  switch(p_frame->type)
  {
  case FRAME_T_CON:
    //固定帧长报文
    m_tx_buf[0] =p_frame->type;
    m_tx_buf[1] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
    m_tx_buf[2] =0x01;//p_frame->address;
    m_tx_buf[3] =calc_check_sum(&m_tx_buf[1], 2);
    m_tx_buf[4] =p_frame->endbyte;
    wSize =5;
    break;
  case FRAME_T_VOL:
    //可变帧长报文
    m_tx_buf[0] =p_frame->type;
    m_tx_buf[1] =p_frame->len;
    m_tx_buf[2] =p_frame->len;
    m_tx_buf[3] =p_frame->type;
    m_tx_buf[4] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
    m_tx_buf[5] =0x01;//p_frame->address;
    m_tx_buf[4 +p_frame->len] =calc_check_sum(&m_tx_buf[4], p_frame->len);
    m_tx_buf[5 +p_frame->len] =p_frame->endbyte;
    wSize =p_frame->len +6;
    break;
  default:
    break;
  }
  //出现差错重传三次
  for(i =0; i <3; i++)
  {
    UART_Write(m_dev_port, m_tx_buf, wSize);
    if(!brx) break;
    size=UART_Read(m_dev_port,m_rx_buf,2000);
    if(size !=0) break;
    NU_Sleep(200);
  }
  //接收报文分类
  if(size)
  {
    p_ied->dev_flag |= DEV_F_ONLINE;//连接正常
    switch(m_rx_buf[0])
    {
    case FRAME_T_CON://固定帧长
      p_frame->type =FRAME_T_CON;
      p_frame->contral =m_rx_buf[1];
      p_frame->address =m_rx_buf[2];
      p_frame->crc =m_rx_buf[3];

      if(p_frame->crc ==calc_check_sum(&m_rx_buf[1],2)
        && p_ied->dev_data[0] == p_frame->address);//校验
      {
        memset(&m_rx_buf[5], 0, (UART_PACKET_SIZE-5));
        return size;
      }
      break;
    case FRAME_T_VOL://可变帧长
      p_frame->type =FRAME_T_VOL;
      p_frame->len =m_rx_buf[1];
      p_frame->contral =m_rx_buf[4];
      p_frame->address =m_rx_buf[5];
      p_frame->crc =m_rx_buf[p_frame->len +4];

      if(p_frame->crc ==calc_check_sum(&m_rx_buf[4], p_frame->len)
        && p_ied->dev_data[0] == p_frame->address);//校验
      {
        return size;
      }
      break;
    }
  }
  if (brx && !size && p_frame->contral != 0x40)	//超时无应答发送复位(复位无应答返回)
  {
    p_ied->dev_flag &=~DEV_F_ONLINE;
  }
  return 0;
}
//===================================================================
//用于初始化的串口函数。出现差错不重传,减少时间
WORD c103_serial_com_init(T_IED* p_ied,T_C103_FRAME* p_frame,BOOL brx)
{
  WORD wSize,size,i;

  m_c103_fcb[p_ied->dev_id] ^=0x20;	//帧记数位取反

  NU_Sleep(20);
  switch(p_frame->type)
  {
  case FRAME_T_CON:
    /* 固定帧长报文 */
    m_tx_buf[0] =p_frame->type;
    m_tx_buf[1] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
    m_tx_buf[2] =0x01;//p_frame->address;
    m_tx_buf[3] =calc_check_sum(&m_tx_buf[1], 2);
    m_tx_buf[4] =p_frame->endbyte;

    wSize =5;
    break;
  case FRAME_T_VOL:
    /* 可变帧长报文 */
    m_tx_buf[0] =p_frame->type;
    m_tx_buf[1] =p_frame->len;
    m_tx_buf[2] =p_frame->len;
    m_tx_buf[3] =p_frame->type;
    m_tx_buf[4] =p_frame->contral | m_c103_fcb[p_ied->dev_id];
    m_tx_buf[5] =0x01;//p_frame->address;
    m_tx_buf[4 +p_frame->len] =calc_check_sum(&m_tx_buf[4], p_frame->len);
    m_tx_buf[5 +p_frame->len] =p_frame->endbyte;

    wSize =p_frame->len +6;
    break;
  default:
    break;
  }
  UART_Write(m_dev_port, m_tx_buf, wSize);
  size=UART_Read(m_dev_port,m_rx_buf,1000);
  //接收报文分类
  if(size)
  {
    p_ied->dev_flag |= DEV_F_ONLINE;	//连接正常
    switch (m_rx_buf[0])
    {
    case FRAME_T_CON:	//固定帧长
      p_frame->type =FRAME_T_CON;
      p_frame->contral =m_rx_buf[1];
      p_frame->address =m_rx_buf[2];
      p_frame->crc =m_rx_buf[3];

      if (p_frame->crc ==calc_check_sum(&m_rx_buf[1], 2)
        && p_ied->dev_data[0] == p_frame->address);		//校验
      {
        memset(&m_rx_buf[5], 0, (UART_PACKET_SIZE-5));
        return size;
      }
      break;
    case FRAME_T_VOL:	//可变帧长
      p_frame->type =FRAME_T_VOL;
      p_frame->len =m_rx_buf[1];
      p_frame->contral =m_rx_buf[4];
      p_frame->address =m_rx_buf[5];
      p_frame->crc =m_rx_buf[p_frame->len +4];

      if (p_frame->crc ==calc_check_sum(&m_rx_buf[4], p_frame->len)
        && p_ied->dev_data[0] == p_frame->address);		//校验
      {
        return size;
      }
      break;
    }
  }

  if (brx && !size && p_frame->contral != 0x40)
  {
    //超时无应答发送复位(复位无应答返回)
    p_ied->dev_flag &=~DEV_F_ONLINE;
  }
  return 0;
}
//===================================================================
//请求一级用户数据
BOOL c103_request_first(T_IED* p_ied)
{
  T_DATE        t_date;
  T_EVENT       t_event;
  T_ALARM       t_alarm;
  T_LIST        t_list;
  T_DIC	        t_dic;
  T_SOE	        t_soe;
  T_DI	        t_di;
  T_C103_FRAME  t_frame;
  T_C103_ASDU	*p_asdu;
  WORD          di_lo;
  WORD          di_hi;
  BYTE          di_grp;
  BYTE          i;

  t_frame.type = FRAME_T_CON;
  t_frame.contral = 0x5a;
  t_frame.address = (BYTE)p_ied->dev_data[0];
  t_frame.len =3;
  t_frame.endbyte =0x16;

  if(!c103_serial_com(p_ied, &t_frame,1))
  {
    return false;
  }

  p_asdu = (T_C103_ASDU *) &m_rx_buf[6];
  switch(p_asdu->type)
  {
  case ASDU5://设备标识
    break;
  case ASDU8://总查询结束
    break;
  case ASDU2://动作事件
    if(p_asdu->cot != 1)
      break;
    SYS_Get_Clock(&t_date);
    t_event.dev_id = m_rx_buf[9];
    t_event.e_state =p_asdu->data[0] - 1;
    t_event.e_date.msec =MAKEWORD(p_asdu->data[5],p_asdu->data[6]);
    t_event.e_date.minute =p_asdu->data[7];
    t_event.e_date.hour =p_asdu->data[8];
    t_event.e_date.day =t_date.day;
    t_event.e_date.month =t_date.month;
    t_event.e_date.year =t_date.year;

    t_list.l_type =LIST_T_EVENT;
    t_event.e_code =C103_Get_Code(p_ied, &t_list, p_asdu->inf);
    if(t_event.e_code!=0)
      INF_Record_Event(&t_event);
    break;
  case ASDU1://自检信息(硬压板的信息是通过ASDU1上送的,以下作为遥信处理)
    if((p_asdu->cot==1)||(p_asdu->cot==9))
    {
      SYS_Get_Clock(&t_date);
      t_alarm.dev_id =m_rx_buf[9];
      t_alarm.e_state =p_asdu->data[0] - 1;
      t_alarm.e_date.msec =MAKEWORD(p_asdu->data[1],p_asdu->data[2]);
      t_alarm.e_date.minute =p_asdu->data[3];
      t_alarm.e_date.hour =p_asdu->data[4];
      t_alarm.e_date.day =t_date.day;
      t_alarm.e_date.month =t_date.month;
      t_alarm.e_date.year =t_date.year;
      t_list.l_type =LIST_T_ALARM;
      t_alarm.e_code = C103_Get_Code(p_ied, &t_list, p_asdu->inf);
      if(t_alarm.e_code!=0)
      {
        if((p_asdu->cot==1)&&(t_alarm.e_code<=(t_list.l_size-p_ied->dev_data[5])))
        {
          //告警事件(不上送压板的事件信息)
          INF_Record_Alarm(&t_alarm);
        }
        //告警事件和硬压板的遥信
        t_dic.dev_id = p_ied->dev_id;
        t_dic.e_code = t_alarm.e_code;
        t_dic.e_state = p_asdu->data[0] - 1;
        INF_Record_Dic(&t_dic);
      }
    }
    break;
  case ASDU10://响应ASDU21的报文(定值,描述...)
    if(p_asdu->cot !=42 || p_asdu->fun !=254 || p_asdu->inf !=241)
      break;
    else
      //此处要返回,让通用报文处理.
      return true;
  case ASDU44://上送全遥信
    break;
    if(p_asdu->cot != 9) break;
    if(p_asdu->fun != 1) break;
    t_di.di_num = p_asdu->vsq * 16;
    di_grp = (t_di.di_num + 31)/32;
    for(i = 0; i < di_grp; i++)
    {
      di_lo = MAKEWORD(p_asdu->data[10*i + 0], p_asdu->data[10*i + 1]);
      di_hi = MAKEWORD(p_asdu->data[10*i + 5], p_asdu->data[10*i + 6]);
      t_di.di_val[i] = MAKEDWORD(di_lo, di_hi);
    }
    INF_Set_Di(p_ied->dev_id, &t_di);
    break;
  case ASDU40://变位遥信
    break;
    if(p_asdu->cot != 1)
      break;
    if(p_asdu->fun == 2)
    {
      t_dic.e_code = p_asdu->inf - DI_FIRST_INF+42;
    }
    else if(p_asdu->fun ==1 )
    {
      t_dic.e_code = p_asdu->inf - DI_FIRST_INF;//超过106个遥信需要计算FUN
    }
    else
      return FALSE;
    t_dic.dev_id = p_ied->dev_id;
    t_dic.e_state= p_asdu->data[0];
    INF_Record_Dic(&t_dic);
    break;
  case ASDU41://SOE
    //break;
    if(p_asdu->cot != 1)
      break;
    SYS_Get_Clock(&t_date);
    t_soe.dev_id = p_ied->dev_id;
    if(p_asdu->fun == 2)
    {
      t_soe.e_code = p_asdu->inf - DI_FIRST_INF+42;
    }
    else if(p_asdu->fun ==1 )
    {
      t_soe.e_code = p_asdu->inf - DI_FIRST_INF;
    }
    t_soe.e_state= p_asdu->data[0];
    t_soe.e_date.msec  = MAKEWORD(p_asdu->data[1],p_asdu->data[2]);
    t_soe.e_date.minute= p_asdu->data[3];
    t_soe.e_date.hour  = p_asdu->data[4];
    t_soe.e_date.day   = t_date.day;
    t_soe.e_date.month = t_date.month;
    t_soe.e_date.year  = t_date.year;
    INF_Record_Soe(&t_soe);
    break;
  case ASDU64:
    break;
  default:
    break;
  }
  //检查是否有一级用户数据
  if((t_frame.contral &0x20)!=0)
  {
    return c103_request_first(p_ied);
  }
  if(t_frame.contral == 0x08 || t_frame.contral ==0x09)
  {
    return true;
  }
  return false;
}
//===================================================================
//请求二级用户数据
BOOL c103_request_second(T_IED* p_ied)
{
  T_C103_FRAME	t_frame;
  T_C103_ASDU	*p_asdu;
  T_MEASURE		mea;
  BYTE			i;

  t_frame.type = FRAME_T_CON;
  t_frame.contral = 0x5b;
  t_frame.address = (BYTE)p_ied->dev_data[0];
  t_frame.len =3;
  t_frame.endbyte =0x16;

  if(!c103_serial_com(p_ied, &t_frame,1))
  {
    return false;
  }

  if(t_frame.type == FRAME_T_CON)
  {
    if((t_frame.contral &0x20)==0)	//无所响应的数据
      return true;
  }
  else//遥测值
  {
    p_asdu = (T_C103_ASDU *) &m_rx_buf[6];
    if(p_asdu->type != ASDU50 || p_asdu->cot != 0x02) return FALSE;

    mea.ms_num = p_asdu->vsq;
    for (i = 0; i < mea.ms_num; i++)
    {
      if (p_asdu->data[2*i+1] & 0x80)//负数
      {
        mea.ms_val[i] =(0-MAKEWORD(p_asdu->data[2*i]&0xf8, (p_asdu->data[2*i+1])))/8
          & INF_MS_VALUE_MASK | INF_MS_NEGATIVE;
      }
      else
      {
        mea.ms_val[i] = (MAKEWORD(p_asdu->data[2*i]&0xf8, (p_asdu->data[2*i+1])))/8
          & INF_MS_VALUE_MASK;
      }
    }
    INF_Set_Measure(p_ied->dev_id, &mea);
  }

  if((t_frame.contral &0x20)!=0)
  {
    //有一级用户数据
    return c103_request_first(p_ied);
  }
  else
    return FALSE;
}
//===================================================================
/* 主站ASDU21读一个(组/条目)的属性/值 */
/*	p_ied:	设备标识
ginh:	条目号(0:全部条目)
ginl:	组号  0 描述 1 参数,2区号 3 保护定值 6 阮压板 9 模拟量
kod:	数据类型
*/
static BOOL c103_generic_read(T_IED *p_ied, BYTE ginl, BYTE ginh, BYTE kod)
{
  T_C103_FRAME t_frame;
  T_C103_ASDU* p_asdu;
  int i;

  /* 构建ASDU21通用分类读命令 */
  p_asdu =(T_C103_ASDU *)&m_tx_buf[6];
  p_asdu->type =21;
  p_asdu->vsq =0x81;
  p_asdu->cot =42;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -