文章目录

  • 前言
  • 一、介绍部分
  • 输出比较简介
  • PWM简介
  • 通用输出比较通道
  • 输出比较模式
  • PWM基本结构
  • 公式
  • 外设介绍
  • 舵机简介
  • 硬件电路
  • 直流电机简介
  • 硬件电路
  • 引脚及定义
  • 二、实例部分
  • PWM驱动呼吸灯
  • 连接电路
  • 配置PWM以及定时器
  • PWM驱动舵机
  • 连接线路
  • 代码实现
  • PWM驱动直流电机
  • 连接电路
  • 代码实现
  • 重点
  • PWM公式
  • 直流电机引脚定义以及正反转原理
  • 相关函数
  • 根据手册了解不同计数器所含引脚的重映射范围

  • 前言

    这部分主要了解定时器的输出比较,了解计数器与捕获比较寄存器的关系,了解PWM原理并使用PWM驱动直流电机、舵机。


    一、介绍部分

    输出比较简介


    对应这部分

    PWM简介

    通用输出比较通道

    输出比较模式

    PWM基本结构

    公式

    外设介绍

    舵机简介

    硬件电路

    直流电机简介

    硬件电路

    引脚及定义

    二、实例部分

    PWM驱动呼吸灯

    连接电路

    配置PWM以及定时器

    使用了重映射,将原本的PA0端口映射到了PB3端口,相关功能表如下

    PWM.c如下:

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void){
    	// 初始化时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    	
    	// 引脚重映射配置(部分重映射),PA1映射到PB3
    	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
    	// 解除JTA调试功能,使这些端口变为普通IO口
    	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
    	
    	// 配置LED所在端口
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 服用推挽输出
    	// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;	
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;	
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    	
    	// 使用内部时钟(默认)
    	TIM_InternalClockConfig(TIM2);
    	// 配置事间基础(时基单元)
    	TIM_TimeBaseInitTypeDef TIM_InitStructure;
    	// 时钟分频
    	TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	// 计算模式
    	TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	// 重载值(有1的偏差)<计数值> ARR
    	TIM_InitStructure.TIM_Period = 100-1;
    	// 预分频(有1的偏差)<频率> PSC
    	TIM_InitStructure.TIM_Prescaler = 720-1;
    	// 重复计数器(不使用)
    	TIM_InitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
    	
    	//初始化输出比较
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	//TIM_OCInitStruct.TIM_OCIdleState = ;
    	//TIM_OCInitStruct.TIM_OCNIdleState = ;
    	//TIM_OCInitStruct.TIM_OCNPolarity = ;
    	//TIM_OCInitStruct.TIM_OutputNState = ;
    	// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
    	TIM_OCStructInit(&TIM_OCInitStruct);
    	// PWM1模式
    	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    	// PWM高电平时有效
    	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    	// 输出使能
    	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    	// CCR,用于控制占空比的值
    	TIM_OCInitStruct.TIM_Pulse = 10;
    	TIM_OC2Init(TIM2,&TIM_OCInitStruct);
    	
    	// 启动定时器
    	TIM_Cmd(TIM2,ENABLE);
    
    }
    
    // 修改占空比
    void PWM_SetCCR(uint16_t Compare){
    	TIM_SetCompare2(TIM2,Compare);
    
    }
    
    

    主函数main.c如下:

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "PWM.h"
    
    uint8_t i;
    int main(void)
    {
    	OLED_Init();
    	PWM_Init();
    	OLED_ShowString(1,3,"better");
    	while (1)
    	{
    		for(i=0;i<100;i++){
    			PWM_SetCCR(i);
    			Delay_ms(50);
    		}
    		for(i=100;i>0;i--){
    			PWM_SetCCR(i);
    			Delay_ms(50);
    		}
    	}
    }
    
    

    PWM驱动舵机

    连接线路

    代码实现

    和呼吸灯基本一致,只需要对角度部分设计好适合的分频(PSC)、重载值(ARP)、与PWM比较值(CCR),由于舵机需要的周期为20ms,所以PWM频率应为1/0.002=50Hz(注意单位),然后50 = 7200000 / PSC / ARP,这里设置PSC = 72,所以ARP = 1000000/50 = 20000,舵机的可变输入信号范围为0.5ms~2.5ms,也就是(500 ~ 2500)us,所以CCR的范围设置在500 ~ 2500之间,然后与角度计算

    PWM.c内容如下:

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void){
    	// 初始化时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    	
    	
    	// 配置LED所在端口
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 服用推挽输出
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;	
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    	
    	// 使用内部时钟(默认)
    	TIM_InternalClockConfig(TIM2);
    	// 配置事间基础(时基单元)
    	TIM_TimeBaseInitTypeDef TIM_InitStructure;
    	// 时钟分频
    	TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	// 计算模式
    	TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	// 重载值(有1的偏差)<计数值> ARR
    	TIM_InitStructure.TIM_Period = 20000-1;
    	// 预分频(有1的偏差)<频率> PSC
    	TIM_InitStructure.TIM_Prescaler = 72-1;
    	// 重复计数器(不使用)
    	TIM_InitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
    	
    	//初始化输出比较
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	//TIM_OCInitStruct.TIM_OCIdleState = ;
    	//TIM_OCInitStruct.TIM_OCNIdleState = ;
    	//TIM_OCInitStruct.TIM_OCNPolarity = ;
    	//TIM_OCInitStruct.TIM_OutputNState = ;
    	// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
    	TIM_OCStructInit(&TIM_OCInitStruct);
    	// PWM1模式
    	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    	// PWM高电平时有效
    	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    	// 输出使能
    	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    	// CCR,用于控制占空比的值
    	TIM_OCInitStruct.TIM_Pulse = 0;
    	TIM_OC2Init(TIM2,&TIM_OCInitStruct);
    	
    	// 启动定时器
    	TIM_Cmd(TIM2,ENABLE);
    
    }
    
    // 设置比较值
    void PWM_SetCCR(uint16_t Compare){
    	TIM_SetCompare2(TIM2,Compare);
    
    }
    
    

    角度转换放在Servo.c

    #include "stm32f10x.h"                  // Device header
    #include "PWM.h"
    
    // 初始化
    void Servo_Init(void){
    	PWM_Init();
    }
    
    // 角度与CCR的数值转换
    void Servo_Set(float Angle){
    	PWM_SetCCR(Angle/180*2000+500);
    }
    
    

    main.c内容如下:

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "Servo.h"
    #include "Button.h"
    
    uint8_t KeyNum;
    float Angle;
    int main(void)
    {
    	OLED_Init();
    	Servo_Init();
    	Button_Init();
    	OLED_ShowString(1,1,"Angle");
    	Servo_Set(90);
    	while (1)
    	{
    		KeyNum = Key_Num();
    		if(KeyNum == 1){
    			Angle += 30;
    			if(Angle >= 180){
    				Angle = 0;
    			}
    			Servo_Set(Angle);
    		}
    		OLED_ShowNum(1,8,Angle,3);
    	}
    }
    
    

    PWM驱动直流电机

    连接电路

    连接USB的5v电压才能驱动直流电机,驱动电源4.5V ~ 10V

    代码实现

    改变了定时器中断频率,不影响占空比的情况下,提高频率使直流电机产生的杂音无法被人耳听见。

    修改PWM.c如下:

    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void){
    	// 初始化时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    	
    	
    	// 配置PWM所在端口
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;		// 服用推挽输出
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    	
    	// 使用内部时钟(默认)
    	TIM_InternalClockConfig(TIM2);
    	// 配置事间基础(时基单元)
    	TIM_TimeBaseInitTypeDef TIM_InitStructure;
    	// 时钟分频
    	TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	// 计算模式
    	TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	// 重载值(有1的偏差)<计数值> ARR
    	TIM_InitStructure.TIM_Period = 100-1;
    	// 预分频(有1的偏差)<频率> PSC
    	TIM_InitStructure.TIM_Prescaler = 36-1;
    	// 重复计数器(不使用)
    	TIM_InitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM2,&TIM_InitStructure);
    	
    	//初始化输出比较
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题
    	TIM_OCStructInit(&TIM_OCInitStruct);
    	// PWM1模式
    	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
    	// PWM高电平时有效
    	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
    	// 输出使能
    	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
    	// CCR,用于控制占空比的值
    	TIM_OCInitStruct.TIM_Pulse = 0;
    	TIM_OC3Init(TIM2,&TIM_OCInitStruct);
    	
    	// 启动定时器
    	TIM_Cmd(TIM2,ENABLE);
    
    }
    
    
    void PWM_SetCCR(uint16_t Compare){
    	TIM_SetCompare3(TIM2,Compare);
    
    }
    
    

    电机驱动函数Motor.c

    #include "stm32f10x.h"                  // Device header
    #include "PWM.h"
    
    void Motor_Init(void){
    	// 控制方向的引脚
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;	
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		// 50Hz翻转速度
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	PWM_Init();
    }
    
    void Motor_SetSpeed(int16_t Speed){
    	// 正转
    	if(Speed>=0){
    		GPIO_SetBits(GPIOA,GPIO_Pin_4);
    		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
    		PWM_SetCCR(Speed);
    	}
    	// 反转
    	else{
    		GPIO_SetBits(GPIOA,GPIO_Pin_5);
    		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
    		PWM_SetCCR(-Speed);
    	}
    }
    
    

    主函数main.c内容:

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "Motor.h"
    #include "Button.h"
    
    
    uint8_t KeyNum;
    int16_t Speed;
    
    int main(void)
    {
    	OLED_Init();
    	Motor_Init();
    	Button_Init();
    	
    	OLED_ShowString(1,1,"Speed");
    	while (1)
    	{
    		KeyNum = Key_Num();
    		if(KeyNum == 1){
    			Speed += 20;
    			if(Speed > 100){
    				Speed = -100;
    			}
    			Motor_SetSpeed(Speed);
    		}
    		OLED_ShowSignedNum(1,8,Speed,3);
    	}
    }
    
    

    重点

    PWM公式

    直流电机引脚定义以及正反转原理

    相关函数

    // 初始化输出比较
    void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
    // 重映射,解除端口的调试功能
    void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
    
    

    根据手册了解不同计数器所含引脚的重映射范围

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32定时器2使用教程

    发表回复