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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> [学习笔记]STM32F1通用定时器-PWM(寄存器、标准库、HAL库) -> 正文阅读

[嵌入式][学习笔记]STM32F1通用定时器-PWM(寄存器、标准库、HAL库)

目录

11. 通用定时器-PWM

1. 实验内容及步骤:

2. 硬件说明

3. 步骤详细讲解

3.1定时器配置

3.2定时器输出PWM配置

4. 程序设计(寄存器)

5. 程序设计(标准库)

6. 程序设计(HAL库)

7. 实验结果

8. 源码下载


?

11. 通用定时器-PWM

1. 实验内容及步骤:

?????? 1. 通过定时器2,经过分频和重装载值生成50Hz=20ms的周期的中断,并且在50次中断后(即1s),让LED反转。

?????? 2. 通过定时器2通道1(PA0)的PWM输出,实现LED呼吸灯。

2. 硬件说明

本电路的硬件如下图所示,LED灯与GPIOB5相连,低电平亮,高电平灭。

?

3. 步骤详细讲解

3.1定时器配置

?????? 1. 时钟的选择,选择内部时钟源;

?????? 2. 计数模式的选择,选择向上计数;

?????? 3. 定时器分频选择,内部时钟源=2*APB1=72M,分频720得到定时器的时钟100KHz

?????? 4. 自动重装载:配置为2000,即100KHz/2000=50Hz=20ms(周期);

?????? 5. 中断源配置:配置只有上下溢出中断,使能中断。

????? 1. 时钟选择

?????? 内部时钟源:

?????? TIMx_SMCR寄存器中的SMS[2:0]=000, 关闭从模式

?????? 本实验中使用内部时钟:

????????????? TIMx_SMCR &= ~((u32)0x07<<0);??? //关闭从模式

?????? TIMx_CR1寄存器的CEN(第0位),决定定时器的使能/禁止。

?????? 内部时钟源(CK_INT)??? CEN位被写成’1’。

?????? 本实验中:

????????????? TIMx_CR1 |= ((u32)0x01<<0);??? //使能计数器

??????

????? 2. 计数方向选择

?????? TIMx_CR1的CMS[1:0]=00, 边沿对齐模式。计数器依据方向位(DIR)向上或向下计数。

?????? TIMx_CR1的DIR位,决定了定时器的计数方向。

?????? 本实验中配置位向上计数模式:

????????????? TIMx_CR1 &= ~((u32)0x03<<5);???? // 边沿对齐模式

????????????? TIMx_CR1 &= ~((u32)0x01<<4); ?????? //向上计数模式

????? 3. 定时器时钟分频

?????? 定时器时钟为CK_CNT=F(CK_PSC)/(PSC[15:0]+1)。

?????? 本实验中:

????????????? 已知定时器2的时钟源F(CK_PSC)=2*APB1(72MHz)

????????????? 分频值720-1,定时器时钟CK_CNT=72M/(720-1+1)=100KHz

????? 4. 自动重装在值

?????? 本实验中:

?????? ?????? 自动重装载值为2000,则定时器中断周期为:100KHz/2000=50Hz=20ms。

????? 5. 更新中断使能

?????? 配置只有上下溢出中断,由TIMx_CR1寄存器中的USR(第二位)决定。

?????? TIMx_CR1 |= ((u32)0x01<<2);??? ??? //只有上下溢出才中断

?????? 更新中断使能在TIMx_DIER寄存器中的UIE(第0位)。

?????? 本实验中:

????????????? TIMx_DIER |= (u32)0x01<<0;???? //使能中断

?????? NVIC中断优先级配置和使能;

?????? SET_NVIC_IP(TIM2_IRQn,14); ?????????//NVIC中断使能(这个是自己写的函数)

?????? 此时配置定时器2中断优先级为14,使能NVIC TIM2中断管理器。

????? 6. 中断函数

?????? 在中断函数中,通过判断TIMx_SR状态寄存器中的UIF(第0位)来确定是否为更新中断。

?????? 为1,则表示为更新中断,需要软件清除。

?????? 中断函数如下所示:

????????????? 进入中断50次后(即1S),LED灯反转。

3.2定时器输出PWM配置

????? PWM配置步骤:

?????? 1. PWM的GPIO配置;

?????? 2. TIM2配置;

?????? 3. PWM占空比设置;

?????? 4. 配置有效电平极性;

?????? 5. 配置PWM的模式;

?????? 6. 配置相应的预装载寄存器缓冲;

?????? 7. PWM输出使能;

????? 1. PWM的GPIO配置

?????? TIM2的比较通道1(PA0)应该配置为推挽复用输出。

?????? 本函数自己写的:

?????? GPIOX_PIN_SetMode(GPIOA,0,GPIOx_AF_PP|GPIOx_OUT_10M);?? //PA0 复用推挽输出

????? 2. TIM2配置

?????? 如3.1 定时器配置一致。

?????? 本实验中配置TIM2的时钟为:72M/720=100KHz(定时器时钟)100K/2000=50Hz=20ms(周期)

????? 3.PWM占空比设置

?????? PWM占空比由TIMx_CCRx寄存器进行配置,寄存器的说明如下所示:

?????? 本实验中配置初始占空比为50%,即:

????????????? TIMx_CCRx= 1000;??????? ??//占空比50%

????? 4. 配置有效电平极性

?????? OCx的极性即比较后有效结果时,输出的电平。其寄存器说明如下所示:

?????? TIMx_CCER寄存器中的CC1P位(位1),决定有效电平是高电平还是低电平。

?????? 本实验中配置为高电平有效:

?????? TIMx_CCER &= ~(0x01<<1);?? //OC1高电平有效

????? 5. 配置PWM的模式

?????? 在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2)。TIMx_CCMRx寄存器中的OCxM位如下所示:

?????? 在TIMx_CCMRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2)

????????????? 向上计数配置:

????????????? PWM模式1:当TIMx_CNT<TIMx_CCRx时PWM信号参考OCxREF为高;

????????????? 向下计数的配置:

????????????? 当TIMx_CNT>TIMx_CCRx时参考信号OCxREF为低;

?????? 本实验中使用PWM模式,使用PWM模式1:

?????? TIMx_CCMRx &= ~(0x07<<4);? //清空输出比较1模式

TIMx_CCMRx |= 0x06<<4;???? //模式1

????? 6. 配置相应的预装载寄存器

这一步骤是配置其作用主要为:写比较寄存器后,是否需要缓冲。有缓冲的话,更新事件到来才更新到相应的寄存器;没有的话就直接更新到相应的寄存器。有没有问题都不是很大。

?????? 本实验中开启预装载使能:

?????? TIMx_CCMR1 |= 0x01<<3;???? //输出比较1预装载使能

????? 7.PWM输出使能

?????? TIMx_CCER寄存器中的CCxE位控制OCx输出使能。OCx位如下图所示:

?????? 使用PWM需要使能输出:

?????? TIMx_CCER |= (0x01<<0);?? //开启输出

????? 8.呼吸灯实现

?????? 没10ms进行PWM的值增加10或减小10,实现呼吸灯的效果。

4. 程序设计(寄存器)

?????? 定时器中断见源码,这里通过TIM2-PWM实现LED成呼吸灯

?????? 配置步骤:

?????? 1. GPIO时钟使能,TIM时钟使能;

?????? 2. 配置PWM输出的GPIO为:推挽输出;

?????? 3. 配置定时器TIM2的分频,预装载值,上下计数模式,定时器使能;

?????? 4. 中断管理器NVIC使能,优先级配置(如果需要中断的话);

?????? 5. 配置PWM占空比,模式,有效极性,比较使能;

?????? 6. 编写PWM修改函数。

?????? 源码:这里只列出配置TIM2-PWM部分

