/******************** (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 "encoder.h"
#include "lcd1602.h"
#include "usart.h"
/* Private variables ---------------------------------------------------------*/
s16 hPrevious_angle, hSpeed_Buffer[SPEED_BUFFER_SIZE], hRot_Speed;
//static s16 hPrevious_angle, hSpeed_Buffer[SPEED_BUFFER_SIZE];
static u8 bSpeed_Buffer_Index = 0;
static volatile u16 hEncoder_Timer_Overflow;
#define TRUE 1
#define FALSE 0
static unsigned char 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_IRQn;
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 //72M捕获?
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)(4294967295 / (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,wtemp_1=0;
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;
for (i=0;i<SPEED_BUFFER_SIZE;i++)
{
if (bSpeed_Buffer_Index == SPEED_BUFFER_SIZE)
{
bSpeed_Buffer_Index = 0;
}
wtemp = ENC_Calc_Rot_Speed();
hSpeed_Buffer[bSpeed_Buffer_Index] = (s16)wtemp;
bSpeed_Buffer_Index++;
wtemp_1 += wtemp;
}
wtemp_1 /= SPEED_BUFFER_SIZE;
hRot_Speed = ((s16)(wtemp_1));
}
/*******************************************************************************
* 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);
// LCD_ShowNum(0,0,(hValue),5);
// printf("%d,",hValue);
// break;
//
// case DISPLAY_THETA:
// Theta = ENC_Get_Electrical_Angle()*360/65535; //U16_MAX;
// if (Theta < 0)
// {
// hValue = (u16)(-Theta);
//// pstr = int2char(hValue);
// *pstr = '-';
// }
// else
// {
// hValue = (u16)Theta;
//// pstr = int2char(hValue);
// if (hValue != 0) *pstr = '+';
// }
// LCD_ShowChar(0,8,*pstr);
// LCD_ShowNum(0,9,hValue,5);
// 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 = '+';
// }
// LCD_ShowChar(0,8,*pstr);
// LCD_ShowNum(1,0,*pstr,5);
// 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 != 65535)
{
hEncoder_Timer_Overflow++;
}
}
//寄存器版本
/******************* (C) COPYRIGHT 2007 STMicroelectronics *****END OF FILE****/
//#include "encoder.h"
//void Encoder_Init(void)
//{
// /* TIM3 clock source enable */
// RCC->APB1ENR|=1<<1; //TIM3时钟使能
// /* Enable GPIOA, clock */
// RCC->APB2ENR|=1<<2; //使能PORTA时钟
// /* Configure PA.06,07 as encoder input */
// GPIOA->CRL&=0XF0FFFFFF;//PA6
// GPIOA->CRL|=0X04000000;//浮空输入
// GPIOA->CRL&=0X0FFFFFFF;//PA7
// GPIOA->CRL|=0X40000000;//浮空输入
// /* Enable the TIM3 Update Interrupt */
// //这两个东东要同时设置才可以使用中断
// TIM3->DIER|=1<<0; //允许更新中断
// TIM3->DIER|=1<<6; //允许触发中断
// MY_NVIC_Init(1,3,TIM3_IRQChannel,2);
// /* Timer configuration in Encoder mode */
// TIM3->PSC = 0x0;//预分频器
// TIM3->ARR = ENCODER_TIM_PERIOD-1;//设定计数器自动重装值
// TIM3->CR1 &=~(3<<8);// 选择时钟分频:不分频
// TIM3->CR1 &=~(3<<5);// 选择计数模式:边沿对齐模式
//
// TIM3->CCMR1 |= 1<<0; //CC1S='01' IC1FP1映射到TI1
// TIM3->CCMR1 |= 1<<8; //CC2S='01' IC2FP2映射到TI2
// TIM3->CCER &= ~(1<<1); //CC1P='0' IC1FP1不反相,IC1FP1=TI1
// TIM3->CCER &= ~(1<<5); //CC2P='0' IC2FP2不反相,IC2FP2=TI2
// TIM3->CCMR1 |= 3<<4; // IC1F='1000' 输入捕获1滤波器
// TIM3->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
// TIM3->CNT = COUNTER_RESET;
// TIM3->CR1 |= 0x01; //CEN=1,使能定时器
//}