STM32HAL库自己写modbus

modbus有的人自己移植lib  modbus,有人自己移植freemodbus  ,日后博主会依次为大家做实验,去用上述两种方法实现,本次先分享自己写的modbus,话不多说上代码。

先是写出串口接收中断部分的代码。

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	extern uint8_t buff1[100];	//接收的数据包
	extern int buff1stat;		//接收数据包当前位
	extern uint8_t RxByte;		//中断接收暂存位置
	extern int RE4851_flag;			//接收结束标志符
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);	//中断启动使能标识
  /* USER CODE BEGIN USART1_IRQn 1 */
	buff1[buff1stat]=RxByte;	//将暂存内容放入接收数据包
	buff1stat++;				//数据包位置后移1位
	HAL_UART_Receive_IT(&huart1,&RxByte,1);	//重新启动接收中断,等待下一位数据到来
	if(buff1[1]==0x03)			//判断功能码,功能码位0x30则为读寄存器,请求数据包应为8位
	{
		if(buff1stat==8)		//数据到8位接收结束符置1,清除接收数据包当前位
		{
			buff1stat=0;
			RE4851_flag=1;
		}
	}
	if(buff1[1]==0x10)			//判断功能码,功能码位0x30则为读寄存器,请求数据包应为9+Code Length位
	{
		if(buff1[6]!=0x00)		//当Code Length位不为0 且数据到9+Code Length位时,接收结束符置1,清除接收数据包当前位
		{
			if(buff1stat==9+buff1[6])
			{
				buff1stat=0;
				RE4851_flag=1;
			}
		}
		
	}
  /* USER CODE END USART1_IRQn 1 */
}

接下来将解析上述结束数据的每一位数据

void  modbus_onebit(char a)
{
	switch (e.stat)
	{
	case 0:               // SLAVE ID
//		slave_id=DeviceAddr;
//		if (a == slave_id)
			e.stat = 1;
		break;
	case 1:
		if(a==0x03)
			e.stat = 2;
		if(a==0x10)
			e.stat=12;
		break;
	case 2:
		addr[cnt] = a;
		cnt++;
		e.stat = 3;	
		break;
	case 3:
		addr[cnt] = a;
		cnt++;
		if (cnt > 3)
		{
			cnt = 0;
			startaddr= addr[1];
			bufflen= addr[3];
			e.stat = 4;
		}
		break;
	case 4:
		e.stat = 5;
		break;
	case 5:
		if(n==bufflen)
		e.stat = 100;
		break;
	case 6:
		e.stat = 6;
		break;
	case 7:
		e.stat = -1;
		break;
	case 8:
		e.stat = 100;
		break;
/********D′è??à????′??÷********/	
	case 12:
		addr[cnt]=a;
		cnt++;
	if(cnt>4)
	{
		cnt=0;
		startaddr= addr[1];
		bufflen= addr[4];
		e.stat = 13;	//×a′?íê±?
	}	
	break;
	case 13:
		if(n==bufflen)
		e.stat = 100;
		break;


	}
}

接下来分析接收到的功能码



void ReadHoldRegister(uint8_t buffIN[100],uint8_t buffOUT[100])
{
	int i,j;
	e.stat = 0;
	for (i = 0; i < 10; i++)
	{
		modbus_onebit(buffIN[i]);
		
		if (e.stat == 100)
		{

		}
		if (e.stat == 0)
		{

		}
		if (e.stat == 1)
		{
			buffOUT[i]= buffIN[i];
		}
		if (e.stat == -1)
		{
			
		}
		if (e.stat == 2)
		{
			buffOUT[i] = buffIN[i];
		}
		if (e.stat == 3)
		{			
		}
		if (e.stat == 4)
		{
			buffOUT[2] = bufflen*2;
		}
		if (e.stat == 5)
		{
			for (j = 0,n=0; j < bufflen * 2; j= j + 2,n++)
			{
				buffOUT[3 + j] =  (DB_R[n+startaddr] >> 8) & 0x00FF;
				buffOUT[3 + j+1] = DB_R[n+startaddr]& 0x00FF;	
			}
		}
		
		if (e.stat == 12)
		{
			buffOUT[i] = buffIN[i];
		}
		if (e.stat == 13)
		{
			for (j = 0,n=0; j < bufflen; j= j + 2,n++)
			{		
				DB_R[n+startaddr]=(buffIN[7 + j] << 8)+buffIN[7 + j + 1];
			}
		}
	}
	if(buffIN[1]==0x03)
	CrcCheck(buffOUT,3+bufflen*2);
	else if(buffIN[1]==0x10)
	CrcCheck(buffOUT,6);
	
	
}

