• STM32F105RBT6 使用定时器TIM3输出PWM波


    1. TIM3的GPIO口,查阅STM32F105RBT6 数据手册,TIM3的4通道用的是PB1

    在这里插入图片描述

    2. 初始化GPIO口和定时器TIM3

    2.1 相关函数

    RCC_APB1PeriphClockCmd、GPIO_Init、TIM_TimeBaseInit、TIM_OC4Init、TIM_OC4PreloadConfig、NVIC_Init、TIM_ITConfig、TIM_Cmd、

    void TIM3_Init(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct;
        TIM_TimeBaseInitTypeDef TIM_InitStruct;
        TIM_OCInitTypeDef TIM_OCInitStruct;
        NVIC_InitTypeDef NVIC_InitStruct;
    
        // Enable clock for TIM3 and GPIOB
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB2Periph_GPIOB, ENABLE);
    
        // Initialize GPIOB to output PWM signal
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStruct);
    
        // Initialize TIM3 for PWM generation with interrupt on update
          TIM_InitStruct.TIM_Prescaler = 0; // Set PWM frequency to 72MHz (72 MHz / (0 + 1))
        TIM_InitStruct.TIM_Period = 999;
        TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
    
        TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStruct.TIM_Pulse = 500; // Duty cycle = 50%
        TIM_OC4Init(TIM3, &TIM_OCInitStruct);
        TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
        NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
        NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 4;
        NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStruct);
    
        TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
        TIM_Cmd(TIM3, ENABLE);
    }
    
    • 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

    3. 中断入口 TIM3_IRQHandler

    3.1 在启动文件里面找到TIM3 对应的中断入口函数,也就是中断服务函数 TIM3_IRQHandler

    在这里插入图片描述

    4. 编写中断服务函数

    void TIM3_IRQHandler(void)
    {
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) // overflow interrupt
        {
            printf("龙傲天说,我三岁拳打南山不老院,四岁脚踢北海幼儿园\r\n");
        }
        TIM_ClearITPendingBit(TIM3,TIM_IT_Update); // clear interrupt flag
    
        // Handle interrupt by updating PWM duty cycle value
    //    static uint16_t duty_cycle = 500; // Initial value of 50%
    //    duty_cycle = duty_cycle < 950 ? duty_cycle + 50 : 0; // Increase duty cycle by 5% every period
    //    TIM_SetCompare4(TIM3, duty_cycle);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.1 中断服务函数需要快速地执行完毕。中断服务函数应该避免执行太多的计算复杂度较高的操作,否则可能会导致中断响应时间过长,甚至因为延迟而导致系统不稳定。

    4.2 如果你需要在中断服务函数中访问全局变量,需要将这些变量定义为volatile类型。这是因为中断服务函数可能会在任何时间被外部中断所打断,如果没有使用volatile类型,就有可能导致变量值不准确。

    4.3 在中断服务函数的结尾处,需要调用NVIC_ClearPendingIRQ()函数来清除中断挂起位。

    4.4 中断函数最好别用printf 函数等耗时、有可能阻塞的一些函数,printf函数本身就比较耗时,在中断服务函数中调用的话,可能会导致中断响应时间过长,使系统不稳定。如果在中断服务函数中使用了printf函数,可能会导致printf函数与被打断的低优先级代码发生冲突,造成数据异常。我这里用 printf 只是为了装13,我龙傲天谁都不服

    4.4 中断服务函数需要快速、简洁、有效地处理中断,并且需要小心地处理共享资源和全局变量。

    5. 主函数调用一下初始化函数就可以了

    int main(void)
    {
        TIM3_Init();
        while (1)
        {
        	printf("剑圣来了,快跑");
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.1 如果没有成功输出pwm波,可能是初始化时序不对,前面已经操作过该IO口了,我有很多的例程放在一起,搞混了,需要把原来的操作去掉,屏蔽掉,或者调整一下 TIM3_Init() 的位置,如果有很多别的初始化函数,就把TIM3_Init() 放到后面一点试试

    在这里插入图片描述

    6. 串口数据

    在这里插入图片描述

    7. 拿示波器或者逻分仪去量PB1 引脚,看波形,有毛刺,我没滤波的,可以处理掉

    在这里插入图片描述

    在这里插入图片描述

    8. PWM 波频率、周期计算

    8.1 频率 F = SYSCLK / ((TIM_Prescaler + 1) / (TIM_Period + 1))

    8.2 周期 T = 1 / F

    8.3 制造一个频率是1 Hz的PWM 波,周期 1s, 占空比50%,改下面三个参数值就行了

    	TIM_InitStruct.TIM_Prescaler = 7199;
       	TIM_InitStruct.TIM_Period = 10000;
        TIM_OCInitStruct.TIM_Pulse = 5000;  // 占空比50% = 5000 / (TIM_Period + 1)
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    9. TIM3的四个通道输出四路PWM,各个通道之间输出的PWM是独立的,频率,占空比可单独设置

    void TIM3_Init(void)
    {
       GPIO_InitTypeDef GPIO_InitStruct;
       TIM_TimeBaseInitTypeDef TIM_InitStruct;
       TIM_OCInitTypeDef TIM_OCInitStruct;
    
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
    
       GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
       GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
       GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
       GPIO_Init(GPIOA, &GPIO_InitStruct);
    
       GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
       GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
       GPIO_Init(GPIOC, &GPIO_InitStruct);
    
       GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
       GPIO_Init(GPIOA, &GPIO_InitStruct);
       /*
        * Initialize TIM3 for generation PWM
        * Set PWM frequency to 72kHz (72 MHz / (999 + 1) / (0 + 1)), TIM3_FRQ = SYSCLK / ((TIM_Period + 1) * (TIM_Prescaler + 1))
        * STM32F105RBT6_PB1 - TIM3_Ch4
        */
       TIM_InitStruct.TIM_Prescaler = 7199; // 0, 7199
       TIM_InitStruct.TIM_Period = 9999; // 999, 9999
       TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
       TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up;
       TIM_TimeBaseInit(TIM3, &TIM_InitStruct);
    
       TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
       TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
       TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
       TIM_OCInitStruct.TIM_Pulse = 5000; // 500,5000 Duty cycle = 50%
    
       TIM_OC1Init(TIM3, &TIM_OCInitStruct);
       TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
       TIM_OC2Init(TIM3, &TIM_OCInitStruct);
       TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    
       TIM_Cmd(TIM3, ENABLE);
    }
    
    • 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

    主函数调用,使能每个通道输出

    while (1) {
    		TIM_SetCompare1(TIM3, 5000);
            TIM_SetCompare2(TIM3, 5000);
            TIM_SetCompare4(TIM3, 5000);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

  • 相关阅读:
    【车载开发系列】汽车嵌入式开发常用工具介绍
    嵌入式(驱动开发)(中断处理)
    儿童剧本杀兴起,为少儿教育增色还是添乱?
    Vue 中为什么要有nextTick?
    训练神经网络解决二分类问题的原理
    进阶:Python序列的修改、散列和切片
    深入理解Linux网络技术内 幕(四)——通知链
    Java-Enum常量特定方法
    ngx_http_set_response_header阅读
    JSON数据格式
  • 原文地址:https://blog.csdn.net/weixin_50212044/article/details/131145925