关于STM32的编码器计数及溢出处理调试总结

简介: 关于STM32的编码器计数及溢出处理调试总结

错误1、pc6 pc7被用作其他用途,GPIO模式配置错误。导致计数不准确; 错误2、引脚模式设置错误,应该设置为GPIO_Mode_IPD;//GPIO_Mode_IPU GPIO_Mode_IN_FLOATING  都可以; 错误3  引脚重映射没有开启AFIO时钟; 总结 关于编码器的溢出处理: 网上的检测数值突变的方法不可靠,会有漏检的情况。在滴答定时器中检测encoder的值突变 void SysTick_Handler(void) {// systick中断,1ms一次 static int encoder[2] = {0 , 0};// 两次编码器读值,用以计算溢出方向 static int N = 0;// 圈数 encoder[1] = TIM3->CNT; if((encoder[1] - encoder[0] ) > 0x7FFF) { N--; } else if( (encoder[0] - encoder[1] ) > 0x7FFF)

{ N++; } EncCnt = N * 0xFFFF + encoder[1]; encoder[0] = encoder[1]; } 我采用了两种方法处理:一种是采用另一个定时器实时的检测溢出标志及方向标志,这种方法是可行的。即使速度很快的时候依然计数准确。但是出现了新的问题,用作定时器的时钟,当定时周期设置的很小的时候才可以计数准确,但是由于中断的优先级高,导致无法进入主循环程序。附上检测代码。这样的处理方法,在速度慢的时候可以检测正确。但是定时周期要设置足够小。CR1的bit4代表计数方向标志,1代表减二代表加;SR的bit0代表溢出中断标志,1代表溢出。该位是硬件置1软件清零。另一种是使用编码器溢出中断。中断的时候对编码器溢出方向进行判断,然后根据方向进行累加。 void TIM2_IRQHandler(void) { if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) { TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);

encoder= TIM3->CNT;
      if((TIM3->CR1&0x10) == 0x10)//向下计数
      {          
           if(TIM3->SR&0x01 == 0x01)//tim3计数溢出
             {
                        TIM3->SR= TIM3->SR&0xFE;//sr的bit0清零
                        N--;
                 }                    
      }
      else if((TIM3->CR1&0x10) == 0x00)//向上计数
      {
           if(TIM3->SR&0x01 == 0x01)//tim3计数溢出
             {
                        TIM3->SR= TIM3->SR&0xFE;//sr的bit0清零
                        N++;
                 }                   
      }
          EncCnt= N * 65536 + TIM3->CNT;  
      //        encoder[0] = encoder[1];
   }                
复制代码

}

最后,我找到了更简单的检测编码器溢出中断并进行累计的方法。 其实当编码器的定时器溢出的时候,会导致进入中断。这样直接用编码器的中断函数即可。但是需要注意的是,需要在编码器的定时器配置的时候,配置中断。如果不配置,就会导致程序一运行就死机。一直停在DMA2_Channel4_5_IRQHandler这一句。 附上最终测试验证完成的代码 编码器初始化配置 ( 注意。如果不适用中断溢出的方法,无需配置 NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); 这部分。。。) 并且我适用的是tim3重定义到pc7  pc6的。也可以使用部分重映射和默认引脚。 void EncoderTimInit() { //     对TIM_ICInitStructure的配置和对TIM_EncoderInterfaceConfig函数的使用实际上是冲突的,两个语句中的极性的设置是重复的 //--------------1 GPIO_InitTypeDefGPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能TIM3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能GPIOC时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //AFIO时钟 GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);       //TIM选择全复用功能使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//PC6 PC7浮空输入 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//GPIO_Mode_IPU  GPIO_Mode_IN_FLOATING GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC,&GPIO_InitStructure); TIM_DeInit(TIM3);       //TIM3初始化 /* Timer configuration in Encoder mode */ TIM_TimeBaseStructure.TIM_Prescaler = 0; // 不分频 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM3_PERIOD-1;  //计数40000  定时 T = 1/72000000 *40000 S=  1/1.8ms TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//设置时钟分频系数:不分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

//     //编码配置                        编码模式

TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); //TIM_ICPolarity_Rising上升沿捕获 TIM_ICStructInit(&TIM_ICInitStructure);       //输入捕获模式配置为硬件默认值 TIM_ICInitStructure.TIM_ICFilter = 0x06;//ICx_FILTER;  //比较滤波器 TIM_ICInit(TIM3, &TIM_ICInitStructure);//调用库函数把配置信息填充进去 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); //     TIM_ARRPreloadConfig(TIM3,ENABLE); //     TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable); //Clear all pending interrupts //     TIM_SetAutoreload(TIM3,0xffff); TIM_ClearFlag(TIM3,TIM_FLAG_Update);//清除TIM3的更新标志位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//使能中断

