第一个关于STM32的MODBUS协议例子 功能码03

这两天一直在有关于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

猜你喜欢

转载自blog.csdn.net/weixin_45075787/article/details/114133307