485(一般称作RS485/ELA-485)隶属于OSI模型物理层,是串行通讯的一种。电气特性规定
为2线,半双工,多点通信的类型。它的电气特性和RS-232大不一样。用缆线两端的电压差值
来表示传递信号。RS485仅仅规定了接受端和发送端的电气特性。它没有规定或推荐任何数据
协议。
RS485的特点包括:
1,接口电平低,不易损坏芯片。RS485的电气特性:逻辑“1”以两线间的电压差为+(2-6)V表示;逻辑“0”以两线间的电压差为-(2~6)V表示。接口信号电平比RS232降低了,不易损坏接口电路的芯片,且该电平与TTL电平兼容,可方便与TTL电路连接。
2,传输速率高。10米时,RS485的数据最高传输速率可达35Mbps,在1200m时,传输速度可达100Kbps.
3,
抗干扰能力强。RS485接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强,即抗噪声干扰性好。
4,传输距离远,支持节点多。RS485总线最长可以传输1200m左右,更远的距离则需要中继传输设备支持但这时(速率≤100Kbps)才能稳定传输,一般最大支持32个节点,如果使用特制的485芯片,可以达到128个或者256个节点,最大的可以支持到400个节点。RS485推荐使用在点对点网络中,比如:线型,总线型网络等,而不能是星型,环型网络。理想情况下RS485需要2个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为1202)。没有特性阻抗的话,当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需要双端的电压差。没有终接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致数据传输出错。485推荐的一主多从连接方式如图36.1.1所示:
在上面的连接中,如果需要添加匹配电阻,我们一般在总线的起止端加入,也就是主机和设备4上面各加一个1202的匹配电阻。由于RS485具有传输距离远、传输速度快、支持节点多和抗干扰能力更强等特点,所以RS485有很广泛的应用。实际多设备时收发器有范围为-7V到+12V的共模电压,为了稳定传输,也有使用3线的布线方式,即在原有的A、B两线上多增加一条地线。(4线制使用全双工通讯方式,这种也叫RS422,由于布线的难度和通讯局限,相对使用得比较少)。TP8485E/SP3485可作为RS485的收发器,该芯片支持3.3V~5.5V供电,最大传输速度可达250Kbps,支持多达256个节点(单位负载为1/8的条件下),并且支持输出短路保护。该芯片的框图如图36.1.2所示:
图中
A、 B总线接口,用于连接 485总线。 RO是接收输出端, DI是发送数据收入端, RE是接收使能信号(低电平有效), DE是发送使能信号(高电平有效)。
RS485 通信采用差分信号传输,通常情况下只需要两根信号线就可以进行正常的通信。
在差分信号中,逻辑0和逻辑1是用两根信号线(A+和B-)的电压差来表示。
逻辑 1:两根信号线(A+和B-)的电压差在 +2V~+6V 之间。
逻辑 0:两根信号线(A+和B-)的电压差在 -2V~-6V 之间。
本次实验采用的是STM32F103ZET6芯片
RS484电路为MAX485,具体电路如图所示:
485通讯实质上就是软件层的串口通讯,再加上物理层上的485芯片,将TTL信号转化为查分信号进行传输,对待上就按照串口通讯就行。
编程思想:
DE: 1 发送使能;0发送禁止
RE: 0 接收使能;1接收禁止
通过1#单片机的串口3将数据发送出去,2#单片机进行接受数据,然后通过2#单片机串口1的打印出接收到的数据,
通过2#单片机的串口3将数据发送出去,1#单片机进行接受数据,然后通过1#单片机串口1的打印出接收到的数据
由于是通过485协议发送数据,每次发送前要对485传输方式设置为发送模式,完成后要改为接收模式,由于是半双工,发送完要有一定的延时,确保数据不会丢失;
具体电平转化过程为:
TTL 信号->485信号->485信号0->TTL 信号;
画的板子外部高速晶振有问题,所以采用内部高速晶振
485通讯的方向选择PD7引脚初始化
串口1和3一样,选择异步就可以,传输速率115200,选择中断传输;
test_rs485.c
先初始化为接收模式
/**
* @description: 初始化RS485为接受模式
* @return {*}
*/
void Rs485_Init(void)
{
//使能串口接收中断
HAL_UART_Receive_IT(&huart3, rx_data, 4);
Rs485_RecMode();
}
发送数据
/**
* @description: 控制rs485发送数据
* @param {uint8_t} *data 要发送的数据
* @param {size_t} len 要发送数据的长度
* @return {*} 0 :发送成功;-1:发送失败;
*/
int Rs485_SendData(uint8_t *data, size_t len)
{
HAL_StatusTypeDef status;
Rs485_SendMode();
status = HAL_UART_Transmit(&huart3, data, len, 0xffff);
HAL_Delay(1);
Rs485_RecMode();
return status == HAL_OK ? 0 : -1;
}
发送完成的回调函数,
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart -> Instance == USART3)
{
//将接收到的数据打印出来
printf("rx_data[0] = 0x%02x\r\n", rx_data[0]);
printf("rx_data[1] = 0x%02x\r\n", rx_data[1]);
printf("rx_data[2] = 0x%02x\r\n", rx_data[2]);
printf("rx_data[3] = 0x%02x\r\n", rx_data[3]);
memset(rx_data, 0, 8);//记得添加头文件string.h
//重新使能串口接收中断
HAL_UART_Receive_IT(&huart3, rx_data, 4);
}
}
main.c
串口重定向,记得在main.h中添加头文件stdio.h
/* USER CODE BEGIN 4 */
int fputc(int ch, FILE *P)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return ch;
}
/* USER CODE END 4 */
添加要发送的数组
/* USER CODE BEGIN 1 */
uint8_t data_1[4] = {0x01, 0x02, 0x03, 0x04};
uint8_t data_2[4] = {0x05, 0x06, 0x07, 0x08};
/* USER CODE END 1 */
初始化发送,这里为了方便观察,当给1#下载程序是用TEST1,当给2#下载时,用test2
/* USER CODE BEGIN 2 */
// printf("STM32F103ZET6_Test 1#!\r\n");
printf("STM32F103ZET6_Test 2#!\r\n");
Rs485_Init();
/* USER CODE END 2 */
while (1)
{
// Rs485_SendData(data_1, 4);
Rs485_SendData(data_2, 4);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
实验现象就是,1#单片机发送数据data_1[]到2#,2#接收到data_1[]中的数据
2#单片机发送数据data_2[]到2#,1#接收到data_2[]中的数据。
引用:STM32CubeMX | 37 - 使用RS485总线进行双板通信(SP3485)