完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek 阿波罗 STM32F767 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子 第三十四章 485 实验 本章我们将向大家介绍如何使用 STM32F767 的串口实现 485 通信(半双工)。在本章中, 我们将使用 STM32F767 的串口 2 来实现两块开发板之间的 485 通信,并将结果显示在 LCD 模 块上。本章分为如下几个部分: 34.1 485 简介 34.2 硬件设计 34.3 软件设计 34.4 下载验证 34.1 485 简介 485(一般称作 RS485/EIA-485)是隶属于 OSI 模型物理层的电气特性规定为 2 线,半双工, 多点通信的标准。它的电气特性和 RS-232 大不一样。用缆线两端的电压差值来表示传递信号。 RS485 仅仅规定了接受端和发送端的电气特性。它没有规定或推荐任何数据协议。 RS485 的特点包括: ① 接口电平低,不易损坏芯片。RS485 的电气特性:逻辑“1”以两线间的电压差为+(2~6)V 表示;逻辑“0”以两线间的电压差为-(2~6)V 表示。接口信号电平比 RS232 降低了, 不易损坏接口电路的芯片,且该电平与 TTL 电平兼容,可方便与 TTL 电路连接。 ② 传输速率高。10 米时,RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输 速度可达 100Kbps。 ③ 抗干扰能力强。RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力 增强,即抗噪声干扰性好。传输距离远,支持节点多。RS485 总线最长可以传输 1200m 以上(速率≤100Kbps) ④ 一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点, 最大的可以支持到 400 个节点。 RS485 推荐使用在点对点网络中,线型,总线型,不能是星型,环型网络。理想情况下 RS485 需要 2 个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为 120Ω)。没有特性阻抗 的话,当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需要双端的电压差。 没有终接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致数据传输出错。485 推荐的连接方式如图 34.1.2 所示: 图 34.1.2 RS485 连接 在上面的连接中,如果需要添加匹配电阻,我们一般在总线的起止端加入,也就是主机和 设备 4 上面各加一个 120Ω的匹配电阻。 由于 RS485 具有传输距离远、传输速度快、支持节点多和抗干扰能力更强等特点,所以 RS485 有很广泛的应用。 阿波罗 STM32F767 开发板采用 SP3485 作为收发器,该芯片支持 3.3V 供电,最大传输速 度可达 10Mbps,支持多达 32 个节点,并且有输出短路保护。该芯片的框图如图 34.1.2 所示: 图 34.1.2 SP3485 框图 图中 A、B 总线接口,用于连接 485 总线。RO 是接收输出端,DI 是发送数据收入端,RE 是接收使能信号(低电平有效),DE 是发送使能信号(高电平有效)。 本章,我们通过该芯片连接 STM32F767 的串口 2,实现两个开发板之间的 485 通信。本章 将实现这样的功能:通过连接两个阿波罗 STM32F767 开发板的 RS485 接口,然后由 KEY0 控 制发送,当按下一个开发板的 KEY0 的时候,就发送 5 个数据给另外一个开发板,并在两个开 发板上分别显示发送的值和接收到的值。 本章,我们只需要配置好串口 2,就可以实现正常的 485 通信了,串口 2 的配置和串口 1 基本类似,只是串口的时钟来自 APB1,最大频率为 54Mhz。 34.2 硬件设计 本章要用到的硬件资源如下: 1) 指示灯 DS0 2) KEY0 按键 3) LCD 模块 4) PCF8574T 5) 串口 2 6) RS485 收发芯片 SP3485 前面 4 个之前都已经详细介绍过了,这里我们介绍 SP3485 和串口 2 的连接关系,如图 34.2.1 所示: 图 34.2.1 STM32F767 与 SP3485 连接电路图 从上图可以看出:STM32F767 的串口 2 通过 P8 端口设置,连接到 SP3485。注意:RS485_RE 信号,是连接在 PCF8574T 的 P6 脚上的,并没有直接连接到 MCU,需要通过 IIC 总线控制 PCF8574T,从而实现对 RS485_RE 的控制。RS485_RE 控制 SP3485 的收发,当 RS485_RE=0 的时候,为接收模式;当 RS485_RE=1 的时候,为发送模式。 另外,PA2,PA3 和 ETH_MDIO 和 PWM_DAC 有共用 IO,所以在使用的时候,注意分时 复用,不能同时使用。 图中的 R34 和 R32 是两个偏置电阻,用来保证总线空闲时,A、B 之间的电压差都会大于 200mV(逻辑 1)。从而避免因总线空闲时,A、B 压差不定,引起逻辑错乱,可能出现的乱码。 然后,我们要设置好开发板上P8排针的连接,通过跳线帽将PA2和PA3分别连接到485_TX 和 485_RX 上面,如图 34.2.2 所示: 图 34.2.2 硬件连接示意图 最后,我们用 2 根导线将两个开发板 RS485 端子的 A 和 A,B 和 B 连接起来。这里注意不 要接反了(A 接 B),接反了会导致通讯异常!! 34.3 软件设计 打开 485 实验例程,可以发现项目中加入了一个 rs485.c 文件以及其头文件 rs485 文件,同 时 485 通信因为底层用的是串口 2,所以需要引入库函数 stm32f7xx_hal_uart.c 文件和对应的头 文件 stm32f7xx_hal_uart.h。 打开 rs485.c 文件,代码如下: UART_HandleTypeDef USART2_RS485Handler; //USART2 句柄(用于 RS485) #if EN_USART2_RX //如果使能了接收 //接收缓存区 u8 RS485_RX_BUF[64]; //接收缓冲,最大 64 个字节. //接收到的数据长度 u8 RS485_RX_CNT=0; void USART2_IRQHandler(void) { u8 res; if((__HAL_UART_GET_FLAG(&USART2_RS485Handler, UART_FLAG_RXNE)!=RESET)) //接收中断 { HAL_UART_Receive(&USART2_RS485Handler,&res,1,1000); if(RS485_RX_CNT<64) { RS485_RX_BUF[RS485_RX_CNT]=res; //记录接收到的值 RS485_RX_CNT++; //接收数据增加 1 } } } #endif //初始化 IO 串口 2 //bound:波特率 void RS485_Init(u32 bound) { //GPIO 端口设置 GPIO_InitTypeDef GPIO_Initure; PCF8574_Init(); //初始化 PCF8574,用于控制 RE 脚 __HAL_RCC_GPIOA_CLK_ENABLE(); /使能 GPIOA 时钟 __HAL_RCC_USART2_CLK_ENABLE(); //使能 USART2 时钟 GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3; //PA2,3 GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速 GPIO_Initure.Alternate=GPIO_AF7_USART2; //复用为 USART2 HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化 PA2,3 //USART 初始化设置 USART2_RS485Handler.Instance=USART2; //USART2 USART2_RS485Handler.Init.BaudRate=bound; //波特率 USART2_RS485Handler.Init.WordLength=UART_WORDLENGTH_8B; //字长 8 位数据 USART2_RS485Handler.Init.StopBits=UART_STOPBITS_1; //一个停止位 USART2_RS485Handler.Init.Parity=UART_PARITY_NONE; //无奇偶校验位 USART2_RS485Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;//无硬件流控 USART2_RS485Handler.Init.Mode=UART_MODE_TX_RX; //收发模式 HAL_UART_Init(&USART2_RS485Handler); //HAL_UART_Init()会使能 USART2 __HAL_UART_DISABLE_IT(&USART2_RS485Handler,UART_IT_TC); #if EN_USART2_RX __HAL_UART_ENABLE_IT(&USART2_RS485Handler,UART_IT_RXNE);//开启接收中断 HAL_NVIC_EnableIRQ(USART2_IRQn); //使能 USART1 中断 HAL_NVIC_SetPriority(USART2_IRQn,3,3); //抢占优先级 3,子优先级 3 #endif RS485_TX_Set(0); //设置为接收模式 } //RS485 发送 len 个字节. //buf:发送区首地址 //len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过 64 个字节) void RS485_Send_Data(u8 *buf,u8 len) { RS485_TX_Set(1); //设置为发送模式 HAL_UART_Transmit(&USART2_RS485Handler,buf,len,1000);//串口 2 发送数据 RS485_RX_CNT=0; RS485_TX_Set(0); //设置为接收模式 } //RS485 查询接收到的数据 //buf:接收缓存首地址 //len:读到的数据长度 void RS485_Receive_Data(u8 *buf,u8 *len) { u8 rxlen=RS485_RX_CNT; u8 i=0; *len=0; //默认为 0 delay_ms(10); //等待 10ms,连续超过 10ms 没有接收到一个数据,则认为接收结束 if(rxlen==RS485_RX_CNT&&rxlen)//接收到了数据,且接收完成了 { for(i=0;i buf=RS485_RX_BUF; } *len=RS485_RX_CNT; //记录本次数据长度 RS485_RX_CNT=0; //清零 } } //RS485 模式控制. //en:0,接收;1,发送. void RS485_TX_Set(u8 en) { PCF8574_WriteBit(RS485_RE_IO,en); } 此部分代码总共 5 个函数,其中 RS485_Init 函数为 485 通信初始化函数,完成对串口 2 的 配置,另外,对 PCF8574 也进行了初始化,方便控制 SP3485 的收发。同时如果使能中断接收 的话,会执行串口 2 的中断接收配置;USART2_IRQHandler 函数用于中断接收来自 485 总线的 数据,将其存放在 RS485_RX_BUF 里面;RS485_Send_Data 和 RS485_Receive_Data 这两个函 数用来发送数据到 485 总线和读取从 485 总线收到的数据,这里重点介绍一下接收数据的流程 (超时法):首先令 rxlen=RS485_RX_CNT,记录当前接收到的字节数,随后,等待 10ms,如 果在这个 10ms 里面,没有接收到任何数据(RS485_RX_CNT 的值未增加),那么就说明接收 完成了。如果有接收到其他数据(RS485_RX_CNT 变大了),那么说明还在继续接收数据,需 等到下一个循环再处理;最后,RS485_TX_Set 函数,用于通过 PCF8574 控制 RS485_RE 脚。 对于串口 2程序编写方式我们需要说明一下。在串口实验章节我们已经讲过,一般情况下, 我们在串口的中断服务函数中会调用中断共用处理 HAL 库函数 HAL_UART_IRQHandler,然 后在函数 HAL_UART_IRQHandler 中,会对中断进行判断,调用想用的回调处理函数。但是 本章实验源码中,我们并没有在中断服务函数中调用 HAL_UART_IRQHandler,也没有修改 中断接收回调函数 HAL_UART_RxCpltCallback,这是因为我们为了保持 RS485 串口部分代 码的独立性,所以直接在中断服务函数中编写中断控制逻辑,方便大家阅读。大家也可以根据 自己的编程习惯来选择,HAL 库是非常灵活的,当我们掌握了 HAL 的编程思路,就可以得心 应手的使用。对于串口初始化 MSP 回调函数也是一样,我们并没有修改初始化回调函数 HAL_UART_MspInit 内容,而是直接在 RS485_Init 函数中一次性初始化所有步骤。 头文件 rs485.h 文件中,我们通过下面一行代码打开了接受中断: #define EN_USART2_RX 1 //0,不接收;1,接收. 其他内容就是一些函数声明,所以这里我们不细说。 接下来,我们来看看主函数代码: int main(void) { u8 key; u8 i=0,t=0; u8 cnt=0; u8 rs485buf[5]; Cache_Enable(); //打开 L1-Cache HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz delay_init(216); //延时初始化 uart_init(115200); //串口初始化 usmart_dev.init(108); //初始化 USMART LED_Init(); //初始化 LED KEY_Init(); //初始化按键 SDRAM_Init(); //初始化 SDRAM LCD_Init(); //LCD 初始化 RS485_Init(9600); //初始化 RS485 POINT_COLOR=RED; LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7"); LCD_ShowString(30,70,200,16,16,"RS485 TEST"); LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(30,110,200,16,16,"2016/7/12"); LCD_ShowString(30,130,200,16,16,"KEY0:Send"); //显示提示信息 POINT_COLOR=BLUE;//设置字体为蓝色 LCD_ShowString(30,150,200,16,16,"Count:"); //显示当前计数值 LCD_ShowString(30,170,200,16,16,"Send Data:"); //提示发送的数据 LCD_ShowString(30,210,200,16,16,"Receive Data:");//提示接收到的数据 while(1) { key=KEY_Scan(0); if(key==KEY0_PRES)//KEY0 按下,发送一次数据 { for(i=0;i<5;i++) { rs485buf=cnt+i;//填充发送缓冲区 LCD_ShowxNum(30+i*32,190,rs485buf,3,16,0X80); //显示数据 } RS485_Send_Data(rs485buf,5);//发送 5 个字节 } RS485_Receive_Data(rs485buf,&key); if(key)//接收到有数据 { if(key>5)key=5;//最大是 5 个数据. for(i=0;i } t++; delay_ms(10); if(t==20) { LED0_Toggle;//提示系统正在运行 t=0; cnt++; LCD_ShowxNum(30+48,150,cnt,3,16,0X80); //显示数据 } } } 此部分代码,我们主要关注下 RS485_Init(54,9600),这里用的是 54,而不是 108,是因为 APB1 的时钟是 54Mhz,故是 54,而串口 1 的时钟来自 APB2,是 108Mhz 的时钟,所以这里 和串口 1 的设置是有点区别的。cnt 是一个累加数,一旦 KEY0 按下,就以这个数位基准连续 发送 5 个数据。当 485 总线收到数据的时候,就将收到的数据直接显示在 LCD 屏幕上。 34.4 下载验证 在代码编译成功之后,我们通过下载代码到 ALIENTEK 阿波罗 STM32 开发板上(注意要 2 个开发板都下载这个代码哦),得到如图 34.4.1 所示: 图 34.4.1 程序运行效果图 伴随 DS0 的不停闪烁,提示程序在运行。此时,我们按下 KEY0 就可以在另外一个开发板 上面收到这个开发板发送的数据了。如图 34.4.2 和图 41.4.3 所示: 图 34.4.2 RS485 发送数据 图 34.4.3 RS485 接收数据 图 34.4.2 来自开发板 A,发送了 5 个数据,图 34.4.3 来自开发板 B,接收到了来自开发板 A 的 5 个数据。 本章介绍的 485 总线时通过串口控制收发的,我们只需要将 P8 的跳线帽稍作改变,该实 验就变成了一个 RS232 串口通信实验了,通过对接两个开发板的 RS232 接口,即可得到同样的 实验现象,有兴趣的读者可以实验一下。 另外,利用 USMART 测试的部分,我们这里就不做介绍了,大家可自行验证下。 |
|
相关推荐
|
|
STM32进行DMA数据转运,为什么只有A组最后一位数据被转运到B组去?
1265 浏览 2 评论
1585 浏览 3 评论
1206 浏览 0 评论
嵌入式开发 Win11安装ST-Link 提示 设备描述符请求失败 怎么处理?
1339 浏览 0 评论
1632 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-18 06:19 , Processed in 0.665976 second(s), Total 65, Slave 48 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号