上述CRC本次采用的是计算法而非查表法。


void CrcCheck(unsigned char *buf,int len)
{
	unsigned short crc = 0xFFFF;
	unsigned char i,j=0;
	while(j < len)
	{
		crc ^= buf[j];
		for(i = 0; i < 8; i++)
		{
			if(crc & 0x01)
				{
				crc >>= 1;
				crc ^= 0xA001;
				}
			else
			crc >>= 1;
		}
		j++;
	}
	buf[j] = crc % 0x100;
	buf[j+1]=crc / 0x100;
}

主函数的定义,以及使用方法如下:

主函数初始化内容

	DB_R[0] = 0x0102;
	DB_R[1] = 0x0204;
	DB_R[2] = 0x0306;
	DB_R[3] = 0x0408;
	int count;

主循环填写内容:

    if(RE4851_flag==1)
		{ RE4851_flag=0;
			DB_R[0] = 待检测数据;
			DB_R[1] = 待检测数据;
			DB_R[2] = 待检测数据;
			DB_R[3] = 待检测数据;
			ReadHoldRegister(buff1,buff2);	//上面写的函数,不懂的滑上去看
			if((buff1[1]==0x03)&&(buff1[0]==slave_id))				//判断功能码,0x03为读寄 
                   存器,发送5+2*length位,不懂为什么的的滑回前面去看
				{
				 buff1[1]=0;buff1[0]=0;
				 RS485_ControlPin_High;
			   for(count=0;count<5+buff1[5]*2;count++)
			   HAL_UART_Transmit(&huart1, &buff2[count],1,0xFFFF);
				 RS485_ControlPin_Low;
				}
		}


串口接受之前定义的内容:
    u8 slave_id=1;          // 从机地址,可设 ,一般存储在flash中
	uint16_t DB_R[100];
	MB e;
	int cnt,n,bufflen,startaddr;
	uint8_t addr[100];

串口接收.h文件中定义内容:
extern u8 slave_id;
typedef struct
{
  int stat;				//Modbus解析位置定义
}MB; 
 
void CrcCheck(unsigned char *buf,int len);
void ReadHoldRegister(unsigned char *buff1,unsigned char *buff2);
void  modbus_onebit(char a);
void ReadHoldRegister(uint8_t buffIN[100],uint8_t buffOUT[100]); 




以上内容即可解析出modbus,待检测数据放入要读的数据,即可通过主机读取通讯的数据。

以上为一版modbus协议,但是上述在线上挂载好多设备时不安全啊。没有定时器去处理接收时间的判断,而接下来这个接收加发送就灰常nB,只需要处理中断就可以,以下为C代码。

#include "main.h"
#include "Uart2.h"


UART_HandleTypeDef huart2;
u8 UART2_ReceiveBuffer[20];
u8 UART2_WriteBuffer[20];
u8 UART2_ReceiveState;
u16 UART2_CRC_Result;
u8 Uart2_res[10];
u8 UART2_ReceiveDataLength;
u8 Usart2_Receivebiginflag;


void MX_USART2_UART_Init(void)
{
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
	UART2_ReceiveDataLength = 0;
	Usart2_Receivebiginflag = false;
	PC_RS485_ControlPin_Low ;
  HAL_UART_Receive_IT(&huart2, (uint8_t *)Uart2_res, 1);	
}



