当前位置:   article > 正文

STM32F103C8T6-RS485通讯完整版_stm32中rs485

stm32中rs485

单片机串口通讯有着许多通讯方式,例如R485/RS232/RS422/TTL/网口等等,在现实生活中RS485通讯是使用频率最高的一种通讯方式,因为485通讯是采用一对多的通讯方法,何为一对多,即一个主机若干个从机,一个负责发数据,其他负者数据的接收;那么那么多数据接收设备不会导致数据混乱吗?答案是肯定会的,在这时就需要用到通讯协议了。

通讯协议一般分为帧头、地址、数据包、帧尾组成;其中帧头一般是2byte,地址1byte,数据包看自己需要自定义字节大小,帧尾1byte;其中帧头是判断整体设备通讯接收数据的正确性,地址是用来区分接收设备的判断,帧尾一般是数据包的校验和,这样帧尾是随着数据的变化而变化,通讯失准确性更加精准。

以上为硬件MAX485通讯芯片连接定义,在本篇当中RXD、TXD我们使用C8T6当中的串口1进行配置(PA9、PA10),其中数据发送时需要把2、3脚拉高,接收数据时需置低;其中PA9需复用推挽输出,PA10浮空输入;

**  1脚和4脚(RO\DI)端分别为接收器的输出和驱动器的输入端

**2脚和3脚(RE/DE)端分别为接收和发送的使能端

** A端和B端分别为接收和发送的差分信号端。

       MAX485芯片的结构和引脚都非常简单,内部含有一个驱动器和接收器。RO和DI端分别为接收器的输出和驱动器的输入端,与单片机连接时只需分别与单片机的RXD和TXD相连即可。RE和DE端分别为接收和发送的使能端,当/RE为逻辑0时,器件处于接收状态;当DE为逻辑1时,器件处于发送状态,因为MAX485工作在半双工状态,所以只需用单片机的一个管脚控制这两个引脚即可。其最主要工作原理就是将RS485信号转成单片机的TTL信号。

