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

📄 modbus.c

📁 富士通单片机MB90F387上实现MODBUS
💻 C
📖 第 1 页 / 共 5 页
字号:
					break;	
			}	  																									    
      default: //错误
      {
					FaultProcess();	      	
      		return(0);
      }
    }
    return(1);
} 
/********************************************************************************************************
* 作者  :冯子龙
* 日期  :200709
* 名称  :Data_anlysis_ASCII()
* 功能  :ASCII模式  接收分析
* 返回  :FRM_ERR,CMD_ERR,1
* 备注  :分析结果存放在*dest中
*********************************************************************************************************/    
char  Data_anlysis_ASCII( int  *dest,uchar *src,uint start_address)
{
    uchar tmp[256];
    uint lenth;
    uint i, j;
    char shift;
		
		//将ASCII码串去除起始符和结束符后转换为二进制
    lenth = ASCII2RTU(tmp,src);
    if ( lenth==0) return FRM_ERR;
    
    switch (tmp[1])//命令解析
    {
      case READ_COIL://01读取线圈状态 
      {
          for ( i=0; i<tmp[2]; i++)
          {
              shift = 1;
              for ( j=0; j<8; j++)
              { 
                  *(dest+start_address+i*8+j) = shift & tmp [i+3];      
                  tmp [i+3] >>= 1;
              }
          }
          break;
      }
      case READ_DI: //02读取开关量输入
      {
          for ( i=0; i<tmp[2]; i++)
          {
                shift = 1;
                for (j=0; j<8; j ++)
                {
                     *(dest+start_address+i*8+j)= shift & tmp [i+3];
                     tmp [i+3]>>=1;    
                }
          }
          break;
			}
      case READ_HLD_REGs://03读取保持寄存器
      {
          for (i=0; i<tmp[2]; i+=2)
          {
                *(dest + start_address+ i/2) = tmp[i+3]*256 +  tmp[i+4] ;  
          }
          #ifdef operatorDEBUG
          if(*( src+2)==2)//手持操作器显示用,因为手持仅进行每次读一个字的操作。连接ABB测试用
          {
          	 para_val = *(src+i+3)*256 +  *(src+i+4);
          }  
          #endif        
          break ;
		  }
      case READ_AI://04读取模拟量输入
      {
          for (i=0; i<tmp[2]; i+=2)
          {
               *(dest+start_address+ i/2) = tmp[i+3]*256 +  tmp[i+4] ;      
          }
          break;         
      }
			case SET_COIL://05强制单个线圈进行
			{
					break;	
			}
			case SET_HLD_REG://06写单个寄存器
			{
					break;	
			}	
			case SET_COILs://15强制多个线圈进行
			{
					break;	
			}	
			case SET_HLD_REGs: //16写多个寄存器
			{
					break;	
			}	
			case READ_SET_HLD_REGs: //23读写多个寄存器
			{
					break;	
			}													
      default: //功能码错误
      {
      		FaultProcess();	
      	  break;
      }
    }
    return(1);
}
/********************************************************************************************************
* 作者  :冯子龙
* 日期  :200709
* 名称  :cmd01_ReadCoilStatus()
* 功能  :读取继电器状态:CMD == 1 
* 返回  :成功返回1,否则返回0
* 备注  :Tested
请求命令:[设备地址] [命令号01] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位]
设备响应:[设备地址] [命令号01] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd01_ReadCoilStatus(uchar DeviceID,uint start_address,uint lenth) 
{
    uchar tmp[256],tmp_lenth;
    
    tmp[0] = DeviceID; //从设备地址
    tmp[1] = 0x01; //命令
    tmp[2] = wordHByte(start_address);//起始地址 高字节
    tmp[3] = wordLByte(start_address);//起始地址 低字节
    tmp[4] = wordHByte(lenth);//读取数据量 高字节
    tmp[5] = wordLByte(lenth);//读取数据量 低字节
    tmp_lenth = 6; //二进制包长度
    if(Modbus_mode)
    {
    		construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串    
    		TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
  	}
  	else
  	{
    		construct_rtu_frm ( Tx_Buffer, tmp, tmp_lenth);  	
    		TxBytes = tmp_lenth+2;
  	}
  	comSend();//发送请求
  	if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
    {    		             
        if(Rx_Buffer[1] == 0x01) //通信正常,数据处理
        {
        	  if(CheckCRC(Rx_Buffer,RxBytes))
        	  {
            	  switch(Rx_Buffer[2])//返回字节数
            	  {     
            	  		case 0x02:
            	  		{                    	  					             	  			 		
            	  				break;	
            	  		}
            	  		case 0x04:
            	  		{        	  			
            	  				break;	
            	  		}
            	  		case 0x06:
            	  		{        	  			
            	  				break;	
            	  		}  
            	  		case 0x08:
            	  		{        	
            	  			  para_val = Rx_Buffer[3]*256 + Rx_Buffer[4];	         	  			  			
            	  				break;	
            	  		} 
            	  		default:
            	  		{          						    									
    										break;         	  			
            	  		}              	  		      	  		      	  		        	  		
            	  }  
            	  return(1);        	  	
        	  } 
        	  else  //CRC校验不一致;可重新发送请求或作其他处理
        	  {
        	  		Rx_Buffer[2] = 0x09;
        	  		FaultProcess();
        	  		return(0);
        	  }                    	
        }
        else //通信异常0x83,查询异常码,可重新发送请求或作其他处理
        {
						FaultProcess();
						return(0);
        }       
    }
    else //通信异常
    {
    	  Rx_Buffer[2] = 255;//异常码填充
				FaultProcess();
				return(0);
    } 
}
/********************************************************************************************************
* 作者  :冯子龙
* 日期  :200709
* 名称  :cmd02_ReadInStatus()
* 功能  :读取开关量输入:CMD == 2 
* 返回  :成功返回1,否则返回0
* 备注  :全局变量Modbus_mode,Tx_Buffer[],TxBytes,Rx_Buffer[],RxBytes
请求命令:[设备地址] [命令号02] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位]
设备响应:[设备地址] [命令号02] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd02_ReadInStatus(uchar DeviceID, uint start_address, uint lenth) 
{
    uchar tmp[256], tmp_lenth;
    
    tmp[0] = DeviceID;//从设备地址
    tmp[1] = 0x02; //命令
    tmp[2] = wordHByte(start_address);//起始地址 高字节
    tmp[3] = wordLByte(start_address);//起始地址 低字节
    tmp[4] = wordHByte(lenth);//读取数据量 高字节
    tmp[5] = wordLByte(lenth);//读取数据量 低字节
           
    tmp_lenth = 6; //二进制包长度
    
    if(Modbus_mode)
    {
    		construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串    
    		TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
  	}
  	else
  	{
    		construct_rtu_frm(Tx_Buffer, tmp, tmp_lenth);  	
    		TxBytes = tmp_lenth+2;
  	}
  	comSend();//发送请求
  	if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
    {    		             
        if(Rx_Buffer[1] == 0x02) //通信正常,数据处理
        {
        	  if(CheckCRC(Rx_Buffer,RxBytes))
        	  {
            	  switch(Rx_Buffer[2])//返回字节数
            	  {     
            	  		case 0x02:
            	  		{        
            	  					             	  			 		
            	  				break;	
            	  		}
            	  		case 0x04:
            	  		{        	  			
            	  				break;	
            	  		}
            	  		case 0x06:
            	  		{        	  			
            	  				break;	
            	  		}  
            	  		case 0x08:
            	  		{        	
            	  			    para_val = Rx_Buffer[3]*256 + Rx_Buffer[4];	         	  			  			
            	  				break;	
            	  		} 
            	  		default:
            	  		{          						    									
    										break;         	  			
            	  		}              	  		      	  		      	  		        	  		
            	  }   
            	  return(1);       	  	
        	  } 
        	  else  //CRC校验不一致;可重新发送请求或作其他处理
        	  {
        	  		Rx_Buffer[2] = 0x09;
        	  		FaultProcess();
        	  		return(0);
        	  }                    	
        }
        else //通信异常0x83,查询异常码,可重新发送请求或作其他处理
        {
						FaultProcess();
						return(0);
        }       
    }
    else //通信异常
    {
    	  Rx_Buffer[2] = 255;//异常码填充
				FaultProcess();
				return(0);
    }  
}
/********************************************************************************************************
* 作者  :冯子龙
* 日期  :200709
* 名称  :cmd03_ReadHldreg()   
* 功能  :读取保持寄存器:CMD == 3 
* 返回  :成功返回1,否则返回0
* 备注  :Tested
请求命令:[设备地址] [命令号03] [起始寄存器地址高8位] [低8位] [读取的寄存器数高8位] [低8位] [CRC校验的低8位] [CRC校验的高8位] 
设备响应:[设备地址] [命令号03] [返回的字节个数][数据1][数据2]...[数据n][CRC校验的低8位] [CRC校验的高8位]
*********************************************************************************************************/
uchar cmd03_ReadHldreg(uchar DeviceID, uint start_address, uint lenth) 
{
    uchar tmp[256], tmp_lenth;    
    int tmmp[256];
    tmp[0] = DeviceID;//从设备地址
    tmp[1] = 0x03;//命令
    tmp[2] = wordHByte(start_address);//起始地址 高字节
    tmp[3] = wordLByte(start_address);//起始地址 低字节
    tmp[4] = wordHByte(lenth);//读取数据量 高字节
    tmp[5] = wordLByte(lenth);//读取数据量 低字节 
    tmp_lenth = 6;
    
    if(Modbus_mode)
    {
    		construct_ascii_frm (Tx_Buffer, tmp, tmp_lenth);//对以上数据构成ASCII码串    
    		TxBytes = 2*tmp_lenth+2; //有效Modbus数据长度,用于中断发送完成判断
  	}
  	else
  	{
    		construct_rtu_frm(Tx_Buffer, tmp, tmp_lenth);  	
    		TxBytes = tmp_lenth+2;
  	}
  	comSend();//发送请求
  	if(comReceive())//获取应答;对应答数据分析;对接收到的应答数据分析
    {    		    
    	  if(Modbus_mode)
    	  {
    	  		//data_anlys_ascii();
    	  		Data_anlysis_ASCII(tmmp,Rx_Buffer,start_address);
    	  }
    	  else
    	  {
    	  	 // data_anlys_rtu();    
    	  	 Data_anlysis_RTU(tmmp,Rx_Buffer,start_address,RxBytes); 	 	  	
    	  }
    	  /*
        if(Rx_Buffer[1] == 0x03) //通信正常
        {
        	  if(CheckCRC(Rx_Buffer,RxBytes))//数据处理
        	  {
            	  switch(Rx_Buffer[2])//返回字节数
            	  {     
            	  		case 0x02:
            	  		{        
            	  				para_val = Rx_Buffer[3]*256 + Rx_Buffer[4];	//提取数据             	  			 		
            	  				break;	
            	  		}
            	  		case 0x04:
            	  		{        	  			
            	  				break;	
            	  		}
            	  		case 0x06:
            	  		{        	  			
            	  				break;	
            	  		}  
            	  		case 0x08:
            	  		{        	            	  			  	         	  			  			
            	  				break;	
            	  		} 
            	  		default:
            	  		{                	
            	  				para_val =   RxBytes;	//显示接收到的字节数:测试用		     						    									
    										break;         	  			

⌨️ 快捷键说明

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