STM32f4日記5之AB相編碼器測速實驗(TIM定時器的編碼器模式使用)
板子:stm32f407zgt6正點原子迷你版
電機引數:減速比 1:90
線數:1170(13乘以90)
//
鑒于目前網上的教學形態各異,很多帶有迷惑、誤導性質,所以寫這篇文章交流自己的看法,也權當紀錄自己的學習經歷,
//
如果你覺得對你有幫助,請點贊同,這對我很重要,謝謝,
//
一、器材介紹
準備:1.L298N,
2.帶AB相編碼器的電機,
3.給L298N供電的電源(建議保持電壓為12V,博主以前用的供電5.6V左右,pwm波輸出很離譜的頻率100hz電機轉的超快)(可以網購12v的電源配接器,大概4~5元左右,把頭子切掉,扒開黑膠套,里面白線負極,紅線正極,插市電就可以用,但請注意用電安全)
4.杜邦線連接(L298N的介紹可以參考我的STM32日記3之diy小車實驗(小車實驗一:驅動小車轉圈,直走,倒走))
明確:一般L298N輸入10khzPWM波,電機功率達到最大
主要器材介紹:
1、電機
最簡單判斷電機好壞的判斷方式就是拿6V左右的電池組加在它兩邊,看會不會轉,(電壓太大會燒掉)

2、AB相編碼器
網上介紹如下:
編碼器分為光電和霍爾編碼器是一種將角位移或者角速度轉換成一連串電數字脈沖的旋轉式傳感器,我們可以通過編碼器測量到位移或者速度資訊,
編碼器從輸出資料型別上分,可以分為增量式編碼器和絕對式編碼器,
從編碼器檢測原理上來分,還可以分為光學式、磁式、感應式、電容式,常見的是光電編碼器(光學式)和霍爾編碼器(磁式),兩種(以下介紹為復制內容):
光電編碼器是一種通過光電轉換將輸出軸上的機械幾何位移量轉換成脈沖或數字量的傳感器,
光電編碼器是由光碼盤和光電檢測裝置組成,光碼盤是在一 定直徑的圓板上等分地開通若干個長方形孔,由于光電碼盤與電動機同軸,電動機旋轉時,檢測裝置檢測輸出若干脈沖信號,為判斷轉向,一般輸出兩組存在一 定相位差的方波信號,
霍爾編碼器是一種通過磁電轉換將輸出軸上的機械幾何位移量轉換成脈沖或數字量的傳感器,
霍爾編碼器是由霍爾碼盤和霍爾元件組成,霍爾碼盤是在一 定直徑的圓板上等分地布置有不同的磁極,霍爾碼盤與電動機同軸,電動機旋轉時,霍爾元件檢測輸出若干脈沖信號,為判斷轉向,一般輸出兩組存在一定相位差的方波信號,

二、硬體連接
我在做這個實驗的時候只使用的L298N的右邊一端的out口
1.將L298N的OUT口分別接到電機編碼器的M+,M-
2.L298N的ENB接pwm的輸出口PF8
3.L298N的兩個IN3,IN4接PF2跟PF6
4.單片機跟L298N共地
5.編碼器跟單片機共地
6.編碼器5V接單片機5V
7.編碼器A,B相接單片機的TIM4的CH1跟CH2就是PD12,PD13
三、核心模塊TIM定時器編碼器模式講解
參考STM32f4中文參考手冊
編碼器模式的好處:




編碼器模式是TIM自帶的對編碼處理的一種特殊的輸入捕獲模式
好處很直接:

1.當編碼器出現抖動,它能夠防止抖動,不影響計數,并且它可以采用四倍頻的方法,使得誤差減小4倍,
2.能通過檢測TIMx_CR1的第四位DIR來判斷電機的轉動方向:正轉還是反轉,這功能很強

