• 【STM32 定时器(二)TIM 输入捕获PWM 总结】


    OC介绍

    在这里插入图片描述

    PWM介绍

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    PWM参数计算
    在这里插入图片描述
    分辨率越细,分的分量越精细,越稳定,假如它为1%,则它可使得风扇以1为单位的等级调速。可以从1调到100档位,假如它为50%,那么只有两个档位。50和 100。

    计算 :如果我现在想要生成一个 PWM频率为1KHZ,占空比可以为任意,PWM分辨率为1%,则PSC(分频器系数),ARR(重装值)应改为多少呢?

    Reso分辨率=1%=1/100 ,又因为Reso=1/ARR+1 故而ARR=100-1=99。

    PWM频率=1k=1000 = CK_PSC / (PSC+1)* (ARR + 1)

    ``由于CK_PSC在上篇文章中已经介绍,为72MHz。 故而

    式子 CK_PSC / (PSC+1)* (ARR + 1)=PWM频率
    变为 72000000 / (PSC + 1) *(99 + 1)=1000,故而PSC=720 -1

    PWM初始化代码部分

    挨个配置 打通这条路即可
    在这里插入图片描述

    开启时钟配置

    	//通用定时器TIM2时钟开启
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	//开启GPIO的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	//内部时钟配置(方便)
    	TIM_InternalClockConfig(TIM2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    时基单元配置

    	//配置时基单元
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数的模式
    	TIM_TimeBaseInitStructure.TIM_Period=100 -1;//重装值ARR,根据上面公式计算
    	TIM_TimeBaseInitStructure.TIM_Prescaler=720 -1;//psc 根据上面公式计算
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    CCR配置

    	//配置CCR
    	TIM_OCInitTypeDef TIM_OCInitStructure;
    	TIM_OCStructInit(&TIM_OCInitStructure);//给所有成员变量先赋个初值
    	//下面单独修改通用定时器才用到的成员变量
    	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1 ;//PWM1模式,参考pptP68,PWM1模式和PWM2模式的区别
    	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//CNT
    	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
    	TIM_OCInitStructure.TIM_Pulse= 50;//设置CCR 即输出比较的值  这里随便给个测试,占空比50%
    	TIM_OC1Init(TIM2,& TIM_OCInitStructure);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    注意,上面用到了TIM_OCStructInit(&TIM_OCInitStructure);给所有成员变量赋值,这是为什么呢?
    原因如下:
    TIM_OCInitStructure.TIM_OCIdleState和TIM_OCInitStructure.TIM_OutputNState: Idle和里面含有N的一般都是高级定时器才用的
    我们用到的都是通用定时器,但TIM_OCInitStructure成员里面有我们用不到的,例如刚才的TIM_OCInitStructure.TIM_OCIdleState
    //那如果我们不给未用到的成员赋初值,那么后续就会有各种问题。
    //这里可以使用TIM_OCStructInit()函数给所有成员给个默认值,然后单独再修改通用定时器模块的成员变量的值。

    GPIO配置

    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//观察引脚图可知,引脚定义,ppt11页可知GPIO_PA0有引脚复用的CH1
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里解释下为何复用推挽,因为下图,来自片上外设一般使用复用功能输出
    在这里插入图片描述

    在这里插入图片描述

    复用和重定义功能

    引脚复用(Pin Multiplexing)是指单个物理引脚可以根据需要被不同的功能模块使用。在许多现代的微控制器中,物理引脚的功能并不是固定的,而是可以通过软件配置进行更改,这样可以使同一个引脚实现多种功能,这就是引脚复用。这种设计可以有效地节省物理引脚,提高了系统的灵活性。

    重定义功能(Alternate Function)则是指在引脚复用功能中,每个物理引脚可以被分配多种不同的功能,这些功能通常是由于同一个引脚在不同的模式下所承担的功能不同而产生的。例如,同一个物理引脚在GPIO模式下可以用作普通的数字输入/输出引脚,而在UART模式下可以用作串行通信的引脚。在这种情况下,这个物理引脚就具有了两种不同的重定义功能。

    在这里插入图片描述

    开启定时器

    最后一定要开启定时器

    TIM_Cmd(TIM2,ENABLE);//开启定时器
    
    • 1

    如何更改占空比的值? 即CCR
    使用TIM_SetCompare1函数即可

    代码实现 :实现呼吸灯

    PWM.c

    
    ```c
    #include "stm32f10x.h"                  // Device header
    /**
      * @brief   PWM初始化
      * @param   无
      * @retval  无
      */
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	//开启GPIO的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	//内部时钟配置
    	TIM_InternalClockConfig(TIM2);
    	//配置时基单元
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数的模式
    	TIM_TimeBaseInitStructure.TIM_Period=100 -1;//重装值ARR
    	TIM_TimeBaseInitStructure.TIM_Prescaler=7200 -1;//psc
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    	
    	//配置CCR
    	TIM_OCInitTypeDef TIM_OCInitStructure;
    	//TIM_OCInitStructure.TIM_OCIdleState和TIM_OCInitStructure.TIM_OutputNState:  Idle和里面含有N的一般都是高级定时器才用的
    	//我们用到的都是通用定时器,但TIM_OCInitStructure成员里面有我们用不到的,例如刚才的TIM_OCInitStructure.TIM_OCIdleState
    	//那如果我们不给未用到的成员赋初值,那么后续就会有各种问题。
    	//这里可以使用TIM_OCStructInit()函数给所有成员给个默认值,然后单独再修改通用定时器模块的成员变量的值。
    	TIM_OCStructInit(&TIM_OCInitStructure);//给所有成员变量先赋个初值
    	//下面单独修改通用定时器才用到的成员变量
    	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1 ;//PWM1模式,参考pptP68,PWM1模式和PWM2模式的区别
    	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//CNT
    	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
    	TIM_OCInitStructure.TIM_Pulse= 0;//设置CCR 即输出比较的值  这里随便给个测试,后面通过函数TIM_SetCompare1单独更改
    	TIM_OC1Init(TIM2,& TIM_OCInitStructure);
    	
    	//GPIO配置
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出,为何用复用推挽?因为ppt20页码,
    	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//观察引脚图可知,引脚定义,ppt11页可知GPIO_PA0有引脚复用的CH1
    	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	
    	TIM_Cmd(TIM2,ENABLE);//开启定时器
    	
    }
    /**
      * @brief   设置占空比 
      * @param   Compare:CCR,比较/捕获 占空比 
      * @retval  无
      */
    
    void PWM_SetCompare1(uint16_t Compare)
    {
    	TIM_SetCompare1(TIM2,Compare);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    main .c

    #include "stm32f10x.h"                  // Device header
    #include "OLED.h"  
    #include "PWM.h" 
    #include "Delay.h" 
    uint8_t i;
    int main()
    {
        OLED_Init();
    	PWM_Init();
    	while(1)
    	{
    		for(i=0;i<=100;i++)//逐渐变亮
    		{
    			PWM_SetCompare1(i);
    			Delay_ms(10);
    		}
    	    for(i=0;i<=100;i++)
    		{
    			PWM_SetCompare1(100-i);//逐渐变灭
    			Delay_ms(10);
    		}
    	}
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    数据结构-在堆中插入或删除新元素
    Android HIDL(2) ----接口和服务
    批量下载MODIS遥感影像:基于LAADS DAAC的方法
    构建一个商业智能 BI 分析平台,公司CIO应该重点关注什么?
    C#面:as 和 is 的区别
    minio报错should be less than or equal解决方案
    简单理解事件冒泡和事件捕获
    opencv [c++] 连通域分析connectedComponentsWithStats() 和 connectedComponents()
    Java中数组array和列表list相互转换
    单线程的JS中Vue导致的“线程安全”问题
  • 原文地址:https://blog.csdn.net/weixin_52924633/article/details/136789255