一个简单的开头
介绍
此笔记为观看B站UP:超子说物联网所写,感谢老师。老师的架构真的特别好!
我在学习HAL库之前有标准库基础,所以学习稍快,但会尽量详细记录
笔记和项目文件在gitee开源了
大家可以在我的gitee仓库 中下载笔记源文件、STM32F1C8T6资料等
笔记源文件可以在Notion中导入
正在更新~
超子物联网 HAL库学习 写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!
内容导航
子页面开头
超子物联网 HAL库学习 汇总入口:超子物联网HAL库笔记:[汇总] 写作不易,如果您觉得写的不错,欢迎给博主来一波点赞、收藏~让博主更有动力吧!
准备篇
1. HAL库简介
HAL库
- HAL库(Hardware Abstraction Layer)是STMicroelectronics提供的STM32微控制器的硬件抽象层库。
- 它通过一套统一的API接口,简化了对STM32外设的配置和操作,使开发者能够更快速地进行嵌入式系统开发,而不必深入了解底层硬件细节。
HAL库的优点
- 高层次抽象:HAL库提供了高层次的抽象接口,简化了对硬件外设的操作。开发者可以通过调用库函数完成复杂的硬件配置,而不必直接操作寄存器。
- 易于使用:由于提供了丰富的库函数和示例代码,开发者可以快速上手进行开发,减少了开发时间。
- 一致性和移植性:HAL库在不同的STM32系列中保持了一致的API接口,增强了代码的移植性和重用性。如果需要更换STM32系列微控制器,代码的修改量较小。
- 简化调试:由于HAL库屏蔽了底层的寄存器操作,调试过程中更容易定位和解决问题,减少了开发和维护的复杂性。
- 代码维护性好:HAL库的高层次封装和良好的代码结构使得代码更容易维护和更新。
对比标准固件库的不同
- 抽象层次:
- 标准固件库:直接操作寄存器,提供底层硬件访问,要求开发者对STM32微控制器的寄存器有较深入的理解。
- HAL库:提供高层次的抽象接口,屏蔽底层寄存器操作,使开发者可以更快速地进行开发。
- 代码复杂性:
- 标准固件库:代码较复杂,涉及大量的寄存器配置,开发者需要处理更多的细节。
- HAL库:代码简洁易读,通过调用库函数进行配置和操作,减少了代码量和复杂性。
- 学习曲线:
- 标准固件库:学习曲线较陡,需要花费较多时间了解和掌握硬件细节。
- HAL库:学习曲线较缓,提供了丰富的示例代码和文档,开发者可以快速上手。
- 开发效率:
- 标准固件库:适合对性能和功耗有严格要求的项目,但开发和调试时间较长。
- HAL库:提高了开发效率,适合快速开发和原型设计,缩短了开发周期。
- 移植性:
- 标准固件库:不同系列的STM32微控制器之间存在较大的差异,代码移植工作量较大。
- HAL库:提供一致的API接口,增强了代码的移植性和重用性,不同系列之间的移植工作量较小。
2. 创建HAL库工程模板
1. 制作文件模板
- 先找一个位置,存放工程模板
- 在工程模板中 添加 User、Library 、 Hardware 、 CMSIS 文件夹:
- User:
- main.c
- Library:
- Include
- Source
- Hardware:
- Include
- Source
- CMSIS :
- Include
- Source
- 下载HAL库 源码 STM32Cube MCU和MPU包: 相关产品
- 解压并打开
- 拷贝HAL库(Library)
- 进入
\STM32Cube_FW_F1_V1.8.0\Drivers\STM32F1xx_HAL_Driver把头文件夹 Inc 和源文件夹 Src 移动到自己的Library的对应的文件中
- 拷贝启动文件(CMSIS\Include)
- 先进入内核文件
\STM32Cube_FW_F1_V1.8.0\Drivers\CMSIS - 进入头文件
\CMSIS\Include把所有文件拷贝到自己的CMSIS/Include文件中 再进入\CMSIS\Device\ST\STM32F1xx\Include把所有文件拷贝到自己的CMSIS/Include文件中
- 拷贝源文件(CMSYS\Source)
- 进入
\STM32Cube_FW_F1_V1.8.0\Drivers\CMSIS\Device\ST\STM32F1xx\Source\Templates - 把
\Templates文件的的system_stm32f1xx.c拷贝到自己的CMSIS/Source文件中 - 再进入/arm文件下,把所有文件拷贝到自己的CMSIS/Source文件中
- 编辑Hardware文件夹
分别在源文件家和头文件夹添加stm32f1xx_it.c 和stm32f1xx_it.h
代码如下
stm32f1xx_it.c
stm32f1xx_it.h
最后需要把自己的Library文件中的Include 文件中的stm32f1xx_hal_conf_template.h 更名为 stm32f1xx_hal_conf.h 。否则编译会找不到这个头文件
文件结构
2. Keil 创建工程
- 创建工程、选择User为目录。
- 点击木箱子设置分组
- User 、 Library 、 Hardware 、 CMSIS
- 导入文件
- 这里只导入必备的。以后用哪个再加那个
- Library:
- stm32f1xx_hal.c
- stm32f1xx_hal_cortex.c
- stm32f1xx_hal_gpio.c
- stm32f1xx_hal_gpio_ex.c
- stm32f1xx_hal_rcc.c
- stm32f1xx_hal_rcc_ex.c
- CNSIS:
- system_stm32f1xx.c
- startup_stm32f103xb.s
- User:
- main.c
- 在魔术棒中设置:
C/C++中:
在Define输入STM32F103xB (目的是通知编译器我们用的是xb)
添加头文件路径(Hardware、CMSIS、Library)。以后有别的添加则再添加。
Target中:
选择ARM编译器为v6.16 否则会报错
- 在main.c中引入头文件stm32f1xx_hal.h (在hal.c中可找到)
- 最后编译即可。0错误0警告
3. HAL库结构初步分析
- 以HAL库的串口为例来讲解
- 串口分为USART和UART 他们分别是同步通信和异步通信。一般我们用异步的
- hal库之中,串口包含三种方式: 轮询、中断、DMA。所以在库文件中必须添加DMA库
所以这里我们添加uart.c的文件。
所以我们这里添加DMA.c的文件
- 在HAL库中每个外设都有两个关键的部分:
- Private:(私有的),是HAL库内部自己调用的
- Exported:(对外的),我们的应用程序中去调用。Exported分为四个部分
- types,各种Struct结构体,用于外设功能配置。对应了CubeMax软件的配置项
- constants,上方各种Struct结构体中的成员的可以配置的选项
- macro,宏定义,相当于直接对寄存器操作。因为在某些时候调用api反而效率不高
- functions,API函数。
这些是可以在文件中验证的。hal_uart.c中 可见
我们对CubeMax的操作,实际上就是与这些结构体、成员变量一一对应的
一个外设的相关结构体会被定义在一个总的结构体中。比如串口是UART_HandleTypedef
时钟篇
1. 汇编启动文件调用SystemInit对时钟的配置内容
汇编的启动文件(.s结尾的那个)在每次复位时,都是先调用SystemInit函数去配置时钟。
默认的最终时钟是 使用的是内部的HSI 内部高速时钟 8MHZ
- SystemInit首先会设置CR寄存器(时钟控制寄存器)把位0置1(使用内部高速时钟)。
- 然后会去设置CFGR寄存器,主要是设置路径,以及倍频之类的东西
2. HAL库输出内部时钟HSI
我们可以调用
HAL_RCC_MCOConfig 来把时钟输出8MHZ的方波到默认的PA8上验证一下。在使用HAL库前要用HAL_Init()初始化一下。
main.c
HAL_Init();//初始化HAL库
HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);//PA8引脚输出、系统时钟、不分频
所以仅仅需要这两行就可以输出时钟了。示波器验证正确。
3. 使用内部HSI时钟通过PLL倍频到64MHZ
注意
- APB1最大时钟为36MHZ
- APB2最大时钟为72MHZ

需要设置的。和路线,其实就是在函数中一步步设置。
代码如下
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
/*函 数 名:hal库rcc输出内部8Mhz方波
*参 数:
*返 回 值:
*注意事项:
*/
uint32_t HCLKFreq = 0;//显示时钟树三处频率
uint32_t PCLK1Freq = 0;
uint32_t PCLK2Freq = 0;
int main (void)
{
HAL_Init();//初始化HAL库
RCC_ClockInit();//配置时钟树初始化
HAL_RCC_MCOConfig(RCC_MCO1,RCC_MCO1SOURCE_SYSCLK,RCC_MCODIV_1);//PA8引脚输出、系统时钟、不分频
HCLKFreq = HAL_RCC_GetHCLKFreq();
PCLK1Freq = HAL_RCC_GetPCLK1Freq();
PCLK2Freq = HAL_RCC_GetPCLK2Freq();
while(1)
{
}
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
void RCC_ClockInit()
{
RCC_OscInitTypeDef RCC_OsInitStructure; //设置内外部时钟源配置结构体
RCC_ClkInitTypeDef RCC_ClkInitStructure;//设置总线时钟结构体
RCC_OsInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSI; //选择震荡电路为内部高速
RCC_OsInitStructure.HSIState = RCC_HSI_ON; //打开时钟
RCC_OsInitStructure.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; //设置微调值 默认
RCC_OsInitStructure.PLL.PLLState = RCC_PLL_ON; //设置PLL为打开
RCC_OsInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; //选择PLL输入为内部高速时钟
RCC_OsInitStructure.PLL.PLLMUL = RCC_PLL_MUL16; //设置16倍频
HAL_RCC_OscConfig(&RCC_OsInitStructure); //传给话务员..
RCC_ClkInitStructure.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 |RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_SYSCLK;//需要配置的时钟
RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //SYSCLK系统时钟输入源 PLL作为系统时钟
RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB预分频 1分频
RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV2; //APB1预分频 2分频
RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV1; //APB2预分频 1分频
HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);//传给话务员,并且根据频率设置FLASH等待周期为2
//话务员相关配置可以在API函数中找到。结构体相关配置在结构体和成员中可找到
}
结果如下(转换成10进制):分别为 64M 32M 64M

4. 使用外部HSE时钟通过PLL倍频到72MHZ
流程如下

只修改了rcc.c的文件
rcc.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
void RCC_ClockInit()
{
RCC_OscInitTypeDef RCC_OsInitStructure; //设置内外部时钟源配置结构体
RCC_ClkInitTypeDef RCC_ClkInitStructure;//设置总线时钟结构体
RCC_OsInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //选择震荡电路为外部高速
RCC_OsInitStructure.HSEState = RCC_HSE_ON; //打开HSE时钟
RCC_OsInitStructure.HSEPredivValue = RCC_HSE_PREDIV_DIV1; //不分频
RCC_OsInitStructure.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; //设置微调值 默认
RCC_OsInitStructure.PLL.PLLState = RCC_PLL_ON; //设置PLL为打开
RCC_OsInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //选择PLL输入为外部高速时钟
RCC_OsInitStructure.PLL.PLLMUL = RCC_PLL_MUL9; //设置9倍频
HAL_RCC_OscConfig(&RCC_OsInitStructure); //传给话务员..
RCC_ClkInitStructure.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 |RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_SYSCLK;//需要配置的时钟
RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //SYSCLK系统时钟输入源 PLL作为系统时钟
RCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB预分频 1分频
RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV2; //APB1预分频 2分频
RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV1; //APB2预分频 1分频
HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);//传给话务员,并且根据频率设置FLASH等待周期为2
//话务员相关配置可以在API函数中找到。结构体相关配置在结构体和成员中可找到
}
结果:

5. HAL_Init库函数源码分析 及 Systick时基
HAL_Init 是 HAL库要求我们调用的第一个函数。
下面是HAL_Init调用时 做的工作:
- 把指令预取功能打开
- 设置中断分组
- 将Systick作为时间基准,配置为1ms的中断
- 初始化底层硬件
- 返回 HAL_OK
标准库和HAL库的很大的一个区别:Systick
- 每次进入Systick中断时 对32位全局变量uwTick累加1
- 提供了HAL_GetTick 获取uwTick全局变量
Systick时基最常用的地方就是各个外设采用阻塞轮训处理数据时,做超时判断、阻塞延时、
中断处理函数及weak弱声明中断回调函数详解
一、STM32 中断处理方式概述
在 STM32 的开发中,中断是一种非常重要的机制,用于响应外部事件或内部异常情况。STM32 在启动文件(stmxxxxx.s)中为我们预先定义了所有中断的中断服务函数。这意味着当特定的中断发生时,处理器会自动跳转到相应的中断服务函数处执行代码。
二、标准库中断处理方式
在标准库中,处理中断需要开发者自己去判断中断标志位,确定中断是否发生,然后执行相应的操作,最后还需要手动清除中断标志位。例如在 EXTI15_10_IRQHandler 中断服务函数中,开发者需要通过检查特定的线(比如线 12)的中断标志位来判断该中断是否发生,如果中断标志位为真,则执行特定的操作,最后还需要清除线 12 产生的中断标志位,以确保下次中断能够正确响应。
三、HAL 库中断处理方式
- 自动判断与清除标志位:
- HAL 库(以 gpio.c 为例)为各个外设的中断提供了更加便捷的处理方式。在 HAL 库提供的中断处理函数中,会自动判断中断标志位并清除标志位。例如在
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)函数中,首先使用__HAL_GPIO_EXTI_GET_IT(GPIO_Pin)!= 0x00u来判断标志位,确定中断是否发生。如果中断发生,接着使用__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin)来清除标志位,确保下次中断能够正常响应。
- 回调函数机制:
- 在自动判断和清除标志位的函数中,还提供了一个回调函数
HAL_GPIO_EXTI_Callback(GPIO_Pin)。这个回调函数的作用是在中断发生并且标志位被正确处理后,执行用户自定义的操作。
- 弱声明的回调函数:
- 在自动判断和清除标志位的函数下,会有回调函数有一个弱声明:
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)。这个弱声明的回调函数只是为了防止编译报错而存在的,它内部实际上什么操作都不执行,只是通过UNUSED(GPIO_Pin)来告诉编译器这个参数虽然没有被使用,防止产生编译错误。
- 强声明的回调函数:
- 开发者可以在自己的代码中定义一个 “强声明” 的中断回调函数,即
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)。当程序编译时,会自动使用这个强声明的回调函数替代弱声明的回调函数。这样,当中断发生时,就会执行开发者自定义的回调函数,而不是弱声明的空函数。
gpio.c中判断中断、清除中断、执行回调函数和对应的弱声明的代码部分:
//stm启动文件中已经定义的中断服务函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)//帮我们判断标志位
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);//帮我们清除标志位
HAL_GPIO_EXTI_Callback(GPIO_Pin);//执行回调函数
}
}
// 弱声明 的回调函数 只是为了防止报错用
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
UNUSED(GPIO_Pin);//什么都不执行,只是为了防止编译时报错:没有使用xxx
}
四、在程序中的应用
为了让 HAL 库的中断处理函数能够正确地响应中断并执行自定义的回调函数,我们只需要在 it.c 文件中,在中断发生时跳转到 HAL 库的中断处理函数。这样,当中断发生时,HAL 库的中断处理函数就会自动帮我们判断中断标志位、清除标志位,并进入对应的回调函数,执行我们自定义的操作。
比如(以gpio.c为例):
it.c文件:
void EXTI15_10_IRQHandler (void) //如果发生了这个中断
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);//跳转到HAL库的中断处理
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12);//跳转到HAL库的中断处理
}
/ 注册回调函数 /
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_13) // 判断是不是13线
{
// 执行13线程序
// ...
}
else if (GPIO_Pin == GPIO_PIN_12) // 判断是不是12线
{
// 执行12线程序
// ...
}
}
串口篇
这篇文章介绍了HAL库大多的使用方法,并配有详细的思路和注释。
一、介绍
HAL库在 异步通信UART 串口部分提供了三种方式:
- 轮询阻塞
- 非阻塞中断 或者 DMA
- 所以在使用串口时,也要添加DMA.c到库
以STM32C8T6为例,有三个串口资源:
- USART1:
- TX:PA9 可重映射为 PB 6
- RX:PA10 可重映射为 PB 7
- USART2:
- TX:PA2
- RX:PA3
- USART3:
- TX:PB10
- RX:PB11
二、HAL库:阻塞轮询方式 实现USART1 串口 异步收发
1. 引脚定义
- USART1:
- TX:PA9
- RX:PA10
2. 补充:为什么在while循环接收时,没必要对HAL_ERROR、HAL_BUSY进行处理
HAL_ERROR:
- 用于判断buff为空指针或者数据长度为0的情况
HAL_BUSY:
- 用于判断Busy状态
所以我们只需要判断他的另外两种状态,HAL_OK(在规定时间内接收到n个数据)、和HAL_TIMEOUT(未在规定时间接收到n个数据,导致超时退出接收)
3. 注意事项:
- HAL库的串口初始化, 硬件部分的时钟以及GPIO口的配置,需要我们自己来配置
在
HAL_UART_Init(&Uart1); 函数被调用时。
会调用一个weak弱声明的void HAL_UART_MspInit(UART_HandleTypeDef *huart) 函数。
这个函数就是留给我们强声明 配置硬件用的。我们需要在里边打开 串口1 和 GPIO的 时钟。 - 需要注意的是USART1与定时器的引脚有冲突。 如果发生冲突 可以重映射 串口到别的引脚。
- RxXferSiZe是用来记录接收总量的
- RxXferCount是用来记录剩余需要接收数量的
注意,这里的RxXferCount 进到while中就先减1 了。这个知识点后面会用到
4. 串口1初始化部分:
5. 串口1配置硬件部分
6. 主函数部分
- 主函数中。需要使用接收串口的函数:
HAL_UART_Receive(&Uart1,Buff,Rx_Size,200)
他的参数分别为:串口配置结构体地址、接收缓冲区(我们自己定义的数组)、预计接收的字节个数(我们自己定义)、超时时间(单位为ms)
这里的
Rx_Size 为 200因此我们需要在UART.h 头文件中添加结构体对外声明
extern UART_HandleTypeDef Uart1;- 接收串口的函数会有 四个返回值:
- HAL_OK、 代表此次在200ms内接受到了 200 字节。 (也就是与预计相等)
- HAL_ERROR 、代表传参错误、 比如超时时间为0、或者数据缓冲区地址为空
- HAL_TIMEOUT 、代表未能在规定时间内接收到 200 个字节
- 往往分为两种情况: 1、接收了但没接收完、2、一点没接收
- HAL_BUSY、代表已经在接受了。你别来烦我
下面可以看代码来分析
三、HAL库:阻塞轮询方式 实现串口2、3 和串口1重映射
1. 引脚定义
- USART1:
- TX:PA9 可重映射为 PB 6
- RX:PA10 可重映射为 PB 7
- USART2:
- TX:PA2
- RX:PA3
- USART3:
- TX:PB10
- RX:PB11
2. 关键代码:
- 如果需要重映射,则还需要打开AFIO的时钟和 使用重映射 API:
3. 串口1、2、3、初始化部分:
与之前的无异,只是添加拷贝了三次
4. 主函数部分
- 与之前的一样,想使用什么修改下”UartX“参数就行,
四、HAL库:中断方式 实现串口1 定长数组异步收发
我们就使用上一小节所讲的多指针定位+循环收发缓冲区方案设计,来实现这次的中断接收~
1. 注意事项
- HAL库为 串口中断提供了很多回调函数。 比如 错误回调、半完成回调、Rx、Tx完成回调。你需要用什么回调,就声明什么回调~
- 这里只用了接收完成回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) - “Rx” 通常代表 “Receive”,即接收。
- “Cplt” 通常代表 “Complete”,即完成。
- “Callback” 即回调,指的是当某个特定事件发生时被调用的函数。
其中“RxCpltCallback” 可以分解为以下部分:
- 我们在回调函数中。 我们将接收缓冲区的数据memcpy到 发送缓冲区。 并置 接收完成标志位。 在主函数中,只需要循环检测 标志位 后 并发送发送缓冲区中的数据就可以完成接收并发送数据了。 中断接收在接收到数据之后 需要在回调函数中要重新打开。 因为中断接收一次会自动关闭
- 在使用UART 的IT 接收时。要配置NVIC :USART 线的 优先级和 使能USART线
- 这里的定长,是因为中断只有接收到20个字节之后,才会进入回调函数
2. 初始化UART1部分
- 主要关注中断 完成接收回调函数部分。 主要完成了数据cpy 和置位接收状态以及 重新启动接收数据。
- 以及关注定义的接收、发送缓冲区和Rx_Date接收状态标志位
3. UART硬件初始化回调
3. 回调函数部分
/ 强声明的错误回调函数 /
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的发送完成回调函数 /
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
4. 函数测试部分
- 主要完成了轮询检测状态并返回接收到的 拷贝到 发送缓冲区 的 数据
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "key.h"
#include "Uart.h"
/函 数 名:HAL库:中断方式。实现UART串口数据收发。 定长 20字节 /
int main (void)
{
HAL_Init();//初始化HAL库
RccClock_Init();//配置时钟树72M
LED_Init();
Uart1_Init(921600);//初始化串口1
while(1)
{
if(Rx_Date == 1) //如果接收标志位置1
{
Rx_Date = 0;
HAL_UART_Transmit_IT(&Uart1,Tx_Buff,20);//发送 发送缓冲区的20个字节
}
}
}
五、多指针定位+循环收发缓冲区方案设计(“六”为实践此方案)
1. 介绍
轮询阻塞的方式效率不高,一般会使用中断或者DMA方式收发数据
这时就需要定义一个缓冲区,这里暂定为2048字节。
- 缓冲区为一个、一维数组,循环使用,要注意缓冲区不要出现回卷覆盖,接收的数据要及时处理。
2. 大致思路
标记2048缓冲区每次数据的起始和结束位置
- 创建一个标记结构体,成员为指针pS(Start)和pE(Een)。他们用来在2048的缓冲区中,指向每次接收的数据的开头和起始位置。
- 使用我们刚才创建的‘标记结构体’,创建一个有10个成员的数组SN
- 创建一个IN和OUT指针,初始化时指向SN数组的起始位置(0号成员)
- 创建一个END指针,指向SN数组的结束位置(9号成员)
巧妙地判断接收到数据,并循环利用标记
- 当第一次接收到数据之后,使用0号成员的pS、pE指针定位数组的起始和结束位置, 同时IN++,指向数组SN的1号成员
- 此时,可以在while循环中判断,当OUT指针与IN指针不指向同一个位置了,那么就代表已经缓冲区收到数据了。在处理完数据之后,使得OUT++,指向第1号成员~
- 当第pS跳到END指向的位置时,应使得PS下次跳的位置为数组SN的起始位置:数据回滚,防止越界
防止2048缓冲区空余位置不够
- 约定每次接收数据的MAX值,防止空余位置不够。
- 所以在每次接收之后,都需要判断空余位置,若小于MAX值,则直接回卷,防止越界
利用空闲中断,完成对数据的处理
- 定义了单次接收的最大值MAX,若MAX=256,那么别人一次发送的值最多为255字节,因为当一次次发送256时,会同时触发完成中断和空闲中断,这是不允许的。
- 我们只利用空闲中断对数据进行处理哦~
六、HAL库:空闲中断方式实现串口1+不定长数据接收+循环收发缓冲区+收发数据
1. 不定长接收数据的实现思路及相关函数
在使用简单串口时,无法知道对方给我发送的确切的数据量。我就没法确切的定义我们需要接收多少个字节的字节。只能接收到固定长度的字节后统一处理。
要实现不定长接收数据,我们通常是利用空闲中断。

