STM32学习笔记6-TIM-2输出比较功能
第二部分,定时器的输出比较功能
OC(Output Compare)输出比较
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
每个高级定时器和通用定时器都拥有4个输出比较通道
高级定时器的前3个通道额外拥有死区生成和互补输出的功能
IC:输入捕获、CC:表示输入捕获和输出比较的单元、CCR:捕获比较寄存器
CCR是输入捕获和输出捕获比较共用的,会根据输出和输入比较的情况,转换对于寄存器功能;在输出比较中,电路会比较CNT和CCR的值,CNT自增,当CNT大于CCR、等于CCR和小于CCR时,会输出对于的置0或1,从而输出一个电平不断跳变的PWN波形;共用一个CNT计数器
PWM(Pulse Width Modulation)脉冲宽度调制
最常见的用途是产生PWM波形,用于驱动电机等设备
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域,是数字信号
PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
Ts图下:代表一个高低电平变换周期的时间
Ton:高电平的时间、Toff 同理
频率越快,等效模拟的信号就越平稳,性能的开销就大
在今天的实验中我们实现的LED呼吸灯中,正常来说数字信号只有0和1,所以只会实现亮和灭的情况,但是通过PWM波形用数字信号来输出一段模拟信号就可以实现呼吸灯:让LED灯不断点亮、熄灭、点亮、熄灭,当点亮和熄灭的频率足够大时,LED就不会闪烁了,而是呈现出一个中等亮度,这时进行调控点亮和熄灭的时间比例,就能呈现出不同亮度;(唯快不破)
输出比较通道(通用)
整体电路所在的方位
CCR与CNT比较,输出数字信号(0和1),输出控制器会改变它输出OC1PRE的高低电平;REF信号可以进入主模式控制器,这样可以将REF映射到TRGO输出上去;主要是走下一路,达到极性选择,通过极性选择到输出使能电路,选择要不要输出,输出至OC1引脚(引脚对应表)
极性选择 :给这个寄存器写0,信号就会往上走,信号电平不翻转;写1,信号会往下走,信号会通过一个非门取反,此时输出的信号就是输入信号高低电平反转的信号
REF信号:实际就是指这里信号的高低电平——参考信号
输出比较的8种模式
输出控制器里的执行逻辑,灵活地控制REF的输出;通过一个寄存器来进行配置
作用:
冻结:在输出PWM波形时,想要进行停止,就可以设置此,此时就暂停了输出,并且高低电平也维持在暂停时的样子
匹配时置无效电平&匹配时置有效电平:一般是高级定时器的说法,与关断、刹车灯功能一起的,有效电平就是高电平,无效电平则反之,一次性的,不适合输出连续变化的波形。
匹配时电平翻转:可以输出一个频率可调,占空比始终50%的PWM波形:比如当CCR设置为0时,CNT每次更新清0时,就会产生一次CNT=CCR的事件,从而导致输出电平翻转一次,每更新两次,输出为一个周期,同时高低电平时间始终相等,占空比始终为50%;则关系是输出频率=更新频率/2
强制为无效电平&强制为有效电平:与冻结差不多
PWM模式1& PWM模式2:用于输出频率和占空比都可调的PWM波形,主要使用
PWM的基本结构:
红色代表:CCR
蓝色代表:CNT
黄色代表:ARR
下面的图表示输出的PWM波形:
蓝色从0开始自增,直到与黄色相同时,出现中断,更新清0继续自增;
红色设置为30,因为输出控制器设置的模式是,当CNT<CCR时,为高电平;所以根据蓝色与黄色不断的更新,CCR会输出不同的REF信号,同时不仅可以调整红色设置的值,并且占空比也受CCR的调控。
参数计算
- PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
- PWM占空比: Duty = CCR / (ARR + 1)
- PWM分辨率: Reso = 1 / (ARR + 1)
CK_PSC:输入定时器的总频率;PSC=预分频器的分频数
占空比变化越细,越好
输出比较通道(高级定时器)
与通用定时器的区别:
当外部设备是一个大功率开关管(Mos管),两边开关分别连接着OC1和OC1N,假设是高电平导通,电平断开;两个开关中间对应输出;如果上管导通,下管断开,则是高电平,反之;但是如果两边都导通,则会短路或者两边都断开,则是高阻态;这就是推挽电路;如果有两个这样的电路相连接,则是H桥电路,可控制直流电路正反转了;如果有三个这样的电路,就可以用于驱动三相无刷电机;
回归内部,如果在上管关断的瞬间,下管立刻就打开,那可能会上管还没完全关断,下管已经导通,出现两边同时导通的现象,从而功率损耗,所以避免这个问题就设置了死区发生器电路,会在关闭的时候延迟一段时间,再导通;
外部设备:
舵机简介
- 舵机是一种根据输入PWM信号占空比来控制输出角度的装置
- 输入PWM信号要求:周期为20ms(50Hz),高电平宽度为0.5ms~2.5ms
逻辑:PWM信号输入到控制板,给控制板一个指定的目标角度,然后这个电位器检测输出轴的当前角度,如果大于目标角度,电机会反转,反之,最终使输出轴固定在指定角度。
输出轴角度:时间是指此输入信号的电平变化到下一个电平变化的时间
这里是PWM当作一个通信协议
硬件电路:
引脚定义图
直流电机及驱动简介
- 直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
- 直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
- TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向
硬件电路:
接线图
6-3 PWM驱动LED呼吸灯
这里我们LED正极接入A0引脚,负极在GND的方法,这样是高电平点亮,正极性驱动;占空比越高越亮;
- RCC开启时钟,把TIM外设和GPIO外设的时钟打开
- 配置时基单元,包括时钟源选择
- 配置输出比较单元:包括CCR的值、输出比较模式、极性选择、输出使能等由结构体统一配置
- 配置GPIO,把PWM对于的GPIO口,初始化为复用推挽输出的配置
- 运行控制
相关库函数:
//配置输出比较模块,一个函数配置一个单元,一共有四个单元,不同的通道对不同的GPIO口,对应关系:
得知:TIM2的ETR引脚和CH1通道1的引脚复用在PA0引脚上,所以我们要输出TIM2的OC1通道输出PWM,那就只能在PA0的引脚上输出;如果想跳出这个映射,则需要看这重定义功能表里是否对应接口映射,再通过配置AFIO来完成。
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);//用来输出比较结构体赋一个默认值
//小功能和运行参数
//配置强制输出模式,就是设置100%高电平一样
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);
//用来单独设置输出比较的极性,带N的就是高级定时器里互补通道的配置
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_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);
//选择输出比较模式
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
//用来单独更改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);
//仅高级定时器使用,在使用高级定时器输出PWM时,需要调用这个函数使能输出
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
示波器:1KHz,CCR为50,此时占空比为50%
1KHz,CCR为10,占空比减少至10%,灯变暗
1KHz,CCR为90,占空比增加至90%,灯变亮
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();while(1){for(i=0;i<=100;i++){PWM_set(i);Delay_ms(50);}for(i=0;i<=100;i++){PWM_set(100-i);Delay_ms(50);}}
}PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启APB1的时钟函数,TIM2在APB1总线中//选择时基单元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=720-1;//PSC预分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,我们用的通用寄存器,所以直接写0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化输出比较单元:频率1kHz,占空比为50%的PWM波形//TIM_OCInitStructure函数有一部分是高级定时器里的,要么就把全部成员拉出来配置,要么就用TIM_OCStructInit先赋一个初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8种输出比较模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能//因此通过观察得知,我们需要完成的呼吸灯的变化效果就与CCR的值息息相关,TIM_SetCompare1单独更改CCR值的函数就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC1Init(TIM2, &TIM_OCInitStructure);//现在把TIM2上的OC1通道上就可以输出PWM波形,这个波形是需要借助GPIO口才能输出,邮引脚定义表得知我们锁定在PA0引脚上/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出,因为普通的推挽输出,引脚的控制权是来自于输出数据寄存器的,那我们这时想让的是定时器来控制引脚,则需要使用复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //启动定时器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare1(TIM2,compare);
}
重定义映射:
开启AFIO时钟
使用引脚重映射配置GPIO_PinRemapConfig
与TIM2的映射关系一共4个,我们要把PA0映射到PA5,就使用2或则和4的关系
APIO的函数参数
注意PA15上电后默认复用调试端口JTDI,需要把它的默认给取消了才能正常使用
继续使用GPIO_PinRemapConfig,参数
三个参数:就是来解除复用的:
GPIO_Remap_SWJ_NoJTRST :解除JTRST引脚的复用
GPIO_Remap_SWJ_JTAGDisable :解除JTAG调试端口的复用
GPIO_Remap_SWJ_Disable :把SWD和JTAG的调试端口全部解除,此参数需要考虑使用,因为如果使用了,那STLInk就没有输出端口了,需要额外去配置
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启APB1的时钟函数,TIM2在APB1总线中//用引脚重映射,所以需要考虑使用AFIORCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_TIM2,ENABLE);//PA0到PA15//注意PA15也有自己的默认,需要把它的默认给取消了才能正常使用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,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=720-1;//PSC预分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,我们用的通用寄存器,所以直接写0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化输出比较单元:频率1kHz,占空比为50%的PWM波形//TIM_OCInitStructure函数有一部分是高级定时器里的,要么就把全部成员拉出来配置,要么就用TIM_OCStructInit先赋一个初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8种输出比较模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能//因此通过观察得知,我们需要完成的呼吸灯的变化效果就与CCR的值息息相关,TIM_SetCompare1单独更改CCR值的函数就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC1Init(TIM2, &TIM_OCInitStructure);//现在把TIM2上的OC1通道上就可以输出PWM波形,这个波形是需要借助GPIO口才能输出,邮引脚定义表得知我们锁定在PA0引脚上/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出,因为普通的推挽输出,引脚的控制权是来自于输出数据寄存器的,那我们这时想让的是定时器来控制引脚,则需要使用复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//重映射GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //启动定时器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare1(TIM2,compare);
}
6-4 PWM驱动舵机
CCR为500,对应转0°
修改参数:
CCR为2500,对应180°;
修改参数:
CCR为1500,对应90°;
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "key.h"
#include "PWM.h"uint8_t Keynum=0;//按键键码
float Angle;//角度变量
int main(void){OLED_Init();PWM_Init();
// //PWM_set(500);//此时时间为0.5ms,处于不动的状态//PWM_set(2500);//此时时间为2.5ms,转180°
// PWM_set(1500);//此时时间为1.5ms,转90°Key_Init();Servo_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);}
}
Servo.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
//给舵机一个模块,用来实现目标功能void Servo_Init(void){PWM_Init();
}void Servo_Setangle(float Angle){PWM_set(Angle/180*2000+500);
}
PWM.c
#include "stm32f10x.h" // Device header
void PWM_Init(void){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启APB1的时钟函数,TIM2在APB1总线中/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟,设置舵机PWM的接口/*GPIO初始化*/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); //选择时基单元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=20000-1;//ARR自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//PSC预分配器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器的值,我们用的通用寄存器,所以直接写0就好了TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_ClearFlag(TIM2,TIM_IT_Update);//初始化输出比较单元:舵机要求的周期是20ms,则频率为1/20ms=50Hz,要求高电平时间是0.5-2.5ms//PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)//PWM占空比: Duty = CCR / (ARR + 1)//PWM分辨率: Reso = 1 / (ARR + 1)//TIM_OCInitStructure函数有一部分是高级定时器里的,要么就把全部成员拉出来配置,要么就用TIM_OCStructInit先赋一个初始值0TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//8种输出比较模式TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出比较极性TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能//因此通过观察得知,我们需要完成的呼吸灯的变化效果就与CCR的值息息相关,TIM_SetCompare1单独更改CCR值的函数就有用了TIM_OCInitStructure.TIM_Pulse=0;//就是CCR的值TIM_OC2Init(TIM2, &TIM_OCInitStructure); //通道修改为2,同一个定时器不同的特性:因为不同的通道相位,产生PWM都是一样的,但是CCR是可以单独设置的//启动定时器TIM_Cmd(TIM2, ENABLE);
}
void PWM_set(uint16_t compare){TIM_SetCompare2(TIM2,compare); //修改通道2的CCR
}
6-5 PWM驱动直流电机
main.c
#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();Key_Init();Motor_Init();//Motor_Speed(50);//正转
// Motor_Speed(-50);//反转OLED_ShowString(1,1,"Speed:");while(1){Keynum=Key_GetNum();if(Keynum==1){Speed +=20;if(Speed>100){Speed=-100;}}Motor_Speed(Speed);OLED_ShowSignedNum(1,7,Speed,3);}
}Motor.c
#include "stm32f10x.h" // Device header
#include "PWM.h"
void Motor_Init(void){PWM_Init();//需要额外去控制电机的方向控制的两个脚/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/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;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA1和PA2引脚初始化为推挽输出//默认就是低电平,所以不需要对输出电平进行设置就可以亮灯}void Motor_Speed(int8_t Speed){if(Speed>=0){//设置方向一个为高,一个为低GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_set(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_set(-Speed);}
}