//Reset counter  计数初始值 TIM3->CNT = 0; TIM_Cmd(TIM3, ENABLE); }

编码器计数模块 void TIM3_IRQHandler(void) {

if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update); if((TIM3->CR1&0x10) == 0x10)//向下计数 {

N--;

} else if((TIM3->CR1&0x10) == 0x00)//向上计数


{
                 N++;            
      }
          EncCnt= N * 65536 + TIM3->CNT;        
}
}


注: N 和EncCnt变量最好定义为volatile


相关文章
|
6月前
STM32实战项目—楼宇人员计数系统
本文介绍了一个基于红外对管的楼宇人员计数系统设计。简单介绍了一下红外对管的原理和使用方法。针对任务要求给出了详细的实现思路和程序设计。
33 3
STM32实战项目—楼宇人员计数系统
|
7月前
|
API 芯片
STM32 使用HAL库调试内部RTC经验总结
STM32 使用HAL库调试内部RTC经验总结
281 1
|
10月前
|
缓存 程序员 内存技术
STM32定时器配置(TIM1-TIM8)高级定时器+普通定时器,定时计数模式下总结
STM32定时器配置(TIM1-TIM8)高级定时器+普通定时器,定时计数模式下总结
469 0
|
11月前
【STM32】高级定时器TIM1计数中断配置
【STM32】高级定时器TIM1计数中断配置
407 0
|
传感器
STM32小项目总结2:(内含:1.对射式红外传感器计次+2.旋转编码器计次+3.定时器定时中断+4.定时器外部中断+5.笔记)
STM32小项目总结2:(内含:1.对射式红外传感器计次+2.旋转编码器计次+3.定时器定时中断+4.定时器外部中断+5.笔记)
254 0
STM32小项目总结2:(内含:1.对射式红外传感器计次+2.旋转编码器计次+3.定时器定时中断+4.定时器外部中断+5.笔记)
STM32:外部中断控制旋转编码器并计次
STM32:外部中断控制旋转编码器并计次
255 0
STM32:外部中断控制旋转编码器并计次
【STM32 .Net MF开发板学习-26】借道调试口与开发板通信
所谓调试口,就是供windows平台上的VS2008/VS2010调试的信道,当然MFDeploy和我编写的工具YFAccessFlash也是通过这个信道和开发板实现通信的。不过,这些通信过程,作为运行到开发板上的应用程序是无从知道的,这些基于开发板底层的通信,完全由TinyCLR进行全权管理。
578 0
STM32学习笔记(五)——通用定时器计数延时
STM32定时器概述 STM32F40x系列总共最多有14个定时器,定时器分为三类:基本定时器、通用定时器和高级定时器。它们的都是通过计数来达到定时的目的,和51的定时器差不多,基本原理都是一样的,就是功能多了一些,这些计数器都是自动重新装载初值的,使用起来非常方便,而且计数时钟频率可以通过分频系数来设置。
2192 0
stm32开发之串口的调试
<p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">总的函数如下</p> <p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">void
1587 0
|
2月前
|
C++ 芯片 编译器
STM32F103标准外设库—— 新建工程与库函数(四)
STM32F103标准外设库—— 新建工程与库函数(四)
44 0
STM32F103标准外设库—— 新建工程与库函数(四)