STM32CubeMX系列06——定时器(定时、PWM、输入捕获)_stm32cubemx 定时器_32Haozi
文章目录
1. 所用硬件2. 生成工程2.1. 创建工程选择主控2.2. 系统配置2.3. 配置工程目录 3. 定时器配置(三选一)3.1. 定时功能3.2. PWM 输出3.3. 输入捕获====>>> 文章汇总(有代码汇总) <<<====
1. 所用硬件
正点原子团Mini板,主要 STM32F103RCT6.定时器简介
这里主要讨论通用定时器(系统嘀嗒定时器、看门狗定时器、RTC定时器不考虑在内)
TIM6
、TIM7
。只能16位向上计数、没有IO口,没有捕获和比较通道,只有计时功能。4个通用定时器。分别是TIM2
、TIM3
、TIM4
、TIM5
。可以16位向上或向下计数。可以定时、输出比较、输入捕获。每个定时器有4个外部IO。2个高级定时器。分别是TIM1
、TIM8
。可以16位向上或向下计数。可以定时、输出比较、输入捕获、还可以输出三相电机互补信号。每个定时器有8个外部IO。
此外延时器的检修通道还可以用到作:
输入捕获输出比较PWM 生成(边缘或中间对齐模式)单脉冲模式输出
以下的时间会产生时会产生断开/DMA:
更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)输入捕获输出比较
2. 生成工程
2.1. 创建工程选择主控
2.2. 系统配置
配置时钟源
配置debug模式(如果需要ST-Link下载及调试可以勾选)
配置时钟树(可以直接在HCLK那里输入72,然后敲回车会自动配置)
2.3. 配置工程目录
3. 定时器配置(三选一)
例案: 定时功能:定时翻转 LED 灯PWM功能:驱动电机 / 呼吸灯输入捕获:PWM信号频率计算 / 信号高电平或低电平持续时间计算3.1. 定时功能
第一步:配置外设
LED:用来看效果
TIMER2:用来计时
在时钟树中可以看到,定时器都是挂在APB1和APB2上,时钟频率都一样,都是72MHZ。我们这里设置预分频系数为7200-1
,也就是分频完之后的频率为72 000 000 / 7200 = 10 000HZ
;计数值为10000
(设置9999,还有0,就是1万)。也就是每1s产生一次溢出中断中断
。
配置中断
第二步:生成代码
第三步:写代码
打开工程,编译。
在stm32f1xx_it.c
中可以看到定时器中断处理函数TIM2_IRQHandler
.
在HAL_TIM_IRQHandler(&htim2);
中,根据发生事件不同,调用了不同函数,其中当发生更新事件的时候,调用了函数HAL_TIM_PeriodElapsedCallback(htim);
这个函数定义如下。可以看到这是个弱函数,在注释中也有写。我们重新定义此函数,然后当中断发生时会执行此函数。此函数被称为回调函数。
当需要回调时,不应修改此函数,
HAL_TIM_PeriodElapsedCallback可以在用户文件中实现
我们把这个函数的重定义写在 tim.c
中。添加到末尾。
/* USER CODE BEGIN 1 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// 这个回调函数 是共用的,因此需要先判断,是不是定时器2
if(htim->Instance == htim2.Instance)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
}
/* USER CODE END 1 */
然后在main.c
中,只需要在while(1)之前 使能定时器中断即可。
// 使能定时器中断
HAL_TIM_Base_Start_IT(&htim2);
第四步:编译、下载、验证
PA8 连结的 LED 相隔瞬间滑动一遍,3.2. PWM 输出
第一步:配置定时器,用于输出PWM信号
在时钟树中可以看到,定时器都是挂在APB1和APB2上,时钟频率都一样,都是72MHZ。我们这里设置预分频系数为72-1
,也就是分频完之后的频率为72 000 000 / 72 = 1 000 000HZ
;计数值为1000
(设置999,还有0,就是1 000)。也就是每1ms产生一次溢出中断中断
。
PWM 生成通道 mode 参数:
TIMx_CNT,表示定时器 TIMx 的计数器寄存器值;
TIMx_CCRn,表示捕获比较寄存器的值,其中 n 表示某个通道,取值为1、2、3、4;
PWM 生成通道 pulse 参数:决定PWM的占空比。
占空比Pulse = pulse / period
这个是可以在程序中改的
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, campNum);
第二步:生成代码
第三步:main.c
/* USER CODE BEGIN WHILE */
// 开启 PWM 输出
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
uint16_t pwm_i = 0; // PWM output
uint16_t pwm_mode = 0; // PWM chance mode
while (1)
{
if(pwm_mode)
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_i--);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm_i--);
if(pwm_i==0)
pwm_mode=0;
}
else
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_i++);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm_i++);
if(pwm_i==1000)
pwm_mode=1;
}
HAL_Delay(1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
第四步:效果验证
编译、烧录
在PA1和GND 或者 PA2和GND之间接个 LED,可以看到LED有呼吸灯的效果。
3.3. 输入捕获
第一步:定时器配置
这里使用定时器3捕获输入
在时钟树中可以看到,定时器都是挂在APB1和APB2上,时钟频率都一样,都是72MHZ。我们这里设置预分频系数为72-1
,也就是分频完之后的频率为72 000 000 / 72 = 1 000 000HZ
;计数值为65536
(设置65535,还有0,就是65536)。因为这里其实还是需要计时,能长就长,减少更新中断。同时设置上升沿触发,也就是上升沿到来产生捕获中断。
设置捕获上升沿还是下降沿 也是可以配置的
__HAL_TIM_SET_CAPTUREPOLARITY();
使能中断
使用定时器2 产生固定占空比的PWM波(配置方法和上一小节一样)
为了方便看效果,也配置一下串口重定向,看往期文章。–>串口重定向配置<–
第二步:生成代码
第三步:写代码
在tim.c
末尾加上下面函数。前者为输入捕获中断回调函数。
后者用来计算 输入信号的占空比和频率。
/* USER CODE BEGIN 1 */
#include "usart.h"
uint16_t CCR1, CCR2, CCR3;
uint8_t measure_flag = 0;
// 定时器3 捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint8_t measure_cnt = 1;
// 初始设置的是捕获上升沿
if (htim == &htim3)
{
// 1. 第一次发生中断肯定是上升沿
if (measure_cnt == 1)
{
// 2. 获取此时定时器计时数据
CCR1 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);
// 3. 将定时器设置为捕获下降沿
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
measure_cnt = 2;
}
// 4. 捕获到下降延
else if (measure_cnt == 2)
{
// 5. 获取此时定时器计时数据
CCR2 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);
// 6. 将定时器重新设置为捕获上升沿
__HAL_TIM_SET_CAPTUREPOLARITY(&htim3, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
measure_cnt = 3;
}
// 7. 再次捕获到上升沿,说明一个周期结束了。
else if (measure_cnt == 3)
{
// 8. 获取此时定时器计时的数据
CCR3 = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);
// 9. 关闭定时器中断。
HAL_TIM_IC_Stop_IT(&htim3, TIM_CHANNEL_1);
measure_cnt = 1;
measure_flag = 1;
}
}
}
// 捕获函数
void capture(void)
{
// diff1:高电平持续时间
// diff2:一个周期的时间
uint16_t diff1 = 0, diff2 = 0;
uint32_t freq; // 频率
uint8_t duty; // 占空比
if (measure_flag)
{
measure_flag = 0;
if (CCR1 < CCR2)
diff1 = CCR2 - CCR1;
else
diff1 = 0xffff + 1 + CCR2 - CCR1; // 设置的最多能数65535,也就是0xffff + 1
if (CCR1 < CCR3)
diff2 = CCR3 - CCR1;
else
diff2 = 0xffff + 1 + CCR3 - CCR1;
// 每秒能数 1000000.一个周期是 diff2。
freq = (72000000 / 72) / diff2;
// 高电平持续时间/低电平持续时间 不让出现小数,所以*100
duty = diff1 * 100 / diff2;
}
printf("freq: %d HZ, duty: %d %% \r\n", freq, duty);
}
/* USER CODE END 1 */
在main.c
中调用函数
// 开启 PWM 输出
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
// 开启定时器输入捕获中断
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
while (1)
{
capture();
// 延时1s
// 在中断回调函数中关掉了,再次开启定时器3捕获中断 重新计算。
HAL_Delay(1000);
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
第四步:效果验证
编译、烧录
用串口查看:
用线把 PA6和PA0 或者 PA6和PA1 连接起来,就可以查看定时器2的两个通道产生的PWM频率和占空比了(下面有几个数不对,因为手动插上的时候有抖动)。
皇冠新体育APP相关的文章
- python网络编程实战-使用etree进行网页数据的解析,etree.xpath的使用_liranke_python etree
- 教你Win11如何运行安卓app_北漂燕郊杨哥_win11运行安卓app
- android项目嵌套uniapp页面及交互_我靠_叫我大当家的_uniapp嵌套页面
- 关于解决Android studio:The emulator process for AVD Pixel_4_XL_API_30 has terminated 以及改变AVD存放位置_Simon同学
- 皇冠新体育APP:绝缘子红外图像检测项目(TF2)_share_data
- MySQL-慢sql优化思路_零点冰.
- 【TTS】uni-app语音播报app开发 / MT-TTS安卓原生自带语音合成插件(免费无限次)_coderYYY_uniapp 语音合成
- 皇冠新体育APP:部署Web项目 (Linux)_yyhgo_
- 年底了,手机通讯录和相册被恶意APP获取,看我如何破局?_经海路大白狗_怎么获取别人的通讯录
- Android??一个简单的音乐APP_FranzLiszt1847_安卓开发音乐app
- 设计模式六大原则_llp1110
- 安卓Android开发快速入门_九 思_安卓开发
- 双非二本、已获HCIA认证的大二学生与C站相遇的2022_Alita11101_
- linux下gcc编程11-window下clion编译调试nginx+集成lua-nginx-module+安装开源x-waf_liaomin416100569_clion nginx
- 皇冠新体育APP:【一】微服务技术栈导学_?Suki
- Linux | 套接字(socket)编程 | TCP协议讲解 | 通信模型搭建_.SacaJawea