//初始化定时器2
//APB1 = 72MHz
void TIM2_Config(u16 psc,u16 arr)
{
    //时钟
    RCC->APB1ENR    |=  RCC_APB1ENR_TIM2EN;
    
    //时钟选择(内部时钟源)
	TIM2->SMCR &= ~((u32)0x07<<0);	    //关闭从模式
    //计数方向选择
    TIM2->CR1 &= ~((u32)0x03<<5);	    // 边沿对齐模式
	TIM2->CR1 &= ~((u32)0x01<<4);		//向上计数模式		
    //预分频
    TIM2->PSC = psc;                    //分频
    //重装载值
    TIM2->ARR = arr;                    //重装在值
    //清空计数器
    TIM2->CNT = 0;                      //清空当前计数器
    //使能中断
    TIM2->CR1 |= ((u32)0x01<<2);	    //只有上下溢出才中断
    TIM2->DIER |= (u32)0x01<<0;         //允许更新中断
    SET_NVIC_IP(TIM2_IRQn,14);          //NVIC中断使能
    //使能定时器
    TIM2->CR1 |= ((u32)0x01<<0);	    //使能计数器
    
}

/*
    TIM2_PWM_配置
*/
void TIM2_PWM_Config(void)
{
    //GPIO初始化
    GPIOX_PIN_SetMode(GPIOA,0,GPIOx_AF_PP|GPIOx_OUT_10M);   //PA0 复用推挽输出 
    //TIM2初始化
    TIM2_Config(720-1,2000-1);  // 72M/720=100KHz    100K/2000=50Hz=20ms(周期)
    //比较寄存器
    TIM2->CCR1 = 1000;          //占空比50%
    //输出比较1模式(模式1)
    TIM2->CCMR1 &= ~(0x07<<4);  //清空输出比较1模式
    TIM2->CCMR1 |= 0x06<<4;     //模式1
    //输出比较1预装载使能
    TIM2->CCMR1 |= 0x01<<3;     //输出比较1预装载使能
    //比较1输出极性
    TIM2->CCER &= ~(0x01<<1);   //OC1高电平有效
    //使能比较1输出
    TIM2->CCER |= (0x01<<0);   //开启
    
}

/*
    设置比较输出1的PWM
*/
void Set_TIM2_PWM_CH1(u16 pwm)
{
    TIM2->CCR1  =   pwm;
}


void TIM2_IRQHandler(void)
{
    static u16 i=0;
    if(TIM2->SR&0x01)   //判断更新中断
    {
      i++;
        if(i>=50-1) //50次  1S
        {
            i=0;
            //BPB_OUT(5) = !BPB_OUT(5);
            printf("1S计时\r\n");
        }
    }
    TIM2->SR &= ~((u32)0x01<<0);    //清除中断标志位
}

5. 程序设计(标准库)

?????? 配置步骤:

?????? 1. GPIO时钟使能,TIM时钟使能;

?????? 2. 配置PWM输出的GPIO为:推挽输出。通过GPIO_InitTypeDef结构体配置;

?????? 3. 配置定时器TIM2的分频,预装载值,上下计数模式。通过TIM_TimeBaseInitTypeDef结构体配置;

?????? 4. 中断管理器NVIC使能,优先级配置(如果需要中断的话)。通过NVIC_InitTypeDef结构体进行配置;

?????? 5. 配置PWM占空比,模式,有效极性,比较使能。通过TIM_OCInitTypeDef结构体配置;

?????? 6. 定时器使能函数,使用:TIM_Cmd函数使能;

?????? 7. PWM修改函数为:TIM_SetCompare1函数。

?????? 源码:这里只列出配置TIM2-PWM部分

#define TIM_x               TIM2
#define TIM_NVIC_IRQ       TIM2_IRQn
#define TIM_NVIC_PP        13
#define TIM_NVIC_SP        0