当一次连续的接收完成后,会出现空闲帧,然后进入空闲中断中。
我们就可以利用空闲中断,来判断当前为一次数据的接收结束。
然后可以利用RxferCount,来获取本次接受了多少个字节。
在空闲中断回调中,我们可以对数据进行处理或判断
注意:
- 定义了单次接收的最大值MAX,若MAX=256,那么别人一次发送的值最多为255字节,因为当一次次发送256时,会同时触发完成中断和空闲中断,这是不允许的。
- 一定要想明白,位置控制数组rxLocation 和 rxInPtr和 rxOutPtr的关系,可以看图理解


- 我们只利用空闲中断对数据进行处理哦~
相关函数
- 空闲中断打开函数:
__HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
- 在每次进入中断后,判断是否为空闲中断:
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE))
- 清除空闲标志位
__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
- 终止当前的接收(会把RxferCount清零)
HAL_UART_AbortReceive_IT(&uart1.uart);
- 终止接收回调函数
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)- 发送完成回调函数
HAL_UART_TxCpltCallback2. 程序设计
STM32C8T6单片机一共有20K的RAM
2.1 设计介绍:
- 定义缓冲区宏
/ 缓冲区宏定义 /
#define U1_RX_SIZE 2048
#define U1_TX_SIZE 2048
#define U1_RX_MAX 256 //这里需要注意,我们是利用空闲中断对数据进行处理,不能单次发送256字节,否则进入完成中断
/ 缓冲区 /
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];
/ Location Ctrl Block /
/ (接收/发送)位置控制块 /
typedef struct{
uint8_t* start;
uint8_t* end;
}LCB;
/ Uart Ctrl Block /
/ 串口控制块 /
typedef struct{
uint32_t rxCount; //记录接收缓冲区中当前已有的数据量
uint32_t txCount; //记录发送缓冲区中当前已有的数据量
LCB rxLocation[10]; //记录接收缓冲区每次接收的位置
LCB txLocation[10]; //记录发送缓冲区每次接收的位置
LCB* rxInPtr; //指向下次接收缓冲区存放位置
LCB* rxOutPtr; //指向下次接收缓冲区读取位置
LCB* rxEndPtr; //指向接收缓冲区结束位置
LCB* txInPtr; //指向下次发送缓冲区存放位置
LCB* txOutPtr; //指向下次发送缓冲区读取位置
LCB* txEndPtr; //指向发送缓冲区结束位置
UART_HandleTypeDef uart; //串口总控结构体
uint8_t TxState; //发送忙碌标志位
}UCB;
/ 初始化 /
void U1_Init(uint32_t bandrate);
/ 初始化UCB控制块指针 /
void U1_PtrInit(void);
/ 转移RxBuff数据到TxBuff /
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
/ 总控结构体 /
extern UCB uart1;
/ 缓冲区 /
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];
/ 状态位 /
extern uint8_t rxState;
2.2 文件架构:
- Uart.h :定义了 宏、结构体、函数与变量声明
- Uart.c :主要针对串口 1 进行配置:空闲中断打开和处理、包括初始化参数、设置缓冲区指针….
- stm32fxx_It.c : 主要是
void USART1_IRQHandler(void)的中断函数:该函数是串口 1 的中断服务函数。首先调用 HAL 库的中断处理函数,后续 检测到串口 1 进入空闲状态时,清除空闲中断标志位,计算接收字节数量并累加,然后终止接收,触发终止接收回调函数。终止接收回调函数在Uart.c中
- main.c :在主循环中,通过判断接收和发送缓冲区的指针状态,实现数据的接收和发送,并在指针到达末尾时进行回卷操作。当接收缓冲区有数据时,将其拷贝到发送缓冲区并移动输出指针;当发送缓冲区有数据且处于空闲状态时,发送数据并移动输出指针。
uart.h
#ifndef __UART_H
#define __UART_H
#include "stm32f1xx_hal.h"
#include "stdint.h"
#include "string.h"
/ 缓冲区宏定义 /
#define U1_RX_SIZE 2048
#define U1_TX_SIZE 2048
#define U1_RX_MAX 256 //这里需要注意,我们是利用空闲中断对数据进行处理,不能单次发送256字节,否则进入完成中断
/ Location Ctrl Block /
/ (接收/发送)位置控制块 /
typedef struct{
uint8_t* start;
uint8_t* end;
}LCB;
/ Uart Ctrl Block /
/ 串口控制块 /
typedef struct{
uint32_t rxCount; //记录接收缓冲区中当前已有的数据量
uint32_t txCount; //记录发送缓冲区中当前已有的数据量
LCB rxLocation[10]; //记录接收缓冲区每次接收的位置
LCB txLocation[10]; //记录发送缓冲区每次接收的位置
LCB* rxInPtr; //指向下次接收缓冲区存放位置
LCB* rxOutPtr; //指向下次接收缓冲区读取位置
LCB* rxEndPtr; //指向接收缓冲区结束位置
LCB* txInPtr; //指向下次发送缓冲区存放位置
LCB* txOutPtr; //指向下次发送缓冲区读取位置
LCB* txEndPtr; //指向发送缓冲区结束位置
UART_HandleTypeDef uart; //串口总控结构体
uint8_t TxState; //发送忙碌标志位
}UCB;
/ 初始化 /
void U1_Init(uint32_t bandrate);
/ 初始化UCB控制块指针 /
void U1_PtrInit(void);
/ 转移RxBuff数据到TxBuff /
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
/ 总控结构体 /
extern UCB uart1;
/ 缓冲区 /
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];
/ 状态位 /
extern uint8_t rxState;
#endif
uart.c
#include "uart.h"
/ 创建串口总控结构体 /
UCB uart1;
/ 缓冲区 /
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];
/ 初始化串口 /
void U1_Init(uint32_t bandrate){
uart1.uart.Instance = USART1; //使用那个串口
uart1.uart.Init.BaudRate = bandrate; //波特率
uart1.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
uart1.uart.Init.StopBits = UART_STOPBITS_1; //停止位
uart1.uart.Init.Parity = UART_PARITY_NONE; //校验模式
uart1.uart.Init.Mode = UART_MODE_TX_RX; //传输模式
uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
HAL_UART_Init(&uart1.uart);
/ 初始化UCB控制块指针 /
U1_PtrInit();
/ 打开空闲中断 /
__HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
/ 开始接收数据 /
HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX); //接收位置为当前LCB位置控制块的In指针所指向的缓冲区的位置
}
/ 初始化U1_UCB控制块指针 /
void U1_PtrInit(void){
uart1.rxCount = 0;
uart1.rxInPtr = &uart1.rxLocation[0];
uart1.rxOutPtr = &uart1.rxLocation[0];
uart1.rxEndPtr = &uart1.rxLocation[9];
uart1.rxInPtr->start = &U1_Rx_Buff[0]; //让当前接收位置控制块的start,指向下一次接收到的数据将要存放的位置
uart1.txCount = 0;
uart1.txInPtr = &uart1.txLocation[0];
uart1.txOutPtr = &uart1.txLocation[0];
uart1.txEndPtr = &uart1.txLocation[9];
uart1.txInPtr->start = &U1_Tx_Buff[0]; //让当前发送位置控制块的start,指向下一次需要发送的数据的存放位置
}
/ 转移U1_Rx_Buff数据到 U1_Tx_Buff /
void U1_DataRxToTx(uint8_t* data, uint32_t data_len){
/ 判断剩余空间是否足够,要不要回卷 /
if((U1_TX_SIZE - uart1.txCount) > data_len){
/ 如果够 /
uart1.txInPtr->start = &U1_Tx_Buff[uart1.txCount];
}
else{/ 如果剩余空间不够 /
uart1.txCount = 0;
uart1.txInPtr->start = &U1_Tx_Buff[0];
}
/ 复制data到U1_Tx_Buff缓冲区 /
memcpy(uart1.txInPtr->start, data, data_len);
/ 累加txCount /
uart1.txCount += data_len;
/ 标记这次的发送数据的结束位置 /
uart1.txInPtr->end = &U1_Tx_Buff[uart1.txCount - 1];
/ 移动txIn /
uart1.txInPtr++;
/ 判断txIn指针是否需要回卷 /
if(uart1.txInPtr == uart1.txEndPtr){
uart1.txInPtr = &uart1.txLocation[0];
}
}
/ UART硬件初始化回调 /
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){ //判断那个串口在进行初始化
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
//打开了串口1的总中断
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}else if(huart->Instance == USART2){
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_11;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
}
}
/ 强声明的接收完成回调函数 /
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的错误回调函数 /
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的发送完成回调函数 /
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
/ 发送完成,标志位清零 /
uart1.TxState = 0;
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的接收终止回调函数 /
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
/ 标记结束位置 /
uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
/ 挪动rxIn指针 /
uart1.rxInPtr++;
/ 判断rxIn指针是否需要回卷 /
if(uart1.rxInPtr == uart1.rxEndPtr){
uart1.rxInPtr = &uart1.rxLocation[0];
}
/ 判断接收缓冲区是否需要回卷 /
if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
uart1.rxCount = 0;
uart1.rxInPtr->start = &U1_Rx_Buff[0];
}else{
/ 剩余位置够 /
uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
}
/ 重新开启中断接收 /
HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
stm32fxx_It.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
/-------------------------------------------------/
/函数名:串口1中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
/ 在每次进入中断后,判断是否为空闲中断 /
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
/ 清除空闲标志位 /
//__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
/ 获取这次传输了多少字节 /
uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
/ 终止当前的接收(会把RxferCount清零) /
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
while(1){
/ 判断接收缓冲区是否有数据 /
if(uart1.rxInPtr != uart1.rxOutPtr){
/ 转移这次接收的一段数据到发送缓冲区 /
U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));
/ 移动rxOutPtr到下一次cpy的地址 /
uart1.rxOutPtr++;
/ 判断rxOutPtr是否需要回卷 /
if(uart1.rxOutPtr == uart1.rxEndPtr){
uart1.rxOutPtr = &uart1.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
uart1.TxState = 1;
/ 发送数据 /
HAL_UART_Transmit_IT(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
/ 移动txOutPtr到下一次cpy的地址 /
uart1.txOutPtr++;
/ 判断txOutPtr是否需要回卷 /
if(uart1.txOutPtr == uart1.txEndPtr){
uart1.txOutPtr = &uart1.txLocation[0];
}
}
}
}
七、HAL库:空闲中断方式实现串口123+不定长数据接收+循环收发缓冲区+收发数据
在第七小节拓展而来:实现串口1 2 3 同时收发数据,可以用来控制多个设备用
uart.h
#ifndef __UART_H
#define __UART_H
#include "stm32f1xx_hal.h"
#include "stdint.h"
#include "string.h"
/ 缓冲区宏定义 /
#define U1_RX_SIZE 2048 //接收缓冲区长度
#define U1_TX_SIZE 2048 //发送缓冲区长度
#define U1_RX_MAX 256 //最大单次发送量(实际值 - 1 = 255字节)
#define U2_RX_SIZE 2048
#define U2_TX_SIZE 2048
#define U2_RX_MAX 256
#define U3_RX_SIZE 2048
#define U3_TX_SIZE 2048
#define U3_RX_MAX 256
/ Location Ctrl Block /
/ (接收/发送)位置控制块 /
typedef struct{
uint8_t* start;
uint8_t* end;
}LCB;
/ Uart Ctrl Block /
/ 串口控制块 /
typedef struct{
uint32_t rxCount; //记录接收缓冲区中当前已有的数据量
uint32_t txCount; //记录发送缓冲区中当前已有的数据量
LCB rxLocation[10]; //记录接收缓冲区每次接收的位置
LCB txLocation[10]; //记录发送缓冲区每次接收的位置
LCB* rxInPtr; //指向下次接收缓冲区存放位置
LCB* rxOutPtr; //指向下次接收缓冲区读取位置
LCB* rxEndPtr; //指向接收缓冲区结束位置
LCB* txInPtr; //指向下次发送缓冲区存放位置
LCB* txOutPtr; //指向下次发送缓冲区读取位置
LCB* txEndPtr; //指向发送缓冲区结束位置
UART_HandleTypeDef uart; //串口总控结构体
uint8_t TxState; //发送忙碌标志位
}UCB;
/ 初始化 /
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);
/ 初始化UCB控制块指针 /
void U1_PtrInit(void);
void U2_PtrInit(void);
void U3_PtrInit(void);
/ 转移RxBuff数据到TxBuff /
void U1_DataRxToTx(uint8_t* data, uint32_t data_len);
void U2_DataRxToTx(uint8_t* data, uint32_t data_len);
void U3_DataRxToTx(uint8_t* data, uint32_t data_len);
/ 总控结构体 /
extern UCB uart1;
extern UCB uart2;
extern UCB uart3;
/ 缓冲区 /
extern uint8_t U1_Rx_Buff[U1_RX_SIZE];
extern uint8_t U1_Tx_Buff[U1_TX_SIZE];
extern uint8_t U2_Rx_Buff[U2_RX_SIZE];
extern uint8_t U2_Tx_Buff[U2_TX_SIZE];
extern uint8_t U3_Rx_Buff[U3_RX_SIZE];
extern uint8_t U3_Tx_Buff[U3_TX_SIZE];
#endif
uart.c
#include "uart.h"
/ 创建串口总控结构体 /
UCB uart1;
UCB uart2;
UCB uart3;
/ 缓冲区 /
uint8_t U1_Rx_Buff[U1_RX_SIZE];
uint8_t U1_Tx_Buff[U1_TX_SIZE];
uint8_t U2_Rx_Buff[U2_RX_SIZE];
uint8_t U2_Tx_Buff[U2_TX_SIZE];
uint8_t U3_Rx_Buff[U3_RX_SIZE];
uint8_t U3_Tx_Buff[U3_TX_SIZE];
/ 初始化串口 /
void U1_Init(uint32_t bandrate){
uart1.uart.Instance = USART1; //使用那个串口
uart1.uart.Init.BaudRate = bandrate; //波特率
uart1.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
uart1.uart.Init.StopBits = UART_STOPBITS_1; //停止位
uart1.uart.Init.Parity = UART_PARITY_NONE; //校验模式
uart1.uart.Init.Mode = UART_MODE_TX_RX; //传输模式
uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
HAL_UART_Init(&uart1.uart);
/ 初始化UCB控制块指针 /
U1_PtrInit();
}
/ 初始化串口 /
void U2_Init(uint32_t bandrate){
uart2.uart.Instance = USART2; //使用那个串口
uart2.uart.Init.BaudRate = bandrate; //波特率
uart2.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
uart2.uart.Init.StopBits = UART_STOPBITS_1; //停止位
uart2.uart.Init.Parity = UART_PARITY_NONE; //校验模式
uart2.uart.Init.Mode = UART_MODE_TX_RX; //传输模式
uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
HAL_UART_Init(&uart2.uart);
/ 初始化UCB控制块指针 /
U2_PtrInit();
}
/ 初始化串口 /
void U3_Init(uint32_t bandrate){
uart3.uart.Instance = USART3; //使用那个串口
uart3.uart.Init.BaudRate = bandrate; //波特率
uart3.uart.Init.WordLength = UART_WORDLENGTH_8B; //数据位长度
uart3.uart.Init.StopBits = UART_STOPBITS_1; //停止位
uart3.uart.Init.Parity = UART_PARITY_NONE; //校验模式
uart3.uart.Init.Mode = UART_MODE_TX_RX; //传输模式
uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE; //流控
HAL_UART_Init(&uart3.uart);
/ 初始化UCB控制块指针 /
U3_PtrInit();
}
/ 初始化U1_UCB控制块指针 /
void U1_PtrInit(void){
uart1.rxCount = 0;
uart1.rxInPtr = &uart1.rxLocation[0];
uart1.rxOutPtr = &uart1.rxLocation[0];
uart1.rxEndPtr = &uart1.rxLocation[9];
uart1.rxInPtr->start = &U1_Rx_Buff[0];
uart1.txCount = 0;
uart1.txInPtr = &uart1.txLocation[0];
uart1.txOutPtr = &uart1.txLocation[0];
uart1.txEndPtr = &uart1.txLocation[9];
uart1.txInPtr->start = &U1_Tx_Buff[0];
__HAL_UART_ENABLE_IT(&uart1.uart,UART_IT_IDLE);
HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
}
void U2_PtrInit(void){
uart2.rxCount = 0;
uart2.rxInPtr = &uart2.rxLocation[0];
uart2.rxOutPtr = &uart2.rxLocation[0];
uart2.rxEndPtr = &uart2.rxLocation[9];
uart2.rxInPtr->start = &U2_Rx_Buff[0];
uart2.txCount = 0;
uart2.txInPtr = &uart2.txLocation[0];
uart2.txOutPtr = &uart2.txLocation[0];
uart2.txEndPtr = &uart2.txLocation[9];
uart2.txInPtr->start = &U2_Tx_Buff[0];
__HAL_UART_ENABLE_IT(&uart2.uart,UART_IT_IDLE);
HAL_UART_Receive_IT(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
}
void U3_PtrInit(void){
uart3.rxCount = 0;
uart3.rxInPtr = &uart3.rxLocation[0];
uart3.rxOutPtr = &uart3.rxLocation[0];
uart3.rxEndPtr = &uart3.rxLocation[9];
uart3.rxInPtr->start = &U3_Rx_Buff[0];
uart3.txCount = 0;
uart3.txInPtr = &uart3.txLocation[0];
uart3.txOutPtr = &uart3.txLocation[0];
uart3.txEndPtr = &uart3.txLocation[9];
uart3.txInPtr->start = &U3_Tx_Buff[0];
__HAL_UART_ENABLE_IT(&uart3.uart,UART_IT_IDLE);
HAL_UART_Receive_IT(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
}
/ 转移Rx_Buff数据到 Tx_Buff /
void U1_DataRxToTx(uint8_t* data, uint32_t data_len){
if((U1_TX_SIZE - uart1.txCount) > data_len){
uart1.txInPtr->start = &U1_Tx_Buff[uart1.txCount];
}
else{
uart1.txCount = 0;
uart1.txInPtr->start = &U1_Tx_Buff[0];
}
memcpy(uart1.txInPtr->start, data, data_len);
uart1.txCount += data_len;
uart1.txInPtr->end = &U1_Tx_Buff[uart1.txCount - 1];
uart1.txInPtr++;
if(uart1.txInPtr == uart1.txEndPtr){
uart1.txInPtr = &uart1.txLocation[0];
}
}
void U2_DataRxToTx(uint8_t* data, uint32_t data_len){
if((U2_TX_SIZE - uart2.txCount) > data_len){
uart2.txInPtr->start = &U2_Tx_Buff[uart2.txCount];
}
else{
uart2.txCount = 0;
uart2.txInPtr->start = &U2_Tx_Buff[0];
}
memcpy(uart2.txInPtr->start, data, data_len);
uart2.txCount += data_len;
uart2.txInPtr->end = &U2_Tx_Buff[uart2.txCount - 1];
uart2.txInPtr++;
if(uart2.txInPtr == uart2.txEndPtr){
uart2.txInPtr = &uart2.txLocation[0];
}
}
void U3_DataRxToTx(uint8_t* data, uint32_t data_len){
if((U3_TX_SIZE - uart3.txCount) > data_len){
uart3.txInPtr->start = &U3_Tx_Buff[uart3.txCount];
}
else{
uart3.txCount = 0;
uart3.txInPtr->start = &U3_Tx_Buff[0];
}
memcpy(uart3.txInPtr->start, data, data_len);
uart3.txCount += data_len;
uart3.txInPtr->end = &U3_Tx_Buff[uart3.txCount - 1];
uart3.txInPtr++;
if(uart3.txInPtr == uart3.txEndPtr){
uart3.txInPtr = &uart3.txLocation[0];
}
}
/ UART硬件初始化回调 /
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}else if(huart->Instance == USART2){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART2_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_11;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(USART3_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
}
}
/ 强声明的接收完成回调函数 /
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的错误回调函数 /
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的发送完成回调函数 /
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
/ 发送完成,标志位清零 /
uart1.TxState = 0;
}else if(huart->Instance == USART2){
uart2.TxState = 0;
}else if(huart->Instance == USART3){
uart3.TxState = 0;
}
}
/ 强声明的接收终止回调函数 /
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
uart1.rxInPtr++;
if(uart1.rxInPtr == uart1.rxEndPtr){
uart1.rxInPtr = &uart1.rxLocation[0];
}
if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
uart1.rxCount = 0;
uart1.rxInPtr->start = &U1_Rx_Buff[0];
}else{
uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
}
HAL_UART_Receive_IT(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
}else if(huart->Instance == USART2){
uart2.rxInPtr->end = &U2_Rx_Buff[uart2.rxCount - 1];
uart2.rxInPtr++;
if(uart2.rxInPtr == uart2.rxEndPtr){
uart2.rxInPtr = &uart2.rxLocation[0];
}
if((U2_RX_SIZE - uart2.rxCount) < U2_RX_MAX){
uart2.rxCount = 0;
uart2.rxInPtr->start = &U2_Rx_Buff[0];
}else{
uart2.rxInPtr->start = &U2_Rx_Buff[uart2.rxCount];
}
HAL_UART_Receive_IT(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
}else if(huart->Instance == USART3){
uart3.rxInPtr->end = &U3_Rx_Buff[uart3.rxCount - 1];
uart3.rxInPtr++;
if(uart3.rxInPtr == uart3.rxEndPtr){
uart3.rxInPtr = &uart3.rxLocation[0];
}
if((U3_RX_SIZE - uart3.rxCount) < U3_RX_MAX){
uart3.rxCount = 0;
uart3.rxInPtr->start = &U3_Rx_Buff[0];
}else{
uart3.rxInPtr->start = &U3_Rx_Buff[uart3.rxCount];
}
HAL_UART_Receive_IT(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
}
}
stm32fxx_It.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
/-------------------------------------------------/
/函数名:串口1中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
/ 在每次进入中断后,判断是否为空闲中断 /
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
/ 清除空闲标志位 /
//__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
/ 获取这次传输了多少字节 /
uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
/ 终止当前的接收(会把RxferCount清零) /
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
/-------------------------------------------------/
/函数名:串口2中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.rxCount += (U2_RX_MAX - uart2.uart.RxXferCount);
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
/-------------------------------------------------/
/函数名:串口3中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.rxCount += (U3_RX_MAX - uart3.uart.RxXferCount);
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
U2_Init(921600);
U3_Init(921600);
while(1){
/ ------------------UART1------------------ /
/ 判断接收缓冲区是否有数据 /
if(uart1.rxInPtr != uart1.rxOutPtr){
U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));
uart1.rxOutPtr++;
if(uart1.rxOutPtr == uart1.rxEndPtr){
uart1.rxOutPtr = &uart1.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
uart1.TxState = 1;
HAL_UART_Transmit_IT(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
uart1.txOutPtr++;
if(uart1.txOutPtr == uart1.txEndPtr){
uart1.txOutPtr = &uart1.txLocation[0];
}
}
/ ------------------UART2------------------ /
if(uart2.rxInPtr != uart2.rxOutPtr){
U2_DataRxToTx(uart2.rxOutPtr->start, (uart2.rxOutPtr->end - uart2.rxOutPtr->start + 1));
uart2.rxOutPtr++;
if(uart2.rxOutPtr == uart2.rxEndPtr){
uart2.rxOutPtr = &uart2.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart2.txInPtr != uart2.txOutPtr) && (uart2.TxState == 0) ){
uart2.TxState = 1;
HAL_UART_Transmit_IT(&uart2.uart, uart2. txOutPtr->start, (uart2.txOutPtr->end - uart2.txOutPtr->start + 1));
uart2.txOutPtr++;
if(uart2.txOutPtr == uart2.txEndPtr){
uart2.txOutPtr = &uart2.txLocation[0];
}
}
/ ------------------UART3------------------ /
if(uart3.rxInPtr != uart3.rxOutPtr){
U3_DataRxToTx(uart3.rxOutPtr->start, (uart3.rxOutPtr->end - uart3.rxOutPtr->start + 1));
uart3.rxOutPtr++;
if(uart3.rxOutPtr == uart3.rxEndPtr){
uart3.rxOutPtr = &uart3.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart3.txInPtr != uart3.txOutPtr) && (uart3.TxState == 0) ){
uart3.TxState = 1;
HAL_UART_Transmit_IT(&uart3.uart, uart3. txOutPtr->start, (uart3.txOutPtr->end - uart3.txOutPtr->start + 1));
uart3.txOutPtr++;
if(uart3.txOutPtr == uart3.txEndPtr){
uart3.txOutPtr = &uart3.txLocation[0];
}
}
}
}
八、HAL库:DMA不定长接收 + 空闲中断 + 循环收发缓冲区 串口123收发数据
1. 介绍
DMA(Direct Memory Access)是一种直接内存访问技术,
可以在不经过CPU的情况下实现外设与内存之间的数据传输,提高数据传输效率
2. DMA实现的相关函数
#define __HAL_LINKDMA(HANDLE, PPP_DMA_FIELD, DMA_HANDLE)
do{
(HANDLE)->PPP_DMA_FIELD = &(DMA_HANDLE);
(DMA_HANDLE).Parent = (HANDLE);
} while(0U)- 三个参数:第一个是外设句柄,第二个是外设句柄内的一个DMA句柄指针,最后一个参数是DMA句柄。
- 每个外设的句柄结构体中都一个该外设关于DMA相关的设置例如串口为
DMA_HandleTypeDef *hdmatx;UART TX 的DMA句柄参数DMA_HandleTypeDef *hdmarx;UART RX 的DMA句柄参数- 函数的第二个参数用于指定外设中的 DMA 请求标识符。 不同外设有不同含义: 如在定时器中可对应更新、捕获 / 比较等事件的 DMA 请求标识符,用于触发相关 DMA 传输实现自动更新参数等; 在 SPI 中是发送或接收 DMA 请求标识符,能实现高速自动收发数据; 在 ADC 中则通常是转换完成 DMA 请求标识符,可将转换结果自动存储到内存缓冲区。 总之,该参数起到将特定外设事件与 DMA 传输关联起来的作用,以提高数据传输处理效率。
调用这个API,会把用到DMA的外设总控结构体和DMA响应通道的总控结构体 进行双向的父子链接, 也就是 你能找到我 我也能找到你。
DMA 1 - 7 有各自的中断入口点, 有各自的 中断处理函数。
通过这个Link 就建立起来的 DMA和外设的双向的链接了。
然后HAL库会自动配置好 在 发生特定事件时,对内存进行搬运的代码。
__HAL_DMA_GET_COUNTER(__HANDLE__);HANDLE用到DMA的外设
获取DMA剩余 未传输的数据量
3. 注意事项:
- DMA有不同的通道,也就需要有不同的DMA总控结构体, 例如 串口3的Tx在通道2 , Rx在通道3…
所以在选用DMA通道的时候, 一定要选对!千万不要Link错了

