STM32 RS485通信

RS485是主流的一种多机通信方式,多用于不同设备间的数据传送。最常见的是主控板和485接口的传感器间的通信。下面介绍常用的通信方式及代码,包括常用的CRC校验。


初始化代码:(初始化控制引脚(收发)和对应串口(看硬件连接))

//bound:波特率	  
void RS485_Init(u32 bound)
{  
  
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOE时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;				 //PE1端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	USART2_Init_JAVE( bound);
	
	RS485_TX_EN=0;			//默认为接收模式
}

串口初始化部分代码不再介绍,其中RS485_TX_EN是控制引脚输出低,为接收模式。


下面是发送和接收部分的代码

//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void RS485_Send_Data(u8 *buf,u8 len)
{
	u8 t;
	RS485_TX_EN=1;			//设置为发送模式
  	for(t=0;t<len;t++)		//循环发送数据
	{		   
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);	  
		USART_SendData(USART2,buf[t]);
	}	 
 
	while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);		
	RX2_Point=0;	  
	RS485_TX_EN=0;				//设置为接收模式	
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf,u8 *len)
{
	u8 rxlen=RX2_Point;
	u8 i=0;
	*len=0;				//默认为0
	delay_ms(10);//等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
	if(rxlen==RX2_Point&&rxlen)//接收到了数据,且接收完成了
	{
		for(i=0;i<rxlen;i++)
		{
			buf[i]=RX2_Temp[i];	
		}		
		*len=RX2_Point;	//记录本次数据长度
		RX2_Point=0;		//清零
	}
}

RX2_Point是串口2的接收指针。


解释一下接收函数,首先定义一个临时变量并赋予它RX2_Point的值,然后做一定的延时。如果这时候已经接收完成了,那么RX_Point的值不会变,rxlen也依然等于它。若还没接收完成,RX2_Point 的值会继续增加rxlen就不会相等,这时候执行这个函数就不会有想得到的结果了,所以在发送和接收之间必须有足够的延时等待从机响应主机的命令。后面以一个传感器读数示例会体现这一点。


RS485通信通常需要使用两个字节的校验码来增加信号传输的可靠性,如果传输过程无误,校验码输出0。

获取CRC代码:

参数分别为:输入数字首地址,校验长度,输出结果(16位,即两字节)

有关于CRC的计算流程可自查百度

void Get_CRC(u8 *buf,u8 len,u16 *crc_out)
{
    int i=0,j=0;
    u16 crc,out;
		crc=0xffff;
    for(i=0;i<len;i++)
    {
        out=buf[i]&0x00ff;
				crc=crc^out;
        for(j=0;j<8;j++)
        {
						out=crc&0x0001;
            if(out==1){
							crc >>= 1;
							crc=crc^0xa001;
            }
						else{
							crc >>= 1;
						}
        }
    }
		*crc_out=crc;
}


主从通信中,主机给从机发送命令,一般也要带校验码,这个校验码有些设备的说明书会带上命令对应的校验码。可以直接发送,也可以程序根据命令计算出校验码后发送。

下面以一485接口的传感器通信为例:

float Task_Read_485Senor(void)
{
		 unsigned char RS485[11]={0x01,0x04,0x00,0x00,0x00,0x03,0,0};
		 unsigned char num=6;
		 u16 CRC_RES=0,temp;	 
		 RS485_Init(9600);					//初始化485
		 Get_CRC(RS485,num,&CRC_RES);		//获取命令CRC
		 RS485[6]=CRC_RES%256;				//CRC低位
		 RS485[7]=CRC_RES/256;				//CRC高位
		 RS485_Send_Data(RS485,8);			//发送8个字节读取命令 
		 delay_ms(2000);					//延时一定时间,确保接收完成了
		 RS485_Receive_Data(RS485,&num);	//接收结果写入数组

		 Get_CRC(RS485,num,&CRC_RES);		//接收结果CRC校验

		 if( CRC_RES == 0 ){		//有效数据		
			 	//return 读数;
		 }
		 else{									//无效
			 MyPrintf("CRC校验错误\r\n");
			 return 0xff;				//返回失败
		 }
		 return 0xff;
}



发布了54 篇原创文章 · 获赞 62 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/u013053268/article/details/52049919