#define PWM_GPIOX           GPIOA
#define PWM_GPIOX_PIN       GPIO_Pin_0    
#define PWM_GPIOX_MODE      GPIO_Mode_AF_PP     //复用推挽
//初始化定时器2
//APB1 = 72MHz
void TIM2_Config(u16 psc,u16 arr)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    NVIC_InitTypeDef  NVIC_InitStruct;
    //时钟
    RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM2EN,ENABLE);    //TIM2定时器
    //定时器基本配置   
    TIM_TimeBaseInitStruct.TIM_Prescaler    =   psc;      //分频  
    TIM_TimeBaseInitStruct.TIM_CounterMode  =   TIM_CounterMode_Up; //向上计数
    TIM_TimeBaseInitStruct.TIM_Period    =   arr;       //从装在值
    TIM_TimeBaseInit(TIM_x,&TIM_TimeBaseInitStruct);
    //中断配置
    TIM_ITConfig(TIM_x,TIM_IT_Update,ENABLE);
    //优先级配置
    NVIC_InitStruct.NVIC_IRQChannel     =   TIM_NVIC_IRQ;
    NVIC_InitStruct.NVIC_IRQChannelCmd  =   ENABLE;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority   =   TIM_NVIC_PP;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority  =   TIM_NVIC_SP;
    NVIC_Init(&NVIC_InitStruct);    //设置中断优先级    
    //定时器使能
    TIM_Cmd(TIM_x,ENABLE);    
}

/*
    TIM2_PWM_配置
*/
void TIM2_PWM_Config(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    TIM_OCInitTypeDef  TIM_OCInitStruct;
    //GPIO初始化
    GPIO_InitStruct.GPIO_Mode   =   PWM_GPIOX_MODE;
    GPIO_InitStruct.GPIO_Pin    =   PWM_GPIOX_PIN;
    GPIO_InitStruct.GPIO_Speed  =   GPIO_Speed_10MHz;
    GPIO_Init(PWM_GPIOX, &GPIO_InitStruct);     //复用推挽输出 
    //TIM2初始化
    TIM2_Config(720-1,2000-1);  // 72M/720=100KHz    100K/2000=50Hz=20ms(周期)
    //通道配置
    TIM_OCInitStruct.TIM_OCMode =   TIM_OCMode_PWM1;    //PWM1模式
    TIM_OCInitStruct.TIM_OutputState    =   TIM_OutputState_Enable; //比较使出使能
    TIM_OCInitStruct.TIM_OCPolarity     =   TIM_OCPolarity_High;    //有效电平 高电平
    TIM_OCInitStruct.TIM_Pulse      =   1000;           //占空比50%
    TIM_OC1Init(TIM_x, &TIM_OCInitStruct);
    
}


//中断函数
void TIM2_IRQHandler(void)
{
    static u16 i=0;
    if(TIM_GetITStatus(TIM_x,TIM_IT_Update))   //判断更新中断
    {
      i++;
        if(i>=50-1) //50次  1S
        {
            i=0;
            //BPB_OUT(5) = !BPB_OUT(5);
            printf("1S计时\r\n");
        }
    }
    TIM_ClearITPendingBit(TIM_x,TIM_IT_Update);    //清除中断标志位
}

6. 程序设计(HAL库)

?????? HAL库与标准库的定时器区别主要在:HAL库进行高度封装,使用相对简便,很多判断标志位和清除标志位都由HAL库完成了。

?????? 总结出HAL库的操作:初始化+使能。

?????? 配置步骤:

?????? 1. GPIO时钟使能,TIM时钟使能;

?????? 2. 通过HAL_TIM_Base_Init函数初始化定时器操作;

?????? 3. 通过HAL_TIM_Base_Start_IT函数使能定时器,并使能中断;

?????? 4. 通过HAL_NVIC_SetPriority、HAL_NVIC_EnableIRQ使能NVIC中断管理和优先级;

?????? 5. 通过HAL_TIM_OC_ConfigChannel初始化PWM配置;

?????? 6. 通过HAL_TIM_OC_Start使能PWM;

?????? 7. 可在HAL_TIM_Base_MspInit回调函数中初始化GPIO;

?????? 8. 在中断中调用HAL_TIM_IRQHandler中断处理函数(其具有标志位判断和清除功能,能够降低开发难度);