- 使用串口的DMA接收和发送之后, 是不会通过中断来接收的(RXNE)
- 使用串口的DMA发送之后, 会进入发送完成回调函数, 和 中断等一样。
(DMA发送完毕之后会置TCIE 发送完成中断为 1)
- 注意循环和正常模式。
4. 程序设计
3.1 大致流程
- 打开DMA时钟
- 配置
DMA_HandleTypeDef类型的 DMA通道 - 实例、初始化的方向、存储区是否递增、目标地址是否自增、两方字长、工作模式等
- 通过
__HAL_LINKDMA链接 外设与通道,并配置第二个参数。在发生发送、或接收事件时,开始搬运数据。
- 打开对应通道的中断(虽然暂时不用)
- 可以利用
__HAL_DMA_GET_COUNTER函数来获得当前DMA的未搬运的量
uart.h
uart.c
/ UART硬件初始化回调 /
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE(); //打开DMA时钟
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/ DMA配置 /
// 发送配置
uart1.dmaTx.Instance = DMA1_Channel4; //DMA通道:4
uart1.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH; //方向:存储区到外设
uart1.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; //存储区数据宽度
uart1.dmaTx.Init.MemInc = DMA_MINC_ENABLE; //存储区是否递增?
uart1.dmaTx.Init.Mode = DMA_NORMAL; //工作模式(正常或循环)
uart1.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; //外设数据宽度
uart1.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE; //目标地址是否递增?
uart1.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM; //优先级
//链接
__HAL_LINKDMA(huart, hdmatx, uart1.dmaTx);
//初始化
HAL_DMA_Init(&uart1.dmaTx);
//打开DMA通道中断
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
// 接收配置
uart1.dmaRx.Instance = DMA1_Channel5; //DMA通道:5
uart1.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY; //方向:外设区到存储
uart1.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmaRx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmaRx.Init.Mode = DMA_NORMAL;
uart1.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;
//链接
__HAL_LINKDMA(huart, hdmarx, uart1.dmaRx);
//初始化
HAL_DMA_Init(&uart1.dmaRx);
//打开DMA中断
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(huart->Instance == USART2){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART2_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
/ DMA配置 /
uart2.dmaTx.Instance = DMA1_Channel7;
uart2.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart2.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmaTx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmaTx.Init.Mode = DMA_NORMAL;
uart2.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart2.dmaTx);
HAL_DMA_Init(&uart2.dmaTx);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
uart2.dmaRx.Instance = DMA1_Channel6;
uart2.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart2.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmaRx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmaRx.Init.Mode = DMA_NORMAL;
uart2.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart2.dmaRx);
HAL_DMA_Init(&uart2.dmaRx);
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_11;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(USART3_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
/ DMA配置 /
uart3.dmaTx.Instance = DMA1_Channel2;
uart3.dmaTx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart3.dmaTx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmaTx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmaTx.Init.Mode = DMA_NORMAL;
uart3.dmaTx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmaTx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmaTx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart3.dmaTx);
HAL_DMA_Init(&uart3.dmaTx);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
uart3.dmaRx.Instance = DMA1_Channel3;
uart3.dmaRx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart3.dmaRx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmaRx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmaRx.Init.Mode = DMA_NORMAL;
uart3.dmaRx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmaRx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmaRx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart3.dmaRx);
HAL_DMA_Init(&uart3.dmaRx);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
}
/ 强声明的接收完成回调函数 /
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的错误回调函数 /
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}else if(huart->Instance == USART2){
}else if(huart->Instance == USART3){
}
}
/ 强声明的发送完成回调函数 /
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
/ 发送完成,标志位清零 /
uart1.TxState = 0;
}else if(huart->Instance == USART2){
uart2.TxState = 0;
}else if(huart->Instance == USART3){
uart3.TxState = 0;
}
}
/ 强声明的接收终止回调函数 /
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.rxInPtr->end = &U1_Rx_Buff[uart1.rxCount - 1];
uart1.rxInPtr++;
if(uart1.rxInPtr == uart1.rxEndPtr){
uart1.rxInPtr = &uart1.rxLocation[0];
}
if((U1_RX_SIZE - uart1.rxCount) < U1_RX_MAX){
uart1.rxCount = 0;
uart1.rxInPtr->start = &U1_Rx_Buff[0];
}else{
uart1.rxInPtr->start = &U1_Rx_Buff[uart1.rxCount];
}
HAL_UART_Receive_DMA(&uart1.uart, uart1.rxInPtr->start, U1_RX_MAX);
}else if(huart->Instance == USART2){
uart2.rxInPtr->end = &U2_Rx_Buff[uart2.rxCount - 1];
uart2.rxInPtr++;
if(uart2.rxInPtr == uart2.rxEndPtr){
uart2.rxInPtr = &uart2.rxLocation[0];
}
if((U2_RX_SIZE - uart2.rxCount) < U2_RX_MAX){
uart2.rxCount = 0;
uart2.rxInPtr->start = &U2_Rx_Buff[0];
}else{
uart2.rxInPtr->start = &U2_Rx_Buff[uart2.rxCount];
}
HAL_UART_Receive_DMA(&uart2.uart, uart2.rxInPtr->start, U2_RX_MAX);
}else if(huart->Instance == USART3){
uart3.rxInPtr->end = &U3_Rx_Buff[uart3.rxCount - 1];
uart3.rxInPtr++;
if(uart3.rxInPtr == uart3.rxEndPtr){
uart3.rxInPtr = &uart3.rxLocation[0];
}
if((U3_RX_SIZE - uart3.rxCount) < U3_RX_MAX){
uart3.rxCount = 0;
uart3.rxInPtr->start = &U3_Rx_Buff[0];
}else{
uart3.rxInPtr->start = &U3_Rx_Buff[uart3.rxCount];
}
HAL_UART_Receive_DMA(&uart3.uart, uart3.rxInPtr->start, U3_RX_MAX);
}
}
stm32fxx_It.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
/-------------------------------------------------/
/函数名:串口1中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
/ 在每次进入中断后,判断是否为空闲中断 /
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
/ 清除空闲标志位 /
//__HAL_UART_CLEAR_FLAG(&uart1.uart, UART_FLAG_IDLE);
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
/ 获取这次传输了多少字节 /
//uart1.rxCount += (U1_RX_MAX - uart1.uart.RxXferCount);
uart1.rxCount += (U1_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart1.dmaRx))); //利用DMA的api 获取剩余未发送数据量
/ 终止当前的接收(会把RxferCount清零) /
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
/-------------------------------------------------/
/函数名:串口2中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.rxCount += (U2_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart2.dmaRx)));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
/-------------------------------------------------/
/函数名:串口3中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.rxCount += (U3_RX_MAX - (__HAL_DMA_GET_COUNTER(&uart3.dmaRx)));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
/-------------------------------------------------/
/函数名:DMA通道4中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel4_IRQHandler(void) //Uart1 Tx通道
{
HAL_DMA_IRQHandler(&uart1.dmaTx);
}
/-------------------------------------------------/
/函数名:DMA通道5中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel5_IRQHandler(void) //Uart1 Rx通道
{
HAL_DMA_IRQHandler(&uart1.dmaRx);
}
/-------------------------------------------------/
/函数名:DMA通道7中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel7_IRQHandler(void) //Uart2 Tx通道
{
HAL_DMA_IRQHandler(&uart2.dmaTx);
}
/-------------------------------------------------/
/函数名:DMA通道6中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel6_IRQHandler(void) //Uart2 Rx通道
{
HAL_DMA_IRQHandler(&uart2.dmaRx);
}
/-------------------------------------------------/
/函数名:DMA通道2中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel2_IRQHandler(void) //Uart3 Tx通道
{
HAL_DMA_IRQHandler(&uart3.dmaTx);
}
/-------------------------------------------------/
/函数名:DMA通道3中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void DMA1_Channel3_IRQHandler(void) //Uart3 Rx通道
{
HAL_DMA_IRQHandler(&uart3.dmaRx);
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
U2_Init(921600);
U3_Init(921600);
while(1){
/ ------------------UART1------------------ /
/ 判断接收缓冲区是否有数据 /
if(uart1.rxInPtr != uart1.rxOutPtr){
U1_DataRxToTx(uart1.rxOutPtr->start, (uart1.rxOutPtr->end - uart1.rxOutPtr->start + 1));
uart1.rxOutPtr++;
if(uart1.rxOutPtr == uart1.rxEndPtr){
uart1.rxOutPtr = &uart1.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart1.txInPtr != uart1.txOutPtr) && (uart1.TxState == 0) ){
uart1.TxState = 1;
HAL_UART_Transmit_DMA(&uart1.uart, uart1. txOutPtr->start, (uart1.txOutPtr->end - uart1.txOutPtr->start + 1));
uart1.txOutPtr++;
if(uart1.txOutPtr == uart1.txEndPtr){
uart1.txOutPtr = &uart1.txLocation[0];
}
}
/ ------------------UART2------------------ /
if(uart2.rxInPtr != uart2.rxOutPtr){
U2_DataRxToTx(uart2.rxOutPtr->start, (uart2.rxOutPtr->end - uart2.rxOutPtr->start + 1));
uart2.rxOutPtr++;
if(uart2.rxOutPtr == uart2.rxEndPtr){
uart2.rxOutPtr = &uart2.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart2.txInPtr != uart2.txOutPtr) && (uart2.TxState == 0) ){
uart2.TxState = 1;
HAL_UART_Transmit_DMA(&uart2.uart, uart2. txOutPtr->start, (uart2.txOutPtr->end - uart2.txOutPtr->start + 1));
uart2.txOutPtr++;
if(uart2.txOutPtr == uart2.txEndPtr){
uart2.txOutPtr = &uart2.txLocation[0];
}
}
/ ------------------UART3------------------ /
if(uart3.rxInPtr != uart3.rxOutPtr){
U3_DataRxToTx(uart3.rxOutPtr->start, (uart3.rxOutPtr->end - uart3.rxOutPtr->start + 1));
uart3.rxOutPtr++;
if(uart3.rxOutPtr == uart3.rxEndPtr){
uart3.rxOutPtr = &uart3.rxLocation[0];
}
}
/ 判断发送缓冲区是否有数据 /
if((uart3.txInPtr != uart3.txOutPtr) && (uart3.TxState == 0) ){
uart3.TxState = 1;
HAL_UART_Transmit_DMA(&uart3.uart, uart3. txOutPtr->start, (uart3.txOutPtr->end - uart3.txOutPtr->start + 1));
uart3.txOutPtr++;
if(uart3.txOutPtr == uart3.txEndPtr){
uart3.txOutPtr = &uart3.txLocation[0];
}
}
}
}
九、HAL库:双机通信,DMA方式收发 控制对方LED灯
在上面的基础上进行修改
1. 大概思路
在本机 按键按下时,进入中断。在中断回调中使用UART1 发送数据LED_ON或LED_OFF
在UART1接收到数据时,进行判断,使用strcmp函数
插线的话,两个设备 TX对RX RX对TX, GND对GND就Ok了
十、HAL库:单线半双工,双机通信,DMA方式收发 控制对方LED灯
在上面的基础上进行修改
1. 单线半双工简介
两个单片机之间通过串口,单线半双工通信。
半双工:同一时间只能发送或者接收,此时仅使用TX引脚
注意:此时TX引脚需要配置为OD模式,外接上拉电阻
2. 大概思路
在本机 按键按下时,进入中断。在中断回调中使用UART1 发送数据LED_ON或LED_OFF
在UART1接收到数据时,进行判断,使用strcmp函数
插线的话,两个设备 TX对RX RX对TX, GND对GND就Ok了
3. 注意
- 在初始化时,要使用
HAL_HalfDuplex_Init来初始化
- 单线半双工用的是串口的Tx引脚, 注意Tx引脚要初始化为AF_OD 模式,并且接上拉电阻
- 一般在初始化的时候,默认为单线半双工的接收状态,只有在使用发送的时候,才使用
HAL_HalfDuplex_EnableTransmitter(&uart1.uart);来使能单线半双工的发射模式。并且在发送完成之后,(一般使用发送完成回调)把发射模式重置为默认的接收模式。HAL_HalfDuplex_EnableReceiver(&uart1.uart);
十一、HAL库:多主机通信 地址检测唤醒 定时器超时 DMA不定长接收
1. 设备唤醒介绍
1.1 唤醒方式:
- 三个及以上单片机之间通过串口,相互通信收发数据时。
- 此时我们需要涉及到主机和从机之分,从机的唤醒有分为:地址 or 空闲唤醒
1.2 地址唤醒:
- 每个从机会具备一个硬件的从机地址, 地址会记录在USART_CR2寄存器的ADD,占用了4个二进制位。范围0x00~0x0F
- 但是主机在发送时,需要区分地址 还是数据:如果最高位为1,表示地址,为0表示数据。 所以主机发送的数据,首个字节是从机的地址,范围应该是0x80~0x8F, 8表示最高位7为1。 所以在发送数据时,最高位为 0 数据的有效位为 bit0~bit6 7位数据
1.3 多处理器通信:
与I2C类似,主机Tx为PP模式
- 主机的tx,接到各个从设备的Rx引脚。 从机的tx输出逻辑 地与(线与)在一起,
- 注意:
- 从机的Tx不能为PP模式,否则两个从机输出1 、0会形成短路。
- 从机的Tx‘应该为OD模式,外接上拉电阻。
- 并且上拉电阻尽量选择外部上拉电阻,否则选择内部上拉,在波特率比较高的时候,电压上拉速度慢,导致检测为0等情况。
- USART_CR1寄存器的RWU位
- RWU可以被硬件自动控制或在某个条件先由软件写入
- RWU高电平表示从机为静默模式,不会接收数据
- RWU低电平表示从机为正常模式,会接收数据
- 从机通过判断地址,来切换到正常模式,
- 未匹配的地址可以把正常模式的从机返回为静默模式,也可以手动返回为静默模式,
- 在初始化从机之后 需要手动把RWU变为高电平:静默模式
2. 特别注意:
- DMA在搬运UART的的数据时,会顺便把RXNE的标志位硬件清除。所以在开启DMA接收时,RXNE在软件上检测不到标志位为1
- 多处理器有空闲总线唤醒机制,只要用了多处理器的模式,那么空闲中断就不会产生了
就不能使用空闲中断来进行数据的不定长接收,可以换一种方式:使用定时器的超时判断,来进行数据的不定长接收。
2.1 使用定时器的超时判断,来进行数据的不定长接收思路详解
假设波特率为9600 ,那么一秒钟最快能发送960个字节,也就是1ms多点。也就是在一个连续的数据流中,每个字节的传输间隔为1ms。
现在开一个定时器,定时时间为大于1ms的值,比如 15 ms。
在每次接收一个字节之后,都清空定时器的计数值。 当定时器超时时,就代表当前一次的数据已经传输完毕。
优点:利用空闲中断时,如果数据发生波动,那么会把一个数据分成两次数据。 而定时器不会,定时器时通过时间判断。
初始化定时器 用于超时计时
TIM4_TimerInit(300,7200); 30ms超时时间需要 打开接收中断
__HAL_UART_ENABLE_IT(&uart2.uart,UART_IT_RXNE);判断接收标志位
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_RXNE)){文件部分
- 需要修改hal_uart.c(虽然不建议,但是只能这样了)
- 关闭了RXNE中断和发生空闲中断,让每次接收字节后都进入自己的函数中stm32f1xx_hal_uart.c
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/ If no error occurs /
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
//删除 RXNE中断
//if (errorflags == RESET)
//{
// / UART in mode Receiver -------------------------------------------------/
// if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
// {
// UART_Receive_IT(huart);
// return;
// }
//}
/ If some errors occur /
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/ UART parity error interrupt occurred ----------------------------------/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/ UART noise error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/ UART frame error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/ UART Over-Run interrupt occurred --------------------------------------/
if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/ Call UART Error Call back function if need be --------------------------/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/ UART in mode Receiver -----------------------------------------------/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/ Disable the UART DMA Rx request if enabled /
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/ Abort the UART DMA Rx channel /
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/ Call Directly XferAbortCallback function in case of error /
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} / End if some error occurs /
/ UART in mode Transmitter ------------------------------------------------/
//删除 发送缓冲区空的中断
// if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
// {
// UART_Transmit_IT(huart);
// return;
// }
/ UART in mode Transmitter end --------------------------------------------/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
/ 写自己的中断回调,现在只能进入我们这个了。 /
#include "uart.h"
#include "timer.h"
else
{
if(uart2.RxState == 0){ / 首字节 /
__HAL_TIM_ENABLE(&htim4); //打开tim4的计数
uart2.RxStat = 1; //标记接收
}else{/ 后续字节 /
__HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
}
}
}
2. 要测试功能
主机SW8(PC14)发送:S1_LED(让从机1 LED4翻转状态 UART1
主机SW11(PA0)发送:S2_LED(让从机2 LED4翻转状态)
从机1+从机2 SW8(PC14):LED ON(让主机LED4点亮) UART2
从机1+从机2 SW11(PA0):LED OFF(让主机LED4熄灭) UART3
一般情况下,从机不会主动发送数据,因为这里并没有硬件仲裁机制。 一般都是主机问,从机答
3. 相关函数
- 可以使用转义字符,在字符串中插入16进制数 用于指定从机地址
((uint8_t*)"\x81S1_LED", 7);\为转义字符 x0x81 为插入的16进制数, 字节为1字节
- 从机初始化函数:
HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK); - 第一个参数,串口总控结构体
- 第二个参数,设备地址:0x00~0x0F
- 第三个参数,唤醒方法:地址唤醒或者空闲唤醒
4. 主机程序
uart.c
#include "stm32f1xx_hal.h"
#include "uart.h"
UCB uart1;
UCB uart2;
UCB uart3;
uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];
uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];
uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];
void U1_Init(uint32_t bandrate){
uart1.uart.Instance = USART1;
uart1.uart.Init.BaudRate = bandrate;
uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart1.uart.Init.StopBits = UART_STOPBITS_1;
uart1.uart.Init.Parity = UART_PARITY_NONE;
uart1.uart.Init.Mode = UART_MODE_TX_RX;
uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&uart1.uart);
U1_PtrInit();
}
void U1_PtrInit(void){
uart1.RxInPtr = &uart1.RxLocation[0];
uart1.RxOutPtr = &uart1.RxLocation[0];
uart1.RxEndPtr = &uart1.RxLocation[9];
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
uart1.TxInPtr = &uart1.TxLocation[0];
uart1.TxOutPtr = &uart1.TxLocation[0];
uart1.TxEndPtr = &uart1.TxLocation[9];
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
__HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
}else{
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
}
memcpy(uart1.TxInPtr->start,data,data_len);
uart1.TxCounter += data_len;
uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
uart1.TxInPtr++;
if(uart1.TxInPtr == uart1.TxEndPtr){
uart1.TxInPtr = &uart1.TxLocation[0];
}
}
void U2_Init(uint32_t bandrate){
uart2.uart.Instance = USART2;
uart2.uart.Init.BaudRate = bandrate;
uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart2.uart.Init.StopBits = UART_STOPBITS_1;
uart2.uart.Init.Parity = UART_PARITY_NONE;
uart2.uart.Init.Mode = UART_MODE_TX_RX;
uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_HalfDuplex_Init(&uart2.uart);
HAL_HalfDuplex_EnableReceiver(&uart2.uart);
U2_PtrInit();
}
void U2_PtrInit(void){
uart2.RxInPtr = &uart2.RxLocation[0];
uart2.RxOutPtr = &uart2.RxLocation[0];
uart2.RxEndPtr = &uart2.RxLocation[9];
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
uart2.TxInPtr = &uart2.TxLocation[0];
uart2.TxOutPtr = &uart2.TxLocation[0];
uart2.TxEndPtr = &uart2.TxLocation[9];
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
__HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
}else{
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
}
memcpy(uart2.TxInPtr->start,data,data_len);
uart2.TxCounter += data_len;
uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
uart2.TxInPtr++;
if(uart2.TxInPtr == uart2.TxEndPtr){
uart2.TxInPtr = &uart2.TxLocation[0];
}
}
void U3_Init(uint32_t bandrate){
uart3.uart.Instance = USART3;
uart3.uart.Init.BaudRate = bandrate;
uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart3.uart.Init.StopBits = UART_STOPBITS_1;
uart3.uart.Init.Parity = UART_PARITY_NONE;
uart3.uart.Init.Mode = UART_MODE_TX_RX;
uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_HalfDuplex_Init(&uart3.uart);
HAL_HalfDuplex_EnableReceiver(&uart3.uart);
U3_PtrInit();
}
void U3_PtrInit(void){
uart3.RxInPtr = &uart3.RxLocation[0];
uart3.RxOutPtr = &uart3.RxLocation[0];
uart3.RxEndPtr = &uart3.RxLocation[9];
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
uart3.TxInPtr = &uart3.TxLocation[0];
uart3.TxOutPtr = &uart3.TxLocation[0];
uart3.TxEndPtr = &uart3.TxLocation[9];
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
__HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
}else{
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
}
memcpy(uart3.TxInPtr->start,data,data_len);
uart3.TxCounter += data_len;
uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
uart3.TxInPtr++;
if(uart3.TxInPtr == uart3.TxEndPtr){
uart3.TxInPtr = &uart3.TxLocation[0];
}
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
uart1.dmatx.Instance = DMA1_Channel4;
uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmatx.Init.Mode = DMA_NORMAL;
uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
HAL_DMA_Init(&uart1.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
uart1.dmarx.Instance = DMA1_Channel5;
uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmarx.Init.Mode = DMA_NORMAL;
uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
HAL_DMA_Init(&uart1.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(huart->Instance == USART2){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_AF_OD;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART2_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
uart2.dmatx.Instance = DMA1_Channel7;
uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmatx.Init.Mode = DMA_NORMAL;
uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
HAL_DMA_Init(&uart2.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
uart2.dmarx.Instance = DMA1_Channel6;
uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmarx.Init.Mode = DMA_NORMAL;
uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
HAL_DMA_Init(&uart2.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_OD;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(USART3_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
uart3.dmatx.Instance = DMA1_Channel2;
uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmatx.Init.Mode = DMA_NORMAL;
uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
HAL_DMA_Init(&uart3.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
uart3.dmarx.Instance = DMA1_Channel3;
uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmarx.Init.Mode = DMA_NORMAL;
uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
HAL_DMA_Init(&uart3.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.TxState = 0;
}else if(huart->Instance == USART2){
uart2.TxState = 0;
}else if(huart->Instance == USART3){
uart3.TxState = 0;
}
}
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
uart1.RxInPtr++;
if(uart1.RxInPtr == uart1.RxEndPtr){
uart1.RxInPtr = &uart1.RxLocation[0];
}
if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
}else{
uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
}
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}else if(huart->Instance == USART2){
uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
uart2.RxInPtr++;
if(uart2.RxInPtr == uart2.RxEndPtr){
uart2.RxInPtr = &uart2.RxLocation[0];
}
if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
}else{
uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
}
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}else if(huart->Instance == USART3){
uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
uart3.RxInPtr++;
if(uart3.RxInPtr == uart3.RxEndPtr){
uart3.RxInPtr = &uart3.RxLocation[0];
}
if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
}else{
uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
}
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
}
uart.h
#ifndef __UART_H
#define __UART_H
#include "string.h"
#include "stdint.h"
#include "stm32f1xx_hal_uart.h"
#include "stm32f1xx_hal_dma.h"
#define U1_TX_SIZE 2048
#define U1_RX_SIZE 2048
#define U1_RX_MAX 256
#define U2_TX_SIZE 2048
#define U2_RX_SIZE 2048
#define U2_RX_MAX 256
#define U3_TX_SIZE 2048
#define U3_RX_SIZE 2048
#define U3_RX_MAX 256
typedef struct{
uint8_t *start;
uint8_t *end;
}LCB;
typedef struct{
uint32_t RxCounter;
uint32_t TxCounter;
uint32_t TxState;
LCB RxLocation[10];
LCB TxLocation[10];
LCB *RxInPtr;
LCB *RxOutPtr;
LCB *RxEndPtr;
LCB *TxInPtr;
LCB *TxOutPtr;
LCB *TxEndPtr;
UART_HandleTypeDef uart;
DMA_HandleTypeDef dmatx;
DMA_HandleTypeDef dmarx;
}UCB;
void U1_Init(uint32_t bandrate);
void U2_Init(uint32_t bandrate);
void U3_Init(uint32_t bandrate);
void U1_PtrInit(void);
void U2_PtrInit(void);
void U3_PtrInit(void);
void U1_Txdata(uint8_t *data, uint32_t data_len);
void U2_Txdata(uint8_t *data, uint32_t data_len);
void U3_Txdata(uint8_t *data, uint32_t data_len);
extern UCB uart1;
extern UCB uart2;
extern UCB uart3;
#endif
sw.c
#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"
uint8_t sw1_sta,sw2_sta; //0:没有按下 1:按下了
void SW_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEvent(void){
GPIO_InitTypeDef GPIO_InitType;
//SW1
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEventOut(void){
GPIO_InitTypeDef GPIO_InitType;
//PA3
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
HAL_GPIOEx_EnableEventout();
}
//mode 0:按下执行 1:抬起执行
void SW_Init_IT(uint8_t mode){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void SW_Init_IT2(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
//返回值 0:无按键触发 8:SW8触发
//mode 0:按下执行 1:抬起执行
uint8_t SW_Scan(uint8_t mode){
uint32_t i;
/-------------SW8------------------/
if((SW1_IN == 1)&&(sw1_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return 0;
}
}
sw1_sta = 1;
if(mode == 0){
return 8;
}
}else if((SW1_IN == 0)&&(sw1_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return 0;
}
}
sw1_sta = 0;
if(mode == 1){
return 8;
}
}
/-------------SW11------------------/
if((SW2_IN == 0)&&(sw2_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 1){
return 0;
}
}
sw2_sta = 1;
if(mode == 0){
return 11;
}
}else if((SW2_IN == 1)&&(sw2_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return 0;
}
}
sw2_sta = 0;
if(mode == 1){
return 11;
}
}
return 0;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
uint32_t i;
//SW8:PC13 SW11:PA0(抢占优先级高)
switch(GPIO_Pin){
case GPIO_PIN_14: if(SW1_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return;
}
}
U1_Txdata((uint8_t *)"x81S1_LED",7);
//U2_Txdata((uint8_t *)"LED_ON",6);
//U3_Txdata((uint8_t *)"LED_ON",6);
}else if(SW1_IN == 0){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
case GPIO_PIN_0: if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
U1_Txdata((uint8_t *)"x82S2_LED",7);
//U2_Txdata((uint8_t *)"LED_OFF",7);
//U3_Txdata((uint8_t *)"LED_OFF",7);
}else if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
}
}
sw.h
#ifndef __SW_H
#define __SW_H
#include "stdint.h"
#define SW1_IN HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define SW2_IN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);
#endif
led.c
#include "stm32f1xx_hal.h"
#include "led.h"
void LED_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_13;
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_ON(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
void LED_OFF(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_Toggle(void){
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED_ON(void);
void LED_OFF(void);
void LED_Toggle(void);
#endif
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmarx);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
SW_Init_IT(0);
LED_Init();
U1_Init(921600);
U2_Init(921600);
U3_Init(921600);
while(1){
//串口1收发
if(uart1.RxOutPtr != uart1.RxInPtr){
if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
LED_ON();
}else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
LED_OFF();
}
uart1.RxOutPtr++;
if(uart1.RxOutPtr == uart1.RxEndPtr){
uart1.RxOutPtr = &uart1.RxLocation[0];
}
}
if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
uart1.TxState = 1;
HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
uart1.TxOutPtr++;
if(uart1.TxOutPtr == uart1.TxEndPtr){
uart1.TxOutPtr = &uart1.TxLocation[0];
}
}
//串口2收发
if(uart2.RxOutPtr != uart2.RxInPtr){
if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==6)&&(memcmp(uart2.RxOutPtr->start,"LED_ON",6) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
}else if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"LED_OFF",7) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
}
uart2.RxOutPtr++;
if(uart2.RxOutPtr == uart2.RxEndPtr){
uart2.RxOutPtr = &uart2.RxLocation[0];
}
}
if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
uart2.TxState = 1;
HAL_HalfDuplex_EnableTransmitter(&uart2.uart);
HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
uart2.TxOutPtr++;
if(uart2.TxOutPtr == uart2.TxEndPtr){
uart2.TxOutPtr = &uart2.TxLocation[0];
}
}
//串口3收发
if(uart3.RxOutPtr != uart3.RxInPtr){
if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==6)&&(memcmp(uart3.RxOutPtr->start,"LED_ON",6) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
}else if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"LED_OFF",7) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
}
uart3.RxOutPtr++;
if(uart3.RxOutPtr == uart3.RxEndPtr){
uart3.RxOutPtr = &uart3.RxLocation[0];
}
}
if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
uart3.TxState = 1;
HAL_HalfDuplex_EnableTransmitter(&uart3.uart);
HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
uart3.TxOutPtr++;
if(uart3.TxOutPtr == uart3.TxEndPtr){
uart3.TxOutPtr = &uart3.TxLocation[0];
}
}
}
}
5. 从机1程序
uart.c
#include "stm32f1xx_hal.h"
#include "uart.h"
UCB uart1;
UCB uart2;
UCB uart3;
uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];
uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];
uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];
void U1_Init(uint32_t bandrate){
uart1.uart.Instance = USART1;
uart1.uart.Init.BaudRate = bandrate;
uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart1.uart.Init.StopBits = UART_STOPBITS_1;
uart1.uart.Init.Parity = UART_PARITY_NONE;
uart1.uart.Init.Mode = UART_MODE_TX_RX;
uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&uart1.uart);
U1_PtrInit();
}
void U1_PtrInit(void){
uart1.RxInPtr = &uart1.RxLocation[0];
uart1.RxOutPtr = &uart1.RxLocation[0];
uart1.RxEndPtr = &uart1.RxLocation[9];
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
uart1.TxInPtr = &uart1.TxLocation[0];
uart1.TxOutPtr = &uart1.TxLocation[0];
uart1.TxEndPtr = &uart1.TxLocation[9];
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
__HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
}else{
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
}
memcpy(uart1.TxInPtr->start,data,data_len);
uart1.TxCounter += data_len;
uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
uart1.TxInPtr++;
if(uart1.TxInPtr == uart1.TxEndPtr){
uart1.TxInPtr = &uart1.TxLocation[0];
}
}
void U2_Init(uint32_t bandrate){
uart2.uart.Instance = USART2;
uart2.uart.Init.BaudRate = bandrate;
uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart2.uart.Init.StopBits = UART_STOPBITS_1;
uart2.uart.Init.Parity = UART_PARITY_NONE;
uart2.uart.Init.Mode = UART_MODE_TX_RX;
uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK); //多设备初始化
HAL_MultiProcessor_EnterMuteMode(&uart2.uart); //手动进入静默模式
TIM4_TimerInit(300, 7200); //定时器超时时间30ms
U2_PtrInit();
}
void U2_PtrInit(void){
uart2.RxInPtr = &uart2.RxLocation[0];
uart2.RxOutPtr = &uart2.RxLocation[0];
uart2.RxEndPtr = &uart2.RxLocation[9];
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
uart2.TxInPtr = &uart2.TxLocation[0];
uart2.TxOutPtr = &uart2.TxLocation[0];
uart2.TxEndPtr = &uart2.TxLocation[9];
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
uart2.RxState = 0; //初始化接受状态为0
__HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
}else{
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
}
memcpy(uart2.TxInPtr->start,data,data_len);
uart2.TxCounter += data_len;
uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
uart2.TxInPtr++;
if(uart2.TxInPtr == uart2.TxEndPtr){
uart2.TxInPtr = &uart2.TxLocation[0];
}
}
void U3_Init(uint32_t bandrate){
uart3.uart.Instance = USART3;
uart3.uart.Init.BaudRate = bandrate;
uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart3.uart.Init.StopBits = UART_STOPBITS_1;
uart3.uart.Init.Parity = UART_PARITY_NONE;
uart3.uart.Init.Mode = UART_MODE_TX_RX;
uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_HalfDuplex_Init(&uart3.uart);
HAL_HalfDuplex_EnableReceiver(&uart3.uart);
U3_PtrInit();
}
void U3_PtrInit(void){
uart3.RxInPtr = &uart3.RxLocation[0];
uart3.RxOutPtr = &uart3.RxLocation[0];
uart3.RxEndPtr = &uart3.RxLocation[9];
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
uart3.TxInPtr = &uart3.TxLocation[0];
uart3.TxOutPtr = &uart3.TxLocation[0];
uart3.TxEndPtr = &uart3.TxLocation[9];
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
__HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
}else{
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
}
memcpy(uart3.TxInPtr->start,data,data_len);
uart3.TxCounter += data_len;
uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
uart3.TxInPtr++;
if(uart3.TxInPtr == uart3.TxEndPtr){
uart3.TxInPtr = &uart3.TxLocation[0];
}
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
uart1.dmatx.Instance = DMA1_Channel4;
uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmatx.Init.Mode = DMA_NORMAL;
uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
HAL_DMA_Init(&uart1.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
uart1.dmarx.Instance = DMA1_Channel5;
uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmarx.Init.Mode = DMA_NORMAL;
uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
HAL_DMA_Init(&uart1.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(huart->Instance == USART2){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_AF_OD; //OD模式
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART2_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
uart2.dmatx.Instance = DMA1_Channel7;
uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmatx.Init.Mode = DMA_NORMAL;
uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
HAL_DMA_Init(&uart2.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
uart2.dmarx.Instance = DMA1_Channel6;
uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmarx.Init.Mode = DMA_NORMAL;
uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
HAL_DMA_Init(&uart2.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_OD;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(USART3_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
uart3.dmatx.Instance = DMA1_Channel2;
uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmatx.Init.Mode = DMA_NORMAL;
uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
HAL_DMA_Init(&uart3.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
uart3.dmarx.Instance = DMA1_Channel3;
uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmarx.Init.Mode = DMA_NORMAL;
uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
HAL_DMA_Init(&uart3.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.TxState = 0;
}else if(huart->Instance == USART2){
uart2.TxState = 0;
}else if(huart->Instance == USART3){
uart3.TxState = 0;
}
}
/ 接收终止回调 /
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
uart1.RxInPtr++;
if(uart1.RxInPtr == uart1.RxEndPtr){
uart1.RxInPtr = &uart1.RxLocation[0];
}
if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
}else{
uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
}
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}else if(huart->Instance == USART2){
uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
uart2.RxInPtr++;
if(uart2.RxInPtr == uart2.RxEndPtr){
uart2.RxInPtr = &uart2.RxLocation[0];
}
if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
}else{
uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
}
HAL_MultiProcessor_EnterMuteMode(&uart2.uart); //手动进入静默模式
__HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}else if(huart->Instance == USART3){
uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
uart3.RxInPtr++;
if(uart3.RxInPtr == uart3.RxEndPtr){
uart3.RxInPtr = &uart3.RxLocation[0];
}
if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
}else{
uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
}
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
}
uart.h
/-----------------------------------------------------/
/ 程序结构 /
/-----------------------------------------------------/
/USER :包含程序的 main 函数,是整个程序的入 /
/HW :包含开发板各种功能外设的驱动程序 /
/LIB :官方提供的 HAL 库文件 /
/CMSIS :CM3 内核相关的启动文件系统文件 /
/-----------------------------------------------------/
/ /
/ 实现定时器功能的头文件 /
/ /
/-----------------------------------------------------/
#ifndef _TIMER_H
#define _TIMER_H
#include "stdint.h"
#include "stm32f1xx_hal_tim.h"
extern TIM_HandleTypeDef htim4; //外部变量声明
void TIM4_TimerInit(uint16_t, uint16_t); //函数声明
#endif
sw.c
#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"
uint8_t sw1_sta,sw2_sta; //0:没有按下 1:按下了
void SW_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEvent(void){
GPIO_InitTypeDef GPIO_InitType;
//SW1
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEventOut(void){
GPIO_InitTypeDef GPIO_InitType;
//PA3
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
HAL_GPIOEx_EnableEventout();
}
//mode 0:按下执行 1:抬起执行
void SW_Init_IT(uint8_t mode){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void SW_Init_IT2(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
//返回值 0:无按键触发 8:SW8触发
//mode 0:按下执行 1:抬起执行
uint8_t SW_Scan(uint8_t mode){
uint32_t i;
/-------------SW8------------------/
if((SW1_IN == 1)&&(sw1_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return 0;
}
}
sw1_sta = 1;
if(mode == 0){
return 8;
}
}else if((SW1_IN == 0)&&(sw1_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return 0;
}
}
sw1_sta = 0;
if(mode == 1){
return 8;
}
}
/-------------SW11------------------/
if((SW2_IN == 0)&&(sw2_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 1){
return 0;
}
}
sw2_sta = 1;
if(mode == 0){
return 11;
}
}else if((SW2_IN == 1)&&(sw2_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return 0;
}
}
sw2_sta = 0;
if(mode == 1){
return 11;
}
}
return 0;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
uint32_t i;
//SW8:PC13 SW11:PA0(抢占优先级高)
switch(GPIO_Pin){
case GPIO_PIN_14: if(SW1_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return;
}
}
//U1_Txdata((uint8_t *)"x81S1_LED",7);
U2_Txdata((uint8_t *)"LED_ON",6);
//U3_Txdata((uint8_t *)"LED_ON",6);
}else if(SW1_IN == 0){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
case GPIO_PIN_0: if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
//U1_Txdata((uint8_t *)"x82S2_LED",7);
U2_Txdata((uint8_t *)"LED_OFF",7);
//U3_Txdata((uint8_t *)"LED_OFF",7);
}else if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
}
}
sw.h
#ifndef __SW_H
#define __SW_H
#include "stdint.h"
#define SW1_IN HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define SW2_IN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);
#endif
led.c
#include "stm32f1xx_hal.h"
#include "led.h"
void LED_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_13;
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_ON(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
void LED_OFF(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_Toggle(void){
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED_ON(void);
void LED_OFF(void);
void LED_Toggle(void);
#endif
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "timer.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
int aaa;
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
//if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
// __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
// uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
// HAL_UART_AbortReceive_IT(&uart2.uart);
//}
aaa++;
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmarx);
}
//定时器中断处理函数
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim4);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
timer.c
/-----------------------------------------------------/
/ 程序结构 /
/-----------------------------------------------------/
/USER :包含程序的 main 函数,是整个程序的入 /
/HW :包含开发板各种功能外设的驱动程序 /
/LIB :官方提供的 HAL 库文件 /
/CMSIS :CM3 内核相关的启动文件系统文件 /
/-----------------------------------------------------/
/ /
/ 实现定时器功能的源文件 /
/ /
/-----------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "timer.h"
#include "uart.h"
TIM_HandleTypeDef htim4; //定时器4总控制结构体
/-------------------------------------------------/
/函数名:定时器4 定时初始化 /
/参 数:arr:自动重装值 /
/参 数:psc:时钟预分频数 /
/返回值:无 /
/-------------------------------------------------/
void TIM4_TimerInit(uint16_t arr, uint16_t psc)
{
htim4.Instance = TIM4; //设置使用哪个定时器
htim4.Init.Prescaler = psc - 1; //设置预分频器的值
htim4.Init.Period = arr - 1; //设置自动重载值
htim4.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重载预装载 禁止
HAL_TIM_Base_Init(&htim4); //配置,如果失败进入if
__HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE); //清除定时器4的中断标志
__HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); //打开更新中断
}
/-------------------------------------------------/
/函数名:定时器底层驱动,开启时钟,设置中断优先级 /
/参 数:htim:定时器句柄 /
/返回值:无 /
/说 明:此函数会被HAL_TIM_Base_Init()函数调用 /
/-------------------------------------------------/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4){ //判断是哪个定时器
__HAL_RCC_TIM4_CLK_ENABLE(); //使能定时器时钟
HAL_NVIC_SetPriority(TIM4_IRQn,4,0); //设置中断优先级,中断分组在HAL_Init()函数中,被设置为4
HAL_NVIC_EnableIRQ(TIM4_IRQn); //开启定时器中断
}
}
/---------------------------------------------------/
/函数名:定时器中断回调函数 /
/参 数:htim:定时器句柄 /
/返回值:无 /
/说 明:此函数会被HAL_TIM_IRQHandler()中断函数调用 /
/---------------------------------------------------/
//超时回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4){ //判断是哪个定时器
__HAL_TIM_DISABLE(htim); //关闭定时器4的计数
__HAL_TIM_SET_COUNTER(htim,0); //清零定时器4计数器
uart2.RxState = 0; //恢复首字节接收标志位
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx)); //记录剩余未发送
HAL_UART_AbortReceive_IT(&uart2.uart); //终止接收
}
}
stm32f1xx_hal_uart.c
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/ If no error occurs /
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
//删除 RXNE中断
//if (errorflags == RESET)
//{
// / UART in mode Receiver -------------------------------------------------/
// if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
// {
// UART_Receive_IT(huart);
// return;
// }
//}
/ If some errors occur /
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/ UART parity error interrupt occurred ----------------------------------/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/ UART noise error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/ UART frame error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/ UART Over-Run interrupt occurred --------------------------------------/
if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/ Call UART Error Call back function if need be --------------------------/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/ UART in mode Receiver -----------------------------------------------/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/ Disable the UART DMA Rx request if enabled /
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/ Abort the UART DMA Rx channel /
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/ Call Directly XferAbortCallback function in case of error /
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} / End if some error occurs /
/ UART in mode Transmitter ------------------------------------------------/
//删除 发送缓冲区空的中断
// if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
// {
// UART_Transmit_IT(huart);
// return;
// }
/ UART in mode Transmitter end --------------------------------------------/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
/ 写自己的中断回调,现在只能进入我们这个了。 /
#include "uart.h"
#include "timer.h"
else
{
if(uart2.RxState == 0){ / 首字节 /
__HAL_TIM_ENABLE(&htim4); //打开tim4的计数
uart2.RxStat = 1; //标记接收
}else{/ 后续字节 /
__HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
}
}
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
SW_Init_IT(0);
LED_Init();
U1_Init(9600);
U2_Init(9600);
U3_Init(9600);
while(1){
//串口1收发
if(uart1.RxOutPtr != uart1.RxInPtr){
if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
LED_ON();
}else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
LED_OFF();
}
uart1.RxOutPtr++;
if(uart1.RxOutPtr == uart1.RxEndPtr){
uart1.RxOutPtr = &uart1.RxLocation[0];
}
}
if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
uart1.TxState = 1;
HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
uart1.TxOutPtr++;
if(uart1.TxOutPtr == uart1.TxEndPtr){
uart1.TxOutPtr = &uart1.TxLocation[0];
}
}
//串口2收发
if(uart2.RxOutPtr != uart2.RxInPtr){
if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"x81S1_LED",7) == 0)){
LED_Toggle();
}
uart2.RxOutPtr++;
if(uart2.RxOutPtr == uart2.RxEndPtr){
uart2.RxOutPtr = &uart2.RxLocation[0];
}
}
if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
uart2.TxState = 1;
HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
uart2.TxOutPtr++;
if(uart2.TxOutPtr == uart2.TxEndPtr){
uart2.TxOutPtr = &uart2.TxLocation[0];
}
}
//串口3收发
if(uart3.RxOutPtr != uart3.RxInPtr){
if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==6)&&(memcmp(uart3.RxOutPtr->start,"LED_ON",6) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
}else if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"LED_OFF",7) == 0)){
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
}
uart3.RxOutPtr++;
if(uart3.RxOutPtr == uart3.RxEndPtr){
uart3.RxOutPtr = &uart3.RxLocation[0];
}
}
if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
uart3.TxState = 1;
HAL_HalfDuplex_EnableTransmitter(&uart3.uart);
HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
uart3.TxOutPtr++;
if(uart3.TxOutPtr == uart3.TxEndPtr){
uart3.TxOutPtr = &uart3.TxLocation[0];
}
}
}
}
6. 从机2程序
uart.c
#include "stm32f1xx_hal.h"
#include "uart.h"
UCB uart1;
UCB uart2;
UCB uart3;
uint8_t U1_RxBuff[U1_RX_SIZE];
uint8_t U1_TxBuff[U1_TX_SIZE];
uint8_t U2_RxBuff[U2_RX_SIZE];
uint8_t U2_TxBuff[U2_TX_SIZE];
uint8_t U3_RxBuff[U3_RX_SIZE];
uint8_t U3_TxBuff[U3_TX_SIZE];
void U1_Init(uint32_t bandrate){
uart1.uart.Instance = USART1;
uart1.uart.Init.BaudRate = bandrate;
uart1.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart1.uart.Init.StopBits = UART_STOPBITS_1;
uart1.uart.Init.Parity = UART_PARITY_NONE;
uart1.uart.Init.Mode = UART_MODE_TX_RX;
uart1.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_UART_Init(&uart1.uart);
U1_PtrInit();
}
void U1_PtrInit(void){
uart1.RxInPtr = &uart1.RxLocation[0];
uart1.RxOutPtr = &uart1.RxLocation[0];
uart1.RxEndPtr = &uart1.RxLocation[9];
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
uart1.TxInPtr = &uart1.TxLocation[0];
uart1.TxOutPtr = &uart1.TxLocation[0];
uart1.TxEndPtr = &uart1.TxLocation[9];
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
__HAL_UART_ENABLE_IT(&uart1.uart, UART_IT_IDLE);
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}
void U1_Txdata(uint8_t *data, uint32_t data_len){
if((U1_TX_SIZE - uart1.TxCounter )>=data_len){
uart1.TxInPtr->start = &U1_TxBuff[uart1.TxCounter];
}else{
uart1.TxCounter = 0;
uart1.TxInPtr->start = U1_TxBuff;
}
memcpy(uart1.TxInPtr->start,data,data_len);
uart1.TxCounter += data_len;
uart1.TxInPtr->end = &U1_TxBuff[uart1.TxCounter - 1];
uart1.TxInPtr++;
if(uart1.TxInPtr == uart1.TxEndPtr){
uart1.TxInPtr = &uart1.TxLocation[0];
}
}
void U2_Init(uint32_t bandrate){
uart2.uart.Instance = USART2;
uart2.uart.Init.BaudRate = bandrate;
uart2.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart2.uart.Init.StopBits = UART_STOPBITS_1;
uart2.uart.Init.Parity = UART_PARITY_NONE;
uart2.uart.Init.Mode = UART_MODE_TX_RX;
uart2.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_MultiProcessor_Init(&uart2.uart, 0x01, UART_WAKEUPMETHOD_ADDRESSMARK); //多设备初始化
HAL_MultiProcessor_EnterMuteMode(&uart2.uart); //手动进入静默模式
TIM4_TimerInit(300, 7200); //定时器超时时间30ms
U2_PtrInit();
}
void U2_PtrInit(void){
uart2.RxInPtr = &uart2.RxLocation[0];
uart2.RxOutPtr = &uart2.RxLocation[0];
uart2.RxEndPtr = &uart2.RxLocation[9];
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
uart2.TxInPtr = &uart2.TxLocation[0];
uart2.TxOutPtr = &uart2.TxLocation[0];
uart2.TxEndPtr = &uart2.TxLocation[9];
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
uart2.RxState = 0; //初始化接受状态为0
__HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}
void U2_Txdata(uint8_t *data, uint32_t data_len){
if((U2_TX_SIZE - uart2.TxCounter )>=data_len){
uart2.TxInPtr->start = &U2_TxBuff[uart2.TxCounter];
}else{
uart2.TxCounter = 0;
uart2.TxInPtr->start = U2_TxBuff;
}
memcpy(uart2.TxInPtr->start,data,data_len);
uart2.TxCounter += data_len;
uart2.TxInPtr->end = &U2_TxBuff[uart2.TxCounter - 1];
uart2.TxInPtr++;
if(uart2.TxInPtr == uart2.TxEndPtr){
uart2.TxInPtr = &uart2.TxLocation[0];
}
}
void U3_Init(uint32_t bandrate){
uart3.uart.Instance = USART3;
uart3.uart.Init.BaudRate = bandrate;
uart3.uart.Init.WordLength = UART_WORDLENGTH_8B;
uart3.uart.Init.StopBits = UART_STOPBITS_1;
uart3.uart.Init.Parity = UART_PARITY_NONE;
uart3.uart.Init.Mode = UART_MODE_TX_RX;
uart3.uart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
HAL_MultiProcessor_Init(&uart3.uart, 0x02, UART_WAKEUPMETHOD_ADDRESSMARK); //多设备初始化
HAL_MultiProcessor_EnterMuteMode(&uart3.uart); //手动进入静默模式
TIM4_TimerInit(300, 7200); //定时器超时时间30ms
U3_PtrInit();
}
void U3_PtrInit(void){
uart3.RxInPtr = &uart3.RxLocation[0];
uart3.RxOutPtr = &uart3.RxLocation[0];
uart3.RxEndPtr = &uart3.RxLocation[9];
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
uart3.TxInPtr = &uart3.TxLocation[0];
uart3.TxOutPtr = &uart3.TxLocation[0];
uart3.TxEndPtr = &uart3.TxLocation[9];
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
uart3.RxState = 0; //初始化接受状态为0
__HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
void U3_Txdata(uint8_t *data, uint32_t data_len){
if((U3_TX_SIZE - uart3.TxCounter )>=data_len){
uart3.TxInPtr->start = &U3_TxBuff[uart3.TxCounter];
}else{
uart3.TxCounter = 0;
uart3.TxInPtr->start = U3_TxBuff;
}
memcpy(uart3.TxInPtr->start,data,data_len);
uart3.TxCounter += data_len;
uart3.TxInPtr->end = &U3_TxBuff[uart3.TxCounter - 1];
uart3.TxInPtr++;
if(uart3.TxInPtr == uart3.TxEndPtr){
uart3.TxInPtr = &uart3.TxLocation[0];
}
}
void HAL_UART_MspInit(UART_HandleTypeDef *huart){
GPIO_InitTypeDef GPIO_InitType;
if(huart->Instance == USART1){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART1_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
uart1.dmatx.Instance = DMA1_Channel4;
uart1.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart1.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmatx.Init.Mode = DMA_NORMAL;
uart1.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart1.dmatx);
HAL_DMA_Init(&uart1.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
uart1.dmarx.Instance = DMA1_Channel5;
uart1.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart1.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart1.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart1.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart1.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart1.dmarx.Init.Mode = DMA_NORMAL;
uart1.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart1.dmarx);
HAL_DMA_Init(&uart1.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(huart->Instance == USART2){
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_AF_OD; //OD模式
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(USART2_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
uart2.dmatx.Instance = DMA1_Channel7;
uart2.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart2.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmatx.Init.Mode = DMA_NORMAL;
uart2.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart2.dmatx);
HAL_DMA_Init(&uart2.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
uart2.dmarx.Instance = DMA1_Channel6;
uart2.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart2.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart2.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart2.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart2.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart2.dmarx.Init.Mode = DMA_NORMAL;
uart2.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart2.dmarx);
HAL_DMA_Init(&uart2.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel6_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
}else if(huart->Instance == USART3){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_10;
GPIO_InitType.Mode = GPIO_MODE_AF_OD; //OD模式
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
GPIO_InitType.Pin = GPIO_PIN_11;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(USART3_IRQn,3,0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
uart3.dmatx.Instance = DMA1_Channel2;
uart3.dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;
uart3.dmatx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmatx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmatx.Init.Mode = DMA_NORMAL;
uart3.dmatx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmatx, uart3.dmatx);
HAL_DMA_Init(&uart3.dmatx);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
uart3.dmarx.Instance = DMA1_Channel3;
uart3.dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;
uart3.dmarx.Init.PeriphInc = DMA_PINC_DISABLE;
uart3.dmarx.Init.MemInc = DMA_MINC_ENABLE;
uart3.dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
uart3.dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
uart3.dmarx.Init.Mode = DMA_NORMAL;
uart3.dmarx.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(huart, hdmarx, uart3.dmarx);
HAL_DMA_Init(&uart3.dmarx);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,3,0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.TxState = 0;
}else if(huart->Instance == USART2){
uart2.TxState = 0;
}else if(huart->Instance == USART3){
uart3.TxState = 0;
}
}
/ 接收终止回调 /
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1){
uart1.RxInPtr->end = &U1_RxBuff[uart1.RxCounter - 1];
uart1.RxInPtr++;
if(uart1.RxInPtr == uart1.RxEndPtr){
uart1.RxInPtr = &uart1.RxLocation[0];
}
if((U1_RX_SIZE - uart1.RxCounter)<U1_RX_MAX){
uart1.RxCounter = 0;
uart1.RxInPtr->start = U1_RxBuff;
}else{
uart1.RxInPtr->start = &U1_RxBuff[uart1.RxCounter];
}
HAL_UART_Receive_DMA(&uart1.uart,uart1.RxInPtr->start,U1_RX_MAX);
}else if(huart->Instance == USART2){
uart2.RxInPtr->end = &U2_RxBuff[uart2.RxCounter - 1];
uart2.RxInPtr++;
if(uart2.RxInPtr == uart2.RxEndPtr){
uart2.RxInPtr = &uart2.RxLocation[0];
}
if((U2_RX_SIZE - uart2.RxCounter)<U2_RX_MAX){
uart2.RxCounter = 0;
uart2.RxInPtr->start = U2_RxBuff;
}else{
uart2.RxInPtr->start = &U2_RxBuff[uart2.RxCounter];
}
HAL_MultiProcessor_EnterMuteMode(&uart2.uart); //手动进入静默模式
__HAL_UART_ENABLE_IT(&uart2.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart2.uart,uart2.RxInPtr->start,U2_RX_MAX);
}else if(huart->Instance == USART3){
uart3.RxInPtr->end = &U3_RxBuff[uart3.RxCounter - 1];
uart3.RxInPtr++;
if(uart3.RxInPtr == uart3.RxEndPtr){
uart3.RxInPtr = &uart3.RxLocation[0];
}
if((U3_RX_SIZE - uart3.RxCounter)<U3_RX_MAX){
uart3.RxCounter = 0;
uart3.RxInPtr->start = U3_RxBuff;
}else{
uart3.RxInPtr->start = &U3_RxBuff[uart3.RxCounter];
}
HAL_MultiProcessor_EnterMuteMode(&uart3.uart); //手动进入静默模式
__HAL_UART_ENABLE_IT(&uart3.uart, UART_IT_RXNE); //打开接收中断
HAL_UART_Receive_DMA(&uart3.uart,uart3.RxInPtr->start,U3_RX_MAX);
}
}
uart.h
/-----------------------------------------------------/
/ 程序结构 /
/-----------------------------------------------------/
/USER :包含程序的 main 函数,是整个程序的入 /
/HW :包含开发板各种功能外设的驱动程序 /
/LIB :官方提供的 HAL 库文件 /
/CMSIS :CM3 内核相关的启动文件系统文件 /
/-----------------------------------------------------/
/ /
/ 实现定时器功能的头文件 /
/ /
/-----------------------------------------------------/
#ifndef _TIMER_H
#define _TIMER_H
#include "stdint.h"
#include "stm32f1xx_hal_tim.h"
extern TIM_HandleTypeDef htim4; //外部变量声明
void TIM4_TimerInit(uint16_t, uint16_t); //函数声明
#endif
sw.c
#include "stm32f1xx_hal.h"
#include "sw.h"
#include "uart.h"
uint8_t sw1_sta,sw2_sta; //0:没有按下 1:按下了
void SW_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_INPUT;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEvent(void){
GPIO_InitTypeDef GPIO_InitType;
//SW1
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_2;
GPIO_InitType.Mode = GPIO_MODE_EVT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
}
void SW_InitEventOut(void){
GPIO_InitTypeDef GPIO_InitType;
//PA3
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_3;
GPIO_InitType.Mode = GPIO_MODE_AF_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_3);
HAL_GPIOEx_EnableEventout();
}
//mode 0:按下执行 1:抬起执行
void SW_Init_IT(uint8_t mode){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
if(mode == 0)
GPIO_InitType.Mode = GPIO_MODE_IT_RISING;
else
GPIO_InitType.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
void SW_Init_IT2(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_14;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI15_10_IRQn,4,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitType.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
//返回值 0:无按键触发 8:SW8触发
//mode 0:按下执行 1:抬起执行
uint8_t SW_Scan(uint8_t mode){
uint32_t i;
/-------------SW8------------------/
if((SW1_IN == 1)&&(sw1_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return 0;
}
}
sw1_sta = 1;
if(mode == 0){
return 8;
}
}else if((SW1_IN == 0)&&(sw1_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return 0;
}
}
sw1_sta = 0;
if(mode == 1){
return 8;
}
}
/-------------SW11------------------/
if((SW2_IN == 0)&&(sw2_sta == 0)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 1){
return 0;
}
}
sw2_sta = 1;
if(mode == 0){
return 11;
}
}else if((SW2_IN == 1)&&(sw2_sta == 1)){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return 0;
}
}
sw2_sta = 0;
if(mode == 1){
return 11;
}
}
return 0;
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
uint32_t i;
//SW8:PC13 SW11:PA0(抢占优先级高)
switch(GPIO_Pin){
case GPIO_PIN_14: if(SW1_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 0){
return;
}
}
//U1_Txdata((uint8_t *)"x81S1_LED",7);
//U2_Txdata((uint8_t *)"LED_ON",6);
U3_Txdata((uint8_t *)"LED_ON",6);
}else if(SW1_IN == 0){
for(i=0;i<0x7FFF;i++){
if(SW1_IN == 1){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
case GPIO_PIN_0: if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
//U1_Txdata((uint8_t *)"x82S2_LED",7);
//U2_Txdata((uint8_t *)"LED_OFF",7);
U3_Txdata((uint8_t *)"LED_OFF",7);
}else if(SW2_IN == 1){
for(i=0;i<0x7FFF;i++){
if(SW2_IN == 0){
return;
}
}
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
}
break;
}
}
sw.h
#ifndef __SW_H
#define __SW_H
#include "stdint.h"
#define SW1_IN HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)
#define SW2_IN HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
void SW_Init(void);
uint8_t SW_Scan(uint8_t mode);
void SW_Init_IT(uint8_t mode);
void SW_Init_IT2(void);
void SW_InitEvent(void);
void SW_InitEventOut(void);
#endif
led.c
#include "stm32f1xx_hal.h"
#include "led.h"
void LED_Init(void){
GPIO_InitTypeDef GPIO_InitType;
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_13;
GPIO_InitType.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitType.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC,&GPIO_InitType);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_ON(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
void LED_OFF(void){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
void LED_Toggle(void){
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);
}
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void LED_ON(void);
void LED_OFF(void);
void LED_Toggle(void);
#endif
stm32f1xx_it.c
/-------------------------------------------------/
/ 超子说物联网STM32系列开发板 /
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "timer.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
//if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
// __HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
// uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
// HAL_UART_AbortReceive_IT(&uart2.uart);
//}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
//if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
// __HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
// uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
// HAL_UART_AbortReceive_IT(&uart3.uart);
//}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmarx);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmatx);
}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmatx);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart3.dmarx);
}
//定时器中断处理函数
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim4);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
timer.c
/-----------------------------------------------------/
/ 程序结构 /
/-----------------------------------------------------/
/USER :包含程序的 main 函数,是整个程序的入 /
/HW :包含开发板各种功能外设的驱动程序 /
/LIB :官方提供的 HAL 库文件 /
/CMSIS :CM3 内核相关的启动文件系统文件 /
/-----------------------------------------------------/
/ /
/ 实现定时器功能的源文件 /
/ /
/-----------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "timer.h"
#include "uart.h"
TIM_HandleTypeDef htim4; //定时器4总控制结构体
/-------------------------------------------------/
/函数名:定时器4 定时初始化 /
/参 数:arr:自动重装值 /
/参 数:psc:时钟预分频数 /
/返回值:无 /
/-------------------------------------------------/
void TIM4_TimerInit(uint16_t arr, uint16_t psc)
{
htim4.Instance = TIM4; //设置使用哪个定时器
htim4.Init.Prescaler = psc - 1; //设置预分频器的值
htim4.Init.Period = arr - 1; //设置自动重载值
htim4.Init.CounterMode = TIM_COUNTERMODE_UP; //设置计数模式
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重载预装载 禁止
HAL_TIM_Base_Init(&htim4); //配置,如果失败进入if
__HAL_TIM_CLEAR_IT(&htim4, TIM_IT_UPDATE); //清除定时器4的中断标志
__HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE); //打开更新中断
}
/-------------------------------------------------/
/函数名:定时器底层驱动,开启时钟,设置中断优先级 /
/参 数:htim:定时器句柄 /
/返回值:无 /
/说 明:此函数会被HAL_TIM_Base_Init()函数调用 /
/-------------------------------------------------/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4){ //判断是哪个定时器
__HAL_RCC_TIM4_CLK_ENABLE(); //使能定时器时钟
HAL_NVIC_SetPriority(TIM4_IRQn,4,0); //设置中断优先级,中断分组在HAL_Init()函数中,被设置为4
HAL_NVIC_EnableIRQ(TIM4_IRQn); //开启定时器中断
}
}
/---------------------------------------------------/
/函数名:定时器中断回调函数 /
/参 数:htim:定时器句柄 /
/返回值:无 /
/说 明:此函数会被HAL_TIM_IRQHandler()中断函数调用 /
/---------------------------------------------------/
//超时回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4){ //判断是哪个定时器
__HAL_TIM_DISABLE(htim); //关闭定时器4的计数
__HAL_TIM_SET_COUNTER(htim,0); //清零定时器4计数器
uart3.RxState = 0; //恢复首字节接收标志位
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx)); //记录剩余未发送
HAL_UART_AbortReceive_IT(&uart3.uart); //终止接收
}
}
stm32f1xx_hal_uart.c
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
/ If no error occurs /
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
//删除 RXNE中断
//if (errorflags == RESET)
//{
// / UART in mode Receiver -------------------------------------------------/
// if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
// {
// UART_Receive_IT(huart);
// return;
// }
//}
/ If some errors occur /
if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/ UART parity error interrupt occurred ----------------------------------/
if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/ UART noise error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/ UART frame error interrupt occurred -----------------------------------/
if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/ UART Over-Run interrupt occurred --------------------------------------/
if (((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/ Call UART Error Call back function if need be --------------------------/
if (huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/ UART in mode Receiver -----------------------------------------------/
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/ Disable the UART DMA Rx request if enabled /
if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/ Abort the UART DMA Rx channel /
if (huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/ Call Directly XferAbortCallback function in case of error /
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/ Call user error callback /
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
/Call registered error callback/
huart->ErrorCallback(huart);
#else
/Call legacy weak error callback/
HAL_UART_ErrorCallback(huart);
#endif / USE_HAL_UART_REGISTER_CALLBACKS /
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} / End if some error occurs /
/ UART in mode Transmitter ------------------------------------------------/
//删除 发送缓冲区空的中断
// if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
// {
// UART_Transmit_IT(huart);
// return;
// }
/ UART in mode Transmitter end --------------------------------------------/
if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
/ 写自己的中断回调,现在只能进入我们这个了。 /
#include "uart.h"
#include "timer.h"
else
{
if(uart3.RxState == 0){ / 首字节 /
__HAL_TIM_ENABLE(&htim4); //打开tim4的计数
uart3.RxStat = 1; //标记接收
}else{/ 后续字节 /
__HAL_TIM_SET_COUNTER(&htim4, 0)//清除tim4的计数
}
}
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
int main(void){
HAL_Init();
RccClock_Init();
SW_Init_IT(0);
LED_Init();
U1_Init(921600);
U2_Init(921600);
U3_Init(921600);
while(1){
//串口1收发
if(uart1.RxOutPtr != uart1.RxInPtr){
if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==6)&&(memcmp(uart1.RxOutPtr->start,"LED_ON",6) == 0)){
LED_ON();
}else if(((uart1.RxOutPtr->end - uart1.RxOutPtr->start + 1)==7)&&(memcmp(uart1.RxOutPtr->start,"LED_OFF",7) == 0)){
LED_OFF();
}
uart1.RxOutPtr++;
if(uart1.RxOutPtr == uart1.RxEndPtr){
uart1.RxOutPtr = &uart1.RxLocation[0];
}
}
if((uart1.TxOutPtr != uart1.TxInPtr)&&(uart1.TxState==0)){
uart1.TxState = 1;
HAL_UART_Transmit_DMA(&uart1.uart,uart1.TxOutPtr->start,uart1.TxOutPtr->end - uart1.TxOutPtr->start + 1);
uart1.TxOutPtr++;
if(uart1.TxOutPtr == uart1.TxEndPtr){
uart1.TxOutPtr = &uart1.TxLocation[0];
}
}
//串口2收发
if(uart2.RxOutPtr != uart2.RxInPtr){
if(((uart2.RxOutPtr->end - uart2.RxOutPtr->start + 1)==7)&&(memcmp(uart2.RxOutPtr->start,"x81S1_LED",7) == 0)){
LED_Toggle();
}
uart2.RxOutPtr++;
if(uart2.RxOutPtr == uart2.RxEndPtr){
uart2.RxOutPtr = &uart2.RxLocation[0];
}
}
if((uart2.TxOutPtr != uart2.TxInPtr)&&(uart2.TxState==0)){
uart2.TxState = 1;
HAL_UART_Transmit_DMA(&uart2.uart,uart2.TxOutPtr->start,uart2.TxOutPtr->end - uart2.TxOutPtr->start + 1);
uart2.TxOutPtr++;
if(uart2.TxOutPtr == uart2.TxEndPtr){
uart2.TxOutPtr = &uart2.TxLocation[0];
}
}
//串口3收发
if(uart3.RxOutPtr != uart3.RxInPtr){
if(((uart3.RxOutPtr->end - uart3.RxOutPtr->start + 1)==7)&&(memcmp(uart3.RxOutPtr->start,"x82S2_LED",7) == 0)){
LED_Toggle();
}
uart3.RxOutPtr++;
if(uart3.RxOutPtr == uart3.RxEndPtr){
uart3.RxOutPtr = &uart3.RxLocation[0];
}
}
if((uart3.TxOutPtr != uart3.TxInPtr)&&(uart3.TxState==0)){
uart3.TxState = 1;
HAL_UART_Transmit_DMA(&uart3.uart,uart3.TxOutPtr->start,uart3.TxOutPtr->end - uart3.TxOutPtr->start + 1);
uart3.TxOutPtr++;
if(uart3.TxOutPtr == uart3.TxEndPtr){
uart3.TxOutPtr = &uart3.TxLocation[0];
}
}
}
}
十二、HAL库:多主机通信 空闲检测唤醒 定时器超时 DMA不定长接收
1. 空闲总线检测
空闲唤醒没有硬件从机地址,需要自己在程序中加入从机地址,并进行管理
RWU被写入1时,USART进入静默模式。当检测到 一空闲帧时,它被唤醒。然后RWU被硬件清零,
所以,在空闲总线唤醒模式下
HAL_MultiProcessor_Init 多设备初始化的第二个参数(从机地址)时无效的2. 思路:
因为空闲总线检测没有从机没有硬件地址,那么思路可以为下:
- 从机默认为正常模式,如果地址匹配,那么继续执行后续操作。
- 如果地址未匹配,那么在应用程序中,调用子函数,将这个从机的RWU变为高电平。静默模式。不对后续的数据进行接收
- 当这一段数据接收完毕,空闲帧出现时,就会重新把从机的RWU拉低为低电平。变为正常模式
- 总结理解:大部分时间为正常模式,当判断地址之后,如果不是自己的地址就进入静默模式,不接收。当这一段数据完毕之后,空闲帧出现,硬件自动拉低RWU。变会正常模式
3. 程序
相较上一节:”HAL库:多主机通信 地址检测唤醒 定时器超时 DMA不定长接收“
主机部分:
- 仅改变了发送数据,由 0x81 变为0x01 .因为此时不是地址检测唤醒,不需要告诉从机这段字节为地址(bit7 为 1)
从机部分:
- 修改主程序判断接收数据的地址由0x81-> 0x01
- 仅在初始化时,改变了下
HAL_MultiProcessor_Init的第三个参数(唤醒方式)为UART_WAKEUPMETHOD_IDLELINE(第二个参数为无效参数) 初始化时和接收完成后不需要进入静默模式,(因为空闲帧会立刻把RWU置位为0,进入正常模式)
- 在stm32f1xx_hal_uart.c中,添加判断地址并进入或不进入静默模式的程序。
/ 写自己的中断回调,现在只能进入我们这个了。 /
if(uart2.RxState == 0){ / 首字节 /
__HAL_TIM_ENABLE(&htim4); //打开tim4的计数
uart2.RxState = 1; //标记接收
/ 判断地址 /
if(*uart2.RxInPtr->start != 0x01){//判断第一个字节是不是自己的地址
HAL_MultiProcessor_EnterMuteMode(&uart1.uart); //进入静默模式
}
}else{/ 后续字节 /
__HAL_TIM_SET_COUNTER(&htim4, 0);//清除tim4的计数
}
十三、串口1 2 3 Printf 格式化输出
void U3_Printf(char* format, ...){
uint8_t tempbuff[256];
va_list ap;
va_start(ap, format);
vsprintf((char*)tempbuff, format, ap);
va_end(ap);
uint16_t i;
for(i = 0; i < strlen((char*)tempbuff); i++){
while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TXE)); //发送寄存器空,才开始发送
uart3.uart.Instance->DR = tempbuff[i]; //把数据依次放入DR 寄存器,发送出去
}
while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TC)); //发送完成,退出printf
}
代码解析:
- 这个函数有一个参数
format,它是一个指向字符的指针,代表格式化字符串 在 C 语言中,函数参数中的 “...” 表示可变参数列表,也称为可变参数。
- 首先定义了一个大小为 256 的无符号 8 位整数数组
tempbuff,用于存储格式化后的字符串。
- 使用可变参数列表的机制。
va_list ap;定义一个可变参数列表指针。va_start(ap, format);初始化可变参数列表指针,使其指向第一个可变参数,这里format是格式化字符串,后面的参数可以是任意类型和数量。vsprintf((char*)tempbuff, format, ap);使用可变参数列表将格式化后的字符串存储到tempbuff数组中。va_end(ap);标记可变参数列表结束。
- 然后通过一个循环逐个字符地将
tempbuff中的内容发送到 UART3。 - 在循环中,使用
while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TXE));等待发送寄存器为空,即可以发送下一个字符。 - 当发送寄存器为空时,将
tempbuff中的字符逐个放入 UART3 的数据寄存器uart3.uart.Instance->DR进行发送。
- 最后,使用
while(!__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_TC));等待发送完成标志位,确保所有数据都已发送完毕后退出函数。
十四、通信双方,参数不匹配时会出现哪些错误
这里用到了错误回调函数
HAL_UART_ErrorCallback我们利用两个实验板,测试通信参数不匹配时,产生哪些错误
利用串口2 相互通信
利用串口1 printf输出提示信息
- 波特率不匹配:噪声错误,不是每次每次都会发生,会伴随无效数据
- 数据字长不匹配时:一个8位 一个9位 帧错误
- 校验不匹配时:PE 校验错误
一旦错误产生,会终止当前的数据传输。
定时器[外部模式]篇
一、资源介绍:STM32F103C8T6定时器资源介绍
高级定时器(TIM1)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
- 重复次数寄存器(TIMx_RCR)
通用定时器(TIM2、TIM3、TIM4)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
定时器1 外部通道:
- 通道 1:PA8,DMA1_Channel2
- 通道 2:PA9,DMA1_Channel3
- 通道 ETR:PA12
定时器2 外部通道:
- 通道 1:PA0(重映射 PA15),DMA1_Channel5(如果重映射,需要内部上拉)
- 通道 2:PA1(重映射 PB3),DMA1_Channel7
- 通道 ETR:PA0(重映射 PA15)
定时器3 外部通道:
- 通道 1:PA6(重映射 PB4),DMA1_Channel6(如果重映射,需要内部上拉)
- 通道 2:PA7(重映射 PB5)
- 通道 ETR:无
定时器4 外部通道:
- 通道 1:PB6,DMA1_Channel1
- 通道 2:PB7,DMA1_Channel4
- 通道 ETR:无
来自江协的定时器基本结构图

