控制步进输出的定时器TIM2初始化函数
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
TIM_TimeBaseStructure.TIM_Period=1000;
TIM_TimeBaseStructure.TIM_Prescaler=0; //72M
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择定时器2中断线
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断通道
NVIC_Init(&NVIC_InitStructure);
我们再设置一个开启定时器和关闭定时器的函数:
开启定时器的函数名称:st_wake_up,
关闭函数则为:st_go_idle
void st_wake_up()
{
//使能控制系统控制的3个或者多个步进电机
MotorsEnable(0x07);
if (sys.state == STATE_CYCLE) {
//设置上电时候输出为低电平,否则会发送一个脉冲信号
out_bits = (0) ^ (settings.invert_mask);
//然后开启定时器的中断功能,设置中断的时候马上写入一遍优先级是一个好习惯
//定时器刚启动,标记逻辑位置为0
NVIC_EnableIRQ (TIM2_IRQn);
NVIC_SetPriority(TIM2_IRQn, 0);
ShowPos = 1;
}
}
关闭定时器的函数如下,关闭定时器时,如果要用到延时脱机,则处理一下延时命令,也可以打印出此时运行的XYZ坐标值:
void st_go_idle()
{
printpos_grbl(0,480);//输出位置信息
ShowPos = 0;
NVIC_DisableIRQ (TIM2_IRQn);
//如果需要延时脱机,则进行延时处理
if ((settings.stepper_idle_lock_time != 0xff) || bit_istrue(sys.execute,EXEC_ALARM)) {
_delay_ms(settings.stepper_idle_lock_time);
if (bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE))
{ STEPPERS_DISABLE_PORT &= ~(1<
定时器的ARR重载和预分频器的重新设置
- 首先,确定好最低运行的步进脉冲速度,这里设置为13HZ,在调用时,如果小于13HZ,则直接按照13HZ来处理,如下:
//最小的步进速度,步进脉冲停下来时,不要低于此值,也就是说,速度不要低于13HZ
#define MINIMUM_STEPS_PER_MINUTE 800
if (steps_per_minute < MINIMUM_STEPS_PER_MINUTE)
{ steps_per_minute = MINIMUM_STEPS_PER_MINUTE; }
如果我们要产生13HZ的输出频率,如果时钟频率为4M,则需要分钟产生4M*60/800=300K个TICKS我们将此参数交给下面的函数:config_step_timer
TIM_ClockDivision设置的不是时钟分频,而是采样时间设置,比如TIM_CKD_DIV1则表示采样的时钟就是定时器时钟。
我们需要输出的步进脉冲信号是随时需要进行调整的,也就是说,ARR需要动态的进行调节,同时,输出的频率跨度比较大,我们同时要设置预分频,可以利用下面的两个函数进行调整,函数的使用示例如下:
TIM_PrescalerConfig(TIM2,i,TIM_PSCReloadMode_Update);
TIM_SetAutoreload(TIM2,1000+i*500);
编写的测试程序如下:
- 定时器的结构体初始化设置如下:
void st_init()
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
TIM_TimeBaseStructure.TIM_Period=1000;
TIM_TimeBaseStructure.TIM_Prescaler=0; //72M
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_EnableIRQ (TIM2_IRQn);
}
- 中断服务程序
在中断函数中,对time进行循环++,如下:
void TIM2_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
{
TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
time++;
}
}
- 我们实现的功能如下,在每次中断事件时,1/72秒以后,将LED引脚翻转,翻转4次以后,进行一次跟新,我们可以同时更新ARR和PSC,测试程序如下:
if(time==1000)
{
time=0;
if((GPIO_ReadOutputDataBit(GPIOF, GPIO_Pin_7 )))
{GPIO_ResetBits(GPIOF, GPIO_Pin_7 );
a++;
if(a%4==0)
{i++;
TIM_PrescalerConfig(TIM2,i,TIM_PSCReloadMode_Update);
TIM_SetAutoreload(TIM2,1000+i*500);
if(i==10)i=0;}
}
else
GPIO_SetBits(GPIOF, GPIO_Pin_7);
}