485 实验

485(一般称作 RS485/EIA-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 个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为 120 Ω)。没有特性阻抗的话,当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需 要双端的电压差。没有终接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致 数据传输出错。485 推荐的一主多从连接方式如图 36.1.1 所示:

在上面的连接中,如果需要添加匹配电阻,我们一般在总线的起止端加入,也就是主机和 设备 4 上面各加一个 120Ω的匹配电阻。

由于 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.h

#ifndef __RS485_H
#define __RS485_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/
/* RS485 引脚 和 串口 定义 */
#define RS485_RE_GPIO_PORT                  GPIOD
#define RS485_RE_GPIO_PIN                   GPIO_PIN_7
#define RS485_RE_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* PD口时钟使能 */#define RS485_TX_GPIO_PORT                  GPIOA
#define RS485_TX_GPIO_PIN                   GPIO_PIN_2
#define RS485_TX_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */#define RS485_RX_GPIO_PORT                  GPIOA
#define RS485_RX_GPIO_PIN                   GPIO_PIN_3
#define RS485_RX_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)   /* PA口时钟使能 */#define RS485_UX                            USART2
#define RS485_UX_IRQn                       USART2_IRQn
#define RS485_UX_IRQHandler                 USART2_IRQHandler
#define RS485_UX_CLK_ENABLE()               do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0)  /* USART2 时钟使能 *//******************************************************************************************//* 控制RS485_RE脚, 控制RS485发送/接收状态* RS485_RE = 0, 进入接收模式* RS485_RE = 1, 进入发送模式*/
#define RS485_RE(x)   do{ x ? \HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_RESET); \}while(0)#define RS485_REC_LEN               64          /* 定义最大接收字节数 64 */
#define RS485_EN_RX                 1           /* 使能(1)/禁止(0)RS485接收 */extern uint8_t g_RS485_rx_buf[RS485_REC_LEN];   /* 接收缓冲,最大RS485_REC_LEN个字节 */
extern uint8_t g_RS485_rx_cnt;                  /* 接收数据长度 */void rs485_init( uint32_t baudrate);  /* RS485初始化 */
void rs485_send_data(uint8_t *buf, uint8_t len);    /* RS485发送数据 */
void rs485_receive_data(uint8_t *buf, uint8_t *len);/* RS485接收数据 */#endif

rs485.c 

