IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32实战(二):用定时器实现呼吸灯 -> 正文阅读

[嵌入式]STM32实战(二):用定时器实现呼吸灯

" 没想到一下鸽了几个月,遥想上一次更新还是在上海疫情在家期间?,忙碌了几个月生活终于回到了正轨,但愿以后不会那么忙碌了。好了我们言归正传,上一期我们学习了模板的建立,今天我们会利用STM32的定时器生成一组PWM驱动LED,并通过定时器中断改变其占空比,实现呼吸灯的效果。 "

??我们这次只使用一块STM32核心板并且基于上篇中实现的工程模板进行开发即可。开始之前,先介绍一下什么是PWM。

一、什么是PWM

??脉冲宽度调制(Pulse Width Modulation)是一种通过数字信号控制模拟器件的方式,它通过产生不同占空比(Duty Cycle)的矩形波来在输出端等效出不同电压值的控制效果,即对输出的脉冲宽度(占空比)进行调制,实现其对模拟器件的控制。下图展示了三种不同占空比PWM波的时间-幅度图:

??PWM的输出等效电压计算公式为:

U o = V C C ? t T = V C C ? D u t y (其中 t 为高电平时间, T 为 P W M 周期) U_o=VCC*\frac {t}{T}=VCC*Duty \\(其中t为高电平时间,T为PWM周期) Uo?=VCC?Tt?=VCC?Duty(其中t为高电平时间,TPWM周期)
??假设上述三种PWM波的VCC为5V,则上述三种等效输出电压分别为1.5V、2.5V、3.5V,即使用数字信号实现了模拟控制。

二、STM32定时器

??从官网上或使用CubeMX查询可知STM32F103RCT6属于大容量产品,共计有8个16位定时器,其中定时器1与定时器8为高级定时器;定时器2、3、4、5为通用定时器;定时器6、7为基本定时器。高级定时器与基本定时器都各有4个通道可以用来实现输入捕获或生成PWM等功能,同时高级定时器还具有输出互补PWM、刹车控制等功能。而基本定时器可以实现定时产生中断的基本功能。

??本次使用的LED连接在PA8上,查询F1的数据手册可知其可被复用为TIM1_CH1,即定时器1的输出通道1,可以使用该通道生成一个PWM。再使用定时器2生成一个周期性中断,改变PWM的占空比,生成一个占空比变化的PWM波,同时学习下定时器的使用方法。

??在HAL库中基本每个.C文件都对应了一个外设,里面封装了对该外设的各种操作函数,在文件中还有详细的注释描述其使用方法.例如定时器操作的源码就在stm32f1xx_hal_tim.c文件中,按照文件开始的注释中的说明,定时器或PWM生成的基本步骤为:

  • 根据用途调用HAL_TIM_Base_MspInit()或HAL_TIM_PWM_MspInit()等函数进行初始化
  • 使用__HAL_RCC_TIMx_CLK_ENABLE()使能定时器对应的时钟,设置使用的IO
  • 根据用途调用HAL_TIM_PWM_ConfigChannel()等进行进一步设置
  • 调用HAL_TIM_Base_Start()或HAL_TIM_PWM_Start()启动定时器

三、代码编写

为了方便后续管理,我将GPIO的部分与定时器的部分分开,并且开启定时器2的中断功能。

  1. GPIO部分负责初始化PA8端口,并设置为功能复用。gpio.c与gpio.h内容如下:
// gpio.c
#include "gpio.h"

int GPIOInit(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOA_CLK_ENABLE();

	GPIO_InitStruct.Pin = GPIO_PIN_8;
	GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	return 0;
}
// gpio.h
#ifndef __GPIO__H__
#define __GPIO__H__

#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f1xx_hal.h"

int GPIOInit(void);

#ifdef __cplusplus
}
#endif

#endif

  1. 定时器部分负责初始化定时器1与定时器2,设定的频率分别为1kHz与100Hz,并且设置定时器1输出PWM的占空比。timer.c与timer.h内容如下:
// timer.c
#include "timer.h"

TimerDef timer1, timer2;

int TimerInit(void)
{
    TimerDef *tmpTim = &timer1;
    /* 1kHz */
    tmpTim->TIM_Handle.Instance = TIM1;
    tmpTim->TIM_Handle.Init.Prescaler = 72 - 1;
    tmpTim->TIM_Handle.Init.Period = 1000;

    __HAL_RCC_TIM1_CLK_ENABLE();
    HAL_TIM_PWM_Init(&tmpTim->TIM_Handle);

    tmpTim = &timer2;
    /* 100Hz */
    tmpTim->TIM_Handle.Instance = TIM2;
    tmpTim->TIM_Handle.Init.Prescaler = 72 - 1;
    tmpTim->TIM_Handle.Init.Period = 10000;

    __HAL_RCC_TIM2_CLK_ENABLE();
    
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM2_IRQn);
    
    HAL_TIM_Base_Init(&tmpTim->TIM_Handle);
    HAL_TIM_Base_Start_IT(&tmpTim->TIM_Handle);

    return 0;
}

/**
 * \brief Set the PWM config and starts the PWM output.
 * \param handle Timer handle
 * \param channel the TIM Channel
 * \param duty the duty of PWM
 * \return status
*/
int TimerSetPulse(TimerDef *handle, uint32_t channel, float duty)
{
    int t = handle->TIM_Handle.Init.Period * duty;
    handle->TIM_OC_Handle.Pulse = t;
    handle->TIM_OC_Handle.OCMode = TIM_OCMODE_PWM1;
    
    HAL_TIM_PWM_ConfigChannel(&handle->TIM_Handle, &handle->TIM_OC_Handle, channel);
    HAL_TIM_PWM_Start(&handle->TIM_Handle, channel);
    return 0;
}
// timer.h
#ifndef __TIMER__H__
#define __TIMER__H__

#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f1xx_hal.h"

typedef struct TimerDef
{
    TIM_HandleTypeDef TIM_Handle;
    TIM_OC_InitTypeDef TIM_OC_Handle;

}TimerDef;

int TimerInit(void);
int TimerSetPulse(TimerDef *handle, uint32_t channel, float duty);

extern TimerDef timer1, timer2;

#ifdef __cplusplus
}
#endif

#endif

  1. 定时器2中断函数:因为上面开启了定时器2中断,所以需要自行实现中断函数。这里在中断函数里每次增加PWM的1%占空比,增加到100%后变为每次减小1%,减小到0后再增加,如此往复。
void TIM2_IRQHandler(void)
{
    static int duty = 0;
    static int inc = 1;
    
    /* HAL库通用定时器中断处理函数 */
    HAL_TIM_IRQHandler(&timer2.TIM_Handle);
    
    duty += inc;
    if((duty >= 100) || (duty <= 0))
    {   /* 当占空比到100或0时改变变化方向 */
        inc = -inc;
    }

    TimerSetPulse(&timer1, TIM_CHANNEL_1, duty / 100.0);
}

四、总结

??至此我们就实现了呼吸灯代码的编写,我们使用了TIM1产生PWM驱动LED,使用TIM2产生中断修改PWM的占空比,让LED的亮度发生变化。

在这里插入图片描述

??通过示波器可以直观的看到该PWM的占空比是时刻在变化的,本期代码可以在文后网址中下载。下期我们来聊聊串口的使用,扫一扫下方二维码关注我,我们下期再见。

在这里插入图片描述

STM32实战(二):用定时器实现呼吸灯

END

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:50:48  更:2022-10-17 12:52:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 16:34:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码