找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1697|回复: 0
打印 上一主题 下一主题
收起左侧

PIC MODBUS从站程序

[复制链接]
跳转到指定楼层
楼主
ID:573529 发表于 2019-6-27 16:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
"p18f46K80.h"
#include "MODBUS.h"
#include "EUSART1.h"
#include "EUSART2.h"
#include "delays.h"
#include "SPI.h"
#include "GM8141.h"
#define DE_485      (LATDbits.LATD4 ) //485发送控制脚宏定义
#define RE_485   (LATDbits.LATD5 ) //485接收控制脚宏定义
#define SLAVE_ADDRESS 0x01   //485从站地址宏定义
#define SLAVE_GXADDRESS 0x01   //光纤从站地址宏定义
#define no_error  0x00   //收到的帧中无
#define function_error 0x01   //功能码不支持异常码
#define regnum_error 0x03   //寄存器数量不支持异常码   
#define addnum_error 0x02   //起始地址和寄存器数量异常码
#define read_coil  0x01   //位数据的读取
#define read_reg  0x03   //字数据的读取
#define write_reg  0x06   //写一个字
#define write_regs  0x10   //写多个字
/***********************************/
///////////////////////////////////////////////////////////////
//接收缓冲区,发送缓冲区,数据存储区定义
///////////////////////////////////////////////////////////////
//#pragma udata bigdata   //7-10
// extern unsigned char    Buffer[1023];  //液晶显示缓冲区 32*160
//#pragma udata
#pragma udata udata2     //该指令可以使receive_rc1放置于另一块bank中
extern unsigned char receive_rc1[250]; //接收数据缓存区
#pragma udata udata3     //该指令可以使trans_tr1放置于另一块bank中
extern unsigned char trans_tr1[250];  //发送数据缓存区
#pragma udata udata4     //该指令可以使receive_rc2放置于另一块bank中
extern unsigned char receive_rc2[250]; //接收数据缓存区
#pragma udata udata5     //该指令可以使trans_tr2放置于另一块bank中
extern unsigned char trans_tr2[250];  //发送数据缓存区
#pragma udata udata1
extern unsigned char  * HOLD_REG;// = &Buffer[0];//1024个字节的寄存器存储区
extern unsigned char recdata;  //接收数据寄存器
extern unsigned char *receive_485; //485帧接收指针,指向存储数组
extern unsigned char *receive_p;  //接收数据处理指针,指向接收数组,crc校验用
unsigned short crc;
extern unsigned char receive_num,trans_num;//接收到的数据个数,发送数据个数
unsigned char    delet_rc1,delet_rc2; //清除帧接收缓存器时用的计数单元
extern unsigned char *receive_p;
unsigned char error_kind;      //检测错误码的类型,get_frame_error()程序中用
unsigned int  start_addr,reg_num;    //收到的帧中的寄存器地址和寄存器数目存储单元。两个字节int型
unsigned char trans_frame_num;    //发送帧中的个数
unsigned int   heart_beat,heart_beat2,heart_beat3;   //每收到一次指令 heart_beat+1  在00 01和02 03字节上显示出来
//////////////光纤MODBUS用数据//////////////////////////////////////////////////
extern unsigned char gxreceive_num,gxtrans_num;//接收到的数据个数,发送数据个数
extern unsigned char *receive_gx;
unsigned char  GXtrans_frame_num;
extern unsigned int read_int;
////////////////////////////////////////////////////////////////////////////////
extern struct {
  unsigned  CAN_FLAG:    1; //CAN标志位
  unsigned  RXB0_FLAG:     1;
  unsigned  RXB1_FLAG:     1;
  unsigned  TX1_FLAG:      1; //EUSART标志位
  unsigned  RX1_FLAG:      1;
  unsigned  parity_FLAG:   1;//偶校验标志位
  unsigned  MOD485_FLAG: 1;//485端口的MODBUS帧接收完成标志位,主程序和定时0中断处理
  unsigned  MOD485_ERROR: 1;//485端口帧偶校验或crc校验错误
} FLAG1bits;//定义
extern struct {
  unsigned  RX2:    1;//EUSART2 RECEIVE   INTERRUPT FLAG
  unsigned  TX2:     1;//EUSART2 TRANSLATE INTERRUPT FLAG
  unsigned  TIME2:     1;//
  unsigned  MODGX_ERROR:      1;//
  unsigned  FLAG4:      1;//
  unsigned  FLAG5:   1;//
  unsigned  FLAG6:  1;//
  unsigned  FLAG7:  1;//
} FLAG3bits;//定义
/* CRC 高位字节值表 */   
   rom unsigned char auchCRCHi[256] = {  
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,   
    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,   
    0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,   
    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,   
    0x80, 0x41, 0x00, 0xC1, 0x81, 0x40  
    };   
      
  rom  unsigned char auchCRCLo[256] = {  
    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,   
    0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,   
    0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,   
    0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,   
    0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,   
    0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,   
    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,   
    0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,   
    0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,   
    0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,   
    0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,   
    0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,   
    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,   
    0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,   
    0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,   
    0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,   
    0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,   
    0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,   
    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,   
    0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,   
    0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,   
    0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,   
    0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,   
    0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,   
    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,   
    0x43, 0x83, 0x41, 0x81, 0x80, 0x40  
    };  
