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

📄 modbus_c_program.txt

📁 单片机与其它仪表之间modbus通讯协议,用c语言编写
💻 TXT
📖 第 1 页 / 共 2 页
字号:
    tmp[1] = READ_HLD_REG; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 
    tmp[4] = HI(lenth); 
    tmp[5] = LOW(lenth); 
    tmp_lenth = 6; 
    construct_rtu_frm ( com_buf,tmp,tmp_lenth); 
    return 8; 
} 


// 4 发送读取模拟量输入 
int ascii_read_anloginput( unsigned char board_adr,unsigned char *com_buf,int start_address,int lenth)  
{ 
    unsigned char tmp[256], tmp_lenth; 
     
    tmp[0] = board_adr; 
    tmp[1] = READ_AI; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 
    tmp[4] = HI(lenth); 
    tmp[5] = LOW(lenth); 
    tmp_lenth = 6; 
    construct_ascii_frm ( com_buf, tmp, tmp_lenth); 
    return 18; 
} 


int rtu_read_anloginput( unsigned char board_adr,unsigned char *com_buf,int start_address,int lenth)  
{ 
unsigned char tmp[256],tmp_lenth; 
    tmp[0] = board_adr; 
    tmp[1] = READ_AI; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 
    tmp[4] = HI(lenth); 
    tmp[5] = LOW(lenth); 
    tmp_lenth = 6; 
    construct_rtu_frm ( com_buf,tmp,tmp_lenth); 
    return 8; 
} 


/* 
5 设置继电器 
发送:status =0 继电器释放 否则继电器吸合,address 为吸合的继电器编号,0为第一个继电器,依次类推 
*/ 

int ascii_set_coil ( unsigned char board_adr,unsigned char *com_buf,int start_address,int status ) 
{ 
    unsigned char tmp[256], tmp_lenth; 
      
    tmp[0] = board_adr; 
    tmp[1] = SET_COIL ;   
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 

    if ( status ) 
    { 
       tmp[4] = 0xff; 
       tmp[5] = 0; 
    } 
    else 
    { 
       tmp[4]= 0; 
       tmp[5]= 0; 
    }  

    tmp_lenth = 6; 
    construct_ascii_frm ( com_buf, tmp, tmp_lenth); 
    return 18; 
} 


int  rtu_set_coil ( unsigned char board_adr,unsigned char *com_buf,int start_address,int status ) 
{ 
    unsigned char tmp[256], tmp_lenth; 
     
    tmp[0] = board_adr; 
    tmp[1] = SET_COIL ; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 

    if ( status ) 
    { 
       tmp[4] = 0xff; 
       tmp[5] = 0; 
    } 
    else 
    { 
       tmp[4]= 0; 
       tmp[5]= 0; 
    }  

    tmp_lenth = 6; 
    construct_rtu_frm ( com_buf, tmp, tmp_lenth); 
    return 8 ; 
} 


/* 
6 设置保持寄存器 
*/ 

int ascii_set_hldreg( unsigned char board_adr,unsigned char *com_buf,int start_address,unsigned int value ) 
{ 
    unsigned char tmp[256], tmp_lenth; 
     
    tmp[0] = board_adr; 
    tmp[1] = SET_HLD_REG; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 
    tmp[4] = HI(value); 
    tmp[5] = LOW(value);     
    tmp_lenth = 6; 
    construct_ascii_frm ( com_buf, tmp, tmp_lenth); 
    return 18; 
} 


int rtu_set_hldreg( unsigned char board_adr,unsigned char *com_buf, int start_address, unsigned int value ) 
{ 
    unsigned char tmp[256], tmp_lenth; 
     
    tmp[0] = board_adr; 
    tmp[1] = SET_HLD_REG; 
    tmp[2] = HI(start_address); 
    tmp[3] = LOW(start_address); 
    tmp[4] = HI(value); 
    tmp[5] = LOW(value);     
    tmp_lenth = 6; 
    construct_rtu_frm ( com_buf, tmp, tmp_lenth); 
    return 8 ; 
} 



/* 
7 
接收分析: 
dest_p 接收到数据指针 
sourc_p 串口接收缓冲区指针 
data_start_address 开始地址 
*/ 