3.重要備注:當定時器檢測到一個正向脈沖計數值**+1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!**這很重要劃重點
所以我們并不能知道檢測一個脈沖用了多少時間,所以還要再開一個定時器,
網上搜到的配置STM32F1編碼器模式的方法不適用于F4
四、代碼撰寫
思路:TIM13用來提供10khzPWM波跟占空比
TIM4配置編碼器模式來實作對AB相編碼器的處理
鑒于所以我們并不能知道檢測一個脈沖用了多少時間,所以還要再開一個定時器TIM5
配置TIM4代碼如下
void Encoder_Init_TIM4(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);
TIM_TimeBaseStructure.TIM_Period = arr;
TIM_TimeBaseStructure.TIM_Prescaler=psc;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter =0;
TIM_ICInit(TIM4,&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter=0;
TIM_ICInit(TIM4,&TIM_ICInitStructure);
TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising );
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x02;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM4,ENABLE);
}
最難配置的已經告訴大家了
最重要的是這個函式TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising );
配置的編碼器模式,具體模式為TIM_EncoderMode_TI12
其它timer.h里代碼如下
void TIM5_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=arr;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM5,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)
{
Encoder_Timer_Overflow++;
}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
u32 Read_Encoder(void)
{
u32 Count;
u16 Current_Count;
u16 Enc_Timer_Overflow_one;
Enc_Timer_Overflow_one=Encoder_Timer_Overflow;
Current_Count = TIM_GetCounter(TIM4);
Encoder_Timer_Overflow=0;
if((TIM4->CR1&0x0010) == 0x0010)
Count = (u32)((-1*Enc_Timer_Overflow_one)*(4*ENCODER_PPR-4) + (Current_Count - Previous_Count));
else
Count = (u32)(Current_Count - Previous_Count + (Enc_Timer_Overflow_one) * (4*ENCODER_PPR-4));
Previous_Count = Current_Count;
return(Count);
}
這里面
if((TIM4->CR1&0x0010) == 0x0010)
Count = (u32)((-1Enc_Timer_Overflow_one)(4*ENCODER_PPR-4) + (Current_Count - Previous_Count));
else
Count = (u32)(Current_Count - Previous_Count + (Enc_Timer_Overflow_one) * (4乘以ENCODER_PPR-4));
用來得到脈沖的數量并通過DIR位來判斷給不給脈沖數量加正負號
主函式代碼如下
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "pwm.h"
#include "gpio.h"
#include "math.h"
#include "stdio.h"
#include "control.h"
int encode;
float speed,t;
extern int Encoder_Timer_Overflow;
u8 key;
int duty=50;
void keyscan(void);
int main(void)
{
delay_init(168);
uart_init(115200);
KEY_Init();
_GPIO_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
TIM13_PWM_Init(8400-1,0); // 84mhz->10khz
TIM_SetCompare1(TIM13,(int)(8400*(duty/100.0)));
Encoder_Init_TIM4((ENCODER_PPR-1)*4,1-1);
TIM5_Int_Init(500-1,8400-1);
while(1)
{
keyscan();
delay_ms(200);
}
}
void keyscan(void)
{
key=KEY_Scan(0);
if(key)
{
switch(key)
{
case WKUP_PRES:
GPIO_ToggleBits(GPIOF,GPIO_Pin_6);
GPIO_ToggleBits(GPIOF,GPIO_Pin_4);
break;
case KEY0_PRES:
duty+=5;
if(duty>100)duty=0;
TIM_SetCompare1(TIM13,8400*(duty/100.0));
break;
}
}
}
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
{
encode=Read_Encoder();
printf("編碼器脈沖為:%d\r\n",encode);
speed=(float)(encode*1.0/(13*90*0.05));
printf("電機轉速為:%.4f\r\n",speed);
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update);
}
***效果如下:***
我用的串口除錯助手是vofa+強烈安利這一款,
五、思考
1.在測速的基礎上怎么實作對電機位置的測量
2.對電機速度位置的準確控制(比如使電機轉2圈每秒,轉動60度)
這個要用到PID調速,我們下一期出,
作者:shawn
可咨詢QQ:965798711(要代碼可加QQ)
2021.1.28
22:46
All rights reserved
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/253974.html
標籤:其他
