基于STM32f103的RS458通信


1. 简介

通常的微处理器都集成有 1 路或多路硬件 UART 通道,可以非常方便地实现串行通讯。在工业控制、电力通讯、智能仪表等领域中,也常常使用简便易用的串行通讯方式作为数据交换的手段。但是,在工业控制等环境中,常会有电气噪声干扰传输线路,使用 RS-232 通讯时经常因外界的电气干扰而导致信号传输错误;另外, RS-232 通讯的最大传输距离在不增加缓冲器的情况下只可以达到 15 米。为了解决上述问题, RS-485/422 通讯方式就应运而生了。

2. RS_485标准

RS-485 标准只对接口的电气特性做出规定,而不涉及接插件、电缆或协议,在此基础上用户可以建立自己的高层通信协议。但由于 PC 上的串行数据通讯是通过 UART 芯片(较老版本的 PC 采用 I8250 芯片或 Z8530 芯片)来处理的,其通讯协议也规定了串行数据单元的格式( 8-N-1 格式): 1 位逻辑 0 的起始位, 6/7/8 位数据位, 1 位可选择的奇(ODD)/偶(EVEN)校验位, 1/2 位逻辑 1 的停止位。基于 PC 的 RS-232、 RS-422 与 RS-485标准均采用同样的通讯协议。

RS-485 标准是为弥补 RS-232 通信距离短、速率低等缺点而产生的。 RS-485 标准只规定了平衡发送器和接收器的电特性,而没有规定接插件、传输电缆和应用层通信协议。RS-485 标准与 RS-232 不一样,数据信号采用差分传输方式(Differential Driver Mode),也称作平衡传输,它使用一对双绞线,将其中一线定义为 A,另一线定义为 B。

通常情况下,发送发送器 A、 B 之间的正电平在+2~+6V,是一个逻辑状态;负电平在-2~-6V,是另一个逻辑状态。另有一个信号地 C。在 RS-485 器件中,一般还有一个“使能”控制信号。 “使能”信号用于控制发送发送器与传输线的切断与连接,当“使能”端起作用时,发送发送器处于高阻状态,称作“第三态”,它是有别于逻辑“ 1”与“ 0”的第三种状态。对于接收发送器,也作出与发送发送器相对的规定,收、发端通过平衡双绞线将 A-A与 B-B 对应相连。当在接收端 A-B 之间有大于+200mV 的电平时,输出为正逻辑电平;小于-200mV 时,输出为负逻辑电平。在接收发送器的接收平衡线上,电平范围通常在 200mV至 6V 之间。

定义逻辑 1(正逻辑电平)为 A>B 的状态,逻辑 0(负逻辑电平)为 B>A 的状态,A、 B 之间的压差不小于 200mV。

3. 连接方式

它可以由一个主机控制多个从机。由于其采用的是半双工方式,通信系统每一端的发送器和接收器,通过收/发开关转换到通信线上,进行方向的切换,因此,会产生时间延迟,而且从机和从机之间要避免同时发送信息,以免数据在总线上互相干扰。

4. 引脚说明



5. 功能分析

(1)发送器

RS485发送器输出是差分输出。空载时输出电压的大小为 0V~+3.3V。即使在差分输出连接了 54Ω负载的条件下,发送器仍可保证输出电压大于 1.5V。 SP3481 和 SP3485 有一根使能控制线(高电平有效)。 DE( Pin3)上的逻辑高电平将使能发送器的差分输出。如果 DE( Pin3)为低,则发送器输出呈现三态。

(2)接收器

RS485接收器的输入是差分输入,输入灵敏度可低至± 200mV。接收器的输入电阻通常为 15kΩ(最小为 12kΩ)。- 7V~+12V 的宽共模方式范围允许系统之间存在大的零电位偏差。 SP3481 和 SP3485 的接收器有一个三态使能控制脚。如果 RE ( Pin2)为低,接收器使能,反之接收器禁止。

6. RS-485 接口电路

微处理器的标准串行口通过 RXD 直接连接 SP485R 芯片的 RO 引脚, 通过 TXD

直接连接 SP485R 芯片的 DI 引脚。

