📄 stm32f10x_encoder.c
字号:
/*******************************************************************************
* 文件名 : stm32f10x_encoder.c
* 功能描述 : 编码器实现程序
*******************************************************************************/
/* 头文件 */
#include "stm32f10x.h"
#include "stm32f10x_encoder.h"
#include "stm32f10x_it.h"
#include "MC_Globals.h"
#include "stm32f10x_MClib.h"
#define COUNTER_RESET (u16) ((((s32)(ALIGNMENT_ANGLE)*4*ENCODER_PPR/360)\
-1)/POLE_PAIR_NUM)
#define ICx_FILTER (u8) 8 // 8<-> 670nsec
#define SPEED_SAMPLING_FREQ (u16)(2000/(SPEED_SAMPLING_TIME+1))
#define TIMx_PRE_EMPTION_PRIORITY 2
#define TIMx_SUB_PRIORITY 0
#define SPEED_SAMPLING_TIME PID_SPEED_SAMPLING_TIME
// To avoid obvious initialization errors...
#if ( (defined(TIMER2_HANDLES_ENCODER) && defined(TIMER3_HANDLES_ENCODER)) \
|| (defined(TIMER2_HANDLES_ENCODER) && defined(TIMER4_HANDLES_ENCODER)) \
|| (defined(TIMER3_HANDLES_ENCODER) && defined(TIMER4_HANDLES_ENCODER)))
#error "Invalid encoder setup: 2 timers selected"
#endif
#ifdef ENCODER
// 编码器未连接提示信息
#ifndef TIMER2_HANDLES_ENCODER
#ifndef TIMER3_HANDLES_ENCODER
#ifndef TIMER4_HANDLES_ENCODER
#warning "Encoder not selected"
#endif
#endif
#endif
#endif // ENCODER
/* 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; //该变量指示UPDATE中断发生的个数,也就是说
//ENC每转一圈,CPU得到 4* PPR个脉冲,中断发生一次
//该变量+1.
static bool bIs_First_Measurement = TRUE;
static bool bError_Speed_Measurement = FALSE;
/*******************************************************************************
* 函数名 : ENC_Init
* 功能描述 : 通用定时器设置->编码器速度/位置感应.
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void ENC_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
#if defined(TIMER2_HANDLES_ENCODER) // 连接到TIM2, 4X模式
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* TIM2时钟使能 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA时钟使能 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
/* 配置PA00,01作为编码器输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 使能TIM2更新中断*/
NVIC_InitStructure.NVIC_IRQChannel = TIM2_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);
#elif defined(TIMER3_HANDLES_ENCODER) // 编码器连接TIM3, 4X 模式
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能TIM3时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
/* 使能GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
/* 配置PA06,07作为编码器输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 使能TIM3 更新中断 */
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);
#elif defined(TIMER4_HANDLES_ENCODER) // 编码器连接到TIM4, 4X 模式
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* 使能TIM4 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* 使能GPIOA*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
/* 配置PB06,07编码器输入 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* 使能TIM4 更新中断 */
NVIC_InitStructure.NVIC_IRQChannel = TIM4_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);
#endif
/* 定时器配置成编码模式 */
TIM_DeInit(ENCODER_TIMER);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
/* No prescaling ,可以改变编码器计数对于脉冲输入个数的倍数*/
TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
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);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);
/*清除所有挂起中断*/
TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);
/*复位计数器*/
ENCODER_TIMER->CNT = COUNTER_RESET;
TIM_Cmd(ENCODER_TIMER, ENABLE);
}
/*******************************************************************************
* 函数名 : ENC_Get_Electrical_Angle
* 功能描述 : 返回转子电角度
* Input : 无
* 输出 : 无
* 返回 : 转子电角度: 0 -> 0 度,
* S16_MAX-> 180 度,
* S16_MIN-> -180 度
*******************************************************************************/
s16 ENC_Get_Electrical_Angle(void)
{
s32 temp;
temp = (s32)(TIM_GetCounter(ENCODER_TIMER)) * (s32)(U32_MAX / (4*ENCODER_PPR));
temp *= POLE_PAIR_NUM;
return((s16)(temp/65536)); // s16结果值
}
/*******************************************************************************
* 函数名 : ENC_Get_Mechanical_Angle
* 功能描述 : 返回转子机械角度
* 输入 : 无
* 输出 : 无
* 返回 : 转子机械角度: 0 -> 0 度,
* S16_MAX-> 180 度,
* S16_MIN-> -180 度
*******************************************************************************/
s16 ENC_Get_Mechanical_Angle(void)
{
s32 temp;
temp = (s32)(TIM_GetCounter(ENCODER_TIMER)) * (s32)(U32_MAX / (4*ENCODER_PPR)) ;
return((s16)(temp/65536)); // s16 result
}
/*******************************************************************************
* 函数名 : ENC_ResetEncoder
* 功能描述 : 写编码器计数器值
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void ENC_ResetEncoder(void)
{
//Reset counter
TIM2->CNT = COUNTER_RESET;
}
/*******************************************************************************
* 函数名 : ENC_Clear_Speed_Buffer
* 功能描述 : 清速度缓存区
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void ENC_Clear_Speed_Buffer(void)
{
u32 i;
for (i=0;i<SPEED_BUFFER_SIZE;i++)
{
hSpeed_Buffer[i] = 0;
}
bIs_First_Measurement = TRUE;
}
/*******************************************************************************
* 函数名 : ENC_Calc_Rot_Speed
* 功能描述 : 返回最后速度测量值
* 输入 : 无
* 输出 : s16
* 返回 :
*******************************************************************************/
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -