
串口通信的文章https://blog.csdn.net/m0_74739916/article/details/136605806?spm1011.2415.3001.5331https://blog.csdn.net/m0_74739916/article/details/136605806?spm1011.2415.3001.5331RS232和RS485它并不是说像串口或者像IIC那样,是一个单独的协议。这两种协议它只是一个电气层物理层的协议做了一些变化他们的编程的时候还是依赖与串口的他们只是在电器的层面做了处理。UART存在的问题UART 只是对信号的时序进行了定义而未定义接口的电气特性eg:单片机的串口通信他只说了高电平是1低电平是0。对于高电平和低电平是几伏并没有提到UART 通信时一般直接使用处理器使用的电平即 TTL 电平但不同的处理器使用的电平存在差异所以不同的处理器使用 UART 通信时一般不能直接相连UART 没有规定不同器件连接时连接器的标准所以不同器件之间通过 UART 通信时连接很不方便抗干扰能力差TTL信号抗干扰能力差容易出错通信距离短一般只用用在一个电路板上两个芯片通信电平类型逻辑 1 电压逻辑 0 电压相关 MCU 示例RS-232 电平-15V ~ -3V3V ~ 15V电平范围不是电压差无COMS 电平3.3V3.3V0VSTM32(发送和接收的是COMS电平)TTL 电平5V5V0V51 单片机发送和接收的是TTL电平他们之间通信不能直接连接需要连接电平转化芯片RS232协议RS232协议是在1970年由美国电子工业协会(EIA)联合贝尔系统、调解调器厂家、计算机终端生产厂家共同制定的用于串行通讯的标准该标准规定采用一个标准的连接器,标准中对连接器的每个引脚的作用加以规定还对信号的电平加以规定:接口该标准规定采用一个25引脚的DB-25连接器标准中对连接器的每个引脚的信号内容加以规定)还对各种信号的电平加以规定;后来1BM的PC机将RS232简化成了DB-9连接器后来成为事实标准;现在工业控制的RS-232接口一般只使用RXD、TXD、GND三条线;■信号该标准规定逻辑“1”的电平为-3v到-15v逻辑“0”的电平为3v到15v选用该电气标准的目的在于提高抗干扰能力增大通信距离:其传送距离一般可达15m;全双工 串行 异步:编程跟UART一样接口:9线制但是真正用的一般来说只有三根线:TX、RX、GND信号:逻辑“1“高电平为-3V ~ -15V 、逻辑“0”低电平为 3V到15V电平范围不是电压差RS232存在的问题接口的信号电平值较高易损坏接口电路的芯片又因为与TTL电平不兼容所以需要使用电平转换芯片才能与TTL电路连接接口信号电平高、容易烧坏接口、要加电平转化芯片 成本高通信速度较低易产生共模干扰抗噪声干扰性弱传输距离较短(15m)只可以点对点和UART一样232其实和串口是一样的不过电压不一样需要芯片转换电压。RS485协议RS485是串行通信标准使用差分信号传输抗干扰能力强常用于工控领域RS485具有强大的组网功能在串口基础协议之上还制定MODBUS协议。串口基础协议:仅指封装了基本数据包格式的协议(基于数据位)MODBUS协议:使用基本数据包组合成通讯帧格式的高层应用协议基于数据包或字节半双工 串行 异步:注意写程序跟RS232、UART串口不一样、 RS485发送就不能接收。接口:两线制 485、485-可以有多个设备 只要地址不同 一般都是modbus协议什么的 你知道的信号:差分信号:两线电压差 逻辑“1高电平电压差为 2V到6V、逻辑“0”低电平电压差为 -2V到-6V该标准由电信行业协会和电子工业联盟定义;使用该标准的通信网络能在远距离条件下以及电子噪声大的环境下有效传输信号。该标准允许连接多个收发器即具有多站能力这样可以利用单一的RS485接口方便地建立起一个设备网络该标准由电信行业协会和电子工业联盟定义;使用该标准的通信网络能在远距离条件下以及电子噪声大的环境下有效传输信号。该标准允许连接多个收发器即具有多站能力这样可以利用单一的RS485接口方便地建立起一个设备网络信号RS485标准规定采用差分信号进行数据传输两线间的电压差为2v到6v表示逻辑“1”两线间的电压差为-2v到-6v表示逻辑“0”;使用差分信号能有效地减少噪声信号的干扰延长通信距离RS485的通信距离可以达到1500m;RS485接口信号的电平比RS232降低了所以不易损坏接口电路的芯片且该电平与TTL电平兼容可方便地与TTL电路连接接口RS485采用两线制这种接线方式为总线式拓扑结构在同一总线上可以同时存在多个节点:因为采用两线制数据的发送和接收都要使用这对差分信号线发送和接收不能同时进行所以只能采用半双工的方式工作编程时也需要加以处理电平转换虽然很多处理器中都会集成UART控制器但处理器产生的信号一般都是TTL信号并不是符合RS485标准的信号所以一般我们还需要在处理器外部去添加电路将TTL信号转换成差分信号;虽然很多处理器中都会集成UART控制器但处理器产生的信号一般都是TTL信号并不是符合RS485标准的信号所以一般我们还需要在处理器外部去添加电路将TTL信号转换成差分信号MAX485RS485的优势接口的信号电平值较低不易损坏接口电路的芯片且与TTL电平兼容可方便地与TTL电路连接通信速度快抗噪声干扰性强传输距离较远(1500m)可实现多节点组网匹配电阻确保RS485总线的稳定性抑制噪声。电平转换芯片SP3485 TP8485E MAX485通信接口通信方式信号线电平标准拓扑结构通信距离通讯速率抗干扰能力TTL全双工TX/RX/GND逻辑 12.4~5V逻辑 00~0.4V点对点1 米100kbps弱RS232全双工TX/RX/GND逻辑 1-15~-3V逻辑 03~15V点对点100 米20kbps较弱RS485半双工差分线 AB逻辑 12~6V(2线之间的电压差)逻辑 0-2~-6V(2线之间的电压差)多点双向1200 米100kbps强一般来说我们使用的是2线制的----》半双工 4线制的----》全双工MODBUS协议RS485和Modbus关系Modbus是一种软件协议支持RS232、RS485、TCP/IP等多种电气接口Modbus协议标准开放、公开发表且无版权要求485就相当于公路而modbus相当于交通规则;Modbus协议消息帧格式简单、通俗易懂便于厂商开发和集成。Modbus可以在各种介质上传输它的传输报文类型支持三种包括ASCI(RS232/485 传输的是字符)、RTU(RS232/485RTU传输的是二进制或者16进制的数据)、TCP(以太网)三种;使用串口传输时可以选择RTU或ASCI模式当然常用的就是RTU模式。Modbus报文是指主机发送给从机的一帧数据其中包含着从机的地址主机想执行的操作校验码等内容最大为256 字节:从机地址:每个从机都有唯一地址(机没有地址)占用一个字节范围0-255其中从机有效地址范围是1-247;功能码: 占用一个字节功能码的意义是告诉从机这帧数据是干啥的可以查询从机的数据也可以修改从机的数据;数据:根据功能码不同对应不同内容比如功能码是查询从机的数据这里就包括要查询哪些数据和查询字节数等;校验: 在传输过程中数据坑会发生错误CRC检验可以检测接收的数据是否正确。功能码寄存器可以理解为设备上的某一个控制项比如传感器或者继电器并不是单片机片上外设的硬件寄存器通信机制:主机轮询从机应答的机制1 系统中只有一个设备是主机:主从通信2 系统中的从机不可以主动的向主机发送数据3 系统上电后所有的主从设备都应该处于监听总线的状态也就是接收状态4 如果要发起一次通信必须由主机主动发起(任何一次的通信或数据交换都必须由主机来发起)1)主机首先切换成发送模式 发送数据包2)立马转成接收模式Modbus是主从方式通信也就是说不能同步进行通信总线上每次只有一个数据进行传输即主机发送从机应答主机不发送总线上就没有数据通信。(所以说这也算是一个缺点了)实验一RS485实验A:硬件电路我们使用的是正点原子的RS485模块在这个电路中我们没有用到单独的收发使能控制引脚而是做了一个自动收发电路而是做了一个自动收发电路其工作原理如下TP8485 的RE和DE接一起的默认10K上拉所以默认为发送模式高电平为发送模式低电平为接收模式RXD通过TP8485芯片的DI脚发送数据发送0数据的时候自动收发电路不动作所以驱动输出ALBH总线表现逻辑0当发送1数据的时候因为R6和C5组成的RC电路当发送速率很高的时候NPN三极管Q1来不及导通RE和DE仍为高电平驱动输出AHBL总线表现逻辑1当发送速率比较低的时候NPN三极管Q1会缓慢导通RE和DE变为低电平TP8485芯片进入接收模式驱动端DI高阻态但是因为偏置电阻R2(下拉B0)R4(上拉A1)所以总线仍然表现逻辑1。而肖特基二极管MBR0520用于加速Q1关断保证DI由高变低时芯片可以快速进入发送模式。当我们需要进行接收时只需要拉高 RXDRE和DE变为低电平数据通过TXD(RO)传输给MCU接口类型序号名称说明TTL 接口1*4 排针1VCC电源输入3.3V~5VTTL 接口1*4 排针2GND电源地TTL 接口1*4 排针3TXTTL 接口的 TX 引脚TTL 接口1*4 排针4RXTTL 接口的 RX 引脚RS485 接口1*3 接线端子1ARS485 接口信号线 ARS485 接口1*3 接线端子2BRS485 接口信号线 BRS485 接口1*3 接线端子3GND电源地下面的这个是F407正点原则板载的RS485硬件下面说的驱动器是TP8485这个芯片RO : 接收器输出端单片机的输入端所以4和6需要短接RE : 接收器输出使能单片机接收数据需要把这个拉低低电平有效DE : 驱动器输出使能单片机发送数据需要把这个拉高高电平有效DI : 驱动器输入端单片机的输出端B : 接收器的输入端 / 驱动器的输出端A: 接收器的输入端 / 驱动器的输出端注意R19和R22是两个偏置电阻用来保证总线空闲时UAB大于0.2V避免压差不定导致逻辑混乱。DI驱动器输入端单片机输出DI为低电平A为低电平B为高电平DI为高电平A为高电平B为低电平RO接收器输出端单片机输入如果 A - B ≥ 0.2VRO则为高电平如果 A - B ≤ -0.2 VRO则为低电1: A-B -0.2V 0A-B 0.2VB:代码他只是在电器层面做出了变化编程的话还是一样的int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ key_init(); /* 初始化按键 */ show_mesg(); /* 显示实验信息 */ demo_run(); /* 运行示例程序 */ } /** **************************************************************************************************** * file atk_rs485.c * author 正点原子团队(ALIENTEK) * version V1.0 * date 2024-11-01 * brief ATK_RS485模块 驱动代码 * license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司 **************************************************************************************************** * attention * * 实验平台:正点原子 M48Z-M3最小系统板STM32F103版 * 在线视频:www.yuanzige.com * 技术论坛:www.openedv.com * 公司网址:www.alientek.com * 购买地址:openedv.taobao.com * **************************************************************************************************** */ #include ./BSP/ATK_RS485/atk_rs485.h #include ./SYSTEM/delay/delay.h UART_HandleTypeDef g_rs458_handler; /* RS485控制句柄(串口) */ uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大RS485_REC_LEN个字节 */ uint8_t g_RS485_rx_cnt 0; /* 接收到的数据长度 */ #ifdef RS485_EN_RX /* 如果使能了接收 */ /** * brief RS485相关串口中断服务函数 * param 无 * retval 无 */ void ATK_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 ATK_RS485模块初始化函数 * note 该函数主要是初始化串口 * param baudrate: 波特率, 根据自己需要设置波特率值 * retval 无 */ void atk_rs485_init(uint32_t baudrate) { GPIO_InitTypeDef gpio_init_struct; ATK_RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */ ATK_RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */ ATK_RS485_UX_CLK_ENABLE(); /* 使能 串口 时钟 */ gpio_init_struct.Pin ATK_RS485_TX_GPIO_PIN; gpio_init_struct.Mode GPIO_MODE_AF_PP; gpio_init_struct.Pull GPIO_PULLUP; gpio_init_struct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(ATK_RS485_TX_GPIO_PORT, gpio_init_struct); /* 串口TX引脚初始化 */ gpio_init_struct.Pin ATK_RS485_RX_GPIO_PIN; gpio_init_struct.Mode GPIO_MODE_AF_INPUT; HAL_GPIO_Init(ATK_RS485_RX_GPIO_PORT, gpio_init_struct); /* 串口RX引脚初始化 */ /* USART 初始化设置 */ g_rs458_handler.Instance ATK_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(ATK_RS485_UX_IRQn); /* 使能USART2中断 */ HAL_NVIC_SetPriority(ATK_RS485_UX_IRQn, 3, 3); /* 抢占优先级3子优先级3 */ #endif } /** * brief RS485发送len个字节数据 * param buf : 缓冲区指针 * param len : 发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节) * retval 无 */ void atk_rs485_send_data(uint8_t *buf, uint8_t len) { HAL_UART_Transmit(g_rs458_handler, buf, len, 1000); /* 串口发送数据 */ g_RS485_rx_cnt 0; /* 清空计数 */ } /** * brief RS485查询接收到的数据 * param buf : 接收缓冲区首地址 * param len : 接收到的数据长度 * arg 0,表示没有接收到任何数据 * arg 其他, 表示接收到的数据长度 * retval 无 */ void atk_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(5); /* 等待5ms,连续超过5ms没有接收到一个数据,则认为接收结束 */ if (rxlen g_RS485_rx_cnt rxlen) /* 接收到了数据,且接收完成了 */ { for (i 0; i rxlen; i) { buf[i] g_RS485_rx_buf[i]; /* 取出数据保存到buf中 */ } *len g_RS485_rx_cnt; /* 记录本次数据长度 */ g_RS485_rx_cnt 0; /* 清零 */ } } /** **************************************************************************************************** * file demo.c * author 正点原子团队(ALIENTEK) * version V1.0 * date 2024-11-01 * brief ATK_RS485模块 测试代码 * license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司 **************************************************************************************************** * attention * * 实验平台:正点原子 M48Z-M3最小系统板STM32F103版 * 在线视频:www.yuanzige.com * 技术论坛:www.openedv.com * 公司网址:www.alientek.com * 购买地址:openedv.taobao.com * **************************************************************************************************** */ #include demo.h #include ./BSP/ATK_RS485/atk_rs485.h #include ./SYSTEM/usart/usart.h #include ./SYSTEM/delay/delay.h #include ./BSP/KEY/key.h #include ./BSP/LED/led.h #include stdio.h /** * brief 例程演示入口函数 * param 无 * retval 无 */ void demo_run(void) { uint8_t key; uint8_t i 0, t 0; uint8_t cnt 0; uint8_t rs485buf[200]; atk_rs485_init(256000); /* 初始化RS485波特率256000 */ while (1) { key key_scan(0); if (key KEY0_PRES) /* KEY0按下,发送一次数据 */ { printf(RS485模块 发送的数据为); for (i 0; i 200; i) { rs485buf[i] cnt i; /* 填充发送缓冲区 */ printf(%02X, rs485buf[i]); /* 打印输出数据 */ } printf(\r\n); atk_rs485_send_data(rs485buf, 200); /* 发送200个字节 */ } atk_rs485_receive_data(rs485buf, key); if (key) /* 接收到数据 */ { if (key 200)key 200; /* 最大有效字节数200个 */ printf(RS485模块 接收的数据为); for (i 0; i key; i) { printf(%02X, rs485buf[i]); /* 打印输出数据 */ } printf(\r\n); } t; delay_ms(10); if (t 20) { LED0_TOGGLE(); /* LED0闪烁, 提示系统正在运行 */ t 0; cnt; } } }A线为正端,B线为负端,线上的bit是1的话,应为-2~-6V左右的电压,线上的bit是0的话,应为2~6V.不通讯时,RS485处于空闲状态,数据线上全是1,当然可以用万用表测Vab电压,电压应该在-2~-6V之间通讯时,电平时高时低,你要看数据的话必须知道波特率,所以还必须用示波器捕捉波形RS485通信的其他问题可以参考这个up的http://www.youjirui.com/dianya/52443.html二MODBUS1:软件模拟使用软件模拟RS485使用传输数据RTU(16进制)Modbus Slave - Mbslave1-----》做主机 Modbus Poll - Mbpoll1------》做从机使用虚拟串口Virtual Serial Port Driver 9.0主机串口配置从机串口配置A:读数据主机查看具体的数据主机使用03功能码读取2个字节分析数据Tx:059-01 03 00 00 00 02 C4 0BRx:060-01 03 04 00 17 00 19 8B FDTX地址码功能码寄存器起始地址读取几个寄存器CRC010300 0000 02C4 0BRX地址码功能码字节数数据1数据2CRC01030400 1700 198B FD我们靠时间间隔来区分一包数据MODBUS:一包数据和一包数据间隔3.5个字符时间; 一个数据包之间的bit之间不能超过1.5个字符时间一个字符起始位停止位数据位校验位10bit3.5个字符时间35bit1传输1bit需要的时间1/96000.000104166us传输3.5个字符需要的时间0.000104166* 350.00364us3.64ms 一包数据和一包数据间隔3.64msB:写单个寄存器主机Tx:079-01 06 00 04 00 64 C9 E0 079-表示第79从发送Rx:080-01 06 00 04 00 64 C9 E0TX地址码功能码寄存器起始地址寄存器的值CRC010600 0400 64C9 E0可以发现读取数据时从机发送的数据是主机发送的数据C:写多个寄存器主机Tx:089-01 10 00 02 00 03 06 00 0A 00 0B 00 0C AE 8CRx:090-01 10 00 02 00 03 21 C8TX地址码功能码寄存器起始地址写几个寄存器字节数数据1数据2数据3CRC011016进制00 0200 030600 0A00 0B00 0CAE 8CRX地址码功能码寄存器起始地址寄存器数量CRC011000 0200 0321 C8面试https://blog.csdn.net/2401_82762455/article/details/153839149https://blog.csdn.net/weixin_41185694/article/details/147926953