我是靠谱客的博主 重要故事,最近开发中收集的这篇文章主要介绍RS485通讯介绍(附批量测试思路)前言,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

做嵌入式开发的无论软件还是硬件,应该经常听见这样一个概念“485协议”,但是呢,去查资料又发现好多人说“485要跑modbus协议”,姑且不论modbus是什么,协议上跑协议,有点晕。到底是怎么回事呢,请往下看。

485通讯标准

485是电气特性规定为2线,半双工,多点通信的的标准,它的电气特性和RS232不太一样,用缆线两端的电压差值来表示传递信号,RS485仅仅规定那个了接收端和发送端的电气特性,它没有规定或推荐任何数据协议(注意这句话:仅仅规定了特性,没规定协议)。
RS485特点:
1.接口电平低,不易损坏芯片,逻辑“1” :VA-VB>+200mv;逻辑“0”:VA-VB<-200mv;|VA-VB|<200mv,总线电平不确定(网上有些资料叙述错误,误人子弟,大家可以网上搜一款485芯片,对照手册来确定逻辑电平和电压差的关系),接口电平比RS232降低了。
2.传输速率高,10 米时, RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输速度可达 100Kbps。
3.抗干扰能力强,RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好。
4.传输距离远,支持节点多, RS485 总线最长可以传输 1200m 以上(速率≤100Kbps)一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点,最大的可以支持到 400 个节点。
注意:
1.485推荐使用在线型,总线型网络,而不能是星型,环形网络(牵扯到信号反射,造成干扰),2.传输距离比较远的情况下RS485需要2个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗120欧姆。(485通讯硬件设计注意事项比较多,稍有不慎就可能对通信造成很大的干扰,要多查资料)
3.具体使用的时候,使用相应的485芯片作为收发器,比如SP3485,max485等
在这里插入图片描述

图1 SP3485芯片框图(管脚定义下面介绍)

modbus协议

去网上搜modbus,关于该协议的介绍可能一大推,其实就一句话:modbus定义了一种数据帧格式:帧头---地址---功能码---数据---CRC校验,注意:协议是一种很灵活的东西,目的是定义数据通讯的格式,上面这个是标准的modbus通讯协议,具体应用的时候可以根据实际需要进行裁剪,比如加个帧尾,比如换成其他的校验方式。

所以,大家现在应该对485和modbus的关系有所认识了吧,我们可以把485总线单纯地理解为硬件通路,它具有自己的电气特性,所有的设备都可以挂在上面,每个设备有唯一的地址,和串口通信不同的是由于485有专门的控制收发引脚,所以代码里面每次发送前后都要对该控制引脚进行控制。此外软件上注意延时(电平稳定);modbus其实可以理解为硬件公路上的车,它本身就是个软件协议,规定上位机和下位机数据以什么样式进行传输。

硬件连接

下面是我用VISIO画的基本框图
在这里插入图片描述
引脚介绍
RX MCU接收管脚
TX MCU发送管脚
IO MCU控制485收发的管脚
RO 属于485芯片的发送管脚
DI 属于485芯片的接收管脚
CTL 是485芯片的控制管脚(实际上是485两个控制管脚接在一起,当IO输出低电平,mcu接收数据,当IO输出高电平,mcu发送数据)

软件编写

在这里插入图片描述
我们做了一个485批量测试软件,测试板上放了16个mcu,通过485协议,PC端读取每个模组的测试数据,基本思路如下
1.通过测试板硬件,固定测试板每个模组的地址,然后由mcu去读各自的Address

