最近在学正交编码器,网上找的不明来源的stm32f10x_encoder.c,个人看了一下,感觉还可以,大致看懂了,有些小问题还需要与各位大神讨论。
先贴代码:
先是stm32f10x_encoder.c
- /******************** (C) COPYRIGHT 2007 STMicroelectronics ********************
- * File Name : stm32f10x_encoder.c
- * Author : IMS Systems Lab
- * Date First Issued : 21/11/07
- * Description : This file contains the software implementation for the
- * encoder unit
- ********************************************************************************
- * History:
- * 21/11/07 v1.0
- ********************************************************************************
- * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
- * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
- * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
- * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
- * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
- *******************************************************************************/
- /* Includes ------------------------------------------------------------------*/
- #include "stm32f10x_lib.h"
- #include "stm32f10x_encoder.h"
- #include "lcd.h"
- /* Private typedef -----------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- #define ENCODER_TIMER TIM3 // Encoder unit connected to TIM3
- #define ENCODER_PPR (u16)(400) // number of pulses per revolution
- #define SPEED_BUFFER_SIZE 8
- #define COUNTER_RESET (u16)0
- #define ICx_FILTER (u8) 6 // 6<-> 670nsec
- #define TIMx_PRE_EMPTION_PRIORITY 1
- #define TIMx_SUB_PRIORITY 0
- #define SPEED_SAMPLING_FREQ (u16)(2000/(SPEED_SAMPLING_TIME+1))
- /* Private functions ---------------------------------------------------------*/
- s16 ENC_Calc_Rot_Speed(void);
- /* Private variables ---------------------------------------------------------*/
- static s16 hPrevious_angle, hSpeed_Buffer[SPEED_BUFFER_SIZE], hRot_Speed;
- static u8 bSpeed_Buffer_Index = 0;
- static volatile u16 hEncoder_Timer_Overflow;
- static bool bIs_First_Measurement = TRUE;
- /*******************************************************************************
- * Function Name : ENC_Init
- * Description : General Purpose Timer x set-up for encoder speed/position
- * sensors
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void ENC_Init(void)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_ICInitTypeDef TIM_ICInitStructure;
-
- /* Encoder unit connected to TIM3, 4X mode */
- GPIO_InitTypeDef GPIO_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- /* TIM3 clock source enable */
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
- /* Enable GPIOA, clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- GPIO_StructInit(&GPIO_InitStructure);
- /* Configure PA.06,07 as encoder input */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- /* Enable the TIM3 Update Interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIMx_PRE_EMPTION_PRIORITY;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIMx_SUB_PRIORITY;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- /* Timer configuration in Encoder mode */
- TIM_DeInit(ENCODER_TIMER);
- TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
-
- TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling
- TIM_TimeBaseStructure.TIM_Period = (4*ENCODER_PPR)-1;
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
- TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);
-
- TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12,
- TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
- TIM_ICStructInit(&TIM_ICInitStructure);
- TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;
- TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
-
- // Clear all pending interrupts
- TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
- TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);
- //Reset counter
- TIM2->CNT = COUNTER_RESET;
-
- ENC_Clear_Speed_Buffer();
-
- TIM_Cmd(ENCODER_TIMER, ENABLE);
- }
- /*******************************************************************************
- * Function Name : ENC_Get_Electrical_Angle
- * Description : Returns the absolute electrical Rotor angle
- * Input : None
- * Output : None
- * Return : Rotor electrical angle: 0 -> 0 degrees,
- * S16_MAX-> 180 degrees,
- * S16_MIN-> -180 degrees
- *******************************************************************************/
- s16 ENC_Get_Electrical_Angle(void)
- {
- s32 temp;
-
- temp = (s32)(TIM_GetCounter(ENCODER_TIMER)) * (s32)(U32_MAX / (4*ENCODER_PPR));
- return((s16)(temp/65536)); // s16 result
- }
- /*******************************************************************************
- * Function Name : ENC_Clear_Speed_Buffer
- * Description : Clear speed buffer used for average speed calculation
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void ENC_Clear_Speed_Buffer(void)
- {
- u32 i;
- for (i=0;i<SPEED_BUFFER_SIZE;i++)
- {
- hSpeed_Buffer[i] = 0;
- }
- bIs_First_Measurement = TRUE;
- }
- /*******************************************************************************
- * Function Name : ENC_Calc_Rot_Speed
- * Description : Compute return latest speed measurement
- * Input : None
- * Output : s16
- * Return : Return the speed in 0.1 Hz resolution.
- *******************************************************************************/
- s16 ENC_Calc_Rot_Speed(void)
- {
- s32 wDelta_angle;
- u16 hEnc_Timer_Overflow_sample_one, hEnc_Timer_Overflow_sample_two;
- u16 hCurrent_angle_sample_one, hCurrent_angle_sample_two;
- signed long long temp;
- s16 haux;
-
- if (!bIs_First_Measurement)
- {
- // 1st reading of overflow counter
- hEnc_Timer_Overflow_sample_one = hEncoder_Timer_Overflow;
- // 1st reading of encoder timer counter
- hCurrent_angle_sample_one = ENCODER_TIMER->CNT;
- // 2nd reading of overflow counter
- hEnc_Timer_Overflow_sample_two = hEncoder_Timer_Overflow;
- // 2nd reading of encoder timer counter
- hCurrent_angle_sample_two = ENCODER_TIMER->CNT;
- // Reset hEncoder_Timer_Overflow and read the counter value for the next
- // measurement
- hEncoder_Timer_Overflow = 0;
- haux = ENCODER_TIMER->CNT;
-
- if (hEncoder_Timer_Overflow != 0)
- {
- haux = ENCODER_TIMER->CNT;
- hEncoder_Timer_Overflow = 0;
- }
-
- if (hEnc_Timer_Overflow_sample_one != hEnc_Timer_Overflow_sample_two)
- { //Compare sample 1 & 2 and check if an overflow has been generated right
- //after the reading of encoder timer. If yes, copy sample 2 result in
- //sample 1 for next process
- hCurrent_angle_sample_one = hCurrent_angle_sample_two;
- hEnc_Timer_Overflow_sample_one = hEnc_Timer_Overflow_sample_two;
- }
-
- if ( (ENCODER_TIMER->CR1 & TIM_CounterMode_Down) == TIM_CounterMode_Down)
- {// encoder timer down-counting
- wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle -
- (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
- }
- else
- {//encoder timer up-counting
- wDelta_angle = (s32)(hCurrent_angle_sample_one - hPrevious_angle +
- (hEnc_Timer_Overflow_sample_one) * (4*ENCODER_PPR));
- }
-
- // speed computation as delta angle * 1/(speed sempling time)
- temp = (signed long long)(wDelta_angle * SPEED_SAMPLING_FREQ);
- temp *= 10; // 0.1 Hz resolution
- temp /= (4*ENCODER_PPR);
-
- } //is first measurement, discard it
- else
- {
- bIs_First_Measurement = FALSE;
- temp = 0;
- hEncoder_Timer_Overflow = 0;
- haux = ENCODER_TIMER->CNT;
- // Check if Encoder_Timer_Overflow is still zero. In case an overflow IT
- // occured it resets overflow counter and wPWM_Counter_Angular_Velocity
- if (hEncoder_Timer_Overflow != 0)
- {
- haux = ENCODER_TIMER->CNT;
- hEncoder_Timer_Overflow = 0;
- }
- }
-
- hPrevious_angle = haux;
-
- return((s16) temp);
- }
- /*******************************************************************************
- * Function Name : ENC_Calc_Average_Speed
- * Description : Compute smoothed motor speed based on last SPEED_BUFFER_SIZE
- informations and store it variable
- * Input : None
- * Output : s16
- * Return : Return rotor speed in 0.1 Hz resolution. This routine
- will return the average mechanical speed of the motor.
- *******************************************************************************/
- void ENC_Calc_Average_Speed(void)
- {
- s32 wtemp;
- u32 i;
-
- wtemp = ENC_Calc_Rot_Speed();
-
- /* Compute the average of the read speeds */
- hSpeed_Buffer[bSpeed_Buffer_Index] = (s16)wtemp;
- bSpeed_Buffer_Index++;
-
- if (bSpeed_Buffer_Index == SPEED_BUFFER_SIZE)
- {
- bSpeed_Buffer_Index = 0;
- }
- wtemp=0;
- for (i=0;i<SPEED_BUFFER_SIZE;i++)
- {
- wtemp += hSpeed_Buffer[i];
- }
- wtemp /= SPEED_BUFFER_SIZE;
-
- hRot_Speed = ((s16)(wtemp));
- }
- /*******************************************************************************
- * Function Name : LCD_Display
- * Description : This function handles the display of timer counter, theta and
- electronical frequency:
- theta --- resolution: 1 degree;
- electronical frequency --- resolution: 0.1Hz.
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void LCD_Display(DisplayType DisplayStatus)
- {
- u16 hValue;
- s16 Theta;
- s16 hSpeed;
- char *pstr;
-
- switch (DisplayStatus)
- {
- case DISPLAY_TIMCNT:
- hValue = TIM_GetCounter(ENCODER_TIMER);
- write_string(int2char(hValue));
- break;
-
- case DISPLAY_THETA:
- Theta = ENC_Get_Electrical_Angle()*360/U16_MAX;
- if (Theta < 0)
- {
- hValue = (u16)(-Theta);
- pstr = int2char(hValue);
- *pstr = '-';
- }
- else
- {
- hValue = (u16)Theta;
- pstr = int2char(hValue);
- if (hValue != 0) *pstr = '+';
- }
- write_string(pstr);
- break;
-
- default:
- hSpeed = hRot_Speed;
- if (hSpeed < 0)
- {
- hValue = (u16)(-hSpeed);
- pstr = int2char(hValue);
- *pstr = '-';
- }
- else
- {
- hValue = (u16)hSpeed;
- pstr = int2char(hValue);
- if (hValue != 0) *pstr = '+';
- }
- write_string(pstr);
- break;
- }
- }
- /*******************************************************************************
- * Function Name : TIM2_IRQHandler
- * Description : This function handles TIMx Update interrupt request.
- Encoder unit connected to TIM2
- * Input : None
- * Output : None
- * Return : None
- *******************************************************************************/
- void TIM3_IRQHandler(void)
- {
- /* Clear the interrupt pending flag */
- TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
-
- if (hEncoder_Timer_Overflow != U16_MAX)
- {
- hEncoder_Timer_Overflow++;
- }
- }
- /******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
再贴代码stm32f10x_encoder.h
- /******************** (C) COPYRIGHT 2007 STMicroelectronics ********************
- * File Name : stm32f10x_encoder.h
- * Author : IMS Systems Lab
- * Date First Issued : 21/11/07
- * Description : This file contains the software implementation for the
- * encoder position and speed reading.
- ********************************************************************************
- * History:
- * 21/11/07 v1.0
- ********************************************************************************
- * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
- * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
- * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
- * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
- * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
- * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
- *******************************************************************************/
- /* Define to prevent recursive inclusion -------------------------------------*/
- #ifndef __STM32F10x_ENCODER_H
- #define __STM32F10x_ENCODER_H
- /* Private typedef -----------------------------------------------------------*/
- typedef enum {DISPLAY_TIMCNT = 0,DISPLAY_THETA,DISPLAY_W} DisplayType;
- /* Includes ------------------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- #define SPEED_SAMPLING_TIME 9 // (9+1)*500usec = 10msec
- /* Exported functions ------------------------------------------------------- */
- void ENC_Init(void);
- s16 ENC_Get_Electrical_Angle(void);
- void ENC_Clear_Speed_Buffer(void);
- void ENC_Calc_Average_Speed(void);
- void LCD_Display(DisplayType DisplayStatus);
- s16 ENC_Get_Speed(void);
- void TIM3_IRQHandler(void);;
- #endif /*__STM32F10x_ENCODER_H*/
- /******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
我的问题是:
1.定时器初始化的时候
TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;
ICx_FILTER宏定义为6,这里为什么要定义成6?
查看stm32不完全手册
这里是输入捕获的数字滤波器的分频,是fdts的四分之一,并且6个事件有一次触发,这和编码器有什么关系,我定义成别的有关系吗?
2.ENC_Get_Electrical_Angle()函数里面为什么这样计算,小弟不太理解
这里main好多东西感觉宏定义漏掉了
例如 这个函数里的U32_MAX从别的地方知道,应该就是32位无符号数的最大值,就是2^32-1
3.ENC_Calc_Rot_Speed()函数里的down-counting和up-counting之后计算的wDelta_angle方法,为什么要这样计算?一个是加,一个是减。
4.ENC_Calc_Rot_Speed()里用到的SPEED_SAMPLING_FREQ,在前面有宏定义
#define SPEED_SAMPLING_FREQ (u16)(2000/(SPEED_SAMPLING_TIME+1))
SPEED_SAMPLING_TIME在头文件里有宏定义,是9
这两个宏定义,一个sample time,一个 sample frequency是什么意思?
这些地方小弟不太明白,还望大神们指点。
PS 有大神知道像这种官方的历程应该怎么找吗?在ST官网找不到,在网上论坛有人说是在stmcu.org,我去搜了下,也没有找到。目前这些代码都是百度搜出来的,有大神知道还望告知!
谢谢各位了!