以下为485通讯.c文件

  1. #include "stm32f10x.h" // Device header
  2. #include <stdio.h>
  3. #include "Delay.h"
  4. #include <stdarg.h>
  5. #include <Serial.h>
  6. uint8_t Serial_RxPacket[8]; //8个字节
  7. uint8_t Serial_RxFlag; //发送完成的标识符
  8. void Serial_Init(void)
  9. {
  10. GPIO_InitTypeDef GPIO_InitStructure;
  11. USART_InitTypeDef USART_InitStructure;
  12. NVIC_InitTypeDef NVIC_InitStructure;
  13. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA
  14. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1时钟
  15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  16. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //控制数据的接收、发送
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18. GPIO_Init(GPIOA, &GPIO_InitStructure);
  19. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
  20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //485-TX
  21. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22. GPIO_Init(GPIOA, &GPIO_InitStructure);
  23. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  24. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //485-RX
  25. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  26. GPIO_Init(GPIOA, &GPIO_InitStructure);
  27. USART_InitStructure.USART_BaudRate = 9600;
  28. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位
  29. USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位1
  30. USART_InitStructure.USART_Parity = USART_Parity_No ;
  31. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  32. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//模式:接收/发送
  33. USART_Init(USART1, &USART_InitStructure); //初始化USART1
  34. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //接收中断使能
  35. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  36. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  37. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  38. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //分优先级
  39. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  40. NVIC_Init(&NVIC_InitStructure);
  41. USART_Cmd(USART1, ENABLE);
  42. RS485_receive(); //默认打开接收机
  43. }
  44. void Serial_SendByte(uint8_t Byte) //发送单个字节
  45. {
  46. RS485_send(); //开启发送模式,关闭接收模式
  47. USART_SendData(USART1, Byte);
  48. while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
  49. Delay_ms(2);
  50. RS485_receive(); //默认打开接收机
  51. }
  52. void Serial_SendArray(uint8_t *Array, uint16_t Length) //发送数组式字节
  53. {
  54. uint16_t i;
  55. for (i = 0; i < Length; i ++)
  56. {
  57. Serial_SendByte(Array[i]);
  58. }
  59. }
  60. uint8_t Serial_GetRxFlag(void)
  61. {
  62. if (Serial_RxFlag == 1)
  63. {
  64. Serial_RxFlag = 0; //开始标识
  65. return 1;
  66. }
  67. return 0;
  68. }
  69. uint8_t Sum_Check(uint8_t *buf, uint16_t len)
  70. {
  71. uint16_t i = 0;
  72. uint8_t sum_temp = 0;
  73. for (i = 0; i < len; i++)
  74. {
  75. sum_temp += buf[i];
  76. }
  77. return sum_temp;
  78. }
  79. void USART1_IRQHandler(void)
  80. {
  81. static uint8_t RxState = 0;
  82. static uint8_t pRxPacket = 0;
  83. if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //接收数据
  84. {
  85. uint8_t RxData = USART_ReceiveData(USART1); //回传数据赋给RxData
  86. if (RxState == 0)
  87. {
  88. if (RxData == 0xFF) //帧头判断
  89. {
  90. RxState = 1; //帧头无误标志位
  91. pRxPacket = 0;
  92. }
  93. }
  94. else if (RxState == 1)
  95. {
  96. Serial_RxPacket[pRxPacket] = RxData; //RxData分别赋给Serial_RxPacket[0]*Serial_RxPacket[3]
  97. pRxPacket ++;
  98. if (pRxPacket >= 6)
  99. {
  100. RxState = 2; //数据接收完毕标志位
  101. }
  102. }
  103. else if (RxState == 2)
  104. {
  105. uint8_t sum;
  106. sum = Sum_Check((u8*)Serial_RxPacket,6);
  107. if (RxData == sum) //校验和验证
  108. {
  109. Serial_RxFlag = 1; //结束标识
  110. Serial_SendArray(Serial_RxPacket,6);
  111. }
  112. if (RxData != sum) Serial_SendByte(0x00); //发送校验不通过字节
  113. pRxPacket = 0; RxState = 0; //pRxPacket、RxState重新赋值方便下次接收数据
  114. }
  115. USART_ClearITPendingBit(USART1, USART_IT_RXNE);
  116. }
  117. }

.h文件

  1. #ifndef __SERIAL_H
  2. #define __SERIAL_H
  3. #include "stm32f10x.h"
  4. #define RS485_send() GPIO_SetBits(GPIOA,GPIO_Pin_11); //发送使能
  5. #define RS485_receive() GPIO_ResetBits(GPIOA,GPIO_Pin_11); //接收使能
  6. extern uint8_t Serial_RxPacket[]; //extern 数组 方便数据调用
  7. void Serial_Init(void);
  8. void Serial_SendByte(uint8_t Byte);
  9. void Serial_SendArray(uint8_t *Array, uint16_t Length);
  10. void USART2_IRQHandler(void);
  11. #endif

main函数

  1. #include "stm32f10x.h" // Device header
  2. #include "Delay.h"
  3. #include "OLED.h" //可以打印出来数据
  4. #include "Serial.h"
  5. #include "Key.h" //可以通过按键来发射数据
  6. uint8_t KeyNum;
  7. int main(void)
  8. {
  9. OLED_Init();
  10. Key_Init();
  11. Serial_Init(); //串口初始化
  12. Serial_SendByte(0XAA); //上电初始化发送AA 表示设备通讯正常
  13. while (1)
  14. {
  15. KeyNum = Key_GetNum();
  16. }
  17. }

以上为通讯全部代码,代码经过博主验证,通讯正常无异;

下图为数据测试截图,测试在100ms/次的发送频率下用通讯全部正常,无异常;

程序设计:

1.帧头正确校验码不对接收数据0x00;

2..帧头不对无回应;

3.帧头正确校验码正确回应接收数据;

如要源码程序包可私信博主

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

闽ICP备14008679号