#define RS485_TX_EN		PAout(8)	//485收发控制.0,接收;1,发送.
uint8_t Address[5];                            //由4个IO口读取电平,拼成一个address
uint8_t RS485_address;                   //存放模组真正地址
void Get_Address()                         //获取模组地址
{
	 //D4    PA10
	 //D3    PA0
	 //D2    PA1
	 //D1    PA2  
	 //D0    PA3 
  GPIO_InitTypeDef  GPIO_InitStructure;     
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  Address[0] = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
  Address[1] = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
  Address[2] = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
  Address[3] = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0);
  Address[4] = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_9);    //最开始是25的模组测试板,16个可取消这个IO口
  RS485_address =  ((~Address[4])&0x01)<<4 | Address[3]<<3 | Address[2]<<2 | Address[1]<<1 | Address[0];

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;        //将PA8配置成收发控制管脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  RS485_TX_EN = 0;                                 //默认为收
}

2.配置串口接收中断
将模组配置成串口中断模式,接收PC端发的指令,然后在中断中执行一些操作,将数据上传到PC
基本协议如下

PC指令
0x19 0x20 address  0x69
0x19 0x20 address  0x89
注:完整指令一共四个字节0x19 0x20是帧头   address是模组的地址,0x69和0x89都是功能码对应不同的操作

3.串口中断函数

uint8_t gRxbuf[4] = {0}; //define the array to store received data
void USART1_IRQHandler(void)
{  
	 uint8_t k,data = 0;
	 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	 {
	     data = USART_ReceiveData(USART1);
		 if(data == 0x19)
			 gRxbuf[0] = data;  
		 else if(data == 0x20)
		     gRxbuf[1] = data;
         else if(data < 0x19)
 		     gRxbuf[2] = data;
		 else if(data > 0x20)
			 gRxbuf[3] = data;
			 
	     if(gRxbuf[3] != 0)  //当此判断条件成立时,表示接收到一条完整的指令
			 {
					if ((gRxbuf[0] == 0x19)&&(gRxbuf[1] == 0x20)&&(gRxbuf[2] == RS485_address)) //确保指令正确性
					{			
						 if(0x69 == gRxbuf[3])   //对应当功能码为0x69时执行的操作
						 {
						      /***************其余操作*********************************/
						      RS485_TX_EN = 1;       //给485控制管脚高电平,发送数据
							  delay_ms(1);                 //延时1ms等485切换控制管脚的电平稳定
								
							    /***************发送操作*******************/
							  delay_ms(1);                 //延时1ms等485切换控制管脚的电平稳定
							  RS485_TX_EN = 0;
   
							  gRxbuf[0] = 0;              //处理完毕将存储指令的数组清空复位      
						      gRxbuf[1] = 0;
							  gRxbuf[2] = 0;
							  gRxbuf[3] = 0;
						 }	
						 
						 if(0x89 == gRxbuf[3])   //对应当功能码为0x89时执行的操作
						 {
							   
							 /***************其余操作*********************************/
						      RS485_TX_EN = 1;
							  delay_ms(1);
								
							    /***************发送操作*******************/
							  delay_ms(5);
							  RS485_TX_EN = 0;

							  gRxbuf[0] = 0;
						      gRxbuf[1] = 0;
							  gRxbuf[2] = 0;
							  gRxbuf[3] = 0;
						 }	       	 
					}
					else              //当功能码既不是0x69也不是0x89时,不做任何操作
					{
					     gRxbuf[0] = 0;
						 gRxbuf[1] = 0;
						 gRxbuf[2] = 0;
						 gRxbuf[3] = 0;
					} 
			 }
	 }
}

此处说一下地址的作用:比如PC向总线发了一个测试指令0x19 0x20 0x00 0x69,485总线上的所有设备都可以收到这四个字节,然后通过软件编写,485设备会将接收到的指令的地址码即0x00和它们自己的地址做比较,当一样时知道是发给自己的,当不一样时不做任何回应,从而实现访问485总线的多点通信。

最后

以上就是重要故事为你收集整理的RS485通讯介绍(附批量测试思路)前言的全部内容,希望文章能够帮你解决RS485通讯介绍(附批量测试思路)前言所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(65)

评论列表共有 0 条评论

立即
投稿
返回
顶部