二、HAL库:TIM1 外部时钟模式1 轮询方式 按键计数
1. 功能说明
- 按下按键,定时器计数
2. 注意事项*
- 引脚冲突问题
外部时钟模式1,定时器1:
通道1 PA8 DMA1_Channel2
通道2 PA9 DMA1_Channel3
而串口1的Tx也为PA9
所以要善用重映射功能(会重映射到PB6),避免引脚冲突
并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置
- ED双边沿检测,不过滤波器
- 外部时钟模式1 通往TRGI, TRGI会产生一个触发事件 会置位TIF为1,也就是HAL库的
TIM_FLAG_TRIGGER标志位会置1,我们可以通过判断标志位来进行判断单次的触发事件。




- 通道1 、2 上的滤波器解释

3. 相关函数
- 重映射串口1
__HAL_RCC_AFIO_CLK_ENABLE();__HAL_AFIO_REMAP_USART1_ENABLE();
TIM_ClockConfigTypeDef时钟配置总控结构体
- 基础的定时器配置初始化(定时器1通道 2举例)
- 初始化硬件配置回调函数
4. 程序
time.c
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitType;
GPIO_InitType.Pin = GPIO_PIN_9;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //上拉
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// / DMA配置 /
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/ DMA配置 /
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/ DMA配置 /
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/ DMA配置 /
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%drn",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%drn",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%drn",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%drn",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
while(1){
/ 获取更新标志位 /
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
}
三、HAL库:TIM1 外部模式1 ETR通道 轮询方式 按键计数
1. 注意事项*
- ETR的通道有专门的预分频器,需要按需配置预分频器
TIM_CLOCKPRESCALER_DIV1/2/4/8

