赞
踩
目录
死区生成和互补输出一般用于对电机的控制
惯性系统:即要能使人眼产生视觉停留的系统
高级定时器比通用定时器多了个互补输出和死区生成
如右图,两个mos管构成了推挽电路,上管导通下管关闭输出高电平,下管导通上管关闭输出低电平,两管都关闭为高阻态,两管都导通为短路,会对元器件造成损伤,所以两管不能同时导通
互补输出:当单片机要控制这个电路时,就需要两个输出端口,且二者电平要相反,即互补,而这里OC1和OC1N就是互补的两个端口,即互补输出
死区发生器:但是若在上管关闭的瞬间下管就导通,很可能由于器件的不理想而出现上下管都导通的情况,为了避免这种情况发生,于是又是死区发生器,即他可以在上管关闭后延迟一段时间再导通下管,避免同时导通
1.我使用的是TIM3的CH2的重定义引脚PB5,所以要打开AFIO时钟
2.开启TIM3和GPIO的时钟
3.初始化GPIO结构体。注意:要记得使用库函数进行重定义
4.选择TIM3的时钟输入,可以为内部时钟,外部时钟模式1和2,
外部时钟模式1:来源可以是ITR(其他定时器,多用于定时器级联),可以是ETR(外部时 钟),可以是CH1引脚的边沿,CH1引脚和CH2引脚(多用于输入捕获测频率)
外部时钟模式2:ETR的触发控制模式
5.初始化TIM3结构体--配置PSC,ARR,计数模式,等等
6.初始化OC结构体--PWM模式选择,CCR,输出ref的有效电平
7.定时器使能
- //使用TIM3的通道2的重定义引脚PB5-指南者上面是红灯
- //我们配置
- void PWM_Config()
- {
- //首先开启GPIO时钟
- //开启AFIO时钟,因为用到了重定义
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);
- //开启定时器的时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
-
- //重定义引脚
- //选择部分重定义
- GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);
-
- //初始化GPIO结构体-PB5-输出比较
- GPIO_InitTypeDef GPIO_InitStruct;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽,手册可看
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;
- GPIO_Init(GPIOB,&GPIO_InitStruct);
-
- //选择TIM3的时钟输入
- TIM_InternalClockConfig(TIM3);//我们直接使用内部时钟
-
- //配置TIM结构体
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
- TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;//PSC
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//计数模式
- TIM_TimeBaseInitStruct.TIM_Period = 100-1;//ARR
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//输入滤波器的分频
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
- TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
-
- //初始化OC结构体
- TIM_OCInitTypeDef TIM_OCInitStruct;
- TIM_OCStructInit(&TIM_OCInitStruct);//先赋初值,因为我们没有把结构体配置完全
- TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//模式选择-PWM1
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//输出使能
- TIM_OCInitStruct.TIM_Pulse = 0;//CCR,这里我们不配置CCR的值,后面用一个库函数直接在主函数
- 里面配置,实现呼吸灯
- TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出ref极性,选择有效电平,即ref有效时输出高电平
- //TIM_OCInitStruct.TIM_OCNPolarity = ;
- //TIM_OCInitStruct.TIM_OCIdleState = ;
- //TIM_OCInitStruct.TIM_OCNIdleState = ;
- //TIM_OCInitStruct.TIM_OutputNState = ;
- TIM_OC2Init(TIM3,&TIM_OCInitStruct);
-
- //启动定时器
- TIM_Cmd(TIM3,ENABLE);
-
- }
-
- void PWM_SetCompare2(uint16_t Compare)
- {
- TIM_SetCompare2(TIM3,Compare);
- }
- main.c
-
- #include "stm32f10x.h" // Device header
- #include "bsp_led.h"
- #include ".\tim\bsp_tim.h"
-
- extern uint16_t Num;//定时器都是16位的
-
- int i;
- void Delay(u32 i)
- {
- u32 temp;
- SysTick->LOAD=9000*i; //设置重装数值, 72MHZ时
- SysTick->CTRL=0X01; //使能,减到零是无动作,采用外部时钟源
- SysTick->VAL=0; //清零计数器
- do
- {
- temp=SysTick->CTRL; //读取当前倒计数值
- }
- while((temp&0x01)&&(!(temp&(1<<16)))); //等待时间到达
- SysTick->CTRL=0; //关闭计数器
- SysTick->VAL=0; //清空计数器
- }
-
-
- //ARR=99-->PWM一个周期是100,那么分辨率为1%
- //占空比 = CCR/(ARR+1)
- //频率 = 计数器溢出频率 = CK_PSC/(PSC+1)/(ARR+1) = 72M/720/100= 1000HZ ->1ms
- int main()
- {
-
- LED_GPIO_Config();
- PWM_Config();
-
- while(1)
- {
- for(i=0;i<=100;i++)
- {
- PWM_SetCompare2(i);
- Delay(10);
- }
- for(i=100;i>=0;i--)
- {
- PWM_SetCompare2(i);
- Delay(10);
- }
- }
- }
-
-
具体TIM的配置过程同呼吸灯一样,同样是输出不同的PWM占空比来实现电机的不同速度
我们需要三个引脚,一个输出PWM给电机,两个接电机的控制引脚
- 使用PA2输出PWM,AIN1/2接到PA4/5
- 频率设置为1KHZ(可以自己随便设置)
- 定义一个八位有符号的变量Speed,+:正转 -:反转
- 使用GPIO_SetBits/ResetBits();来设置AIN1/2的电平高低
- 使用按键来改变转速
- void PWM_Config()
- {
- //开启时钟
- //使用TIM2的CH3的PA2
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启PWM引脚
-
-
- //初始化GPIO
- GPIO_InitTypeDef GPIO_InitStruct;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽,手册可看
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 ;
- GPIO_Init(GPIOA,&GPIO_InitStruct);
-
- //选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
- TIM_InternalClockConfig(TIM2);
- //初始化时基单元
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
-
- //配置1KHZ的PWM
- TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1;//PSC-预分频器
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
- TIM_TimeBaseInitStruct.TIM_Period = 100-1;//ARR寄存器-重装载寄存器
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
- 也可以由内部时钟加一个时钟分频而来,
- 分频系数就是由TIM_ClockDivision决定*/
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
- TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
-
- //初始化OC-输出比较结构体
- TIM_OCInitTypeDef TIM_OCInitStruct;
- TIM_OCStructInit(&TIM_OCInitStruct);//因为结构体里面的成员有些是高级定时器采用得到,所以这里就先全部初始化一遍,然后再配置具体的值
- TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
- //TIM_OCInitStruct.TIM_Pulse = 50;//CRR
- TIM_OCInitStruct.TIM_Pulse = 0;//输出要求波型,这里的CRR就不需要了,用固件库的一个函数 TIM_SetCompare3 直接配置CRR
- TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性
- TIM_OC3Init(TIM2,&TIM_OCInitStruct);//CH3通道
-
-
- //启动定时器
- TIM_Cmd(TIM2,ENABLE);
-
- }
- //电机控制函数
-
- void Motor_SetSpeed(int8_t Speed)//+:正转 -:反转
- {
- if(Speed >= 0)
- {
- GPIO_SetBits(GPIOA,GPIO_Pin_4);
- GPIO_ResetBits(GPIOA,GPIO_Pin_5);
- TIM_SetCompare3(TIM3,Speed);
- }
- else
- {
- GPIO_ResetBits(GPIOA,GPIO_Pin_4);
- GPIO_SetBits(GPIOA,GPIO_Pin_5);
- TIM_SetCompare3(TIM3,-Speed);
- }
- }
- //主函数
-
-
- #include "stm32f10x.h" // Device header
- #include ".\tim\bsp_tim.h"
- #include ".\KEY\bsp_key.h"
-
- uint8_t KeyNum;
- int8_t Speed;
-
- int main()
- {
- KEY_GPIO_Config();
- PWM_Config();
-
- while(1)
- {
- KeyNum = Key_Scan();
- if(KeyNum == 0)
- {
- Speed += 20;
- if(Speed > 100)
- {
- Speed = -100;
- }
- }
- else if(KeyNum == 1)
- {
- Speed -= 20;
- if(Speed < -100)
- {
- Speed = 100;
- }
- }
- Motor_SetSpeed(Speed);
- }
- }
-TB6612驱动板
VM->STLINK的5v
VCC->面包板3.3v
GND->面包板负极
AO1 AO2 接电机
STBY->待机控制引脚,这里不需要待机,接面包3.3v
AIN1/2-> 任意接两个引脚
PWMA->PWM输出控制引脚
驱动VM放在左下角使用PA2输出PWM,AIN1/2接到PA4/5
- 要点:输出如上图右侧所示的PWM波型
- 指南者的PA0引脚为按键1,所以使用TIM2的CH3通道的PA2
- PWM要求频率为50HZ,即总时间20ms,高电平占0.5~2.5ms,这里我们可以给ARR配置20000-1,PSC配置72-1
- 封装Angle转换函数0-50 180->2500 -->y=Angle/180*2500+50, Angle使用浮点型,利于计算
- 使用按键来改变角度
- #include "bsp_tim.h"
-
- void PWM_Config()
- {
- //开启时钟
- //使用TIM2的CH3的PA2
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启PWM引脚
-
-
- //初始化GPIO
- GPIO_InitTypeDef GPIO_InitStruct;
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽,手册可看
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
- GPIO_Init(GPIOA,&GPIO_InitStruct);
-
- //选择时基单元的时钟-为内部时钟--定时器上电后默认是内部时钟,故不写这一个也行
- TIM_InternalClockConfig(TIM2);
- //初始化时基单元
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
-
- TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1;//PSC-预分频器
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
- TIM_TimeBaseInitStruct.TIM_Period = 20000-1;//ARR寄存器-重装载寄存器
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;/*不分频----滤波器的采样频率,可以由内部时钟直接提供,
- 也可以由内部时钟加一个时钟分频而来,
- 分频系数就是由TIM_ClockDivision决定*/
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;//重复计数器,只有高级定时器才有
- TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
-
- //初始化OC-输出比较结构体
- TIM_OCInitTypeDef TIM_OCInitStruct;
- TIM_OCStructInit(&TIM_OCInitStruct);//因为结构体里面的成员有些是高级定时器采用得到,所以这里就先全部初始化一遍,然后再配置具体的值
- TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//输出比较模式
- TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
- //TIM_OCInitStruct.TIM_Pulse = 50;//CRR --舵机要求设置频率50HZ-即总时间20ms,高电平时间在0.5~2.5ms之间的PWM波型即CCR->500~2500
- TIM_OCInitStruct.TIM_Pulse = 0;//输出要求波型,这里的CRR就不需要了,用固件库的一个函数 TIM_SetCompare3 直接配置CRR
- TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//输出比较极性
- TIM_OC3Init(TIM2,&TIM_OCInitStruct);//CH3通道
-
-
- //启动定时器
- TIM_Cmd(TIM2,ENABLE);
- }
- //0.5ms-0度 2.5ms-180度
- //0度 CCR=500
- //180度 CCR=2500
- //舵机设置角度,范围0~180
- void Servo_SetAngle(float Angle)
- {
- TIM_SetCompare3(TIM2,Angle*2000/180+500);
- }
-
-
- void PWM_SetCompare3(uint16_t Compare)//设置CRR
- {
- TIM_SetCompare3(TIM2,Compare);
- }
- #include "stm32f10x.h" // Device header
- #include ".\tim\bsp_tim.h"
- #include ".\KEY\bsp_key.h"
- uint8_t KeyNum;
- float Angle;
-
- int main()
- {
- KEY_GPIO_Config();
- LED_GPIO_Config();
- PWM_Config();
-
- while(1)
- {
- KeyNum = Key_Scan();
- if(KeyNum == 0)
- {
- Angle+=30;
- if(Angle>180)
- {
- Angle = 0;
- }
- }
- else if(KeyNum == 1)
- {
- Angle-=30;
- if(Angle<0)
- {
- Angle = 180;
- }
- }
- Servo_SetAngle(Angle);
- }
- }
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。