?????? 9. 在更新回调函数(HAL_TIM_PeriodElapsedCallback)中编写更新中断内容;

?????? 源码:这里只列出配置TIM2-PWM部分

#include "My_GP_TIM.h"
#include "stdio.h"
#include "My_exti.h"
#include "My_bit.h"
#include "My_gpio.h"
//TIM2
TIM_HandleTypeDef TIM2_HandleStruct;

#define TIM_x              TIM2
#define TIM_NVIC_IRQ       TIM2_IRQn
#define TIM_NVIC_PP        13
#define TIM_NVIC_SP        0

#define PWM_GPIOX           GPIOA
#define PWM_GPIOX_PIN       GPIO_PIN_0    
#define PWM_GPIOX_MODE      GPIO_MODE_AF_PP     //复用推挽
//初始化定时器2
//APB1 = 72MHz
void TIM2_Config(u16 psc,u16 arr)
{
    //时钟
    __HAL_RCC_TIM2_CLK_ENABLE();    //TIM2定时器
    //定时器基本配置  
    TIM2_HandleStruct.Instance   =   TIM_x;
    TIM2_HandleStruct.Init.Prescaler =   psc;    //分频
    TIM2_HandleStruct.Init.CounterMode   =   TIM_COUNTERMODE_UP; //向上计数
    TIM2_HandleStruct.Init.Period    =   arr;    //从装在值
    TIM2_HandleStruct.Channel    =   HAL_TIM_ACTIVE_CHANNEL_1;   //通道1
    HAL_TIM_Base_Init(&TIM2_HandleStruct);
    //中断配置
    HAL_TIM_Base_Start_IT(&TIM2_HandleStruct);
    //优先级配置
    HAL_NVIC_SetPriority(TIM_NVIC_IRQ,13,0);    //响应优先级为13 最低   
    HAL_NVIC_EnableIRQ(TIM_NVIC_IRQ);           //使能中断线    
 
}

/*
    TIM2_PWM_配置
*/
void TIM2_PWM_Config(void)
{
    GPIO_InitTypeDef GPIO_Init;
    TIM_OC_InitTypeDef TIM_OC_InitStruct;
    //时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //GPIO初始化
    GPIO_Init.Mode  =   PWM_GPIOX_MODE;
    GPIO_Init.Pin   =   PWM_GPIOX_PIN;
    GPIO_Init.Speed =   GPIO_SPEED_FREQ_MEDIUM;
    HAL_GPIO_Init(PWM_GPIOX,&GPIO_Init);   //复用推挽输出 
    //TIM2初始化
    TIM2_Config(720-1,2000-1);  // 72M/720=100KHz    100K/2000=50Hz=20ms(周期)
    //通道配置
    TIM_OC_InitStruct.OCMode    =   TIM_OCMODE_PWM1;        //PWM1模式
    TIM_OC_InitStruct.OCPolarity    =   TIM_OCPOLARITY_HIGH;    //有效电平 高电平
    TIM_OC_InitStruct.OCIdleState   =   TIM_OCIDLESTATE_SET;    //比较使出使能
    TIM_OC_InitStruct.Pulse =   1000;   //占空比50%
    HAL_TIM_OC_ConfigChannel(&TIM2_HandleStruct,&TIM_OC_InitStruct,TIM_CHANNEL_1);
    HAL_TIM_OC_Start(&TIM2_HandleStruct,TIM_CHANNEL_1);
}


//中断函数
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM2_HandleStruct);
}

//更新事件回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static u16 i=0;
    i++;
    if(i>=50-1) //50次  1S
    {
        i=0;
        //BPB_OUT(5) = !BPB_OUT(5);
        printf("1S计时\r\n");
    }    
}

7. 实验结果

?????? 1. 每隔1S,定时器中断中会输出“1S计时”;

?????? 2. PWM呼吸灯实验,LED灯会呈现呼吸效果;

8. 源码下载

????????源码下载

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:21:57  更:2021-07-15 16:23:54 
 
开发: 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/6 19:40:17-

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