- 特别注意:当设置ETR的预分频器为2、4、8分频时,如果ETR的有效电平(取决于是否ETR反向)与IO的引脚默认电平不匹配,那么复位后首次按下会直接产生一次触发事件,后续正常。
- 解决办法:匹配IO与ETR的有效电平 (例如IO下拉,ETR有效电平为低电平,也就是ETR反转。那么就能匹配默认电平与ETR,就不会出现上述错误)
- 特别注意:如果通道的 分频因子 加大(同时加大分频因子),会使得检测变慢,也就是频率和带宽就变低了,变得更严格。会导致复位之后立刻产生一次触发事件。
- 解决办法:在启动定时器之前,
先进行一段时间的延时操作,再清除TIm的Counter和TRIG触发事件标志位
这样就能保证在启动时不会有任何触发事件产生(添加延时的原因是因为程序运行太快了,得等段时间反映。)
2. 相关函数
TIM_ClockConfigTypeDef时钟配置总控结构体
- 基础的定时器配置初始化(定时器1通道 2举例)
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/ 外部模式1 ETR通道 /
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效) 为了匹配IO和ETR,防止复位后按一下就产生触发事件
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
/ 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 /
HAL_Delay(50);
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除触发事件标志位
__HAL_TIM_SET_COUNTER(&tim1, 0); // 清除计数值
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
- 初始化硬件配置回调函数
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/ 外部模式1 ETR通道 /
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效) 为了匹配IO和ETR,防止复位后按一下就产生触发事件
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV4; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
/ 防止加大分频因子或滤波强度而导致的 复位后产生触发事件 /
HAL_Delay(50);
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除触发事件标志位
__HAL_TIM_SET_COUNTER(&tim1, 0); // 清除计数值
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitType;
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
GPIO_InitType.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// / DMA配置 /
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/ DMA配置 /
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/ DMA配置 /
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/ DMA配置 /
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%drn",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%drn",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%drn",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%drn",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
while(1){
/ 获取更新标志位 /
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
}
四、HAL库:TIM234 外部模式1 通道1 2 轮询方式 重映射通道 边沿检测 按键计数
1. 注意事项*
- 引脚冲突问题
要善用重映射功能,避免引脚冲突
并且在切换不同的通道的时候,注意GPIO口的初始化与上下拉配置
- 还是引脚冲突问题
单片机在默认状态佳,SW+JTAG仿真都是开启状态的。
当定时器2 的通道1 重映射会映射到 PA15,会与JTAG的引脚冲突。注意一下需要
- 如果映射TIM2时, 一旦设计仿真接口切换为普通接口,需要在初始化时保持一致

2. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/ 外部模式1 ETR通道 /
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 双边沿检测 重映射/
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim2); //打开定时器(轮询方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 /
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim3); //打开定时器(轮询方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/ 外部模式1 通道2 /
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
HAL_TIM_Base_Start(&tim4); //打开定时器(轮询方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/ 定时器1 外部模式1 ETR通道IO /
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
// HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
// HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
//
// / DMA配置 /
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/ 定时器2 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM2_IRQn);
//
// / DMA配置 /
// tim2_dmaup.Instance = DMA1_Channel2;
// tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
// HAL_DMA_Init(&tim2_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/ 定时器3 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM3_IRQn);
//
// / DMA配置 /
// tim3_dmaup.Instance = DMA1_Channel3;
// tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
// HAL_DMA_Init(&tim3_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/ 定时器4 外部模式1 通道2 /
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
// HAL_NVIC_EnableIRQ(TIM4_IRQn);
//
// / DMA配置 /
// tim4_dmaup.Instance = DMA1_Channel7;
// tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
// HAL_DMA_Init(&tim4_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%drn",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%drn",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%drn",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%drn",time4++);
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
// uint16_t time1 = 0;
// uint16_t time2 = 0;
// uint16_t time3 = 0;
// uint16_t time4 = 0;
while(1){
/ 获取更新标志位 /
/ TIM1 /
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_TRIGGER); ///清除标志位
U1_Printf("定时器 1 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim1)); //输出当前计数值
}
/ TIM2 /
if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
U1_Printf("定时器 2 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_TRIGGER);
U1_Printf("定时器 2 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim2));
}
/ TIM3 /
if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
U1_Printf("定时器 3 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_TRIGGER);
U1_Printf("定时器 3 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim3));
}
/ TIM4 /
if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
U1_Printf("定时器 4 更新事件rn");
}
if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_TRIGGER)){
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_TRIGGER);
U1_Printf("定时器 4 触发事件:%drn", __HAL_TIM_GET_COUNTER(&tim4));
}
//
// if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
// U1_Printf("定时器 2 定时时间:%drn",time2++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
// U1_Printf("定时器 3 定时时间:%drn",time3++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
// U1_Printf("定时器 4 定时时间:%drn",time4++);
// }
}
}
五、HAL库:TIM1234 外部模式1 中断方式 按键计数
1. 注意事项*
- HAL库只会打开Up中断,触发中断需要手动打开
- 注意定时器与别的外设 引脚冲突
2. 相关函数
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER);手动打开触发中断
HAL_TIM_Base_Start_IT(&tim4);打开定时器(中断方式)
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/ 外部模式1 ETR通道 / //PA12 下降沿 按下计数 上拉
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim1); //打开定时器(中断方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 双边沿检测 重映射/ //PA15 双边边沿 上拉
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim2); //打开定时器(中断方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 / //PB4 上升沿 上拉 抬起计数
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim3); //打开定时器(中断方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/ 外部模式1 通道2 / //PB7 下降沿 上拉 按下计数
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER); //手动打开触发中断
HAL_TIM_Base_Start_IT(&tim4); //打开定时器(中断方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/ 定时器1 外部模式1 ETR通道IO /
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
//
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0); //配置、打开 触发中断
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);
//
// / DMA配置 /
// tim1_dmaup.Instance = DMA1_Channel5;
// tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
// tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
// tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
// tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
// tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim1_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
// HAL_DMA_Init(&tim1_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
//
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/ 定时器2 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
//
// / DMA配置 /
// tim2_dmaup.Instance = DMA1_Channel2;
// tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
// HAL_DMA_Init(&tim2_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/ 定时器3 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
//
// / DMA配置 /
// tim3_dmaup.Instance = DMA1_Channel3;
// tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim3_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
// HAL_DMA_Init(&tim3_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/ 定时器4 外部模式1 通道2 /
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
// __HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
//
// / DMA配置 /
// tim4_dmaup.Instance = DMA1_Channel7;
// tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
// tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
// tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
// tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
// tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
// tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
// __HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
// HAL_DMA_Init(&tim4_dmaup);
//
// HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
// HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
// / 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA1 完成中断rn");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 1 定时时间:%drn",time1++);
// }
U1_Printf("定时器 1 更新事件rn");
}else if(htim->Instance == TIM2){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA2 完成中断rn");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 2 定时时间:%drn",time2++);
// }
U1_Printf("定时器 2 更新事件rn");
}else if(htim->Instance == TIM3){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA3 完成中断rn");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 3 定时时间:%drn",time3++);
// }
U1_Printf("定时器 3 更新事件rn");
}else if(htim->Instance == TIM4){
// if(htim->State == HAL_DMA_STATE_READY){
// U1_Printf("DMA4 完成中断rn");
// htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
// }else{
// U1_Printf("定时器 4 定时时间:%drn",time4++);
// }
U1_Printf("定时器 4 更新事件rn");
}
}
//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
U1_Printf("初始化完成rn");
while(1){
}
}
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM1_TRG_COM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
六、HAL库:TIM1234 外部模式1 DMA单次/循环模式 中断方式 按键计数
1. 注意事项*
- DMA方式,HAL库不会开启任何中断,需要自己开启更新和触发中断
- 注意定时器与别的外设 引脚冲突
- 普通的更新中断与DMA完成中断共用一个回调函数
2. 简单介绍
DMA方式,会在每次更新时,传递新的值到ARR重载值,我们初始
化的时候设置ARR为5,然后启动DMA 4次传输分别传输6,7,8,9。
对于单次DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效
边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1
个有效边沿,之后一直都是9+1个有效边沿。
对于循环DMA向上计数,第一次5+1个有效边沿,第二次6+1个有效
边沿,第三次7+1个有效边沿,第四次8+1个有效边沿,第五次9+1
个有效边沿,第六次6+1个有效边沿,第七次7+1个有效边沿,第八
次8+1个有效边沿,第九次9+1个有效边沿,第十次6+1个有效边
沿.......往复循环
2. 相关函数
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER);手动打开中断
HAL_TIM_Base_Start_DMA(&tim4);打开定时器(DMA方式)
3. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //定时器结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup; //DMA通道配置结构体
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
TIM_ClockConfigTypeDef tim1_clock; //时钟配置结构体
TIM_ClockConfigTypeDef tim2_clock;
TIM_ClockConfigTypeDef tim3_clock;
TIM_ClockConfigTypeDef tim4_clock;
uint16_t tim1_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim2_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim3_dmaBuff[4] = {6, 7, 8, 9};
uint16_t tim4_dmaBuff[4] = {6, 7, 8, 9};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
/ 外部模式1 ETR通道 / //PA12 下降沿 按下计数 上拉
tim1_clock.ClockSource = TIM_CLOCKSOURCE_ETRMODE1; //通道1 ETR
tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED; //ETR反向 (低电平或下降沿有效)
//tim1_clock.ClockPolarity = TIM_CLOCKPOLARITY_NOINVERTED; //ETR不反向 (高电平或上升沿有效)
tim1_clock.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; //ETR的预分频器配置
tim1_clock.ClockFilter = 0x03; //滤波(注意是外部时钟的波)
HAL_TIM_ConfigClockSource(&tim1, &tim1_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim1, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim1, (uint32_t* )tim1_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 双边沿检测 重映射/ //PA15 双边边沿 上拉
tim2_clock.ClockSource = TIM_CLOCKSOURCE_TI1ED; //通道1 边沿检测
HAL_TIM_ConfigClockSource(&tim2, &tim2_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim2, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t* )tim2_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1; //中央对齐模式
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
/ 外部模式1 通道1 / //PB4 上升沿 上拉 抬起计数
tim3_clock.ClockSource = TIM_CLOCKSOURCE_TI1; // 通道1
tim3_clock.ClockPolarity = TIM_CLOCKPOLARITY_RISING; // 上升沿
tim3_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim3, &tim3_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim3, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t* )tim3_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
/ 外部模式1 通道2 / //PB7 下降沿 上拉 按下计数
tim4_clock.ClockSource = TIM_CLOCKSOURCE_TI2; // 通道2
tim4_clock.ClockPolarity = TIM_CLOCKPOLARITY_FALLING; // 下降沿
tim4_clock.ClockFilter = 0x03; // 滤波
HAL_TIM_ConfigClockSource(&tim4, &tim4_clock); //初始化定时器时钟配置
__HAL_TIM_ENABLE_IT(&tim4, TIM_IT_TRIGGER | TIM_IT_UPDATE); //手动打开触发中断、更新中断
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t* )tim4_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitType;
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
/ 定时器1 外部模式1 ETR通道IO /
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_12;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 3, 0); //配置、打开 触发中断
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);
/ DMA配置 /
__HAL_RCC_DMA1_CLK_ENABLE();
tim1_dmaup.Instance = DMA1_Channel5;
tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
HAL_DMA_Init(&tim1_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM2_ENABLE();
//__HAL_AFIO_REMAP_TIM2_PARTIAL_1(); //(同样的功能)
__HAL_AFIO_REMAP_SWJ_NOJTAG();
/ 定时器2 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_0;
GPIO_InitType.Pin = GPIO_PIN_15;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOA,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/ DMA配置 /
__HAL_RCC_DMA1_CLK_ENABLE();
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
//__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL(); //部分映射
__HAL_AFIO_REMAP_SWJ_NONJTRST(); //完全SW+JATG 但没有NJTRST
/ 定时器3 外部模式1 通道1 重映射/
//GPIO_InitType.Pin = GPIO_PIN_6;
GPIO_InitType.Pin = GPIO_PIN_4;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB,&GPIO_InitType);
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/ DMA配置 /
__HAL_RCC_DMA1_CLK_ENABLE();
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
/ 定时器4 外部模式1 通道2 /
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitType.Pin = GPIO_PIN_7;
GPIO_InitType.Mode = GPIO_MODE_AF_INPUT;
GPIO_InitType.Pull = GPIO_PULLUP; //低电平按下,上拉
HAL_GPIO_Init(GPIOB, &GPIO_InitType);
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/ DMA配置 /
__HAL_RCC_DMA1_CLK_ENABLE();
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
//tim2_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断DMA的状态是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 1 更新事件rn");
}
}else if(htim->Instance == TIM2){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 2 更新事件rn");
}
}else if(htim->Instance == TIM3){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 3 更新事件rn");
}
}else if(htim->Instance == TIM4){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 4 更新事件rn");
}
}
}
//触发中断 回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 触发事件:%drn", __HAL_TIM_GET_COUNTER(htim)); //输出当前计数值
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(5 - 1, 0, 1 - 1); //5次有效边沿
Timer2_Init(5 - 1, 0); // 5次
Timer3_Init(5 - 1, 0); // 5次
Timer4_Init(5 - 1, 0); // 5次
U1_Printf("初始化完成rn");
while(1){
}
}
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM1_TRG_COM_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
七、HAL库:TIM12 外部模式2 循环 中断 DMA方式 按键计数
具体方式与外模1类似,但是需要注意一下 两 点:
- 外部模式2并没有触发中断