/* RTU  接收分析 */ 
int rtu_data_anlys( int  *dest_p, unsigned char *source_p, int data_start_address, int fr_lenth) 
{ 
    unsigned short crc_result, crc_tmp; 
    unsigned char tmp1, tmp2, shift; 
    
    crc_tmp = *(source_p + fr_lenth-2); // crc  第一字节 
    crc_tmp = crc_tmp * 256 + *( source_p+fr_lenth-1); // CRC 值 
    crc_result = crc(source_p, fr_lenth-2); // 计算CRC 值 
     
    
    if ( crc_tmp != crc_result ) // CRC 校验正确 
    { 
       hld_reg[0x31]++; 
       return -1; 
    } 
    switch ( *(source_p+1) ) // 功能码 
    { 
       case READ_COIL:                   /*读取继电器状态 */ 
       for ( tmp1=0; tmp1<*( source_p+2); tmp1++) 
       { 
            shift = 1; 
            for ( tmp2=0; tmp2<8; tmp2++) 
            {  
                 *(dest_p+data_start_address+tmp1*8+tmp2) = shift & *( source_p+3); 
                 *( source_p+3) >>= 1; 
            
            } 
       } 
       break; 

       case READ_DI: /*读取开关量输入*/ 
       for ( tmp1=0; tmp1<*( source_p+2); tmp1++) 
       { 
            shift = 1; 
            for (tmp2=0; tmp2<8; tmp2 ++) 
            {  
                     *(dest_p+data_start_address+tmp1*8+tmp2) = shift & *( source_p+3); 
                 *( source_p+3)>>=1; 
               
            } 
       } 
       break; 

       case READ_HLD_REG:  /*读取保持寄存器*/ 
       for ( tmp1=0; tmp1<*( source_p+2); tmp1+=2) 
       { 
            *(dest_p + data_start_address+ tmp1/2)= *( source_p+tmp1+3)*256 +  *( source_p+tmp1+4) ; 
          
       } 
       break ; 

       case 4:      /*读取模拟量输入*/ 
       for ( tmp1=0; tmp1<*( source_p+2); tmp1+=2) 
       { 
            *(dest_p + data_start_address+ tmp1/2) = *( source_p+tmp1+3)*256 +  *( source_p+tmp1+4) ; 
         
       } 
       break; 

       case PROTOCOL_EXCEPTION: 
       return -1*PROTOCOL_ERR;    
       //break; 

       default: 
       return -1*PROTOCOL_ERR; 
       // break; 
    } 
    return 0; 
} 
         
         
int  ascii_data_anlys( int   *dest_p,char *source_p,int data_start_address) 
{ 
    unsigned char tmp[256]; 
    int lenth; 
    int tmp1, tmp2; 
    char shift; 

    lenth = asctortu(tmp, source_p); 
    if ( lenth==0) return -1* FRM_ERR; 
    switch (tmp[1] ) 
    { 
       case READ_COIL:                   /*读取继电器状态 */ 
       for ( tmp1=0; tmp1<tmp[2]; tmp1++) 
       { 
            shift = 1; 
            for ( tmp2=0; tmp2<8; tmp2++) 
            {  
                        *(dest_p+data_start_address+tmp1*8+tmp2) = shift & tmp [tmp1+3]; 
        
                 tmp [tmp1+3] >>= 1; 
            } 
       } 
       break; 

       case READ_DI: /*读取开关量输入*/ 
       for ( tmp1=0; tmp1<tmp[2]; tmp1++) 
       { 
            shift = 1; 
            for (tmp2=0; tmp2<8; tmp2 ++) 
            { 
                      *(dest_p+data_start_address+tmp1*8+tmp2)= shift & tmp [tmp1+3]; 
                  tmp [tmp1+3]>>=1; 
  
            } 
       } 
       break; 

       case READ_HLD_REG:  /*读取保持寄存器*/ 
       for (tmp1=0; tmp1<tmp[2]; tmp1+=2) 
       { 
            *(dest_p + data_start_address+ tmp1/2) = tmp[tmp1+3]*256 +  tmp[tmp1+4] ; 
   
       } 
       break ; 

       case 4:      /*读取模拟量输入*/ 
       for (tmp1=0; tmp1<tmp[2]; tmp1+=2) 
       { 
            *(dest_p+data_start_address+ tmp1/2) = tmp[tmp1+3]*256 +  tmp[tmp1+4] ; 
   
       } 
       break; 

       case PROTOCOL_EXCEPTION: 
       return -1*PROTOCOL_ERR;    
       //break; 

       default: 
       break; 
    } 
    return 0; 
} 


/* 
主程序按照一定的顺序调用 1~6子程序,然后把生成的缓存内容写入串口。 
接收到数据送给7的子程序分析即可。 
ASCII 方式下,用0X0D, 0X0A作为帧结束判断的依据 
RTU方式下,以两个字节间的时间间隔大于3.5倍的一个字符周期为帧结束判断依据 
READ() WRITE()是两个假想存在的函数 ,需要根据不同的系统来完成。 
比如在单片机中,可能要用到中断模式;在LINUX下可能是一个阻塞的READ WRITE调用,在WINDOWS下可能是串口控件的READ WRITE 方法。。。。。 
因为系统各式各样,所以只能抽象出一个假想的函数,由代码的使用者实现。 

*/ 

/*void main ( void) 
{ 
ascii_read_coil_status ( 1,tx_buf,0,8);          
write (com1,tx_buf ); 
read  (com1,rx_buf); 
ascii_data_anlys( coil,rx_buf,0); 

ascii_read_input_status ( 1,tx_buf,0,8);          
write ( com1,tx_buf ); 
read  (com1, rx_buf); 
ascii_data_anlys( di,rx_buf,0);         

ascii_read_hldreg ( 1,tx_buf,0,8);          
write ( com1,tx_buf ); 
read  (com1, rx_buf); 
ascii_data_anlys( hld_reg,rx_buf,0); 

ascii_read_anloginput( 1,tx_buf,0,8);          
write ( com1,tx_buf ); 
read  (com1, rx_buf); 
ascii_data_anlys( ai,rx_buf,0); 

ascii_set_coil (1,tx_buf,0,1); //第一个继电器吸合/ 
write ( com1,tx_buf ); 
read  (com1, rx_buf); 
ascii_data_anlys( di,rx_buf,0);         

ascii_set_coil (1,tx_buf,0,0); //第一个继电器释放/ 
write ( com1,tx_buf ); 
read  (com1, rx_buf); 
ascii_data_anlys( di,rx_buf,0);         
         
}*/ 

⌨️ 快捷键说明

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