龙岗网站app建设,网站素材网站,做建筑效果图最好的网站,wordpress管理员登入准备工作
了解485通信基本概念与原理#xff1a;RS485通信详解_485通讯de接什么口-CSDN博客
安装编译软件#xff1a;keil uVision 5.6 软件资料#xff1a;STM32CubeF4 固件包#xff0c;正点原子RS485通信例程
参考视频#xff1a;第26讲 基础篇-新建H…准备工作
了解485通信基本概念与原理RS485通信详解_485通讯de接什么口-CSDN博客
安装编译软件keil uVision 5.6 软件资料STM32CubeF4 固件包正点原子RS485通信例程
参考视频第26讲 基础篇-新建HAL版本MDK工程1_哔哩哔哩_bilibili
第27讲 基础篇-新建HAL版本MDK工程2_哔哩哔哩_bilibili
第156讲 入门篇- RS485_哔哩哔哩_bilibili
使用 STM32F407 串口实现 485 通信半双工
1.新建工程文件夹
1.1新建工程文件夹
首先新建一个工程根目录文件夹最好不要出现中文路径后续的工程文件都将在这个文件夹里建立文件夹重命名为485TestOne。 1.1 新建工程根目录文件夹 为了让工程的文件目录结构更加清晰易懂在工程根目录文件夹下建立以下几个文件夹每个文件夹名称及其作用如表 1.1 所示 表1.1 工程根目录新建文件夹及其作用 新建完成以后最后得到的工程根目录文件夹如图 1.2 所示。 1.2 工程根目录文件夹 1.2拷贝工程相关文件
接下来按根目录文件夹顺序介绍每个文件夹及其需要拷贝的文件。
1.2.1 Drivers 文件夹
该文件夹用于存放与硬件相关的驱动层文件一般包括如表 1.2 所示的三个文件夹 表 1.2.1 Drivers 包含文件夹 BSP 文件夹用于存放正点原子提供的板级支持包驱动代码如LED、蜂鸣器、按键、RS485等。 CMSIS 文件夹用于存放 CMSIS 底层代码ARM 和 ST 提供如启动文件.s 文件、stm32f4xx.h 等各种头文件。该文件夹可以直接从 STM32CubeF4 固件包里面拷贝但由于固件包里面的 CMISIS 兼容了太多芯片会导致非常大170 MB因此可根据实际情况对其进行精简。 SYSTEM 文件夹用于存放正点原子提供的系统级核心驱动代码如sys.c、delay.c 和usart.c 等方便大家快速搭建自己的工程。 BSP、CMSIS、SYSTEM文件夹可以之间从正点原子提供的RS485通信例程中拷贝。 STM32F4xx_HAL_Driver 文件夹用于存放 ST 提供的 F4xx HAL 库驱动代码。该文件夹可以直接从 STM32CubeF4 固件包里面拷贝。直接拷贝“STM32CubeF4 固件包→Drivers”路径下的 “STM32F4xx_HAL_Driver”文件夹到工程的 Drivers 下只保留 Inc 和 Src 文件夹即可。 执行完以上操作后Drivers 文件夹最终结构如图 1.3 所示 图 1.3 工程根目录下的 Drivers 文件夹 关于工程根目录下的 Drivers 文件操作到这里就完成了。
1.2.2 Middlewares 文件夹
该文件夹用于存放正点原子和其他第三方提供的中间层代码组件/Lib 等如USMART、MALLOC、TEXT、FATFS、USB、LWIP、各种 OS、各种 GUI 等等。
1.2.3 Output 文件夹
该文件夹用于存放编译器编译工程输出的中间文件比如.hex、.bin、.o 文件等等。这里不需要操作后面只需要在 MDK 里面设置该文件夹为编译过程中间文件的存放文件夹就行。
1.2.4 Projects 文件夹
该文件夹用于存放编译器MDK、IAR 等工程文件工程主要用 MDK为了方便区分在该文件夹下新建MDK-ARM 文件夹用于存放 MDK 的工程文件如图 1.4 所示 图 1.4 在 Projects 文件夹下新建 MDK-ARM 文件夹 1.2.5 User 文件夹
User 文件夹用于存放 HAL 库用户配置文件、main.c、中断处理文件以及分散加载文件。
首先从官方固件包里面直接拷贝官方的模板工程下的 HAL 库用户配置文件和中断处理文件到 User 文件夹里。官方的模板工程路径STM32Cube_FW_F4_V1.26.0\Projects\STM324xG_EVAL\Templates打开Template_Project 文件夹如图 1.5 所示。 图1.5 官方模板工程根目录 在 Inc 和 Src 两个文件夹里面找到stm32f4xx_it.c、 stm32f4xx_it.h、stm32f4xx_hal_conf.h 这三个文件并且拷贝到 User 文件夹下。
注意main.c文件也是放在User文件夹里面的后面需要在MDK 里面新建.c 文件并保存。
2. 新建一个工程框架
2.1 首先打开 MDK 软件。然后点击 Project→New uVision Project 如图 2.1 所示 图 2.1 新建 MDK 工程 2.2 然后弹出工程命名和保存的操作窗口将工程文件保存路径设置在上一节新建的工程文件夹内具体路径为485TestOne→Projects→MDK-ARM
工程名字为atk_f407最后点击保存即可。具体操作窗口如图 2.2所示 图 2.2 工程命名和保存的操作窗口 2.3 之后弹出器件选择对话框如图2.3所示。 图2.3 器件选择界面 因为探索者 STM32F407 开发板所使用的STM32 型号为 STM32F407ZGT6所以选择STMicroelectronics → STM32F4 Series →STM32F407 → STM32F407ZGTx如果使用的是其他系列的芯片选择相应的型号就可以了特别注意一定要安装对应的器件 pack 才会显示这些内容哦如果没得选择请关闭 MDK安装后重试。
2.4 点击 OKMDK 会弹出 Manage Run-Time Environment 对话框如图2.4所示 图2.4 Manage Run-Time Environment 界面 这是 MDK5 新增的一个功能在这个界面可以添加自己需要的组件从而方便构建开发环境这里不做介绍。直接点击 Cancel即可
2.5 得到如图 2.5 所示界面 图2.5 工程初步建立 2.6 此时打开 MDK-ARM 文件夹会看到 MDK 在该文件夹下自动创建了 3 个文件夹 DebugConfig、Listings 和 Objects如图所示 图2.6 MDK 新建工程时自动创建的文件夹 这三个文件夹的作用 DebugConfig用于存放调试设置信息文件.dbgconf不可删除 Listings用于存放编译过程产生的链接列表等文件 Objects用于存放编译过程产生的调试信息、.hex、预览、.lib 文件等 编译过程产生的链接列表、调试信息、预览、lib 等文件统称为中间文件。为了统一管理方便使用可以把输出在 Listings 和 Objects 文件夹的内容统一改为输出到 Output 文件夹通过魔术棒设置这里先把 MDK 自动生成的这两个文件夹Listings 和 Objects删除。
至此完成了框架的构建还有好几个步骤要做比如添加文件、魔术棒设置、编写 main.c 等
3. 添加文件
本节将分 5 个步骤1设置工程名和分组名2添加启动文件3添加 SYSTEM 源码4添加 User 源码5添加 STM32F4xx_HAL_Driver 源码。
3.1 设置工程名和分组名
3.1.1在 Project→Target 上右键选择 Manage Project Items…方法一或在菜单栏点击品字形红绿白图标方法二进入工程管理界面如图 3.1 所示 图3.1 进入工程管理界面 3.1.2 在工程管理界面可执行设置工程名字Project Targets、分组名字Groups以及添加每个分组的文件Files等操作。设置工程名字为RS485并设置以下分组 Startup存放启动文件 User存放 main.c 等用户代码 Drivers/SYSTEM存放系统级驱动代码 Driver/STM32F4xx_HAL_Driver存放 HAL 库代码 Driver/BSP存放板级支持包驱动代码如LED、按键等 Middleware/USMART存放中间层代码 Readme存放工程说明文件可选 如图 3.2 所示 图 3.2 设置工程名和分组名 3.1.3 设置好之后点击 OK回到 MDK 主界面可以看到设置的工程名和分组名如图所示 图 3.3 设置成功 注意为了让工程结构清晰尽量使 MDK 的工程分组和前面新建的工程文件夹对应起来由于 MDK 分组不支持多级目录因此将路径也带入分组命名里面以便区 分。如User 分组对应 User 文件夹里面的源码Drivers/SYSTEM 分组对应 Drivers/SYSTEM 文件夹里面的源码Drivers/BSP 分组对应 Drivers/BSP 文件夹里面的源码等。
3.2 添加启动文件
启动文件.s 文件包含 STM32 的启动代码其主要作用包括1、堆栈SP的初始化2、初始化程序计数器PC3、设置向量表异常事件的入口地址4、调用 main 函数等是每个工程必不可少的一个文件。
3.2.1 启动文件由 ST 官方提供存放在 STM32CubeF4 软件包的Drivers → CMSIS → Device →ST → STM32F4xx → Source → Templates → arm 文件夹下。开发板STM32F407ZGT6对应的启动文件为startup_stm32f407xx.s。
有两种方法给 MDK 的分组添加文件1双击 Project 下的分组名添加。2进入工程管理界面添加。这里我们使用方法 1 添加路径实验 0-3新建工程实验-HAL 库版本\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm如图3.4所示 图3.4 双击分组添加启动文件startup_stm32f407xx.s 上图中也可以点击 Add 按钮进行文件添加。添加完后点击 Close完成启动文件添加得到工程分组如图所示 图 3.5 启动文件添加成功 3.3 添加 SYSTEM 源码
3.3.1 这里使用工程管理界面方法 2进行 SYSTEM 源码添加。点击 按钮进入工程管 理界面选中 Drivers/SYSTEM 分组然后点击Add Files进入文件添加对话框在依次添加 delay.c、sys.c 和 usart.c 到该分组下如图 3.6 所示 图 3.6 添加 SYSTEM 源码 注意这些源码都是在第 1.2 小节的第二步拷贝过来的如果之前没拷贝是找不到这些源码的。
3.3.2 添加完成后如图3.7所示 图 3.7 SYSTEM 源码添加完成 3.4 添加 User 源码
和3.2步骤一样在工程管理界面方法 2进行 User 源码添加。点击 按钮进入工程管理界面选中 User 分组然后点击Add Files进入文件添加对话框依次添加 stm32f4xx_it.c 480TestOne\User目录下和system_stm32f4xx.c480TestOne\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates目录下 到该分组下。
注意这些源码都是在第 1.2 小节的第二步拷贝过来的如果之前没拷贝是找不到这些源码的。添加完成后如图 3.8 所示 图 3.8 User 源码添加完成 3.5 添加 STM32F4xx_HAL_Driver 源码
和3.2步骤一样在工程管理界面方法 2选中 Drivers/STM32F4xx_HAL_Driver 分组然后点击Add Files进入文件添加对话框在480TestOne\Drivers\STM32F4xx_HAL_Driver\Src目录下找到文件依次添加 stm32f4xx_hal.c 、 stm32f4xx_hal_cortex.c 、stm32f4xx_hal_dma.c 、stm32f4xx_hal_dma_ex.c、stm32f4xx_hal_gpio.c、 stm32f4xx_hal_pwr.c、stm32f4xx_hal_pwr_ex.c、stm32f4xx_hal_rcc.c、stm32f4xx_hal_rcc_ex.c、stm32f4xx_hal_sram.c、stm32f4xx_hal_tim.c、stm32f4xx_hal_tim_ex.c、stm32f4xx_hal_uart.c、stm32f4xx_hal_usart.c 、stm32f4xx_ll_fsmc.c到该分组下如图3.9所示 图 3.9 STM32F4xx_HAL_Driver 源码添加完成 注意如果看到分组中有些.c 文件有个小钥匙的符号这是因为官方的固件包的文件设置了只读权限取消480TestOne\Drivers\CMSIS与480TestOne\Drivers\STM32F4xx_HAL_Driver两个文件夹的只读权限就好了。
3.6 添加 BSP 源码
这里和3.2步骤一样在工程管理界面方法 2进行 User 源码添加。点击 按钮进入工程管理界面选中 User 分组然后点击Add Files进入文件添加对话框依次添加 key.c480TestOne\Drivers\BSP\KEY目录下、 led.c480TestOne\Drivers\BSP\LED目录下、lcd.c480TestOne\Drivers\BSP\LCD目录下 、rs485.c 480TestOne\Drivers\BSP\RS485目录下到该分组下。
注意这些源码都是在第 1.2 小节的第二步拷贝过来的如果之前没拷贝是找不到这些源码的。添加完成后如图3.10 所示 图 3.10 BSP 源码添加完成 3.7 添加 USMART 源码
这里和3.2步骤一样在工程管理界面方法 2进行 User 源码添加。点击 按钮进入工程管理界面选中 User 分组然后点击Add Files进入文件添加对话框依次添加 usmart.c480TestOne\Drivers\BSP\KEY目录下、 led.c480TestOne\Drivers\BSP\LED目录下、lcd.c480TestOne\Drivers\BSP\LCD目录下 到该分组下。
注意这些源码都是在第 1.2 小节的第二步拷贝过来的如果之前没拷贝是找不到这些源码的。添加完成后如图 3.11 所示 图 3.11 USMART 源码添加完成 4. 魔术棒设置
为避免编写代码和编译报错需要通过魔术棒对 MDK 工程进行相关设置。在 MDK主界面点击 魔术棒图标即 Options for Target 按钮进入工程设置对话框将进行如下几个选项卡的设置。
4.1 设置 Target 选项卡 图4.1 Target 选项卡设置 在图 4.1 中设置芯片所使用的外部晶振频率为 8MhzuVision 5.36及以上版本是灰色不用设置选择 ARM Compiler 版本为Use default compiler version 5即 AC5 编译器。
AC5 和 AC6 编译的差异 表 4.1 AC5AC6 简单对比 4.2 设置 Output 选项卡
在魔术棒→Output 选项卡里面进行如图 4.2 所示设置 图 4.2 设置 Output 选项卡 注意勾选Browse Information可用于输出浏览信息就能使用 go to definition查看函数/变量的定义对后续调试代码比较有帮助如果不需要调试代码则可以去掉勾选以提高编译速度。
4.3 设置 Listing 选项卡
在魔术棒→Listing 选项卡里面进行如图 4.3 所示设置 图 4.3 设置 Listing 选项卡 经过 Output 和 Listing 这两步设置原来存储在 Objects 和 Listings 文件夹的内容中间文件就都改为输出到 Output 文件夹了。
4.4 设置 C/C选项卡
在魔术棒→C/C选项卡里面进行如图 4.4 所示设置 图 4.4 设置 C/C选项卡 在②处设置了全局宏定义USE_HAL_DRIVER和STM32F407xx他们之间用英文逗号隔开。STM32F407xx用于定义所用 STM32 型号在 stm32f4xx.h 里面会用到该宏定义。
在③处设置了优化等级为-O0可以得到最好的调试效果当然为了提高优化效果提升性能并降低代码量可以设置-O1~-O3数字越大效果越明显不过也越容易出问题。注意当使用AC6 编译器的时候这里推荐默认使用-O1 优化。
在④处勾选 C99 模式即使用 C99 C 语言标准。
在⑤处进行头文件包含路径设置点击此按钮进行如图 所示设置 图 4.5 设置头文件包含路径 上图中设置了 6 个头文件包含路径其中 3 个在 Drivers 文件夹下一个在 User 文件夹下一个在 Middlewares 文件夹下。为避免频繁设置头文件包含路径正点原子最新源码的include 全部使用相对路径即只需要在头文件包含路径里面指定一个文件夹那么该文件夹下的其他文件夹里面的源码全部使用相对路径则无需再设置头文件包含路径了直接在 include 里面就指明了头文件所在。 关于相对路径这里大家记住 3 点 1默认路径就是指 MDK 工程所在的路径即.uvprojx 文件所在路径文件夹 2“./”表示当前目录相对当前路径也可以写做“.\” 3“../”表示当前目录的上一层目录也可以写做“..\” 举例来说上图中..\..\Drivers\CMSIS\Device\ST\STM32F4xx\Include前面两个“..\”表示 Drivers 文件夹在当前 MDK 工程所在文件夹MDK-ARM的上 2 级目录下。
再举个例子在完成头文件包含路径设置以后在代码里面编写#include ./SYSTEM/sys/sys.h即表示当前头文件包含路径所指示的 4 个文件夹里面肯定有某一个文件夹包含了SYSTEM/sys/sys.h 的路径实际上就是在 Drivers 文件夹下面两者结合起来就相当于#include ../../Drivers/SYSTEM/sys/sys.h
这就是相对路径。它既可以减少头文件包含路径设置即减少 MDK 配置步骤免去频繁设置头文件包含路径的麻烦同时又可以很方便的知道头文件具体在那个文件夹因此我们推荐在编写代码的时候使用相对路径。
最后我们如果使用 AC6 编译器则在Target选项卡的 Misc Controls 处需要设置-Wno-invalid source-encoding避免中文编码报错如果使用 AC5 编译器则不需要该设置 4.5设置 Debug 选项卡
在魔术棒→Debug 选项卡里面进行如图 4.6 所示设置 图 4.6 Debug 选项卡设置 在图4.6中选择使用ST-Link Debugger 仿真器请根据使用的仿真器进行选择使用 SW 模式并设置最大时钟频率为 10Mhz以得到最高下载速度。将仿真器和开发板连接好并给开发板供电以后仿真器就会找到开发板芯片并在 SW Device 窗口显示芯片的 IDCODE、Device Name 等信息图中⑤处当无法找到时请检查供电和仿真器连接状况。
4.6设置 Utilities 选项卡
在魔术棒→Utilities 选项卡里面进行如图 4.7 所示设置 图 4.7 Utilities 选项卡设置 注意图中⑥处下载算法是 MDK 默认添加的如果⑥处没有下载算法则点击 Add 按钮添加下载算法即可算法名字和⑥处的算法名字一样
5. 代码分析与编写
正点原子已经有包装好的RS485通信源码。在1.2小节中已经拷贝在Drivers\BSP文件夹下并在3.6小节中添加到了工程中。
5.1 驱动源码分析
RS485 驱动相关源码包括两个文件rs485.c 和 rs485.h。
rs485.h 中使用宏定义 485 相关的控制引脚和串口编号如果需要使用其它的引脚或者串口修改宏和串口的定义即可它们在 rs485.h 中定义它们列出如下
/******************************************************************************************/
/* RS485 引脚 和 串口 定义 * 默认是针对RS4852的.* 注意: 通过修改这10个宏定义, 可以支持UART1~UART7任意一个串口.*/
#define RS485_RE_GPIO_PORT GPIOG
#define RS485_RE_GPIO_PIN GPIO_PIN_8
#define RS485_RE_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0) /* PD口时钟使能 */#define RS485_TX_GPIO_PORT GPIOA
#define RS485_TX_GPIO_PIN GPIO_PIN_2
#define RS485_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */#define RS485_RX_GPIO_PORT GPIOA
#define RS485_RX_GPIO_PIN GPIO_PIN_3
#define RS485_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA口时钟使能 */#define RS485_UX USART2
#define RS485_UX_IRQn USART2_IRQn
#define RS485_UX_IRQHandler USART2_IRQHandler
#define RS485_UX_CLK_ENABLE() do{ __HAL_RCC_USART2_CLK_ENABLE(); }while(0) /* USART2 时钟使能 *//******************************************************************************************//* 控制RS485_RE脚, 控制RS485发送/接收状态* RS485_RE 0, 进入接收模式* RS485_RE 1, 进入发送模式*/
#define RS485_RE(x) do{ x ? \HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(RS485_RE_GPIO_PORT, RS485_RE_GPIO_PIN, GPIO_PIN_RESET); \}while(0)
5.1.1 rs485_init 函数
rs485_init 的配置与串口类似也需要设置波特率等参数另外还需要配置收发模式的驱动引脚程序设计如下
/*** brief RS485初始化函数* note 该函数主要是初始化串口* param baudrate: 波特率, 根据自己需要设置波特率值* retval 无*/
void rs485_init(uint32_t baudrate)
{/* IO 及 时钟配置 */RS485_RE_GPIO_CLK_ENABLE(); /* 使能 RS485_RE 脚时钟 */RS485_TX_GPIO_CLK_ENABLE(); /* 使能 串口TX脚 时钟 */RS485_RX_GPIO_CLK_ENABLE(); /* 使能 串口RX脚 时钟 */RS485_UX_CLK_ENABLE(); /* 使能 串口 时钟 */GPIO_InitTypeDef gpio_initure;gpio_initure.Pin RS485_TX_GPIO_PIN; /* 设置 TX 引脚 */gpio_initure.Mode GPIO_MODE_AF_PP; /* 设置引脚模式为复用推挽输出 */gpio_initure.Pull GPIO_PULLUP; /* 启用上拉电阻保证在空闲状态下引脚为高电平 */gpio_initure.Speed GPIO_SPEED_FREQ_HIGH; /* 设置引脚速度为高频率保证信号稳定 */gpio_initure.Alternate GPIO_AF7_USART2; /* 将引脚复用为串口 2 (USART2) */HAL_GPIO_Init(RS485_TX_GPIO_PORT, gpio_initure); /* 串口TX 脚 模式设置 */gpio_initure.Pin RS485_RX_GPIO_PIN; /* 设置 RX 引脚 */HAL_GPIO_Init(RS485_RX_GPIO_PORT, gpio_initure); /* 串口RX 脚 必须设置成输入模式 */gpio_initure.Pin RS485_RE_GPIO_PIN; /* 设置 RS485_RE 引脚用于控制发送/接收模式 */gpio_initure.Mode GPIO_MODE_OUTPUT_PP; /* 设置为推挽输出模式 */gpio_initure.Pull GPIO_PULLUP; /* 启用上拉电阻 */gpio_initure.Speed GPIO_SPEED_FREQ_HIGH; /* 设置引脚速度为高频率 */HAL_GPIO_Init(RS485_RE_GPIO_PORT, gpio_initure); /* RS485_RE 脚 模式设置 *//* USART 初始化设置 */g_rs458_handler.Instance 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); /* 使能对应的串口, 但会调用MSp */__HAL_UART_DISABLE_IT(g_rs458_handler, UART_IT_TC);#if RS485_EN_RX /* 如果使能了接收 *//* 使能接收中断 */__HAL_UART_ENABLE_IT(g_rs458_handler, UART_IT_RXNE); /* 开启接收中断 */HAL_NVIC_EnableIRQ(RS485_UX_IRQn); /* 使能USART1中断 */HAL_NVIC_SetPriority(RS485_UX_IRQn, 3, 3); /* 抢占优先级3子优先级3 */
#endifRS485_RE(0); /* 默认为接收模式 */
}
可以看到代码基本跟串口的配置一样只是多了收发控制引脚的配置。
5.1.2发送函数
发送函数用于输出 485 信号到 485 总线上默认的 485 方式一般空闲时为接收状态只有发送数据时485 芯片才进入发送状态发送完成后马上回到空闲接收状态这样可以保证操作过程中 485 的数据丢失最小。实现的发送函数如下
/*** brief RS485发送len个字节* param buf : 发送区首地址* param len : 发送的字节数(为了和本代码的接收匹配,这里建议不要超过 RS485_REC_LEN 个字节)* retval 无*/
void rs485_send_data(uint8_t *buf, uint8_t len)
{RS485_RE(1); /* 进入发送模式 */HAL_UART_Transmit(g_rs458_handler, buf, len, 1000); /* 串口2发送数据 */g_RS485_rx_cnt 0;RS485_RE(0); /* 进入接收模式 */
}
5.1.3 485 接收中断函数
RS485 的接收就与串口中断一样不过要注意空闲时要切换回接收状态否则会收不到数据。这里定义了一个全局的缓冲区 g_RS485_rx_buf 进行接收测试通过串口中断接收数据编写的接收代码如下
uint8_t g_RS485_rx_buf[RS485_REC_LEN]; /* 接收缓冲, 最大 RS485_REC_LEN 个字节. */
uint8_t g_RS485_rx_cnt 0; /* 接收到的数据长度 */void 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 */}}
}
5.1.4 485 查询接收数据函数
该函数用于查询 485 总线上接收到的数据主要实现的逻辑是一开始进入函数时先记录下当前接收计数器的值再来一个延时去判断接收是否结束即该期间有无接收到数据假如说接收计数器的值没有改变就证明接收结束我们就可以把当前接收缓冲区传递出去。函数实现如下
/*** brief RS485查询接收到的数据* param buf : 接收缓冲区首地址* param len : 接收到的数据长度* arg 0 , 表示没有接收到任何数据* arg 其他, 表示接收到的数据长度* retval 无*/
void 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(10); /* 等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束 */if (rxlen g_RS485_rx_cnt rxlen) /* 接收到了数据,且接收完成了 */{for (i 0; i rxlen; i){buf[i] g_RS485_rx_buf[i];}*len g_RS485_rx_cnt; /* 记录本次数据长度 */g_RS485_rx_cnt 0; /* 清零 */}
}5.2 添加 main.c并编写代码
5.2.1 在 MDK 主界面点击 新建一个txt文件。 图 5.1 新建文件 5.2.2 点击保存命名为main.c 并保存在 User 文件夹下如图 5.2 所示。 图 5.2 重命名并保存main.c 5.2.3 参考第3节添加文件步骤双击 User 分组弹出添加文件的对话框将 User 文件夹下的 main.c 文件添加到 User 分组下。得到 如图 5.3 所示的界面 图 5.3 在 User 分组下加入 main.c 文件 5.2.4程序流程图 图 5.4 程序流程图 在 main.c 文件里面输入如下代码
#include ./SYSTEM/sys/sys.h
#include ./SYSTEM/usart/usart.h
#include ./SYSTEM/delay/delay.h
#include ./BSP/LED/led.h
#include ./BSP/LCD/lcd.h
#include ./USMART/usmart.h
#include ./BSP/KEY/key.h
#include ./BSP/RS485/rs485.hint main(void)
{uint8_t key;uint8_t i 0, t 0;uint8_t cnt 0;uint8_t rs485buf[5];HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200); /* 串口初始化为115200 */usmart_dev.init(84); /* 初始化USMART */led_init(); /* 初始化LED */lcd_init(); /* 初始化LCD */key_init(); /* 初始化按键 */rs485_init(9600); /* 初始化RS485 */lcd_show_string(30, 50, 200, 16, 16, STM32, RED);lcd_show_string(30, 70, 200, 16, 16, RS485 TEST, RED);lcd_show_string(30, 90, 200, 16, 16, ATOMALIENTEK, RED);lcd_show_string(30, 110, 200, 16, 16, KEY0:Send, RED); /* 显示提示信息 */lcd_show_string(30, 130, 200, 16, 16, Count:, RED); /* 显示当前计数值 */lcd_show_string(30, 150, 200, 16, 16, Send Data:, RED); /* 提示发送的数据 */lcd_show_string(30, 190, 200, 16, 16, Receive Data:, RED);/* 提示接收到的数据 */while (1){key key_scan(0);if (key KEY0_PRES) /* KEY0按下,发送一次数据 */{for (i 0; i 5; i){rs485buf[i] cnt i; /* 填充发送缓冲区 */lcd_show_xnum(30 i * 32, 170, rs485buf[i], 3, 16, 0X80, BLUE); /* 显示数据 */}rs485_send_data(rs485buf, 5); /* 发送5个字节 */}rs485_receive_data(rs485buf, key);if (key) /* 接收到有数据 */{if (key 5)key 5; /* 最大是5个数据. */for (i 0; i key; i){lcd_show_xnum(30 i * 32, 210, rs485buf[i], 3, 16, 0X80, BLUE); /* 显示数据 */}}t;delay_ms(10);if (t 20){LED0_TOGGLE(); /* LED0闪烁, 提示系统正在运行 */t 0;cnt;lcd_show_xnum(30 48, 130, cnt, 3, 16, 0X80, BLUE); /* 显示数据 */}}
}
5.2.5 编译结果 0 错误 0 警告即编译成功。
编译结果提示代码总大小Porgram Size为FLASH 占用 44,864 字节Code RO RWSRAM 占用 2,128 字节RW ZI并成功创建了 Hex 文件可执行文件放在 Output 目录下。 图 5.5 运行成功结果 注意如果编译提示有错误/警告请根据提示从第一个错误/警告开始解决直到 0 错误0 警告。如果出错很有可能是之前的操作存在问题请对照教程找问题。
6. 下载验证
连接开发板在 MDK 主界面点击下载按钮也可以按键盘快捷键F8就可以将代码下载到开发板Build Output 提示Application running…则表示代码下载成功且开始运行。 图 6.1 下载成功 6.1 验证方式一
使用一个STM32开发板和USB 转 485 调试器串口助手A接AB接B。 图 6.2 STM32开发板和USB 转 485 调试器 图 6.3 串口调试助手收发结果16进制显示 6.2 验证方式二
通过下载代码到正点原子探索者 STM32F407 开发板上注意要 2 个开发板都下载这个代码。
使用 STM32F407 的串口 2 来实现两块开发板之间的 485 通信并将结果显示在 TFTLCD 模块上。 A连AB连B。 图 6.4 两块开发板 开发板下载成功后显示屏显示内容如图所示 图 6.5 程序运行效果图 伴随 DS0 的不停闪烁提示程序在运行。此时按下 KEY0 就可以在另外一个开发板上面收到这个开发板发送的数据了。 图 6.6 发送 RS485 数据的开发板界面 图 6.7 接收 RS485 数据的开发板界面 图 6.6 来自开发板 A发送了 5 个数据图 6.7 来自开发板 B接收到了来自开发板A 的 5 个数据。