可以看到外部模式1 有TIF触发事件的产生

但是外部模式2并没有

- 外部模式2仅支持ETR通道
- STMF103C8T6只有TIM 1 2 有ERT通道
定时器[基础定时]篇
一、资源介绍:STM32F103C8T6定时器资源介绍
高级定时器(TIM1)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
- 重复次数寄存器(TIMx_RCR)
通用定时器(TIM2、TIM3、TIM4)
- 时基单元包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器(TIMx_PSC)
- 自动装载寄存器(TIMx_ARR)
定时器 1 通道
- 通道 1:PA8、 DMA1_Channel2
- 通道 2:PA9、 DMA1_Channel3
- 通道 3:PA10、 DMA1_Channel6
- 通道 4:PA11、 DMA1_Channel4
- 通道 ETR:PA12
- 刹车: PB12、PA6(重映射)
- 通道 1 互补:PB13、PA7(重映射)
- 通道 2 互补:PB14、PB0(重映射)
- 通道 3 互补:PB15、PB1(重映射)
定时器 2 通道
- 通道 1:PA0(重映射 PA15)、PA1(重映射 PB3)
- 通道 2:PA2(重映射 PB10)
- 通道 3:DMA1_Channel5、DMA1_Channel7、DMA1_Channel1、DMA1_Channel7
- 通道 4:PA3(重映射 PB11)
- 通道 ETR:PA0(重映射 PA15)
定时器 3 通道
- 通道 1:PA6(重映射 PB4)、DMA1_Channel6、DMA1_Channel2、DMA1_Channel3
- 通道 2:PA7(重映射 PB5)
- 通道 3:PB0
- 通道 4:PB1
- 通道 ETR:无
定时器 4 通道
- 通道1:PB6 DMA1 Channel1
- 通道2:PB7 DMA1 Channel4
- 通道3:PB8 DMA1 Channel5
- 通道4:PB9
- 通道ETR:无
二、HAL库:TIM1234轮询方式 基础定时
1. 相关函数
TIM_HandleTypeDef定时器总控结构体
HAL_TIM_Base_Init(&tim3);轮询 初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);清除更新标志位
HAL_TIM_Base_Start(&tim3);开启定时器
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)定时器DeInit回调函数
- 基础的初始化
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)定时器Init回调函数
- 基础的初始化
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动清除更新事件
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 定时时间:%drn",time1++);
}
2. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动清除更新事件
HAL_TIM_Base_Start(&tim1); //打开定时器(轮询方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
HAL_TIM_Base_Start(&tim2); //打开定时器(轮询方式)
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
HAL_TIM_Base_Start(&tim3);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
HAL_TIM_Base_Start(&tim4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
}
}
//定时器 De回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM1_CLK_DISABLE();
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
/ 初始化函数 /
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(20000 - 1, 3600 - 1, 4 - 1); // 72000000/3600/20000 = 1 * 4 = 4s
Timer2_Init(30000 - 1, 7200 - 1); // 3s
Timer3_Init(20000 - 1, 7200 - 1); // 2s
Timer4_Init(10000 - 1, 7200 - 1); // 1s
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
while(1){
/ 获取更新标志位 /
if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
U1_Printf("定时器 1 定时时间:%drn",time1++);
if(time1 > 5){
U1_Printf("定时器 1 关闭rn");
HAL_TIM_Base_Stop(&tim1); //停止定时器
HAL_TIM_Base_DeInit(&tim1); //释放
}
}
if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
U1_Printf("定时器 2 定时时间:%drn",time2++);
}
if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
U1_Printf("定时器 3 定时时间:%drn",time3++);
}
if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
U1_Printf("定时器 4 定时时间:%drn",time4++);
}
}
}
三、解释:定时器初始化后 立刻产生的更新事件 是哪里来的
哪里来的更新事件:
来源于
HAL_TIM_Base_Init(&tim1); 初始化定时器基础配置函数中 TIM_Base_SetConfig 函数中的最后一行: TIMx->EGR = TIM_EGR_UG; 这里HAL库人为的 更新了一下EGR寄存器的Ug位,也就是事件产生寄存器为1。为什么要在初始化的时候更新一下事件:
原因是因为 定时器中的 PSC 和重复计数器Rep(这个是高级定时器才有)
只有在一次更新事件之后才会彻底写入(影子寄存器)
ARR虽然也有影子寄存器。但是他不管是在关闭还是开启的状态下,只要设置就能直接转正(写入)。
如何避免复位后直接产生更新事件?
在Start之前,手动清除UIF位
四、HAL库:TIM1234中断方式 基础定时
在轮询基础上,配置和开启了中断。
这里需要大概知道 需要定义 定时器的更新回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
注意开启定时器使用挂it方式的就ok ..
然后在对应的中断函数中处理就ok
程序
time.c
五、HAL库:TIM1234 DMA单次方式 改变定时时间
1. 如何做到改变定时时间
更新DMA事件可以改变ARR重载值,从而改变基础定时时间
2. 实验现象
DMA单次方式,传输4次数据,改变定时时间:第一次定时1s,第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,然后以后一直都是5s
3. 注意
- DMA有半完成回调 和 完成回调
- 其中完成回调,和定时器更新回调的函数是一个函数
- 所以,如果要使用更新中断和DMA完成中断,则需要判断一下。
- 方法:通过判断DMA的状态,如果为Busy,则说明是更新中断进入的 定时器更新回调函数
- DMA方式的定时器并不会开启更新中断,所以要手动打开更新中断
- DMA使用数 要注意通道的重复使用。避免重复。
- LinkDMA时,第二个参数的 外设句柄内的一个DMA句柄指针(可以理解为通道绑定),可以在这里直接看到他的所有成员。在用时,可以这样用
__HAL_LINKDMA(&tim1,hdma[TIM_DMA_ID_UPDATE], &tim1_dmaup);- / 判断DMA是否为Ready状态,如果是则是DMA完成中断进入的回调函数 /
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){


- DMA在Link TIM和DMA的某通道之后,可以直接在TIM中找到通道的配置总控结构体
4. 相关函数
TIM_HandleTypeDef定时器总控结构体
DMA_HandleTypeDefDMA总控结构体
__HAL_TIM_CLEAR_FLAG清除标志位
__HAL_TIM_ENABLE_IT使能中断
HAL_TIM_Base_Start_DMADMA方式启动定时器
__HAL_LINKDMADMA LINK
4. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
__HAL_TIM_ENABLE_IT(&tim1, TIM1_UP_IRQn); //手动 使能 定时器 更新中断
HAL_TIM_Base_Start_DMA(&tim1, (uint32_t*)tim1_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM1_UP_IRQn, 3, 0); //配置、打开 更新中断
HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
/ DMA配置 /
tim1_dmaup.Instance = DMA1_Channel5;
tim1_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim1_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim1_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim1_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim1_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim1_dmaup.Init.Mode = DMA_NORMAL; //单次模式
tim1_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim1, hdma[TIM_DMA_ID_UPDATE], tim1_dmaup);
HAL_DMA_Init(&tim1_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
/ DMA配置 /
tim2_dmaup.Instance = DMA1_Channel2;
tim2_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim2_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim2_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim2_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim2_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim2_dmaup.Init.Mode = DMA_NORMAL; //单次模式
tim2_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim2, hdma[TIM_DMA_ID_UPDATE], tim2_dmaup);
HAL_DMA_Init(&tim2_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM3_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
/ DMA配置 /
tim3_dmaup.Instance = DMA1_Channel3;
tim3_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim3_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim3_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim3_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim3_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim3_dmaup.Init.Mode = DMA_NORMAL; //单次模式
tim3_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim3, hdma[TIM_DMA_ID_UPDATE], tim3_dmaup);
HAL_DMA_Init(&tim3_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM4_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
/ DMA配置 /
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH; //存储区到外设
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE; //存储区递增
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE; //外设不递增
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; //半字 2字节
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_NORMAL; //单次模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 3, 0); //配置、打开 通道5的中断
HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);
}
}
//定时器 硬件 De 回调函数
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_DISABLE();
}else if(htim->Instance == TIM2){
__HAL_RCC_TIM2_CLK_DISABLE();
}else if(htim->Instance == TIM3){
__HAL_RCC_TIM3_CLK_DISABLE();
}else if(htim->Instance == TIM4){
__HAL_RCC_TIM4_CLK_DISABLE();
}
}
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断DMA是否为Ready状态,如果是则是DMA完成中断进入的回调函数 /
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 1 定时时间:%drn",time1++);
if(time1 >= 6){ //大于等于6 则关闭
U1_Printf("定时器1 关闭rn");
HAL_TIM_Base_Stop_DMA(htim);
HAL_TIM_Base_DeInit(htim);
}
}
}else if(htim->Instance == TIM2){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 2 定时时间:%drn",time2++);
if(time2 >= 6){ //大于等于6 则关闭
U1_Printf("定时器2 关闭rn");
HAL_TIM_Base_Stop_DMA(htim);
HAL_TIM_Base_DeInit(htim);
}
}
}else if(htim->Instance == TIM3){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 3 定时时间:%drn",time3++);
if(time3 >= 6){ //大于等于6 则关闭
U1_Printf("定时器3 关闭rn");
HAL_TIM_Base_Stop_DMA(htim);
HAL_TIM_Base_DeInit(htim);
}
}
}else if(htim->Instance == TIM4){
if(htim->hdma[TIM_DMA_ID_UPDATE]->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
HAL_DMA_DeInit(htim->hdma[TIM_DMA_ID_UPDATE]); //关闭DMA
}else{
U1_Printf("定时器 4 定时时间:%drn",time4++);
if(time4 >= 6){ //大于等于6 则关闭
U1_Printf("定时器4 关闭rn");
HAL_TIM_Base_Stop_DMA(htim);
HAL_TIM_Base_DeInit(htim);
}
}
}
}
//DMA 半完成回调函数
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
U1_Printf("定时器 1 DMA半完成中断rn");
}else if(htim->Instance == TIM2){
U1_Printf("定时器 2 DMA半完成中断rn");
}else if(htim->Instance == TIM3){
U1_Printf("定时器 3 DMA半完成中断rn");
}else if(htim->Instance == TIM4){
U1_Printf("定时器 4 DMA半完成中断rn");
}
}
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(10000 - 1, 7200 - 1, 1 - 1); // 72000000/7200/10000 = 1s
Timer2_Init(10000 - 1, 7200 - 1); // 1s
Timer3_Init(10000 - 1, 7200 - 1); // 1s
Timer4_Init(10000 - 1, 7200 - 1); // 1s
// uint16_t time1 = 0;
// uint16_t time2 = 0;
// uint16_t time3 = 0;
// uint16_t time4 = 0;
while(1){
/ 获取更新标志位 /
// if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
// U1_Printf("定时器 1 定时时间:%drn",time1++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
// U1_Printf("定时器 2 定时时间:%drn",time2++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
// U1_Printf("定时器 3 定时时间:%drn",time3++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
// U1_Printf("定时器 4 定时时间:%drn",time4++);
// }
}
}
六、HAL库:TIM1234 DMA循环方式 改变定时时间
1. 实验现象
DMA循环方式,传输4次*n数据,改变定时时间:第一次定时1s(初始化),第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,然后第六次 2s,第七次3s,第八次4s,第、九次5s,第十次2s
2. 如何判断DMA中断还是更新中断*
- 上一小节所说:DMA有半完成回调 和 完成回调
- 其中完成回调,和定时器更新回调的函数是一个函数
- 所以,如果要使用更新中断和DMA完成中断,则需要判断一下。
- 方法:通过判断DMA的状态,如果为Busy,则说明是更新中断进入的 定时器更新回调函数
- 那么在这一节是行不通的,因为DMA一直在循环模式,一直处于BUSY状态,所以不能判断了。但是 DMA的半完成中断和完成中断,在进入回调函数之前 就会把定时器设置成Ready状态,而定时器更新中断 并不会设置定时器的状态为Ready。
- 所以,着急需要判断定时器的更新中断,就可以判断这次中断是更新中断还是 DMA的中断。
- 并且,判断过后,需要把定时器状态重新赋值为 BUSY, 这样是为了防止更新中断在进入时,仍然进入DMA完成的分支
代码节选
//更新中断 回调函数(同时也是DMA完成的回调函数)
uint16_t time1 = 1;
uint16_t time2 = 1;
uint16_t time3 = 1;
uint16_t time4 = 1;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
/ 判断TIM是否为Ready状态,如果是 则是DMA完成中断进入的回调函数 /
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA1 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 1 定时时间:%drn",time1++);
}
}else if(htim->Instance == TIM2){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA2 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 2 定时时间:%drn",time2++);
}
}else if(htim->Instance == TIM3){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA3 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 3 定时时间:%drn",time3++);
}
}else if(htim->Instance == TIM4){
if(htim->State == HAL_DMA_STATE_READY){
U1_Printf("DMA4 完成中断rn");
htim->State = HAL_TIM_STATE_BUSY; //设置定时器 BUSY状态
}else{
U1_Printf("定时器 4 定时时间:%drn",time4++);
}
}
}
4. 相关函数
TIM_HandleTypeDef定时器总控结构体
DMA_HandleTypeDefDMA总控结构体
__HAL_TIM_CLEAR_FLAG清除标志位
__HAL_TIM_ENABLE_IT使能中断
HAL_TIM_Base_Start_DMADMA方式启动定时器
__HAL_LINKDMADMA LINK
/ DMA配置 /
tim4_dmaup.Instance = DMA1_Channel7;
tim4_dmaup.Init.Direction = DMA_MEMORY_TO_PERIPH;
tim4_dmaup.Init.MemInc = DMA_MINC_ENABLE;
tim4_dmaup.Init.PeriphInc = DMA_PINC_DISABLE;
tim4_dmaup.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
tim4_dmaup.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
tim4_dmaup.Init.Mode = DMA_CIRCULAR; //循环模式
tim4_dmaup.Init.Priority = DMA_PRIORITY_MEDIUM;
__HAL_LINKDMA(&tim4, hdma[TIM_DMA_ID_UPDATE], tim4_dmaup);
HAL_DMA_Init(&tim4_dmaup);
4. 程序
time.c
#include "stm32f1xx_hal.h"
#include "time.h"
TIM_HandleTypeDef tim1; //(高级)定时器1总控结构体
TIM_HandleTypeDef tim2;
TIM_HandleTypeDef tim3;
TIM_HandleTypeDef tim4;
DMA_HandleTypeDef tim1_dmaup;
DMA_HandleTypeDef tim2_dmaup;
DMA_HandleTypeDef tim3_dmaup;
DMA_HandleTypeDef tim4_dmaup;
uint16_t tim1_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim2_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim3_dmaBuff[4] = {20000, 30000, 40000, 50000};
uint16_t tim4_dmaBuff[4] = {20000, 30000, 40000, 50000};
//定时器 1
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
tim1.Instance = TIM1; // 实例
tim1.Init.Period = arr; // 重装载值
tim1.Init.Prescaler = psc; // 分频系数
tim1.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
tim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 分频因子
tim1.Init.RepetitionCounter = rep; // 重复计数值
tim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 自动重装载值 预装载使能位(影子寄存器)
HAL_TIM_Base_Init(&tim1); //初始化定时器
__HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); //手动 清除 定时器 更新事件
__HAL_TIM_ENABLE_IT(&tim1, TIM1_UP_IRQn); //手动 使能 定时器 更新中断
HAL_TIM_Base_Start_DMA(&tim1, (uint32_t*)tim1_dmaBuff, 4); //打开定时器(DMA方式)
}
//定时器 2
void Timer2_Init(uint16_t arr, uint16_t psc)
{
tim2.Instance = TIM2;
tim2.Init.Period = arr;
tim2.Init.Prescaler = psc;
tim2.Init.CounterMode = TIM_COUNTERMODE_UP;
tim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim2);
__HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim2, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim2, (uint32_t*)tim2_dmaBuff, 4);
}
//定时器 3
void Timer3_Init(uint16_t arr, uint16_t psc)
{
tim3.Instance = TIM3;
tim3.Init.Period = arr;
tim3.Init.Prescaler = psc;
tim3.Init.CounterMode = TIM_COUNTERMODE_UP;
tim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim3);
__HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim3, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim3, (uint32_t*)tim3_dmaBuff, 4);
}
//定时器 4
void Timer4_Init(uint16_t arr, uint16_t psc)
{
tim4.Instance = TIM4;
tim4.Init.Period = arr;
tim4.Init.Prescaler = psc;
tim4.Init.CounterMode = TIM_COUNTERMODE_UP;
tim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
tim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&tim4);
__HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
__HAL_TIM_ENABLE_IT(&tim4, TIM1_UP_IRQn);
HAL_TIM_Base_Start_DMA(&tim4, (uint32_t*)tim4_dmaBuff, 4);
}
//定时器 硬件初始化回调函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
__HAL_RCC_TIM1_CLK_ENABLE(); //使能时钟
__HAL_RCC_DMA1_CLK_ENABLE();
time.h
#ifndef __TIME_H
#define __TIME_H
#include "uart.h"
/ 对外声明总控结构体 /
extern TIM_HandleTypeDef tim1;
extern TIM_HandleTypeDef tim2;
extern TIM_HandleTypeDef tim3;
extern TIM_HandleTypeDef tim4;
extern DMA_HandleTypeDef tim1_dmaup;
extern DMA_HandleTypeDef tim2_dmaup;
extern DMA_HandleTypeDef tim3_dmaup;
extern DMA_HandleTypeDef tim4_dmaup;
/ 初始化函数 /
void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep);
void Timer2_Init(uint16_t arr, uint16_t psc);
void Timer3_Init(uint16_t arr, uint16_t psc);
void Timer4_Init(uint16_t arr, uint16_t psc);
#endif
stm32f1xx_it.c
/-------------------------------------------------/
/ /
/ 实现各种中断服务函数的源文件 /
/ /
/-------------------------------------------------/
#include "stm32f1xx_hal.h"
#include "stm32f1xx_it.h"
#include "uart.h"
#include "time.h"
void EXTI15_10_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_14);
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart1.uart);
if(__HAL_UART_GET_FLAG(&uart1.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart1.uart);
uart1.RxCounter += (U1_RX_MAX - __HAL_DMA_GET_COUNTER(&uart1.dmarx));
HAL_UART_AbortReceive_IT(&uart1.uart);
}
}
void USART2_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart2.uart);
if(__HAL_UART_GET_FLAG(&uart2.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart2.uart);
uart2.RxCounter += (U2_RX_MAX - __HAL_DMA_GET_COUNTER(&uart2.dmarx));
HAL_UART_AbortReceive_IT(&uart2.uart);
}
}
void USART3_IRQHandler(void)
{
HAL_UART_IRQHandler(&uart3.uart);
if(__HAL_UART_GET_FLAG(&uart3.uart, UART_FLAG_IDLE)){
__HAL_UART_CLEAR_IDLEFLAG(&uart3.uart);
uart3.RxCounter += (U3_RX_MAX - __HAL_DMA_GET_COUNTER(&uart3.dmarx));
HAL_UART_AbortReceive_IT(&uart3.uart);
}
}
void DMA1_Channel4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart1.dmatx);
}
//void DMA1_Channel5_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart1.dmarx);
//}
//void DMA1_Channel7_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart2.dmatx);
//}
void DMA1_Channel6_IRQHandler(void)
{
HAL_DMA_IRQHandler(&uart2.dmarx);
}
//void DMA1_Channel2_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmatx);
//}
//void DMA1_Channel3_IRQHandler(void)
//{
// HAL_DMA_IRQHandler(&uart3.dmarx);
//}
void DMA1_Channel5_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim1_dmaup);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim2_dmaup);
}
void DMA1_Channel3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim3_dmaup);
}
void DMA1_Channel7_IRQHandler(void)
{
HAL_DMA_IRQHandler(&tim4_dmaup);
}
void TIM1_UP_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim1);
}
void TIM2_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim2);
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim3);
}
void TIM4_IRQHandler(void)
{
HAL_TIM_IRQHandler(&tim4);
}
/-------------------------------------------------/
/函数名:不可屏蔽中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void NMI_Handler(void)
{
}
/-------------------------------------------------/
/函数名:硬件出错后进入的中断处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void HardFault_Handler(void)
{
}
/-------------------------------------------------/
/函数名:软中断,SWI 指令调用的处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SVC_Handler(void)
{
}
/-------------------------------------------------/
/函数名:可挂起的系统服务处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void PendSV_Handler(void)
{
}
/-------------------------------------------------/
/函数名:SysTic系统嘀嗒定时器处理函数 /
/参 数:无 /
/返回值:无 /
/-------------------------------------------------/
void SysTick_Handler(void)
{
HAL_IncTick();
}
main.c
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "sw.h"
#include "uart.h"
#include "time.h"
int main(void){
HAL_Init();
RccClock_Init();
U1_Init(921600);
Timer1_Init(10000 - 1, 7200 - 1, 1 - 1); // 72000000/7200/10000 = 1s
Timer2_Init(10000 - 1, 7200 - 1); // 1s
Timer3_Init(10000 - 1, 7200 - 1); // 1s
Timer4_Init(10000 - 1, 7200 - 1); // 1s
// uint16_t time1 = 0;
// uint16_t time2 = 0;
// uint16_t time3 = 0;
// uint16_t time4 = 0;
while(1){
/ 获取更新标志位 /
// if(__HAL_TIM_GET_FLAG(&tim1, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim1, TIM_FLAG_UPDATE); ///清除标志位
// U1_Printf("定时器 1 定时时间:%drn",time1++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim2, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim2, TIM_FLAG_UPDATE);
// U1_Printf("定时器 2 定时时间:%drn",time2++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim3, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim3, TIM_FLAG_UPDATE);
// U1_Printf("定时器 3 定时时间:%drn",time3++);
// }
//
// if(__HAL_TIM_GET_FLAG(&tim4, TIM_FLAG_UPDATE)){
// __HAL_TIM_CLEAR_FLAG(&tim4, TIM_FLAG_UPDATE);
// U1_Printf("定时器 4 定时时间:%drn",time4++);
// }
}
}
- 作者:L_Z_J
- 链接:https://www.mcoi.top/article/Post-stm32-hal
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。










