当前位置:   article > 正文

串口程序总结(3)-485通信_无效的句柄 485通信 st程序

无效的句柄 485通信 st程序

1.485通信简介

485(一般称作 RS485/EIA-485)隶属于OSI 模型物理层,是串行通讯的一种。

电气特性规定为 2 线,半双工,多点通信的类型。它的电气特性和 RS-232 大不一样。用缆线两端的电压差值来表示传递信号。RS485 仅仅规定了接受端和发送端的电气特性。它没有规定或推荐任何数据协议。

1.1 RS485的特点

1、 接口电平低,不易损坏芯片。RS485 的电气特性:逻辑“1”以两线间的电压差为+(2~6)V 表 示;逻辑“0”以两线间的电压差为-(2~6)V 表示。接口信号电平比 RS232 降低了,不易损坏接口电路的芯片,且该电平与 TTL 电平(3.3V/5V表示逻辑1,0V表示逻辑0)兼容,可方便与 TTL 电路连接。

2、 传输速率高。10 米时,RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输速度 可达 100Kbps。

3、抗干扰能力强。RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力增强, 即抗噪声干扰性好。

4、传输距离远,支持节点多。RS485 总线最长可以传输 1200m 左右,更远的距离则需要中继传输设备支持,但这时(速率≤100Kbps)才能稳定传输,一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点,最大的可以支持到 400 个节点。

1.2 RS485的使用场景

RS485 推荐使用在点对点网络中,比如:线型,总线型网络等,而不能是星型,环型网络。 理想情况下 RS485 需要 2 个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为 120 Ω)。没有特性阻抗的话,当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需要双端的电压差。没有终接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致数据传输出错。485 推荐的一主多从连接方式如图 37.1.1 所示:

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

由于 RS485 具有传输距离远、传输速度快、支持节点多和抗干扰能力更强等特点,所以 RS485有很广泛的应用。实际多设备时收发器有范围为-7V到+12V的共模电压,为了稳定传输, 也有使用 3 线的布线方式,即在原有的 A、B 两线上多增加一条地线。(4 线制只能实现点对点 的全双工通讯方式,这种也叫 RS422,由于布线的难度和通讯局限,相对使用得比较少)。

1.3 RS485的常用转换芯片

 TP8485E/SP3485 可作为 RS485 的收发器,该芯片支持 3.3V~5.5V 供电,最大传输速度可 达 250Kbps,支持多达 256 个节点(单位负载为 1/8 的条件下),并且支持输出短路保护。该芯片图中 A、B 总线接口,用于连接 485 总线。RO 是接收输出端,DI 是发送数据收入端,RE 是接收使能信号(低电平有效),DE 是发送使能信号(高电平有效)。

2. 485通信具体编程及注意事项

2.1 rs485.h

  1. #ifndef __RS485_H
  2. #define __RS485_H
  3. #include "./SYSTEM/sys/sys.h"
  4. /******************************************************************************************/
  5. /* RS485 引脚 和 串口 定义
  6. */
  7. #define RS485_RE_GPIO_PORT GPIOD
  8. #define RS485_RE_GPIO_PIN GPIO_PIN_7
  9. #define RS485_RE_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* PD口时钟使能 */
  10. #define RS485_TX_GPIO_PORT GPIOA
  11. #define RS485_TX_GPIO_PIN GPIO_PIN_2
  12. #define RS485_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
  13. #define RS485_RX_GPIO_PORT GPIOA
  14. #define RS485_RX_GPIO_PIN GPIO_PIN_3
  15. #define RS485_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */
  16. #define RS485_UX USART2
  17. #define RS485_UX_IRQn USART2_IRQn
  18. #define RS485_UX_IRQHandler USART2_IRQHandler
  19. #define RS485_UX_CLK_ENABLE() do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0) /* USART2 时钟使能 */
  20. /******************************************************************************************/
  21. /* 控制RS485_RE脚, 控制RS485发送/接收状态
  22. * RS485_RE = 0, 进入接收模式
  23. * RS485_RE = 1, 进入发送模式
  24. */
  25. #define RS485_RE(x) do{ x ? \
  26. HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_SET) : \
  27. HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_RESET); \
  28. }while(0)
  29. #define RS485_REC_LEN 64 /* 定义最大接收字节数 64 */
  30. #define RS485_EN_RX 1 /* 使能(1)/禁止(0)RS485接收 */
  31. extern uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收缓冲,最大RS485_REC_LEN个字节 */
  32. extern uint8_t g_RS485_rx_cnt; /* 接收数据长度 */
  33. void rs485_init( uint32_t baudrate); /* RS485初始化 */
  34. void rs485_send_data(uint8_t *buf, uint8_t len); /* RS485发送数据 */
  35. void rs485_receive_data(uint8_t *buf, uint8_t *len);/* RS485接收数据 */
  36. #endif