void Uart2_Send_Byte(u8 SendData)
{
	 HAL_UART_Transmit(&huart2, (uint8_t *)&SendData,1,200);
}


void Uart2_Send_DuoByte(u8 *SendDataBuffer, u8 SendDataLength)
{
	 u8 i;
	 PC_RS485_ControlPin_High ;
	 for(i=0; i<SendDataLength;i++)
	 {
	   Uart2_Send_Byte(SendDataBuffer[i]);
	 }
	  PC_RS485_ControlPin_Low; 
}

u8 uart_chongfu=0,jieshou_zuhoubit=0;

u8 Uart1JieShouDataTimerRunFlag= 0;
void USART2_IRQHandler(void)
{
	u8 res;
	u16 Read_Start_Address;
	u16 Read_Register_Length;
  HAL_UART_IRQHandler(&huart2);
	HAL_UART_Receive_IT(&huart2, (u8 *)Uart2_res, 1); 	
  res = Uart2_res[0];
//	//接收地址
//if((((unsigned char)STM32valuet.Usart2_address == res)||(0x01 == res)||(0x02 == res))&&( 0 == UART2_ReceiveDataLength))   //兼容老款何佳 BEE-M-300/500程序   
  if((((unsigned char)STM32valuet.Usart2_address == res))&&( 0 == UART2_ReceiveDataLength))   //兼容老款何佳 BEE-M-300/500程序   
	{	
		Usart2_Receivebiginflag  = True;
		Uart1JieShouDataTimerRunFlag = true;
	}
  if(True == Usart2_Receivebiginflag)
  {
		
	 UART2_ReceiveBuffer[UART2_ReceiveDataLength] = res;
		if ((uart_chongfu==1)&&((UART2_ReceiveBuffer[UART2_ReceiveDataLength]==4)||(UART2_ReceiveBuffer[UART2_ReceiveDataLength]==3)))
		{
			UART2_ReceiveDataLength=1;uart_chongfu=0;
			UART2_ReceiveBuffer[UART2_ReceiveDataLength] = res;
		}
		
	 if(UART2_ReceiveBuffer[UART2_ReceiveDataLength]==STM32valuet.Usart2_address)
    uart_chongfu=1;
	 else
		uart_chongfu=0;
	 
	 UART2_ReceiveDataLength++;	
	 if(2 == UART2_ReceiveDataLength)
	 {
	    if((0x03 == UART2_ReceiveBuffer[1])||(0x06 == UART2_ReceiveBuffer[1])||(0x04 == UART2_ReceiveBuffer[1]))   //兼容04命令
	    ;
	    else
	    {
	      UART2_ReceiveDataLength = 0;
	      Usart2_Receivebiginflag = false;
				Uart1JieShouDataTimerRunFlag = false;
	   }
	}
	   if(UART2_ReceiveBuffer[7]==STM32valuet.Usart2_address)
        jieshou_zuhoubit=1;
		 else
			  jieshou_zuhoubit=0;
	
	if(8 <= UART2_ReceiveDataLength)	 // 数据长度为8
	{
		     
			  UART2_CRC_Result = crc16(UART2_ReceiveBuffer, 6);
			  if((UART2_ReceiveBuffer[6] == (u8)(UART2_CRC_Result/256))&&(UART2_ReceiveBuffer[7] == (u8)(UART2_CRC_Result%256)))   // 判断数据传输校验
				{   
					
					UART2_ReceiveDataLength=0;
					  Uart1JieShouDataTimerRunFlag = false;
					  Read_Start_Address=((u16)UART2_ReceiveBuffer[2]*256 + (u16)UART2_ReceiveBuffer[3]);  
					  Read_Register_Length = ((u16)UART2_ReceiveBuffer[4]*256 + (u16)UART2_ReceiveBuffer[5]);  
						if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x02)&&(Read_Register_Length==2)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
						 {
									 UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
									 UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
							     UART2_WriteBuffer[2] = Read_Register_Length*2;
									 UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
									 UART2_WriteBuffer[4] =	(u8)((u16)STM32valuet.Display_O2%256);
									 UART2_WriteBuffer[5] = (u8)((u16)Usart1.Send_CO/256);
									 UART2_WriteBuffer[6] =	(u8)((u16)Usart1.Send_CO%256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									 Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
						 } 
						 
						 // STM32valuet.Flash_Data_Buff[2] = Usart1.Send_O2;
							//   STM32valuet.Flash_Data_Buff[3] = Usart1.Send_CO;
						 if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x02)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
						 {
									 UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
									 UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
							     UART2_WriteBuffer[2] = Read_Register_Length*2;
									 UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
									 UART2_WriteBuffer[4] =	(u8)((u16)STM32valuet.Display_O2%256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									 Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
						 } 
						 
						 
						  if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x03)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
						 {
									 UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
									 UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
							     UART2_WriteBuffer[2] = Read_Register_Length*2;
									 UART2_WriteBuffer[3] = (u8)((u16)Usart1.Send_CO/256);
									 UART2_WriteBuffer[4] =	(u8)((u16)Usart1.Send_CO%256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									 Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
						 } 
						 if((0x03 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==0x04)&&(Read_Register_Length==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
						 {
									 UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
									 UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
							     UART2_WriteBuffer[2] = Read_Register_Length*2;
									 UART2_WriteBuffer[3] = (u8)((u16)HIT10_Temperature/256);
									 UART2_WriteBuffer[4] =	(u8)((u16)HIT10_Temperature%256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									 UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									 Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
						 } 

			       if((0x04 == UART2_ReceiveBuffer[1])&&(Read_Start_Address==1)&&(STM32valuet.Usart2_address == UART2_ReceiveBuffer[0])) //代表读寄存器
						 {

									 UART2_WriteBuffer[0] = UART2_ReceiveBuffer[0];
									 UART2_WriteBuffer[1] = UART2_ReceiveBuffer[1];
							     UART2_WriteBuffer[2] =Read_Register_Length*2;
									if(0x01 == UART2_ReceiveBuffer[0]) 
									{
										UART2_WriteBuffer[3] = (u8)((u16)STM32valuet.Display_O2/256);
										UART2_WriteBuffer[4] = (u8)((u16)STM32valuet.Display_O2%256);	
										UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									  UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									  Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
									}	 
									else if(0x02 == UART2_ReceiveBuffer[0])
									{
										 UART2_WriteBuffer[3] = (u8)((u16)Usart1.Send_CO/256);
										 UART2_WriteBuffer[4] = (u8)((u16)Usart1.Send_CO%256);	
										 UART2_WriteBuffer[(UART2_WriteBuffer[2]+3)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))/256);
									   UART2_WriteBuffer[(UART2_WriteBuffer[2]+4)] =  (u8)(crc16(UART2_WriteBuffer,(UART2_WriteBuffer[2]+3))%256);
									   Uart2_Send_DuoByte(UART2_WriteBuffer,(UART2_WriteBuffer[2]+5));
									} 
						 } 
						 

						 if(0x06 == UART2_ReceiveBuffer[1]) //代表写寄存器
	           {
						 	  if(1006 == UART2_ReceiveBuffer[2]*256 + UART2_ReceiveBuffer[3]) 
		            {
			             STM32valuet.Usart2_address = (u16)UART2_ReceiveBuffer[4]*256 + (u16)UART2_ReceiveBuffer[5];
			             Uart2_Send_DuoByte(UART2_ReceiveBuffer,8);
		   	           Writedatatoeeprom(); 
		            } 
			       }		 
						 
				}	UART2_ReceiveDataLength=jieshou_zuhoubit; 
          if(UART2_ReceiveDataLength==0)Usart2_Receivebiginflag = false;
	   }
  }
}


以上为手搓modbus的另一种方式,目前测试过10台设备挂机都可以正常测试。已经算是手搓modbus协议的完美作品了。 处理了其他从机的干扰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值