论坛元老
 
- 积分
- 3347
- 金钱
- 3347
- 注册时间
- 2013-4-10
- 在线时间
- 333 小时
|
发表于 2016-5-19 02:12:27
|
显示全部楼层
本帖最后由 likunxue 于 2016-5-19 02:27 编辑
兄弟, 作两个定时器来完成, 比如定时器3设成编码器模式, 用于计数 另一个定时器设成10MS中断一次, 每次中断读取 定时器3的计数值, 从计数值中算出电机当前速度就行了
速度 = (中断频率 * 60 * 脉冲个数 ) / 编码器的线数 ;
如果编码器模式设成4倍频, 哪就要用线数*4
你这个电机好像是 448线的, 4倍频后 是 1792
#define ENCODER_PERIOD (u16)40000 //编码器溢出重装值
#define COUNTER_RESET 0u //编码器初值
#define CONSTER_BYTE (s32)(CONSTER_DAT + TIM3->CNT) //当前转子机械坐标
typedef struct
{
vs32 OLD_Byte; //采样前编码器的值
vu16 SuDu; //当前速度
vu16 JIASUDU; //加速度
vu16 LeiJiaQi; //累加器
vu16 Buf[10]; //速度滤波队列数据缓存区
vu8 front; //速度滤波处理队列指针
}DIANJISUDU;
DIANJISUDU SUDU;
/*******************************************************************************************
函 数 名: 定时器3编码器模式初始化函数
调 用: TIM3_BMQMS_Init(u8 remap)
参 数: reamap 复用功能重映像 00,01,11 如果参数错误,则采用00参数
反 回 值: 无
说 明: 初始化编码器的AB信号接于 CH1,CH2上 四倍频输出
********************************************************************************************/
void TIM3_BMQMS_Init(u8 remap)
{
switch(remap)//IO接器重映像处理
{
case 2: { //TM3_REMAP[1,0] = 10
RCC->APB2ENR |= 1<< 0; //开启辅助功能时钟
BIT_ADM(AFIO->MAPR,11) = 1; //高电平
BIT_ADM(AFIO->MAPR,10) = 0; //高电平
RCC->APB2ENR |= 1<<3; //使能PORTB时钟
GPIOB->CRL &= 0xFF00FFFF; //PB4,PB5
GPIOB->CRL |= 0x00440000; //浮空输入
}break;
case 3: {//TM3_REMAP[1,0] = 11
RCC->APB2ENR |= 1<< 0; //开启辅助功能时钟
BIT_ADM(AFIO->MAPR,11) = 1; //高电平
BIT_ADM(AFIO->MAPR,10) = 1; //高电平
RCC->APB2ENR |= 1<<4; //使能PORTC时钟
GPIOC->CRL &= 0x00FFFFFF; //PC6,PC7
GPIOC->CRL |= 0x44000000; //浮空输入
}break;
default:{////TM3_REMAP[1,0] = 00
RCC->APB2ENR |= 1<<2; //使能PORTA时钟
GPIOA->CRL &= 0x00FFFFFF; //PA6,PA7
GPIOA->CRL |= 0x44000000; //浮空输入
}break;
}
BIT_ADM(RCC->APB1ENR,1) = 1; //TIM3时钟使能
BIT_ADM(RCC->APB1RSTR,1) = 1; //复位TIM3定时器,使之进入初始状态
BIT_ADM(RCC->APB1RSTR,1) = 0; //结束复位
TIM3->ARR = ENCODER_PERIOD-1; //设定计数器自动重装值
TIM3->PSC = 0; //预分频器,不分频
BIT_ADM(TIM3->CR1,7) = 1; //定时器ARPE充许
BIT_ADM(TIM3->CR1, 8) = 0; //选择时钟分频:不分频(在输入捕获中止参数无效)
BIT_ADM(TIM3->CR1, 9) = 0;
BIT_ADM(TIM3->CR1, 5) = 0; //选择计数模式:边沿对齐模式
BIT_ADM(TIM3->CR1, 6) = 0;
BIT_ADM(TIM3->CR1, 4) = 0; //计数器向上计数
BIT_ADM(TIM3->CCMR1,8) = 1; //CC2S='01' IC2FP2映射到TI2
BIT_ADM(TIM3->CCMR1,9) = 0;
BIT_ADM(TIM3->CCMR1,0) = 1; //CC1S='01' IC1FP1映射到TI1
BIT_ADM(TIM3->CCMR1,1) = 0;
BIT_ADM(TIM3->CCER ,1) = 0; //CC1P='0'IC1FP1不反相,IC1FP1=TI1
BIT_ADM(TIM3->CCER ,5) = 0; //CC2P='0'IC2FP2不反相,IC2FP2=TI2
//输入捕获1滤波器
BIT_ADM(TIM3->CCMR1,4) = 0; //IC1F='1000'(可能影响采集响应速度)
BIT_ADM(TIM3->CCMR1,5) = 1;
BIT_ADM(TIM3->CCMR1,6) = 0;
BIT_ADM(TIM3->CCMR1,7) = 0;
//编码器模式3 (四倍频的输出)
BIT_ADM(TIM3->SMCR, 0) = 1; //SMS='011' 所有的输入均在上升沿和下降沿有效
BIT_ADM(TIM3->SMCR, 1) = 1;
BIT_ADM(TIM3->SMCR, 2) = 0;
SHURUMAICHONG = COUNTER_RESET; //清外部输入脉冲计数器为零
TIM3->CNT = COUNTER_RESET; //计数器的初值
CONSTER_DAT = COUNTER_RESET; //清零中断计数累加器的值为初始值
BIT_ADM(TIM3->DIER, 0) = 1; //允许定时器更新中断
MY_NVIC_Init(0,0,TIM3_IRQn,4); //抢占0,子优先级0,组4 设定时器3更新中断为最高级别中断
BIT_ADM(TIM3->CR1,0) = 1; //开编码器
}
/*******************************************************************************************
函 数 名: 定时器3中断函数
调 用: 无
参 数: 无
反 回 值: 无(这里在编码器模式中CPU唯于需要处理的函数)
*******************************************************************************************/
void TIM3_IRQHandler(void)
{
if(BIT_ADM(TIM3->SR,0) == 1) //溢出中断
{
BIT_ADM(TIM3->SR,0) = 0; //清除中断标志位
if(BIT_ADM(TIM3->CR1,4) == 1)CONSTER_DAT -= ENCODER_PERIOD;
else{
CONSTER_DAT += ENCODER_PERIOD;
}
}
}
别一个定时器的中断处理函数内部代码如下!! 这里使用了滑动滤波与一阶滤波, 计算的速度值在 SUDU.SuDu 中
s32 Dat;
u16 Error,Byte;
u8 ptr = SUDU.front&0x07; //得到当前要处理队列位置指针
Dat = CONSTER_BYTE; //取当前编码器的值
Error = CDSK_ABS(Dat,SUDU.OLD_Byte); //计算脉冲个数
SUDU.JIASUDU = (int)SUDU.SuDu - Error; //加速度
SUDU.OLD_Byte = Dat; //更新比较差值
Byte = SUDU.Buf[ptr]; //旧数据出队
SUDU.Buf[ptr] = Error; //新数据入队
SUDU.LeiJiaQi += Error; //累加新值
SUDU.LeiJiaQi -= Byte; //减去出队数据
SUDU.front ++; //指针加1
Byte = SUDU.LeiJiaQi>>3; //得到均值
if(Byte < SUDU.SuDu) //如果新采样值小于前次采样值
{
Error = (((SUDU.SuDu - Byte)<<7)+128)>>8; //+128是为了四舍五入
SUDU.SuDu -= Error;
}
else{
if(Byte > SUDU.SuDu) //如果新采样值大于前次采样值
{
Error = (((Byte - SUDU.SuDu)<<7)+128)>>8;//+128是为了四舍五入
SUDU.SuDu += Error;
}
}
*******************************************************/
主函数中读取速度的方法 以上假若窗口读取定时器设为 10ms 中断一次, 10MS = 100HZ,
100 *60 = 6000;
TD = 6000*SUDU.SuDu/1792; //每分钟多少转
|
|