2.2 rs485.c

  1. #include "./BSP/RS485/rs485.h"
  2. #include "./SYSTEM/delay/delay.h"
  3. UART_HandleTypeDef g_rs458_handler; /* RS485控制句柄(串口) */
  4. #ifdef RS485_EN_RX /* 如果使能了接收 */
  5. uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节. */
  6. uint8_t g_RS485_rx_cnt = 0; /* 接收到的数据长度 */
  7. void RS485_UX_IRQHandler(void)
  8. {
  9. uint8_t res;
  10. if ((__HAL_UART_GET_FLAG(&g_rs458_handler, UART_FLAG_RXNE) != RESET)) /* 接收到数据 */
  11. {
  12. HAL_UART_Receive(&g_rs458_handler, &res, 1, 1000);
  13. if (g_RS485_rx_cnt < RS485_REC_LEN) /* 缓冲区未满 */
  14. {
  15. g_RS485_rx_buf[g_RS485_rx_cnt] = res; /* 记录接收到的值 */
  16. g_RS485_rx_cnt++; /* 接收数据增加1 */
  17. }//该全局变量g_RS485_rx_cnt在485查询接收函数中清零
  18. }
  19. }
  20. #endif
  21. /**
  22. * @brief RS485初始化函数
  23. * @note 该函数主要是初始化串口
  24. * @param baudrate: 波特率, 根据自己需要设置波特率值
  25. * @retval 无
  26. */
  27. void rs485_init(uint32_t baudrate)
  28. {
  29. /* IO 及 时钟配置 */
  30. RS485_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_RE 脚时钟 */
  31. RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */
  32. RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */
  33. RS485_UX_CLK_ENABLE(); /* 使能 串口 时钟 */
  34. GPIO_InitTypeDef gpio_initure;
  35. gpio_initure.Pin = RS485_TX_GPIO_PIN;
  36. gpio_initure.Mode = GPIO_MODE_AF_PP;
  37. gpio_initure.Pull = GPIO_PULLUP;
  38. gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
  39. HAL_GPIO_Init(RS485_TX_GPIO_PORT, &gpio_initure); /* 串口TX 脚 模式设置 */
  40. gpio_initure.Pin = RS485_RX_GPIO_PIN;
  41. gpio_initure.Mode = GPIO_MODE_AF_INPUT;
  42. HAL_GPIO_Init(RS485_RX_GPIO_PORT, &gpio_initure); /* 串口RX 脚 必须设置成输入模式 */
  43. gpio_initure.Pin = RS485_RE_GPIO_PIN;
  44. gpio_initure.Mode = GPIO_MODE_OUTPUT_PP;
  45. gpio_initure.Pull = GPIO_PULLUP;
  46. gpio_initure.Speed = GPIO_SPEED_FREQ_HIGH;
  47. HAL_GPIO_Init(RS485_RE_GPIO_PORT, &gpio_initure); /* RS485_RE 脚 模式设置 */
  48. /* USART 初始化设置 */
  49. g_rs458_handler.Instance = RS485_UX; /* 选择485对应的串口 */
  50. g_rs458_handler.Init.BaudRate = baudrate; /* 波特率 */
  51. g_rs458_handler.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
  52. g_rs458_handler.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
  53. g_rs458_handler.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
  54. g_rs458_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
  55. g_rs458_handler.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
  56. HAL_UART_Init(&g_rs458_handler); /* HAL_UART_Init()会使能UART2 */
  57. #if RS485_EN_RX /* 如果使能了接收 */
  58. /* 使能接收中断 */ //接收到一个数据就产生中断
  59. __HAL_UART_ENABLE_IT(&g_rs458_handler, UART_IT_RXNE); /* 开启接收中断 */
  60. HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART2中断 */
  61. HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
  62. #endif
  63. RS485_RE(0); /* 默认为接收模式 */
  64. }
  65. /**
  66. * @brief RS485发送len个字节
  67. * @param buf : 发送区首地址
  68. * @param len : 发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)
  69. * @retval 无
  70. */
  71. /*发送函数用于输出 485 信号到 485 总线上,我的默认的 485 方式一般空闲时为接收状态,
  72. 只有发送数据时我们才控制 485 芯片进入发送状态,发送完成后马上回到空闲接收状态,这样
  73. 可以保证操作过程中 485 的数据丢失最小。我们实现的发送函数如下:*/
  74. void rs485_send_data(uint8_t *buf, uint8_t len)
  75. {
  76. RS485_RE(1); /* 进入发送模式 */
  77. HAL_UART_Transmit(&g_rs458_handler, buf, len, 1000); /* 串口2发送数据 */
  78. g_RS485_rx_cnt = 0;
  79. RS485_RE(0); /* 进入接收模式 */
  80. }
  81. /**
  82. * @brief RS485查询接收到的数据
  83. * @param buf : 接收缓冲区首地址
  84. * @param len : 接收到的数据长度
  85. * @arg 0 , 表示没有接收到任何数据
  86. * @arg 其他, 表示接收到的数据长度
  87. * @retval 无
  88. */
  89. //uint8_t *len:用指针传递接收字节个数,在函数内改变该值可以传递出去
  90. void rs485_receive_data(uint8_t *buf, uint8_t *len)
  91. {
  92. uint8_t rxlen = g_RS485_rx_cnt;
  93. uint8_t i = 0;
  94. *len = 0; /* 默认为0 */
  95. delay_ms(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */
  96. if (rxlen == g_RS485_rx_cnt && rxlen) /* 接收到了数据,且接收完成了 */
  97. {
  98. for (i = 0; i < rxlen; i++)
  99. {
  100. buf[i] = g_RS485_rx_buf[i];
  101. }
  102. *len = g_RS485_rx_cnt; /* 记录本次数据长度 */
  103. g_RS485_rx_cnt = 0; /* 清零 */
  104. }
  105. }

2.3 main.c

  1. #include "./SYSTEM/sys/sys.h"
  2. #include "./SYSTEM/usart/usart.h"
  3. #include "./SYSTEM/delay/delay.h"
  4. #include "./USMART/usmart.h"
  5. #include "./BSP/LED/led.h"
  6. #include "./BSP/LCD/lcd.h"
  7. #include "./BSP/KEY/key.h"
  8. #include "./BSP/RS485/rs485.h"
  9. int main(void)
  10. {
  11. uint8_t key;
  12. uint8_t i = 0, t = 0;
  13. uint8_t cnt = 0;
  14. uint8_t rs485buf[5];
  15. HAL_Init(); /* 初始化HAL库 */
  16. sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  17. delay_init(72); /* 延时初始化 */
  18. usart_init(115200); /* 串口初始化为115200 */
  19. usmart_dev.init(72); /* 初始化USMART */
  20. led_init(); /* 初始化LED */
  21. lcd_init(); /* 初始化LCD */
  22. key_init(); /* 初始化按键 */
  23. rs485_init(9600); /* 初始化RS485 */
  24. lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  25. lcd_show_string(30, 70, 200, 16, 16, "RS485 TEST", RED);
  26. lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  27. lcd_show_string(30, 110, 200, 16, 16, "KEY0:Send", RED); /* 显示提示信息 */
  28. lcd_show_string(30, 130, 200, 16, 16, "Count:", RED); /* 显示当前计数值 */
  29. lcd_show_string(30, 150, 200, 16, 16, "Send Data:", RED); /* 提示发送的数据 */
  30. lcd_show_string(30, 190, 200, 16, 16, "Receive Data:", RED);/* 提示接收到的数据 */
  31. while (1)
  32. {
  33. key = key_scan(0);
  34. if (key == KEY0_PRES) /* KEY0按下,发送一次数据 */
  35. {
  36. for (i = 0; i < 5; i++)
  37. {
  38. rs485buf[i] = cnt + i; /* 填充发送缓冲区 */
  39. lcd_show_xnum(30 + i * 32, 170, rs485buf[i], 3, 16, 0X80, BLUE); /* 显示数据 */
  40. }
  41. rs485_send_data(rs485buf, 5); /* 发送5个字节 */
  42. }
  43. rs485_receive_data(rs485buf, &key);
  44. if (key) /* 接收到有数据 */
  45. {
  46. if (key > 5)key = 5; /* 最大是5个数据. */
  47. for (i = 0; i < key; i++)
  48. {
  49. lcd_show_xnum(30 + i * 32, 210, rs485buf[i], 3, 16, 0X80, BLUE); /* 显示数据 */
  50. }
  51. }
  52. t++;
  53. delay_ms(10);
  54. if (t == 20)
  55. {
  56. LED0_TOGGLE(); /* LED0闪烁, 提示系统正在运行 */
  57. t = 0;
  58. cnt++;
  59. lcd_show_xnum(30 + 48, 130, cnt, 3, 16, 0X80, BLUE); /* 显示数据 */
  60. }
  61. }
  62. }

3. 485通信与232通信的区别

3.1 电平标准简介

首先我们应明确串口是物理接口,它属于硬件;而TTL、RS-232、RS-485是指的电平标准,它们都属于电信号。现在市面上的产品有:USB转TTL/RS-232/RS-485、TTL转RS-232/RS-485、RS-232转RS485

1.TTL也称三极管逻辑,由于在早期的半导体都是双极型晶体管工艺的,因此命名为串口。这种规定只是针对以前那种TTL工艺下的芯片所指定的,由于目前的半导体都为CMOS技术,因此但凡满足CMOS电平的串口也沿用了“TTL串口”这个名称。

2.RS-232接口是属于美国制定的一款比较高端的接口,使用在串行接口外设的连接上。是目前应用在通讯中较为广泛的一种。

3.2 RS-232与RS-485的区别

1.RS-232串口通信接口(全双工

RS-232,有三个接口,RXD、TXD和GND;RS-232通信接口的信号电平值较高,易损坏接口电路芯片;

①RS-232为负逻辑,1:-3~-15V,0:+3~+15V;

RS-232采用TXD和RXD两根线形成共地传输形式,易产生共模干扰

③RS-232传输距离较短,最大传输标准为15m

④RS-232传输速率较低,在异步传输时,波特率为 20Kbps

2.RS-485总线通信接口(半双工

RS-485使用屏蔽双绞线,采用平衡发送和差分接收,可抑制共模干扰

②RS-485通信接口的信号电平值较低,不易损坏接口电路芯片;

③RS-485为正逻辑,即1:2~6V,0:-2~-6V;

④RS-485传输距离较远,最大传输标准为3000m

⑤RS-485 的数据最高传输速率为 10Mbps

若RS-232与RS-485通信,则需通过RS-232/RS-485转换电路进行信号的转换, RS-232是点对点通信,而RS-485可实现多机间通信。

3.3 通信相关知识

1.RJ-45以太网通信接口

RJ-45有两种连接方式,直连线和交叉线。

交叉线是指一端是568A,另一端是568-B。

直连线是指两端都是568-A或两端都是568-B的双绞线。

EIA/TIA-568-A从左到右:白绿、绿、白橙、蓝、白蓝、橙、白棕、棕。

EIA/TIA-568-B从左到右:橙白、橙、绿、白蓝、蓝白、绿、棕白、棕。

2.设备通信方式

①单工通信:只支持数据在一个方向上传输,如无线电广播;

②半双工通信:允许数据在两个方向上传输,但同一时刻数据只能在一个方向上传输,如对讲机、计算机网络的非主干线路;

③全双工通信:允许数据同时在两个方向上传输,如电话。

3.设备传输方向

①并行传输:数据以组的形式,在多条并行信道上同时传输;

②串行传输:构成字符的二进制代码在一条信道上按时间顺序逐位传输;

③同步传输:数据传输的双方时钟同步,传输效率较高,可达2400bit/s以上;

④异步传输:数据传输的双方时钟不同,增加了起、止信号,传输效率较低;

4.设备传输网络

①总线通信传输:利用金属导线、光纤等有形媒介传送信息的方式;

②无线通信传输:利用电磁波信号进行信息交换的通信方式;

③网络通信传输:通过TCP/IP协议利用RJ-45通信接口连接方式进行的通信

5.设备通信协议

①通信协议三要素:语法、语义、定时规则(时序)

②分层网络通信协议(OSI参考模型):

7应用层:给OSI环境的用户提供服务

6表示层:完成数据转换,提供应用接口和通信接口

5 会话层:提供在两个进程间建立、维护和结束会话的手段

4 传输层:在端点间提供可靠的、透明的数据传输

3 网络层:负责路由选择和拥挤控制

2 链路层:将不可靠的传输通道转变为可靠的传输通道

1 物理层:有关在物理链路上传输非结构的比特流

上文来自 <RS-232与RS-485的区别 - 知乎>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/974933?site=
推荐阅读
相关标签
  

闽ICP备14008679号