打印
[STM32F1]

STM32F103C8T6定时器产生PWM

[复制链接]
941|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
概述:
        这里我们来了解一下何为PWM,PWM是Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式。

        在实际项目应用中最常见的有 使用PWM驱动舵机转动到固定的角度 或是 通过PWM调节直流电机实得到想要的转速 ,还有我们常见大多设备上的呼吸灯。

        我们生产PWM有常见的两种的方法,分别是:(1)定时器中断变量累加比较、(2)定时器自身的3个寄存器通过通道输出PWM。

        这里我用常见的呼吸灯项目来为大家讲解如何用 定时器自身的3个寄存器通过通道输出PWM。

硬件介绍:
主控板采用的是:STM32F103C8T6

呼吸灯这里采用LED小灯珠,因为该主控芯片的IO输出电压只用3.3V,所以无需加装电阻;


使用特权

评论回复
沙发
为你转身|  楼主 | 2024-1-29 16:33 | 只看该作者
软件部分:
   1.寄存器:
         在编写软件前,我们先来了解一些重要的东西。在stm32f103c8t6中一共有4个定时器,其中TIM1为高级定时器。这里我使用是TIM4_CH2作为PWM比较输出通道;

使用特权

评论回复
板凳
为你转身|  楼主 | 2024-1-29 16:33 | 只看该作者
我们这里用到的6个寄存器分别为:
(1)TIMx_ARR:自动装载 寄存器

(2)TIMx_CNT:计数器 寄存器

(3)TIMx_PSC:预分频器 寄存器

(4)TIMX_CCR1~4:通道1~4 捕获/比较 寄存器

(5)TIMx_CCER: 捕获/比较使能寄存器(设置输出/输入模式)

(6)TIMx_CCMR1/2: 捕获/比较模式寄存器(设置输入/输出通道为1,2/3,4)

使用特权

评论回复
地板
为你转身|  楼主 | 2024-1-29 16:33 | 只看该作者
这些寄存器中有3个寄存器带有影子寄存器,他们分别是:      
(1)TIMx_PSC:由于该控制寄存器具有缓冲功能,因此可对预分频器进行实时更改。而新的预分频比将在下一更新事件发生时被采用。

(2)TIMx_ARR:预装载寄存器的内容既可以直接传送到影子寄存器,也可以在每次发生更新事件(UEV)时传送到影子寄存器,这取决于TIMx_CR1 寄存器中的自动重载预装载使能位(ARPE)。也就是TIMx_CR1的ARPE位决定了预装寄存器数据传入影子寄存器的时间先后顺序。

(3)TIMX_CCR1~4:通过软件将TIMx_CR1寄存器中的UDIS位置1可禁止更新事件UEV事件。这可避免向预装载寄存器写入新值时更新影子寄存器。也就是TIMx_CR1寄存器中UDIS位间接决定了预装寄存器数据是否传入影子寄存器。

使用特权

评论回复
5
为你转身|  楼主 | 2024-1-29 16:34 | 只看该作者
PWM信号产生过程:
        初始化时,我们先对 TIMx_ARR(自动装载 寄存器)、TIMx_PSC(预分频器 寄存器) 和 TIMX_CCR2(通道2 捕获/比较 寄存器)、TIMx_CCER(捕获/比较使能寄存器) 、TIMx_CCMR1 (捕获/比较模式寄存器)进行配置,然后对定时器进行使能。这时TIMx_CNT(计数器 寄存器)开始工作,TIMx_PSC(预分频器 寄存器)、 TIMx_ARR(自动装载 寄存器)和 TIMx_CCMR1 (捕获/比较模式寄存器)将 预装载的数值 拷贝到他们各自的 影子寄存器中,当计数值(CNT)大于或等于 TIMX_CCR2(通道2 捕获/比较 寄存器)中的比较数值时,IO口输出有效电平,当计数值(CNT)等于 TIMx_ARR 的 预装载数值时,计数值(CNT)被清0,产生更新事件(UVE);进入下一次定时器计数的次循环,产生的波形近似为正弦波,实现过程如下图所示:

使用特权

评论回复
6
为你转身|  楼主 | 2024-1-29 16:34 | 只看该作者
代码部分
PWM.C

#include "PWM.h"



void TIM4_PWM_Init(u16 arr,u16 psc)                        //初始化 定时器4_PWM
{
    //宏定义 配置
        GPIO_InitTypeDef TIM4_PWM_Pin;
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM4_OCInitStructure;
       
    //时钟配置
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);        //使能定时器4时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   //使能GPIO外设功能模块时钟
       
        //配置PWM输出IO口
        TIM4_PWM_Pin.GPIO_Mode = GPIO_Mode_AF_PP;                            //功能模式:复用推挽输出
        TIM4_PWM_Pin.GPIO_Pin = GPIO_Pin_7;                     //IO管脚号:7
        TIM4_PWM_Pin.GPIO_Speed = GPIO_Speed_50MHz;             //传输速度:50M
        GPIO_Init(GPIOB,&TIM4_PWM_Pin);
       
        //初始化TIM4
        TIM_TimeBaseStructure.TIM_Period = arr - 1; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
        TIM_TimeBaseStructure.TIM_Prescaler =psc - 1; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

        //初始化TIM4_CH2  PWM模式         
        TIM4_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
        TIM4_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        TIM4_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
        TIM_OC2Init(TIM4, &TIM4_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC2

        TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);  //使能TIM4在CCR2上的预装载寄存器
       
        TIM_Cmd(TIM4, ENABLE);  //使能TIM4
}

使用特权

评论回复
7
为你转身|  楼主 | 2024-1-29 16:34 | 只看该作者
  注意:这里我们使用定时器4 为 IO口输出PWM,该功能是 IO口的复用功能,所以我这里的IO口模式设置为了 复用推挽输出,但是这里我没有使用 重映射管脚,所以没有使能 端口映射功能时钟,如果你使用了重映射端口,就要使能该时钟。

使用特权

评论回复
8
为你转身|  楼主 | 2024-1-29 16:34 | 只看该作者
PWM.H
#ifndef __PWM_H
#define        __PWM_H

#include "stm32f10x.h"
#include "stm32f10x_tim.h"


void TIM4_PWM_Init(u16 arr,u16 psc);                        //初始化 定时器4_PWM

#endif

使用特权

评论回复
9
为你转身|  楼主 | 2024-1-29 16:35 | 只看该作者
main.c

#include "stm32f10x.h"
#include "PWM.h"

       
u8 dir=1;
u16 led0pwmval=0;




int main(void)
{
       
        SystemInit();                        // 配置系统时钟为72M        
        TIM4_PWM_Init(720,100);

        while(1)
        {

                delay_ms(10);         
                if(dir)led0pwmval++;
                else led0pwmval--;

                if(led0pwmval>300)dir=0;
                if(led0pwmval==0)dir=1;                                                                                 
                TIM_SetCompare2(TIM4,led0pwmval);
        }
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

681

帖子

0

粉丝