由于工作需求需要测试每一路的步进电机输出脉冲和方向是否能够正常工作。但通过上位机点击每个轴号并观察每一路比较繁琐,所以就设计了八通道的测试工具。
先上原理图。
定时器我用到了4组。定时器分别为1、2、5、8这4个。你明明是说8个通道的呀,怎么是4个呢?先别急。先看下面。
我用的是2选1选择器,看看他的手册。他写的高传输速度,我也不知道是多少也没测过反正够用就行。第六管脚就是选择通道。
6号引脚在低电平的作用下B0连接到A。 高电平的作用下B1连接到A。
代码部分:
举例子定时器1启用捕获功能
static void ADVANCE_TIM1_Mode_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
// 开启定时器时钟,即内部时钟CK_INT=72M
ADVANCE_TIM1_APBxClock_FUN(ADVANCE_TIM1_CLK,ENABLE);
/*--------------------时基结构体初始化-------------------------*/
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM1_PERIOD;
// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM1_PSC;
// 时钟分频因子 ,配置死区时间时需要用到
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
// 初始化定时器
TIM_TimeBaseInit(ADVANCE_TIM1, &TIM_TimeBaseStructure);
/*--------------------输入捕获结构体初始化-------------------*/
// 使用PWM输入模式时,需要占用两个捕获寄存器,一个测周期,另外一个测占空比
// 捕获通道IC1配置
// 选择捕获通道
TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM1_IC1PWM_CHANNEL;
// 设置捕获的边沿
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
// 设置捕获通道的信号来自于哪个输入通道,有直连和非直连两种
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
// 1分频,即捕获信号的每个有效边沿都捕获
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// 不滤波
TIM_ICInitStructure.TIM_ICFilter = 0x0;
// 初始化PWM输入模式
TIM_PWMIConfig(ADVANCE_TIM1, &TIM_ICInitStructure);
// 当工作做PWM输入模式时,只需要设置触发信号的那一路即可(用于测量周期)
// 另外一路(用于测量占空比)会由硬件自带设置,不需要再配置
// 捕获通道IC2配置
// TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;
// TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
// TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;
// TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// TIM_ICInitStructure.TIM_ICFilter = 0x0;
// TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
// 选择输入捕获的触发信号,触发的那一路信号对应的就是周期
TIM_SelectInputTrigger(ADVANCE_TIM1, TIM_TS_TI1FP1);
// 选择从模式: 复位模式
// PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
TIM_SelectSlaveMode(ADVANCE_TIM1, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(ADVANCE_TIM1,TIM_MasterSlaveMode_Enable);
// 使能捕获中断,这个中断针对的是主捕获通道(测量周期那个)
TIM_ITConfig(ADVANCE_TIM1, TIM_IT_CC1, ENABLE);
// 清除中断标志位
TIM_ClearITPendingBit(ADVANCE_TIM1, TIM_IT_CC1);
// 使能高级控制定时器,计数器开始计数
TIM_Cmd(ADVANCE_TIM1, ENABLE);
}
举例子TIM1计算占空和频率
//然后在中断服务函数中读取CCR1 和 CCR2寄存器的值,并计算 频率 和 占空比。
__IO uint16_t TIM1_IC2Value = 0;
__IO uint16_t TIM1_IC1Value = 0;
__IO float TIM1_DutyCycle = 0;
__IO float TIM1_Frequency = 0;
/*
* 如果是第一个上升沿中断,计数器会被复位,锁存到CCR1寄存器的值是0,CCR2寄存器的值也是0
* 无法计算频率和占空比。当第二次上升沿到来的时候,CCR1和CCR2捕获到的才是有效的值。其中
* CCR1对应的是周期,CCR2对应的是占空比。
*/
void ADVANCE_TIM1_IRQHandler(void)
{
/* 清除中断标志位 */
TIM_ClearITPendingBit(ADVANCE_TIM1, TIM_IT_CC1);
/* 获取输入捕获值 */
TIM1_IC1Value = TIM_GetCapture1(ADVANCE_TIM1);
TIM1_IC2Value = TIM_GetCapture2(ADVANCE_TIM1);
// 注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须加1
if (TIM1_IC1Value != 0)
{
/* 占空比计算 */
TIM1_DutyCycle = (float)((TIM1_IC2Value+1) * 100) / (TIM1_IC1Value + 1);
/* 频率计算 */
TIM1_Frequency = (72000000/(ADVANCE_TIM1_PSC+1))/(float)(TIM1_IC1Value + 1);
printf("TIM1_占空比:%0.2f%% TIM1_频率:%0.2fHz\n",TIM1_DutyCycle,TIM1_Frequency);
if(Duty_ratio ==TIM1_DutyCycle && Frequency ==TIM1_Frequency)
{
TIM1_Sun++;
if(TIM1_Sun >= 8)
{
TIM_Cmd(ADVANCE_TIM1, DISABLE);
TIM1_DISABLE = 1;
}
}
}
else
{
TIM1_DutyCycle = 0;
TIM1_Frequency = 0;
}
}
主函数部分。
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
DIR_Init(); //IO初始化
either_or_Init();
ADVANCE_TIM1_Init();
ADVANCE_TIM8_Init();
ADVANCE_TIM5_Init();
ADVANCE_TIM2_Init();
GPIO_SetBits(GPIOB,GPIO_Pin_13);
GPIO_SetBits(GPIOD,GPIO_Pin_9);
GPIO_SetBits(GPIOC,GPIO_Pin_7);
GPIO_SetBits(GPIOA,GPIO_Pin_11);
QDTFT_Test1();
while(1)
{
DIR_decide();
if(TIM1_DISABLE == 1)
{
if( GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_7) == 1)//DIR_CH4
{
QDTFT_Test2(3);
}
else if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_13) == 1 && GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_7) == 0)//DIR_CH3
{
QDTFT_Test2(2);
}
}
if(TIM8_DISABLE == 1)
{
if( GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_9) == 1)//DIR_CH6
{
QDTFT_Test2(5);
}
else if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11) == 1 && GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_9) == 0)//DIR_CH5
{
QDTFT_Test2(4);
}
}
if(TIM5_DISABLE == 1)
{
if( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == 1)//DIR_CH8
{
QDTFT_Test2(7);
}
else if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9) == 1 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13) == 0)//DIR_CH7
{
QDTFT_Test2(6);
}
}
if(TIM2_DISABLE == 1)
{
if( GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == 1)//DIR_CH2
{
QDTFT_Test2(1);
}
else if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_15) == 1 && GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11) == 0)//DIR_CH1
{
QDTFT_Test2(0);
}
}
if(TIM1_DISABLE == 1 && TIM8_DISABLE == 1 && TIM2_DISABLE == 1 && TIM5_DISABLE == 1)
{
TIM1_DISABLE =0;
TIM8_DISABLE =0;
TIM2_DISABLE =0;
TIM5_DISABLE =0;
GPIO_ResetBits(GPIOA,GPIO_Pin_11);//Motor_CH1
GPIO_ResetBits(GPIOC,GPIO_Pin_7);//Motor_CH2
GPIO_ResetBits(GPIOD,GPIO_Pin_9);//Motor_CH3
GPIO_ResetBits(GPIOB,GPIO_Pin_13);//Motor_CH4
delay_ms(50);
TIM_Cmd(ADVANCE_TIM1, ENABLE);
TIM_Cmd(ADVANCE_TIM8, ENABLE);
TIM_Cmd(ADVANCE_TIM2, ENABLE);
TIM_Cmd(ADVANCE_TIM5, ENABLE);
}else if(TIM1_DISABLE == 0 && TIM8_DISABLE == 0 && TIM2_DISABLE == 0 && TIM5_DISABLE == 0)
{
// GPIO_ResetBits(GPIOA,GPIO_Pin_11);//Motor_CH1
// GPIO_ResetBits(GPIOC,GPIO_Pin_7);//Motor_CH2
// GPIO_ResetBits(GPIOD,GPIO_Pin_9);//Motor_CH3
// GPIO_ResetBits(GPIOB,GPIO_Pin_13);//Motor_CH4
// delay_ms(50);
}
}
}
由于我这里是同时测8路的直接测完将对应的通道就关闭一路定时器。不然会阻塞住,导致后面的定时器无法运行。
加入实时时钟或者调整好优先级效果会更好。但我并没有这样做,毕竟是个测试工具,简单一点的功能就可以完成工作。
完整的代码链接:https://download.csdn.net/download/weixin_41226265/86400313