// ****************************************************************
// 函 数 名: getparity(unchar parity_target)
// 功能描述: 对parity_target的8位依次进行相加,考察结果的奇偶性
//    偶数:FLAG1bits.parity_FLAG为0,奇数:为1
//*****************************************************************
void getparity(uchar target)
{
uchar parity_i,parity_temp,parity;
parity=target;
for(parity_i=0,parity_temp=0;parity_i<8;parity_i++)
{
  if(parity & 0x01)
  parity_temp++;
  parity>>=1;
}
if(parity_temp%2==0)
  FLAG1bits.parity_FLAG=0; //偶数个“1”返回0
else
  FLAG1bits.parity_FLAG=1; //奇数个“1”返回1
}
/*********************************************************************************/  
/*函数名称: GetCRC16()                           
*输入参数:  共  个参数;  
*输出参数:  共  个参数;  
*返回值:   
*需储存的参数: 共  个参数;      
*功能介绍:(1)CRC16校验; 返回校验码;                                               
/*                                      */  
/*********************************************************************************/  
  
unsigned short GetCRC16(unsigned char *puchMsg, unsigned char usDataLen)   
{   
    unsigned char uchCRCHi = 0xFF ; /* 高CRC字节初始化 */   
    unsigned char uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */   
    unsigned uIndex = 0; /* CRC循环中的索引 */   
      
    while (usDataLen--) /* 传输消息缓冲区 */   
    {   
        uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */   
        uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;   
        uchCRCLo = auchCRCLo[uIndex] ;   
    }   
    return (unsigned short)((unsigned short)uchCRCHi << 8 | uchCRCLo) ;   
}   
/*****************************************************************************/
//MODBUS_RTU函数,功能实现MODBUS——RTU协议
/*****************************************************************************/  
void MODBUS_RTU(void)
{
   
   if(FLAG1bits.MOD485_ERROR==0)   //判断偶校验是否错误
   {
    //receive_p=&receive_rc1[0];
    crc=GetCRC16(&receive_rc1[0],receive_num);
    if(crc!=0)       //判断crc校验是否错误
    {
     FLAG1bits.MOD485_ERROR=1;      
    }
   }
   
   if(FLAG1bits.MOD485_ERROR==0)
   {
    LATBbits.LATB4=~LATBbits.LATB4; //小灯闪烁
    if(receive_rc1[0]==SLAVE_ADDRESS) //判断从站地址是否相符,不符合不操作
    {
     error_kind=get_frame_error();   //判断是否有异常码
     switch(error_kind)
     {
      case no_error:  rtu_data();//support_function(); //无异常码情况下执行RTU操作函数
        break;
      case function_error: unsupport_function();   //功能异常码 执行功能异常返回函数
        break;
      case regnum_error: unsupport_regnum();    //寄存器数量异常,执行异常返回函数
        break;
      case addnum_error: unsupport_addnum();    //地址和数量异常,执行异常返回函数
        break;
      default : break;
      
     }     
    }
   
   
    for(delet_rc1=0;delet_rc1<receive_num;delet_rc1++)
    {       //帧接受暂存器清零
     receive_rc1[delet_rc1]=0;
    }
    receive_num=0;    //发送完成后接受个数清零,等待下一帧
    trans_num=0;    //发送完成后发送个数清零,等待下一帧
   }
   if(FLAG1bits.MOD485_ERROR==1)   //偶校验错误或crc校验错误,清除各个数据,等待下一帧
   {
    receive_num=0;
    trans_num=0;
    FLAG1bits.MOD485_ERROR=0;
    /******************************************************
     //测试用心跳函数,CRC校验失
    /************************/
   
   }     
}
/************************************************
*****发送帧函数,入口参数:帧中字节数目,发送trans_tr1数组中的数据**********
************************************************/
void trans_frame(/*unsigned char *trans_frame,*/unsigned char trans_num1)
{
  RE_485=1;     //禁止485的接收功能
  DE_485=1;     //使能485的发送功能  
  
  for(trans_num=0;trans_num<trans_num1;trans_num++)
  {
   getparity(trans_tr1[trans_num]); //进行偶校验
   TXSTA1bits.TX9D1=FLAG1bits.parity_FLAG;//偶校验结果放入第九位
   TXREG1=trans_tr1[trans_num];  //返送接收到的数据
   //receive_rc1[trans_num]=0;   // ***发送完后清零****/
            ///////////调试用/////
   while(TXSTA1bits.TRMT1==0);   //等待数据发送完毕
  }
  
  DE_485=0;  
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表