一、原理
计数器的值到达CCRx_1设置值时,电平会进行一次翻转。而后进入中断,输出比较回调函数函数HAL_TIM_OC_DelayElapsedCallback。如果在回调函数里重新设值CCRx_2,那么进行到达CCRx_2电平再次翻转。
二、配置
计数器时钟频率CK_CNT=fck_psc/(PSC[15:0]+1)
16位分频器设置位84-1,分频后计数器时钟频率位1MHZ,周期1uS
TIM_OCMode_Toggle TIM输出比较触发模式
翻转––TIMx_CNT=TIMx_CCR1 时,OC1REF 发生翻转。至于跟PWM模式的区别见总结篇
三、代码
keil ver. V5.29.0.0
cubemx ver. v5.6.0
firmware ver. FW_F4 V1.25.1
file_name: ALIENTEK_PWM
pin discreble: CLK 84M
PH3 | KEY0 |
PH2 | KEY1 |
PC13 | KEY2 |
PA0 | KEY_UP |
PB1 | TIM3_CH4 | √ (脉冲)STEP
PB0 | LED1 | 电机方向
PA10 | USART1_RX |
PA9 | USART1_TX |
bsp_ocompare.c
#include "bsp_ocompare.h"
/*全局变量*/
uint8_t dir = 0;//0:顺时钟 1:逆时钟
uint8_t ena = 0;//0:正常运行 1:停机
uint32_t Toggle_Pulse=500;
__IO uint32_t pulse_count=0;/*脉冲计数,一个完整的脉冲会增加2*/
//定时器比较输出中断回调函数,在定时器计数值与捕获比较寄存器值相等时发送中断,就会调用该函数
输出比较回调,进入中断后翻转,重新设置下一次翻转值,脉冲周期位T=2*Toggle_Pulse
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
__IO uint16_t count;
count = __HAL_TIM_GET_COUNTER(&htim3);
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,count+Toggle_Pulse);
pulse_count++;
}
void bsp_InitOcompare(void)
{
/*初始化设置了通道的脉冲数位Toggle_Pluse,启动定时器后计数器达到Toggle_Pulse,产生中断翻转通道引脚*/
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_4,Toggle_Pulse);
HAL_TIM_Base_Start(&htim3);
HAL_TIM_OC_Start_IT(&htim3,TIM_CHANNEL_4);//启动比较输出使能中断
}
bsp_ocompare.h
#ifndef _BSP_OCOMPARE_H
#define _BSP_OCOMPARE_H
#include "stm32f4xx_hal.h"
#include "main.h"
#include "pub_gpio.h"
#include "tim.h"
#include "bsp_led.h"
/*宏定义*/
//STEPMOTOR_OUTPUT_DISABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_SET);
//STEPMOTOR_OUTPUT_DISABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_RESET);
#define STEPMOTOR_DIR_REVERSAL() LED1_OFF() //翻转
#define STEPMOTOR_DIR_FORWARDL() LED1_ON() //正转
#define STEPMOTOR_MICRO_STEP 32 //步进电机驱动器细分,必须与驱动器实际设置对应
extern uint32_t Toggle_Pulse;
extern uint8_t dir;//0:顺时钟 1:逆时钟
extern uint8_t ena;//0:正常运行 1:停机
extern __IO uint32_t pulse_count;/*脉冲计数,一个完整的脉冲会增加2*/
void bsp_InitOcompare(void);
#endif
main函数
void main_task (void * arg)
{
uint8_t ucKeyCode;
while(1)
{
ucKeyCode = bsp_GetKey();
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
/* K1键按下,打印调试说明 */
case KEY_DOWN_K0:/*功能选择*/
printf("K1键按下\r\n");
key1_count++;
if(key1_count == 5)
key1_count = 1;
break;
case KEY_UP_K0:
printf("K1键松开\r\n");
break;
case KEY_LONG_K0:
printf("K1键长按\r\n");
break;
case KEY_DOWN_K1://功能调节
printf("K2键按下\r\n");
switch(key1_count)
{
case 1://加速
Toggle_Pulse -=50;
if( Toggle_Pulse<300 )
Toggle_Pulse = 300;
break;
case 2://减速
Toggle_Pulse +=100;
if(Toggle_Pulse >3500 )
Toggle_Pulse = 3500;
break;
case 3: //方向控制
if(dir == 0)
{
STEPMOTOR_DIR_REVERSAL(); //反转
dir = 1;
}
else
{
STEPMOTOR_DIR_FORWARDL();// 正转
dir = 0;
}
break;
case 4:
if(ena == 0)
{
// STEPMOTOR_OUTPUT_ENABLE();
ena=1;
}
else
{
pulse_count=0;
// STEPMOTOR_OUTPUT_DISABLE();
}
break;
default:
break;
}
break;
case KEY_UP_K1:
printf("K2键松开\r\n");
break;
case KEY_LONG_K1:
printf("K2键长按\r\n");
break;
case KEY_DOWN_K2:
printf("K3键按下\r\n");
break;
case KEY_UP_K2:
printf("K3键松开\r\n");
break;
case KEY_LONG_K2:
printf("K3键长按\r\n");
break;
case KEY_DOWN_K3:
printf("K4键按下\r\n");
break;
case KEY_UP_K3:
printf("K4键松开\r\n");
break;
case KEY_LONG_K3:
printf("K4键长按\r\n");
break;
case SYS_DOWN_K0K2:
printf("K0K2键按下\r\n");
break;
case SYS_UP_K0K2:
printf("K0K2键松开\r\n");
break;
case SYS_LONG_K0K2:
printf("K0K2键长按\r\n");
break;
case SYS_DOWN_K1K3:
printf("K1K3键按下\r\n");
break;
case SYS_UP_K1K3:
printf("K1K3键松开\r\n");
break;
case SYS_LONG_K1K3:
printf("K1K3键长按\r\n");
break;
default:
break;
}
}
if(pulse_count == STEPMOTOR_MICRO_STEP*200*2*10)//转10圈后停止 一圈200步
// STEPMOTOR_OUTPUT_DISABLE();
osThreadYield();
}
}