一、RS-232
RS-232是一种常见的串行通信接口标准,用于在计算机和外部设备之间传输数据。
1.历史背景与发展
1.1.起源与发展
RS-232(Recommended Standard 232)最初由美国电子工业协会(EIA)制定,旨在定义计算机和调制解调器之间的数据通信标准。
随着时间的推移,RS-232标准也被用于许多其他类型的串行通信设备,包括打印机、显示器、仪器设备等。
1.2标准的演变
RS-232标准最初发布于1960年代末和1970年代初,经历了几个修订和扩展版本。
目前较为常见的版本是RS-232C,后续还有RS-232D、RS-232E等。
2.物理连接和电气特性
2.1物理接口
RS-232通常使用9针或25针D型连接器,用于连接计算机和外部设备。
9针连接器包含数据引脚、控制引脚和地线,而25针连接器添加了更多的控制引脚和保留引脚。
2.2电气特性
RS-232使用单端(单极性)信号传输,典型的工作电压为±12V,表示逻辑1和逻辑0。
逻辑1一般对应于负电平(-12V),逻辑0对应于正电平(+12V)。
3.数据传输格式和控制
3.1数据格式
RS-232传输的数据是串行的,通常以ASCII码形式传输。
数据位可以是5位、6位、7位或8位,通常还包括校验位和停止位。
3.2控制信号
RS-232定义了几种控制信号(如RTS、CTS、DTR、DSR、RI、CD等),用于设备之间的流量控制和状态指示。
4.优劣
4.1优点
- 广泛应用:RS-232曾经是计算机和外围设备之间最常见的通信标准,因此具有广泛的应用基础和兼容性。
- 简单易实现:RS-232使用简单的单端信号传输,易于实现和调试,适合一些简单和稳定的数据传输需求。
- 跨平台性:RS-232通常不依赖特定的操作系统或硬件平台,使得它在不同系统之间的兼容性较好。
- 稳定性:RS-232在短距离和适当的环境下能够提供稳定的数据传输,对一些应用场景依然具有良好的可靠性。
4.2缺点
- 传输速率有限:RS-232的传输速率相比现代通信标准如USB和以太网较低,不适合大量数据的高速传输需求。
- 信号传输距离短:RS-232信号在长距离传输时容易受到衰减和干扰影响,需要额外的信号放大或者抗干扰措施。
- 大型连接器:传统的RS-232连接器(如25针D型连接器)相对于现代接口而言较为笨重,不便于高密度的设备连接。
- 电气标准不统一:尽管RS-232有标准化的接口和信号定义,但在实际使用中,不同厂商或设备可能会有一些不同的实现,导致兼容性问题。
5.引脚定义(以9针D型连接器为例)
5.1数据传输引脚
- TXD (Transmit Data):发送数据。
- RXD (Receive Data):接收数据。
5.2控制引脚
- RTS (Request to Send):请求发送。
- CTS (Clear to Send):允许发送。
5.3数据控制引脚
- DTR (Data Terminal Ready):数据终端就绪。
- DSR (Data Set Ready):数据集就绪。
5.4其他引脚
- GND (Ground):地线,电气信号的参考。
6.应用和使用
6.1应用领域
RS-232曾经广泛用于计算机与外围设备(如调制解调器、打印机、终端)之间的数据通信。
如今,随着USB和以太网等更先进的通信标准的普及,RS-232在PC和主流设备之间的应用逐渐减少。
6.2使用注意事项
RS-232的实现对传输线路的品质有一定的要求,特别是在较长距离或高速传输时,可能需要考虑信号的衰减和干扰问题。
在使用RS-232时,通常需要确保设备之间的信号匹配(如波特率、数据位数等)以及正确配置控制信号。
二、RS-485
RS-485是一种用于串行通信的标准,与RS-232类似,但有一些显著的区别和优势。
1.概述与应用
1.1多点通信
RS-485支持多点通信,允许多个发送器和接收器同时连接在同一条总线上,适用于工业控制和数据采集系统等需要长距离传输和抗干扰能力的场景。
1.2半双工和全双工
RS-485可以实现半双工或全双工通信。在半双工模式下,数据传输是双向交替进行的;在全双工模式下,可以同时进行双向数据传输。
1.3通信距离:
RS-485支持长距离通信,可以覆盖数千英尺(几百米)的距离,这使其在工业控制系统中具有重要应用。
2.物理连接和电气特性
2.1连接器
RS-485通常使用方便的端子连接器或RJ45连接器,便于在现代化的工业环境中使用。
2.2电气特性
RS-485使用差分信号传输,即每个数据线上的信号相互对立。这种差分信号可以有效抵消电磁干扰(EMI)和其他干扰,提高了数据传输的稳定性和可靠性。
2.3信号电平
典型的RS-485信号电平为±1.5V至±5V,这使得它适合在工业环境中长距离传输数据。
3.数据传输格式和控制
3.1数据格式
RS-485传输的数据通常是以ASCII码或其他编码格式进行的,支持多种数据位和校验位设置。
3.2控制信号
RS-485包含了一些控制信号(如DE、RE),用于控制数据发送和接收,以及通信的开始和结束。
4.优劣
4.1优点
- 适用于长距离通信:RS-485能够在工业环境中传输数据长达几百米,远超过RS-232的传输距离能力。
- 抗干扰能力强:使用差分信号传输,RS-485能够有效抵抗电磁干扰(EMI)和其他外部干扰,提供稳定的通信质量。
- 多点连接:支持多个设备连接在同一总线上,实现灵活的设备布线和数据采集方案。
- 速率和灵活性:RS-485支持较高的数据传输速率,可根据需求进行配置,适用于不同的数据传输要求。
4.2缺点
- 设备实现复杂:RS-485的实现相对复杂,需要考虑信号调理、总线终端和保护电路等因素,以确保可靠的通信。
- 不适用于点对点通信:RS-485虽然支持多点通信,但在一些只需点对点连接的应用中可能显得过于复杂和昂贵。
三、Modbus
Modbus是一种用于工业领域常见的串行通信协议,广泛应用于自动化控制系统中。它由Modicon(现在的施耐德电气)公司在1979年开发,最初用于连接他们的可编程逻辑控制器(PLC)。
1.协议特点
1.1通信方式
Modbus协议是一种主从(Master-Slave)结构的协议。在通信过程中,一个主站(Master)可以同时与多个从站(Slave)进行通信,实现数据的读取和写入操作。
1.2传输介质
Modbus最初是基于串行通信,使用RS-232或RS-485等物理层标准。后来也发展了基于以太网(Modbus TCP/IP)的变种,适应了更快的数据传输速率和广域网络的需求。
1.3数据传输格式
Modbus协议支持不同的数据传输格式,包括ASCII格式和RTU(Remote Terminal Unit)二进制格式。RTU格式是最常见的,因为它在传输效率和通信稳定性方面都有优势。
1.4功能码
Modbus通信的基本单位是功能码(Function Code),用于定义通信的目的和操作类型。常见的功能码包括读取保持寄存器、写入单个寄存器、读取输入状态等,每个功能码对应一种具体的操作。
1.5寄存器
Modbus协议中的数据存储单元称为寄存器(Registers),有不同类型的寄存器用于存储不同种类的数据,如输入寄存器(Input Registers)、保持寄存器(Holding Registers)等。
2.Modbus的应用场景
2.1工业自动化
Modbus最初是为了工业自动化而设计的,广泛用于连接PLC、传感器、执行器等设备,实现控制和数据采集。
2.2能源管理
在能源监控和管理系统中,Modbus被用来收集电能表、能源计量设备等的数据,实现远程监控和控制。
2.3楼宇自动化
在楼宇自动化系统中,Modbus可以连接空调、照明控制、安全系统等设备,实现集中管理和控制。
2.4环境监控
用于环境监测系统中,例如连接气象站、空气质量传感器等设备,实现对环境数据的实时监测。
2.5数据中心
在数据中心中,Modbus被用于监控UPS(不间断电源)、温度传感器等设备,确保设备安全运行并优化能效。
3.Modbus协议的优缺点
3.1优点
- 简单易用,协议规范清晰,容易实现和部署。
- 支持主从结构,适用于复杂的工业控制系统。
- 被广泛支持和应用,有大量的设备和系统兼容Modbus协议。
3.2缺点
- 由于其是基于串行通信设计的,速率较低,不适合大规模数据传输和实时性要求较高的应用。
- 安全性较低,不提供数据加密和身份验证等安全特性。
四、stm32多路超声波测距
1.设计方案
这里假设设定四路超声波。设定4个输入捕获通道,当超声波模块echo收到回波后,即触发输入捕获上升沿,开始echo持续时间的计时,然后下降沿后开始使用公式进行换算,得到距离,通过串口发送出去。其中,着重要考虑以下问题;
- stm32的定时器资源是否足够,同一定时器可以采用多路记录超声波吗
可知stm32一个定时器有几个通道,这些通道可以用来进行输入捕获,此方案也节省了io口资源。但是需要考虑如何设定定时器计数频率,以及如何避免这种情况:假设定时器的重载值为200,echo在180时收到上升沿开始计数,会持续50个计数值,即在下一轮的30得到下降沿,此时如果直接使用减法,会造成负数或者不准确数值的问题。所以为了避免这种情况,需要使用一个变量来判断是否完成了一个计数周期。 - stm32的定时器之间是否会有计数冲突:
在实验检验过程中,单独测试一个通道时记录结果大致准确,但是接入两个模块时,似乎结果发生了干扰,但无法确认是否是定时器问题还是其它问题,后续有待解决。 - 若采用轮询(状态机)方案访问会出现当一个超声波停止工作时,其它超声波也无法正常工作的状态。
2.代码
2.1GPIO定时器初始化
void GPIO_Init(void) {
// 配置Trig引脚为输出,Echo引脚为输入
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2; // Trig1, Trig2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3; // Echo1, Echo2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void Timer_Init(void) {
// 配置定时器用于捕获Echo信号
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 72-1; // 1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
2.2Modbus设计
void USART_Init(void) {
// 配置USART用于RS485通信
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // USART1_TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // USART1_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void Send_Modbus_Response(uint8_t* response, uint8_t length) {
// 发送Modbus响应帧
for (uint8_t i = 0; i < length; i++) {
USART_SendData(USART1, response[i]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
}