由微处理器输出的 R/D 信号直接控制 SP485R 芯片的发送器/接收器使能: R/D 信号为“ 1”,则 SP485R 芯片的发送器有效,接收器禁止,此时微处理器可以向 RS-485 总线发送数据字节; R/D 信号为“0”,则 SP485R 芯片的发送器禁止,接收器有效,此时微处理器可以接收来自 RS-485 总线的数据字节。此电路中,任一时刻 SP485R 芯片中的“接收器”和“发送器”只能够有 1 个处于工作状态。

在本次实验中所用的开发板485电路图是

RO --RS485_TX – PB10 – USART3_TX – 复用
DI --RS485_RX – PB11 – USART3_RX – 复用
RS485_RE – PC9 – 通用 //RS485_RE是发送器和接收器的开关

程序

在这里我用的是用485与电脑串口连接,实现通信

#include "rs485.h"

void RS485_Config(uint32_t brr)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	USART_InitTypeDef USART_InitStruct;
	//打开时钟  PB PC USART3
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
	//PB10 配置为 复用 推挽 无上下
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;  //推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_Init(GPIOB,&GPIO_InitStruct);	 //GPIO初始化
	//PB11 配置为 浮空输入
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;  //推挽输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
	GPIO_Init(GPIOB,&GPIO_InitStruct);	 //GPIO初始化
	//PC9
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIO_Init(GPIOC,&GPIO_InitStruct);	 //GPIO初始化
	//配置串口
	//232协议  1+8+0+1
	USART_InitStruct.USART_BaudRate = brr;
	USART_InitStruct.USART_Parity =  USART_Parity_No;//禁止奇偶检验
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;//数据位:8位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;//停止位:1位
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//发送,接收使能
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件控制流
	USART_Init(USART3,&USART_InitStruct);
	USART_Cmd(USART3,ENABLE);
	Usart3_RxNVICConfig();
	//配置为接收器
	RS485_RE = RS485_ModeRx;
}

void Usart3_RxNVICConfig(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	//接收中断
	USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);
	NVIC_InitStruct.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //中断通道使能
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;//次级
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//占先
	NVIC_Init(&NVIC_InitStruct);//初始化 NVIC 寄存器
}

void RS485_Echo(void)
{
	u8 ch;
	//配置为接收器
	RS485_RE = RS485_ModeRx;
//	USART3->CR1 &=~ (1<<2);
	//接收数据 -- 判断是否接收到数据
	while(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)!=SET);
	//保存数据
	 ch=USART3->DR;
	//配置发送器
	RS485_RE = RS485_ModeTx;
	//发送数据
	USART3->DR = ch;
	//判断数据是否发送完成
	while(USART_GetFlagStatus(USART3,USART_FLAG_TC)!=SET);//等待发送结束
	
//	u8 da = 0;
//	if((USART3->SR & (1<<5)) != 0)
//	{
//			da = USART3->DR;
//			USART3->CR1 &= ~(1<<2);
//			GPIOC->ODR |=(0x01<<9);//DE 发送器输出使能(高电平有效)
//			__NOP();__NOP();__NOP();__NOP();__NOP();
//			 
//			USART3->DR = da;
//			while((USART3->SR & (1<<6)) == 0);
//			GPIOC->ODR &=~(0x01<<9);//RE 接收器输出使能(低电平有效)
//			__NOP();__NOP();__NOP();__NOP();__NOP();
//			USART3->CR1 |= (1<<2);
//	}
}

void RS485_MoreEcho(void)
{
	u8 ch[5],i=0;
	//配置为接收器
	RS485_RE = 0;
	for(i=0;i<5;i++)
	{
		//接收数据 -- 判断是否接收到数据
		while(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)!=SET);
		//保存数据
		 ch[i]=USART3->DR;
	}
	//配置发送器
	RS485_RE = 1;
	for(i=0;i<5;i++)
	{
		//发送数据
		USART3->DR = ch[i];
		//判断数据是否发送完成
		while(USART_GetFlagStatus(USART3,USART_FLAG_TC)!=SET);//等待发送结束
	}
}