完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
/************************************************************************** 函数功能:外部中断采集编码器初始化 入口参数:无 返回 值:无 **************************************************************************/ void Encoder_Init_TIM_Exit0(void)//用于检测编码器A相使用PA0引脚 { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); EXTI_InitStructure.EXTI_Line=EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//跳变沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器 // 配置中断优先级 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } void Encoder_Init_TIM_Exit1(void)//用于检测编码器B相使用PA1引脚 { GPIO_InitTypeDef GPIO_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); EXTI_InitStructure.EXTI_Line=EXTI_Line1; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//跳变沿触发 EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器 //配置中断优先级 NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 以上代码完成了A相 B相外部中断的初始化当有跳变沿发生时则进入外部中断服务函数,在外部中断服务函数中对脉冲进行计数,如果电机正转则计数的变量Encoder_A_EXTI(在中断服务函数中计数时使用)就加1,反转则减1。使用四倍频计数提高测速精度,所以A相和B相的跳变沿检测到后我们都进行计数。首先看A相 void EXTI0_IRQHandler(void) //外部中断线0服务函数 { EXTI->PR=1<<0; //清除LINE上的中断标志位 if(PAin(0)==0) //这里判断检测到的是否是下降沿 { if(PAin(1)==0) Encoder_A_EXTI++;//看B相的电平如果是高电机就是正转则加1,否则就是反转减1 else Encoder_A_EXTI--; } else //上升沿 { if(PAin(1)==0) Encoder_A_EXTI--; //B相低电平为正转,加1,高电平反转减1 else Encoder_A_EXTI++; } } B相同理 void EXTI1_IRQHandler(void)//外部中断线1服务函数 { EXTI->PR=1<<1; //清除LINE上的中断标志位 if(PAin(1)==1) //这里判断检测到的是否是上升沿 { if(PAin(0)==0) Encoder_A_EXTI++; //看A相的电平如果是低,电机就是正转则加1,否则就是反转减1 else Encoder_A_EXTI--; } else { if(PAin(0)==0) Encoder_A_EXTI--; else Encoder_A_EXTI++; } } 通过上数代码我们就可以在Encoder_A_EXTI这个变量中记录A相和B相的脉冲数,然后我们再通过一个函数来读取并清零Encoder_A_EXTI。 int Read_Encoder(u8 TIMX) { int Encoder_TIM; switch(TIMX) { case 2: Encoder_TIM=(short)Encoder_A_EXTI; Encoder_A_EXTI=0; break; default: Encoder_TIM=0; } return Encoder_TIM; } 然后再一个定时中断中使用此函数即可知道电机的转速。下面是第二种方法的代码 定时器编码器模式 /************************************************************************** 函数功能:把TIM3初始化为编码器接口模式 入口参数:无 返回 值:无 **************************************************************************/ void Encoder_Init_TIM3(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PB端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOB TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD-1; //设定计数器自动重装值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3 TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; TIM_ICInit(TIM3, &TIM_ICInitStructure); TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //Reset counter TIM_SetCounter(TIM3,0); TIM_Cmd(TIM3, ENABLE); } 初始化完成后我们可以直接在TIM3的CNT计数器中读取到我们捕获的脉冲数,这里要注意一点应为CNT寄存器的最大只能是65536超过这个值该计数器(CNT)就会溢出,所以我们要即使去读取CNT然后把它清空。同样是利用 Read_Encoder()这个函数 int Read_Encoder(u8 TIMX) { int Encoder_TIM; switch(TIMX) { case 2: Encoder_TIM=(short)Encoder_A_EXTI; Encoder_A_EXTI=0; break; case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break; default: Encoder_TIM=0; } return Encoder_TIM; } 显而易见利用定时器的编码器模式来测速更加快捷简单,并且没有这么多中断占用的MCU资源更少,所以测速我们一般优先使用第二种方法,只有当定时器资源不足时才会使用第一种方法。完整的Keil代码我也会提供给大家 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1090 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1107 浏览 1 评论
545 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
412 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
990 浏览 2 评论
1591浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
262浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
274浏览 3评论
244浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
238浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-16 06:23 , Processed in 0.629350 second(s), Total 46, Slave 40 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号