这两天一直在有关于modbus协议的传输,没有想到会这般困难,原谅我是一个新手。具体的modbus协议,网上很多了,我就不多说了,直接发出来。
第一部分
u8 receiveOK_flag = 0;
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
LED_Init();//LED初始化
while(1)
{
if( receiveOK_flag ) //一帧数据接收完成后开始处理数据
{
DisposeReceive(); //处理modbus通信
receiveOK_flag = 0;
}
delay_ms(10);
}
}
第二部分
void DisposeReceive( void )
{
u16 CRC16 = 0, CRC16Temp = 0;
if(receiveOK_flag)
{
delay_ms(10);
if( USART_RX_BUF[0] == SlaveID ) //地址等于本机地址 地址范围:1 - 32
{
CRC16 = CRC_Compute(USART_RX_BUF,USART_RX_CNT-2);//计算所接收数据的CRC; //CRC校验 低字节在前 高字节在后 高字节为报文最后一个字节
CRC16Temp = USART_RX_BUF[USART_RX_CNT-1]|(((u16)USART_RX_BUF[USART_RX_CNT-2])<<8);
if( CRC16 != CRC16Temp )
{
err = 4; //CRC校验错误
}
StartRegAddr = ( u16 )( USART_RX_BUF[2] << 8 ) | USART_RX_BUF[3];
if( StartRegAddr > (HoldRegStartAddr + HoldRegCount - 1) )
{
err = 2; //起始地址不在规定范围内 00 - 07 1 - 8号通道
}
if( err == 0 )
{
switch( USART_RX_BUF[1] ) //功能码
{
case 3: //读多个寄存器
{
Modbus_03_Slave();
break;
}
case 6: //写单个寄存器
{
Modbus_06_Slave();
break;
}
case 16: //写多个寄存器
{
Modbus_16_Slave();
break;
}
default:
{
err = 1; //不支持该功能码
break;
}
}
}
USART_RX_CNT=0;//接收计数器清零
USART_RX_BUF[USART_REC_LEN]=0;
if( err > 0 )
{
SendBuf[0] = USART_RX_BUF[0];
SendBuf[1] = USART_RX_BUF[1] | 0x80;
SendBuf[2] = err; //发送错误代码
CRC16Temp = CRC_Compute( SendBuf, 3 ); //计算CRC校验值
SendBuf[3] = CRC16Temp & 0xFF; //CRC低位
SendBuf[4] = ( CRC16Temp >> 8 ); //CRC高位
usart_SendData( SendBuf, 5 );
err = 0; //发送完数据后清除错误标志
}
}
}
}
void Modbus_03_Slave( void )
{
u16 RegNum = 0;
u16 CRC16Temp = 0;
u8 i = 0;
RegNum = ( u16 )( USART_RX_BUF[4] << 8 ) | USART_RX_BUF[5]; //获取寄存器数量
if( ( StartRegAddr + RegNum ) <= (HoldRegStartAddr + HoldRegCount) ) //寄存器地址+寄存器数量 在规定范围内 <=8
{
SendBuf[0] = USART_RX_BUF[0]; //地址
SendBuf[1] = USART_RX_BUF[1]; //功能码
SendBuf[2] = RegNum * 2; //返回字节数量
for( i = 0; i < RegNum; i++ ) //循环读取保持寄存器内的值
{
SendBuf[3 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2];
SendBuf[4 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2 + 1];
}
CRC16Temp = CRC_Compute( SendBuf, RegNum * 2 + 3 ); //获取CRC校验值
SendBuf[RegNum * 2 + 3] = CRC16Temp & 0xFF; //CRC低位
SendBuf[RegNum * 2 + 4] = ( CRC16Temp >> 8 ); //CRC高位
usart_SendData( SendBuf, RegNum * 2 + 5 );
}
else
{
err = 3; //寄存器数量不在规定范围内
}
}
第三部分
void USART1_IRQHandler( void )
{
u8 tem = 0;
if( USART_GetITStatus( USART1, USART_IT_RXNE ) != RESET ) //接收中断
{
tem = USART_ReceiveData( USART1 );
if(USART_RX_CNT<USART_REC_LEN)
{
USART_RX_BUF[USART_RX_CNT]=tem;
USART_RX_CNT++;
}
receiveOK_flag = 1; //置位数据接收完成标志位
USART_ClearITPendingBit( USART1, USART_IT_RXNE );
USART_ClearFlag(USART1,USART_FLAG_RXNE);
}
第四部分
最后:想说的就是,我自己一开始看着还挺简单,然后做的时候出现很多问题,这边多次发送报错,那边发生不回复,还有发错一次,之后再发正确命令,无反应等等。还好解决了,如果需要例程,可以看看链接,就是这个的全部内容。
https://download.csdn.net/download/weixin_45075787/15483014