#include "./BSP/RS485/rs485.h"
#include "./SYSTEM/delay/delay.h"UART_HandleTypeDef g_rs458_handler;     /* RS485控制句柄(串口) */#ifdef RS485_EN_RX /* 如果使能了接收 */uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节. */
uint8_t g_RS485_rx_cnt = 0;            /* 接收到的数据长度 */void RS485_UX_IRQHandler(void)
{uint8_t res;if ((__HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */{HAL_UART_Receive(&g_rs458_handler, &res, 1, 1000);if (g_RS485_rx_cnt < RS485_REC_LEN)         /* 缓冲区未满 */{g_RS485_rx_buf[g_RS485_rx_cnt] = res;   /* 记录接收到的值 */g_RS485_rx_cnt++;                       /* 接收数据增加1 */}}
}#endif/*** @brief       RS485初始化函数*   @note      该函数主要是初始化串口* @param       baudrate: 波特率, 根据自己需要设置波特率值* @retval      无*/
void rs485_init(uint32_t baudrate)
{/* IO 及 时钟配置 */RS485_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_RE 脚时钟 */RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */RS485_UX_CLK_ENABLE();      /* 使能 串口 时钟 */GPIO_InitTypeDef gpio_initure;gpio_initure.Pin = RS485_TX_GPIO_PIN;gpio_initure.Mode = GPIO_MODE_AF_PP;gpio_initure.Pull = GPIO_PULLUP;gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_initure); /* 串口TX 脚 模式设置 */gpio_initure.Pin = RS485_RX_GPIO_PIN;gpio_initure.Mode = GPIO_MODE_AF_INPUT;HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_initure); /* 串口RX 脚 必须设置成输入模式 */gpio_initure.Pin = RS485_RE_GPIO_PIN;gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;gpio_initure.Pull = GPIO_PULLUP;gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(RS485_RE_GPIO_PORT, &gpio_initure); /* RS485_RE 脚 模式设置 *//* USART 初始化设置 */g_rs458_handler.Instance = RS485_UX;                  /* 选择485对应的串口 */g_rs458_handler.Init.BaudRate = baudrate;             /* 波特率 */g_rs458_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */g_rs458_handler.Init.StopBits = UART_STOPBITS_1;      /* 一个停止位 */g_rs458_handler.Init.Parity = UART_PARITY_NONE;       /* 无奇偶校验位 */g_rs458_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */g_rs458_handler.Init.Mode = UART_MODE_TX_RX;          /* 收发模式 */HAL_UART_Init(&g_rs458_handler);                      /* HAL_UART_Init()会使能UART2 */#if RS485_EN_RX /* 如果使能了接收 *//* 使能接收中断 */__HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_RXNE); /* 开启接收中断 */HAL_NVIC_EnableIRQ(RS485_UX_IRQn);                    /* 使能USART2中断 */HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3);            /* 抢占优先级3,子优先级3 */
#endifRS485_RE(0); /* 默认为接收模式 */
}/*** @brief       RS485发送len个字节* @param       buf     : 发送区首地址* @param       len     : 发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)* @retval      无*/
void rs485_send_data(uint8_t *buf, uint8_t len)
{RS485_RE(1);                                         /* 进入发送模式 */HAL_UART_Transmit(&g_rs458_handler, buf, len, 1000); /* 串口2发送数据 */g_RS485_rx_cnt = 0;RS485_RE(0); /* 进入接收模式 */
}/*** @brief       RS485查询接收到的数据* @param       buf     : 接收缓冲区首地址* @param       len     : 接收到的数据长度*   @arg               0   , 表示没有接收到任何数据*   @arg               其他, 表示接收到的数据长度* @retval      无*/
void rs485_receive_data(uint8_t *buf, uint8_t *len)
{uint8_t rxlen = g_RS485_rx_cnt;uint8_t i = 0;*len = 0;     /* 默认为0 */delay_ms(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */if (rxlen == g_RS485_rx_cnt && rxlen) /* 接收到了数据,且接收完成了 */{for (i = 0; i < rxlen; i++){buf[i] = g_RS485_rx_buf[i];}*len = g_RS485_rx_cnt; /* 记录本次数据长度 */g_RS485_rx_cnt = 0;    /* 清零 */}
}

main.c 

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/RS485/rs485.h"int main(void)
{uint8_t key;uint8_t i = 0, t = 0;uint8_t cnt = 0;uint8_t rs485buf[5];HAL_Init();                                 /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */delay_init(72);                             /* 延时初始化 */usart_init(115200);                         /* 串口初始化为115200 */led_init();                                 /* 初始化LED */lcd_init();                                 /* 初始化LCD */key_init();                                 /* 初始化按键 */rs485_init(9600);                           /* 初始化RS485 */lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);lcd_show_string(30,  70, 200, 16, 16, "RS485 TEST", RED);lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);lcd_show_string(30, 110, 200, 16, 16, "KEY0:Send", RED);    /* 显示提示信息 */lcd_show_string(30, 130, 200, 16, 16, "Count:", RED);       /* 显示当前计数值 */lcd_show_string(30, 150, 200, 16, 16, "Send Data:", RED);   /* 提示发送的数据 */lcd_show_string(30, 190, 200, 16, 16, "Receive Data:", RED);/* 提示接收到的数据 */while (1){key = key_scan(0);if (key == KEY0_PRES)   /* KEY0按下,发送一次数据 */{for (i = 0; i < 5; i++){rs485buf[i] = cnt + i;      /* 填充发送缓冲区 */lcd_show_xnum(30 + i * 32, 170, rs485buf[i], 3, 16, 0X80, BLUE);    /* 显示数据 */}rs485_send_data(rs485buf, 5);   /* 发送5个字节 */}rs485_receive_data(rs485buf, &key);if (key)    /* 接收到有数据 */{if (key > 5)key = 5;    /* 最大是5个数据. */for (i = 0; i < key; i++){lcd_show_xnum(30 + i * 32, 210, rs485buf[i], 3, 16, 0X80, BLUE);    /* 显示数据 */}}t++;delay_ms(10);if (t == 20){LED0_TOGGLE();  /* LED0闪烁, 提示系统正在运行 */t = 0;cnt++;lcd_show_xnum(30 + 48, 130, cnt, 3, 16, 0X80, BLUE);    /* 显示数据 */}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/161728.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python趣味编程-5分钟实现一个太空大战游戏(含源码、步骤讲解)

飞机战争游戏系统项目是使用Python编程语言开发的,是一个简单的桌面应用程序。 Python 中的飞机战争游戏使用pygame导入和随机导入。 Pygame 是一组跨平台的 Python 模块,专为编写视频游戏而设计。它包括设计用于 Python 编程语言的计算机图形和声音库。

【word技巧】Word制作试卷,ABCD选项如何对齐?

使用word文件制作试卷&#xff0c;如何将ABCD选项全部设置对齐&#xff1f;除了一直按空格或者Tab键以外&#xff0c;还有其他方法吗&#xff1f;今天分享如何将ABCD选项对齐。 首先&#xff0c;我们打开【替换和查找】&#xff0c;在查找内容输入空格&#xff0c;然后点击全部…

结构体打印

打印输出 通过注解来派生Debug trait&#xff0c;才可以通过println!进行打印。默认的占位符是{}&#xff0c;底层是按照std::fmt::Display具体实现进行格式化输出。 {}、{:?}、{#?}是格式化的几种形式&#xff0c;{#?}是更加易读的JSON话格式。 方法 结构体声明方法&…

【应用前沿】索托斯平台:个性化推荐变身SaaS 服务

随着互联网技术和人工智能的迅速发展&#xff0c;面对海量的数据和资源&#xff0c;如何快速准确地为每个用户提供其感兴趣的内容&#xff0c;成为我们亟待解决的问题。个性化推荐系统正是为了解决这一问题而诞生的&#xff0c;它能够通过对用户行为的分析和挖掘&#xff0c;为…

5-6求1-20的阶乘和

#include<stdio.h> //求阶乘 int main(){int n;double sum0;//求和&#xff1a;一点一点加int t1;for (n1;n<15;n){tt*n;sumsumt;}printf("结果是&#xff1a;%22.15e \n",sum);return 0; }为啥最后是%22.15e呢&#xff1f; 因为这个求和的结果太大了 所以转…

【VScode】安装配置、插件及远程SSH连接

一、VSCode安装 二、配置安装插件 三、配置远程连接SSH 四、MinGW 一、VSCode安装 VS官网 Visual Studio Code - Code Editing. Redefined下载安装包&#xff1a; 二、配置安装插件 安装中文插件 配置字体为20 配置文件–>首选项->设置->Font Size为20 设置 VSC…

【libGDX】使用Mesh绘制圆形

1 前言 使用Mesh绘制三角形 中介绍了绘制三角形的方法&#xff0c;使用Mesh绘制矩形 中介绍了绘制矩形的方法&#xff0c;本文将介绍绘制圆形的方法。 libGDX 以点、线段、三角形为图元&#xff0c;没有提供绘制圆形的接口。要绘制圆形边框&#xff0c;必须通过割圆法逼近圆形&…

【中间件】服务化中间件理论intro

中间件middleware 内容管理 intro服务化middleware架构注册中心intro服务治理系统intro 本文主要intro服务化中间件的探讨 去年cfeng写了一篇博客走马观花般阐述了Spring Cloud下面的各种中间件&#xff0c;连深入使用都谈不上&#xff0c;只能说intro&#xff0c;在实际work中…

数字孪生助力污水处理升级

随着科技的发展&#xff0c;数字孪生技术在各行各业中得到了广泛应用。在污水处理领域&#xff0c;数字孪生技术为流程监控、效率提升、问题诊断等提供了强有力的支持。本文就借用山海鲸可视化软件的污水处理解决方案为大家介绍数字孪生在污水处理领域的作用。 一、实时监控 …

VsCode学习

一、在VsCode 上编写第一个C语言 在VsCode上写代码都是先打开文件夹&#xff0c;这样也方便管理代码和编译器产生的可执行程序&#xff0c;VsCode生成的配置文件等。 1.1打开文件夹 写代码前&#xff0c;首先创立一个文件夹存储以后我们写的VsCode代码&#xff0c;便于管理。…

SpringBoot:kaptcha生成验证码

GitHub项目地址&#xff1a;GitHub - penggle/kaptcha: kaptcha - A kaptcha generation engine. kaptcha介绍 kaptcha官网&#xff08;Google Code Archive - Long-term storage for Google Code Project Hosting.&#xff09;对其介绍如下&#xff0c; kaptcha十分易于安装…

linux CentOS7.6安装jenkins(小白版本)

前言 本人是一个前端开发者&#xff0c;由于有时候需要发版自己的东西&#xff0c;所以想搞一个Jenkins玩玩&#xff0c;看了网上好多教程&#xff0c;但是都不是针对小白的&#xff0c;比如linux怎么输入&#xff0c;怎么结束&#xff0c;自己也是搞了好久踩了好多坑 所以记录…

filebeat配置解析【待续】

目录 filebeat概览filebeat是如何工作的工作原理采集日志注册表发送日志 容器日志采集的三种方式方式一&#xff1a;Filebeat 与 应用运行在同一容器&#xff08;不推荐&#xff09;方式二&#xff1a;Filebeat 与 应用运行不在同一容器方式三&#xff1a;通过 Kubernetes File…

oracle “ORA-25153:临时表空间为空”

从生产上面备份出来了一个数据库&#xff0c;应用在使用时显示ORA-25153临时表空间为空的报错&#xff0c;原因一般是数据库迁移时&#xff0c;没有迁移完整造成的 解决方法 1.创建新的临时表空间temp2 create temporary tablespace temp2 tempfile DATA size 100M autoexten…

【Python百题】--1.输出Hello,world【2023.11.22】

1.问题描述 编写一个Python程序&#xff0c;将字符串 ‘Hello World!’ 存储在变量 str 中&#xff0c;然后使用 print 语句将其打印出来。 2.解决思路 使用print()函数即可 3.代码实现 print("Hello,world")4.运行结果

系统移植-交叉编译工具链

不同架构的机器码 与 汇编语言 都不可移植&#xff0c; 且二者一一对应 c语言中三种成分&#xff1a; 1.分号结尾的叫做语句 语句可以让CPU执行&#xff0c;可以进行预处理&#xff0c;编译等生成机器码 2.#开头的为预处理指令 不带分号 CPU无法执行 3.注释&#xff0c;…

vue中列表渲染

列表渲染 实际开发中&#xff0c;使用每条数据的唯一标识作为key,也就是对于数组列表&#xff0c;对象中的属性如&#xff1a;id、手机号、身份证号、学号等唯一值&#xff0c;对象列表同理 只要不对列表的逆序添加&#xff0c;逆序删除等破坏顺序的操作&#xff0c;仅用于渲染…

Mysql 递归查询子类Id的所有父类Id

文章目录 问题描述先看结果表结构展示实现递归查询集合查询结果修复数据 问题描述 最近开发过程中遇到一个问题,每次添加代理关系都要去递归查询一下它在不在这个代理关系树上.很麻烦也很浪费资源.想着把代理关系的父类全部存起来 先看结果 表结构展示 表名(t_agent_user_rela…

Android 10.0 mtp模式下连接PC后只显示指定文件夹功能实现

1. 前言 在android10.0的系统定制化开发中,对于usb作为otg连接电脑时,在mtp模式下会作为一个存储器在电脑端显示,作为电脑的 一个盘符,来显示设备的内部存储的文件,所以说如果要对设备内部的资料做保密处理的时候,需要在mtp模式下不显示某些 文件夹,接下来就分析下相关…

【算法萌新闯力扣】:两句话中的不常见单词

力扣热题&#xff1a;两句话中的不常见单词 开篇 今天是备战蓝桥杯的第19天&#xff0c;今天到目前刷了4道力扣算法题。其中&#xff0c;这道题是对我来说收获最大的一道&#xff0c;让我更熟练地掌握了一些算法题中方法&#xff0c;于是来与大家分享一下。 题目链接: 884.两…