6.4 输出比较演示**
演示1: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 TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct); //赋默认值
仅高级定时器使用,在使用高级定时器输出PWM时,需要调用这个函数,使能主动输出,否则pwm将不能正常输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
配置强制输出模式(了解)
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
用来配置CCR寄存器的预装功能的(了解)
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
用来配置快速使能(了解)
void TIM_OC1FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC2FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC3FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
void TIM_OC4FastConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCFast);
外部事件清除REF信号(了解)
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
在使用输出比较模式,配置定时器得触发极性
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
单独更改输出比较模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
单独更改输出使能参数
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
单独更改CCR寄存器值得函数(修改占空比)(掌握)
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
引脚重映射配置(掌握)
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
//参数说明:
/**
* @param GPIO_Remap: selects the pin to remap.
* @arg GPIO_PartialRemap1_TIM2 : TIM2 Partial1 Alternate Function mapping 部分重映射1
* @arg GPIO_PartialRemap2_TIM2 : TIM2 Partial2 Alternate Function mapping 部分重映射2
* @arg GPIO_FullRemap_TIM2 : TIM2 Full Alternate Function mapping 完全重映射
//如果使用这个参数,查引脚表可知,PB4就变成正常的GPIO口了
* @arg GPIO_Remap_SWJ_NoJTRST : Full SWJ Enabled (JTAG-DP + SW-DP) but without JTRST
//查表可知,PA15 PB3 PB4这三个端口变成正常的GPIO口了
* @arg GPIO_Remap_SWJ_JTAGDisable : JTAG-DP Disabled and SW-DP Enabled
//完全禁用调试接口(包括JTAG-DP和SW-DP)慎用慎用慎用
* @arg GPIO_Remap_SWJ_Disable : Full SWJ Disabled (JTAG-DP + SW-DP)
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWN_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);
}
}
}
pwm函数编写步骤:
1.把TIM外设与GPIO外设的时钟打开
2.配置时基单元
3.配置输出比较单元(CRR的值,输出比较模式,极性选择,输出使能)
4.配置GPIO,PWM对应的GPIO配置为复位推挽输出
5.运行控制,启动计数器
PWM.c
#include "stm32f10x.h" // Device header
void PWN_Init(void)
{
//1.把TIM外设与GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2); //选择内部时钟源TIM2
//PA0改到PA15(GPIO_InitStructure处也得进行修改Pin_0改为Pin_15)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //打开AFIO时钟
GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); //在定义表,PA15没给加粗,上电默认复用为调试端口JTDI,所以需要关闭调试端口
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); //查表可知,PA15 PB3 PB4这三个端口变成正常的GPIO口了
//4.配置GPIO,PWM对应的GPIO配置位复位推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
//对于普通的开漏推挽输出,引脚的控制权来自输出数据库,如果用定时器来控制引脚,需使用复用开漏,来自片上外设控制引脚,断开输出数据寄存器
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //修改了引脚复用,这里也得进行对应修改(0-15)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.配置时基单元
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才有)
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//3.配置输出比较单元(输出比较模式,极性选择,输出使能,设置CRR的值)
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //赋一个初始值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //PA0口对应OC1口(参考引脚定义表)
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
演示2:PWM驱动舵机
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"
uint8_t KeyNum;
float Angle;
int main(void)
{
OLED_Init();
Servo_Init();
Key_Init();
OLED_ShowString(1,1,"Angle:");
while (1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Angle += 30;
if(Angle > 180)
{
Angle = 0;
}
}
Servo_SetAngle(Angle);
OLED_ShowNum(1,7,Angle,3);
}
}
PWM函数:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.把TIM外设与GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2); //选择内部时钟源TIM2
//4.配置GPIO,PWM对应的GPIO配置位复位推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR自动重装值(总数)
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 -1; //PSC预分频的值(一周期计多少次)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值(高级TIM才有)
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//3.配置输出比较单元(输出比较模式,极性选择,输出使能,设置CRR的值)
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //赋一个初始值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC2Init(TIM2, &TIM_OCInitStructure); //PA0口对应OC1口(参考引脚定义表) 这里采用的是OC2通道2
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare2(uint16_t Compare)
{
TIM_SetCompare2(TIM2, Compare);
}
Servo函数:
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Servo_Init(void)
{
PWM_Init();
}
//设置舵机角度(y=kx+b)
void Servo_SetAngle(float Angle)
{
PWM_SetCompare2(Angle / 180 * 2000 + 500);
}
演示3:PWM驱动直流电机
主函数:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
uint8_t KeyNum;
int8_t Speed;
int main(void)
{
OLED_Init();
Motor_Init();
Key_Init();
OLED_ShowString(1,1,"Speed:");
while (1)
{
KeyNum = Key_GetNum();
if (KeyNum == 1)
{
Speed += 20;
if (Speed > 100)
{
Speed = -100;
}
}
Motor_SetSpeed(Speed);
OLED_ShowSignedNum(1,7,Speed,3);
}
}
PWM函数:
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
//1.把TIM外设与GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2); //选择内部时钟源TIM2
//4.配置GPIO,PWM对应的GPIO配置位复位推挽输出
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
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;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//2.配置时基单元
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 = 36 -1; //PSC预分频的值(一周期计多少次)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器的值(高级TIM才有)
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
//3.配置输出比较单元(输出比较模式,极性选择,输出使能,设置CRR的值)
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure); //赋一个初始值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //设置输出比较模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //设置极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //设置输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC3Init(TIM2, &TIM_OCInitStructure); //PA2口对应OC3口(参考引脚定义表)
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare3(uint16_t Compare)
{
TIM_SetCompare3(TIM2, Compare);
}
Motor函数:
#include "stm32f10x.h" // Device header
#include "PWM.H"
//初始化电机控制引脚
void Motor_Init(void)
{
//step1:使用RCC开启GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//step2:使用GPIO_Init函数初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //(Out_PP:Out Push Pull)推挽输出(高低电平都是有驱动能力)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
void Motor_SetSpeed(int8_t Speed)
{
if (Speed >= 0)
{
//配置引脚电平和CCR的值
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare3(Speed);
}
else
{
GPIO_SetBits(GPIOA, GPIO_Pin_5);
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
PWM_SetCompare3(-Speed);
}
}