目錄
?前言
一、pwm輸出讓電機(jī)轉(zhuǎn)?
1.電機(jī)的接線說(shuō)明
2.驅(qū)動(dòng)的接線說(shuō)明
3.pwm輸出代碼
?pwm.c
pwm.h
4.輸出pwm控制電機(jī)旋轉(zhuǎn)
二、配置定時(shí)器編碼器模式
1.定時(shí)器編碼器模式
編碼器原理
編碼器相關(guān)的概念
2.編碼器模式——代碼部分
3.獲取脈沖數(shù)
三、定時(shí)讀取編碼器讀取的脈沖數(shù)
四、計(jì)算速度(本篇最重要部分)
1.速度計(jì)算原理
2. 速度計(jì)算代碼
?前言
正文之前先介紹一下我使用的主控芯片、電機(jī)以及驅(qū)動(dòng)。
主控芯片是STM32F103C8T6(這個(gè)芯片比較普遍、便宜,這款芯片使用熟練之后,我的建議是轉(zhuǎn)到CH32V307VCT6);
這里我還想在說(shuō)一點(diǎn)就是C8T6內(nèi)的定時(shí)器只有4個(gè)(TIM1、TIM2、TIM3、TIM4),資源比較少。
電機(jī)是JGB37-520霍爾編碼器直流減速電機(jī)(DC:12V)(530rpm);
磁環(huán)轉(zhuǎn)一圈是11個(gè)脈沖(即11線);
電機(jī)的減速比為19;
驅(qū)動(dòng)是TB6612FNG(這種驅(qū)動(dòng)比較穩(wěn)定,但是特別容易燒,注意一定不要接錯(cuò)線)
一、pwm輸出讓電機(jī)轉(zhuǎn)?
1.電機(jī)的接線說(shuō)明
電機(jī)電源線(紅線和白線)接AO1、AO2(或者BO1、BO2);
編碼器電源線(黑線和藍(lán)線)接地和5V,一定不要接錯(cuò),不然電機(jī)上的編碼器會(huì)出問(wèn)題;
編碼器信號(hào)線(黃線和綠線)接定時(shí)器編碼器接口;
2.驅(qū)動(dòng)的接線說(shuō)明
PWMA接PA0;PWMB接PA1;
AIN1、AIN2、BIN1、BIN2接單片機(jī)IO口;
STBY接5V;VM接12V;VCC接5V;
AO1、AO2、BO1、BO2接電機(jī)電源線(兩輪);
電機(jī)和驅(qū)動(dòng)的具體接線原理圖如下:
?
?
提醒:
1.電機(jī)電源線接線問(wèn)題:正接反接影響的是輪子的正轉(zhuǎn)反轉(zhuǎn)(自己可以按照實(shí)測(cè)一下);
2.編碼器信號(hào)線接線問(wèn)題:正接反接影響的是脈沖數(shù)的讀取的正負(fù)(畫(huà)板子的時(shí)候自己得重點(diǎn)注意);
3.pwm輸出代碼
?使用#define,可以方便我們修改IO口。
-
?pwm.c
#include "pwm.h"
void AIN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//AIN1
RCC_APB2PeriphClockCmd(AIN1_GPIO_CLK,ENABLE); //開(kāi)啟時(shí)鐘
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //50MHz
GPIO_InitStruct.GPIO_Pin = AIN1_GPIO_PIN;
GPIO_Init(AIN1_GPIO_PORT ,&GPIO_InitStruct);
GPIO_SetBits(AIN1_GPIO_PORT,GPIO_Pin_All); //初始化
//AIN2
RCC_APB2PeriphClockCmd(AIN2_GPIO_CLK,ENABLE);
GPIO_InitStruct.GPIO_Pin = AIN2_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(AIN2_GPIO_PORT ,&GPIO_InitStruct);
GPIO_SetBits(AIN2_GPIO_PORT,GPIO_Pin_All);
//BIN1
RCC_APB2PeriphClockCmd(BIN1_GPIO_CLK,ENABLE);
GPIO_InitStruct.GPIO_Pin = BIN1_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BIN1_GPIO_PORT ,&GPIO_InitStruct);
GPIO_SetBits(BIN1_GPIO_PORT,GPIO_Pin_All);
//BIN2
RCC_APB2PeriphClockCmd(BIN2_GPIO_CLK,ENABLE);
GPIO_InitStruct.GPIO_Pin = BIN2_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(BIN2_GPIO_PORT ,&GPIO_InitStruct);
GPIO_SetBits(BIN2_GPIO_PORT,GPIO_Pin_All);
}
static void GENERAL_TIM_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
//輸出比較通道1GPIO初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH1_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);
//輸出比較通道2GPIO初始化
RCC_APB2PeriphClockCmd(GENERAL_TIM_CH2_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = GENERAL_TIM_CH2_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GENERAL_TIM_CH2_PORT, &GPIO_InitStructure);
}
static void GENERAL_TIM_Mode_Config(void)
{
// 開(kāi)啟定時(shí)器時(shí)鐘,即內(nèi)部時(shí)鐘CK_INT=72M
GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);
/*--------------------時(shí)基結(jié)構(gòu)體初始化-------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 自動(dòng)重裝載寄存器的值,累計(jì)TIM_Period+1個(gè)頻率后產(chǎn)生一個(gè)更新或者中斷
TIM_TimeBaseStructure.TIM_Period = GENERAL_TIM_PERIOD;
// 驅(qū)動(dòng)CNT計(jì)數(shù)器的時(shí)鐘 = Fck_int/(psc+1)
TIM_TimeBaseStructure.TIM_Prescaler = GENERAL_TIM_PSC;
// 初始化定時(shí)器
TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);
/*--------------------輸出比較結(jié)構(gòu)體初始化-------------------*/
TIM_OCInitTypeDef TIM_OCInitStructure;
// 配置為PWM模式1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
// 輸出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 輸出通道電平極性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
// 設(shè)置占空比大小GENERAL_TIM_CH1_PULSE=2000
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CH1_PULSE;
TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 設(shè)置占空比大小GENERAL_TIM_CH2_PULSE=4000
TIM_OCInitStructure.TIM_Pulse = GENERAL_TIM_CH2_PULSE;
TIM_OC2Init(GENERAL_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);
// 使能計(jì)數(shù)器
TIM_Cmd(GENERAL_TIM, ENABLE);
}
void GENERAL_TIM_Init(void)
{
GENERAL_TIM_Mode_Config();
GENERAL_TIM_GPIO_Config();
}
/*正負(fù)表示正轉(zhuǎn)和反轉(zhuǎn),0表示停止
PERIOD = 8000-1固定
*/
void GENERAL_TIM_Change_PULSE(int lun, int direction, int input_PULSE)
{
int PULSE = (GENERAL_TIM_PERIOD + 1) * input_PULSE / 100;//input_PULSE設(shè)置為最高為100
if(lun == 1)
{
// TIM_SetCompare1(TIM2, input_PULSE);
GENERAL_TIM->CCR1 = PULSE;
if(direction == 0)//停止
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_RESET);
}
else if(direction == 1)//正轉(zhuǎn)
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_SET);
}
else if(direction == -1)//反轉(zhuǎn)
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_SET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_RESET);
}
}
if(lun == 2)
{
// TIM_SetCompare2(TIM2, input_PULSE);
GENERAL_TIM->CCR2 = PULSE;
if(direction == 0)//停止
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_RESET);
}
else if(direction == 1)//正轉(zhuǎn)
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_SET);
}
else if(direction == -1)//反轉(zhuǎn)
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_SET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_RESET);
}
}
}
-
pwm.h
#ifndef _PWM_H
#define _PWM_H
#include "stm32f10x.h"
// 這里我們使用通用定時(shí)器TIM2
#define GENERAL_TIM TIM2
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM2
// PWM 信號(hào)的頻率 F = TIM_CLK/{(ARR+1)*(PSC+1)}
// 占空比是 PULSE / (PERIOD+1)
#define GENERAL_TIM_PERIOD (8000-1)
#define GENERAL_TIM_PSC (9-1)
#define GENERAL_TIM_CH1_PULSE 2000
#define GENERAL_TIM_CH2_PULSE 4000
#define GENERAL_TIM_IRQ TIM2_UP_IRQn
#define GENERAL_TIM_IRQHandler TIM2_UP_IRQHandler
//輸出通道1
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_0
//輸出通道2
#define GENERAL_TIM_CH2_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH2_PORT GPIOA
#define GENERAL_TIM_CH2_PIN GPIO_Pin_1
//對(duì)PA0初始化---AIN1
#define AIN1_GPIO_CLK RCC_APB2Periph_GPIOB
#define AIN1_GPIO_PORT GPIOB
#define AIN1_GPIO_PIN GPIO_Pin_14
//對(duì)PA1初始化---AIN2
#define AIN2_GPIO_CLK RCC_APB2Periph_GPIOB
#define AIN2_GPIO_PORT GPIOB
#define AIN2_GPIO_PIN GPIO_Pin_15
//對(duì)PB0初始化---BIN1
#define BIN1_GPIO_CLK RCC_APB2Periph_GPIOB
#define BIN1_GPIO_PORT GPIOB
#define BIN1_GPIO_PIN GPIO_Pin_13
//對(duì)PB1初始化---BIN2
#define BIN2_GPIO_CLK RCC_APB2Periph_GPIOB
#define BIN2_GPIO_PORT GPIOB
#define BIN2_GPIO_PIN GPIO_Pin_12
void AIN_GPIO_Config(void);
void GENERAL_TIM_Init(void);
void GENERAL_TIM_Change_PULSE(int lun, int direction, int input_PULSE);
#endif
4.輸出pwm控制電機(jī)旋轉(zhuǎn)
?這里把控制電機(jī)旋轉(zhuǎn)的函數(shù)提取出來(lái),讓大家看得更明白。
void GENERAL_TIM_Change_PULSE(int lun, int direction, int input_PULSE)
{
int PULSE = (GENERAL_TIM_PERIOD + 1) * input_PULSE / 100;//input_PULSE設(shè)置為最高為100
if(lun == 1)
{
// TIM_SetCompare1(TIM2, input_PULSE);
GENERAL_TIM->CCR1 = PULSE;
if(direction == 0)//停止
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_RESET);
}
else if(direction == 1)//正轉(zhuǎn)
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_SET);
}
else if(direction == -1)//反轉(zhuǎn)
{
GPIO_WriteBit(AIN1_GPIO_PORT,AIN1_GPIO_PIN,Bit_SET);
GPIO_WriteBit(AIN2_GPIO_PORT,AIN2_GPIO_PIN,Bit_RESET);
}
}
if(lun == 2)
{
// TIM_SetCompare2(TIM2, input_PULSE);
GENERAL_TIM->CCR2 = PULSE;
if(direction == 0)//停止
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_RESET);
}
else if(direction == 1)//正轉(zhuǎn)
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_RESET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_SET);
}
else if(direction == -1)//反轉(zhuǎn)
{
GPIO_WriteBit(BIN1_GPIO_PORT,BIN1_GPIO_PIN,Bit_SET);
GPIO_WriteBit(BIN2_GPIO_PORT,BIN2_GPIO_PIN,Bit_RESET);
}
}
}
在這個(gè)函數(shù)中設(shè)定了三個(gè)參數(shù),分別是電機(jī)(A或B)、旋轉(zhuǎn)方向(正轉(zhuǎn)反轉(zhuǎn)停止)、占空比(以百分比的形式);
可以先下面代碼中這樣使用:
GENERAL_TIM_Change_PULSE(1, 1, 25);
GENERAL_TIM_Change_PULSE(2, -1, 35);
二、配置定時(shí)器編碼器模式
這里先介紹一下定時(shí)器編碼器模式
1.定時(shí)器編碼器模式
編碼器原理
????????如果倆個(gè)相位差為90度,這倆個(gè)信號(hào)稱(chēng)為正交。由于倆個(gè)信號(hào)相差90度,可以根據(jù)倆個(gè)信號(hào)那個(gè)先那個(gè)后判斷方向,根據(jù)編碼器的脈沖數(shù)量及編碼輪的周長(zhǎng)可以算出行駛的距離。加上一個(gè)定時(shí)器去計(jì)數(shù)單位時(shí)間內(nèi)采集到的編碼脈沖數(shù)量就可以算出電機(jī)的速度。
編碼器相關(guān)的概念
1.分辨率:編碼器的軸每轉(zhuǎn)一圈所輸出的脈沖數(shù)。編碼器以每旋轉(zhuǎn)360度提供多少的通或暗刻線稱(chēng)為分辨率,也稱(chēng)解析分度、或直接稱(chēng)多少線,一般在每轉(zhuǎn)分度5~10000線。
2.最大響應(yīng)頻率:編碼器在1秒鐘內(nèi)能響應(yīng)的最大脈沖數(shù)。其公式為: 最高響應(yīng)頻率(Hz) = ?編碼器分辨率 × 軸的轉(zhuǎn)速(r/min)/60 ?另稱(chēng)PPS
3.最大轉(zhuǎn)速:是指編碼器機(jī)械系統(tǒng)能夠承受的最高轉(zhuǎn)速。
4.絕對(duì)編碼器信號(hào)傳輸方式:并行、串行輸出或總線型輸出。輸出電路與增量編碼器相似,有集電極開(kāi)路PNP、NPN型、差分驅(qū)動(dòng)、推挽式。
2.編碼器模式——代碼部分
?兩個(gè)霍爾編碼器于是就使用了兩個(gè)定時(shí)器(TIM3和TIM4)
/*下面是編譯器配置函數(shù)*/
//編碼器1初始化函數(shù)
void Encoder_TIM3_Init(void)
{
//結(jié)構(gòu)體定義
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStructure;
//時(shí)鐘配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE); // 開(kāi)啟定時(shí)器3時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE); // 開(kāi)啟GPIO時(shí)鐘
//GPIO配置
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空輸入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 編碼器1:PA0/PA1
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA ,&GPIO_InitStruct);
//定時(shí)器配置
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 不分頻
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period = 65535;
//重裝載值65535
TIM_TimeBaseInitStruct.TIM_Prescaler = 0;
//分頻系數(shù)0(自動(dòng)加1)
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//編碼器配置:定時(shí)器3,模式3,上升沿
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
//輸入捕獲配置
TIM_ICStructInit(&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_ICFilter = 10; //濾波器設(shè)置為10
TIM_ICInit(TIM3,&TIM_ICInitStruct);
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定時(shí)器3中斷分組配置
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //搶占優(yōu)先級(jí)1
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x02; //響應(yīng)優(yōu)先級(jí)2
NVIC_Init(&NVIC_InitStructure); //配置定時(shí)器3
//清除定時(shí)器溢出更新標(biāo)志位(清除計(jì)數(shù)值)
TIM_ClearFlag(TIM3,TIM_FLAG_Update);
//定時(shí)器3,溢出更新,使能
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
//定時(shí)數(shù)據(jù)清零(輸入捕獲的值從0開(kāi)始計(jì)數(shù))
TIM_SetCounter(TIM3,0);
//定時(shí)器3使能
TIM_Cmd(TIM3,ENABLE);
}
void Encoder_TIM4_Init(void)
{
//結(jié)構(gòu)體定義
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
NVIC_InitTypeDef NVIC_InitStructure;
//時(shí)鐘配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //開(kāi)啟定時(shí)器4時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //開(kāi)啟GPIO時(shí)鐘
//GPIO配置
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //編碼器2:PB6/PB7
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB ,&GPIO_InitStruct);
//定時(shí)器配置
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 不分頻
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period = 65535; //重裝載值65535
TIM_TimeBaseInitStruct.TIM_Prescaler = 0; //分頻系數(shù)0(自動(dòng)加1)
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
//編碼器配置:定時(shí)器4,模式3,上升沿
TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
//輸入捕獲配置
TIM_ICStructInit(&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_ICFilter = 10; //濾波器設(shè)置為10
TIM_ICInit(TIM4,&TIM_ICInitStruct);
NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; //定時(shí)器4中斷分組配置
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //搶占優(yōu)先級(jí)1
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x03; //響應(yīng)優(yōu)先級(jí)2
NVIC_Init(&NVIC_InitStructure); //配置定時(shí)器4
//清除定時(shí)器溢出更新標(biāo)志位(清除計(jì)數(shù)值)
TIM_ClearFlag(TIM4,TIM_FLAG_Update);
//定時(shí)器4,溢出更新,使能
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
//定時(shí)數(shù)據(jù)清零(輸入捕獲的值從0開(kāi)始計(jì)數(shù))
TIM_SetCounter(TIM4,0);
//定時(shí)器4使能
TIM_Cmd(TIM4,ENABLE);
}
// 定時(shí)器3中斷服務(wù)函數(shù)
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) // 中斷標(biāo)志位置1
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); // 清楚中斷標(biāo)志位
}
}
// 定時(shí)器4中斷服務(wù)函數(shù)
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET) // 中斷標(biāo)志位置1
{
TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 清楚中斷標(biāo)志位
}
}
3.獲取脈沖數(shù)
?配置好定時(shí)器的編碼器模式后并且能夠很好的運(yùn)行,就可以進(jìn)行下一步,來(lái)讀取編碼器的計(jì)數(shù)值。
下面是代碼:
// 編碼器速度讀取函數(shù)
// 入口參數(shù):定時(shí)器
// 編碼器產(chǎn)生的是脈沖,計(jì)數(shù)器計(jì)脈沖數(shù)(位移)
int Read_Speed(int x)
{
int value_1;
switch(x)
{
case 3:
// 單周期位移作為速度值
value_1 = (short)TIM_GetCounter(TIM3); // 采集編碼器的計(jì)數(shù)值并保存
TIM_SetCounter(TIM3,0); // 將定時(shí)器的計(jì)數(shù)值清零
break;
case 4:
// 單周期位移作為速度值
value_1 = (short)TIM_GetCounter(TIM4); // 采集編碼器的計(jì)數(shù)值并保存
TIM_SetCounter(TIM4,0); // 將定時(shí)器的計(jì)數(shù)值清零
break;
default: value_1 = 0;
}
return value_1;
}
這個(gè)函數(shù)比較簡(jiǎn)單,但是我還是想提一下下面兩個(gè)函數(shù),必須要認(rèn)真去理解兩個(gè)函數(shù)里的內(nèi)容!
uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
三、定時(shí)讀取編碼器讀取的脈沖數(shù)
?之所以要定時(shí)來(lái)讀取值,是因?yàn)槲覀冊(cè)谟?jì)算速度的時(shí)候必須要有個(gè)時(shí)間,很簡(jiǎn)單的原理我就不解釋了。
這部分又涉及到定時(shí)器中斷的問(wèn)題,我使用的是TIM2;
在這里跟大家說(shuō)一下定時(shí)器pwm輸出和定時(shí)器中斷能不能使用一個(gè)定時(shí)器來(lái)運(yùn)行的問(wèn)題。
答案是可以的,但是需要注意一個(gè)問(wèn)題,就是pwm輸出和中斷兩者的定時(shí)器頻率一定要相同,不然會(huì)影響實(shí)際的運(yùn)行。什么是定時(shí)器頻率大家應(yīng)該知道吧就是對(duì)arr與psc的配置。
再補(bǔ)充說(shuō)一下,定時(shí)器中斷與串口中斷能不能同時(shí)運(yùn)行?
我測(cè)試過(guò),是不能夠同時(shí)運(yùn)行的,具體什么原因我就不知道了,上次因?yàn)檫@個(gè)問(wèn)題糾纏我很久!
回歸正文,下面是TIM2定時(shí)器代碼:
#include "TIME.h"
/*********************************************陀螺儀數(shù)據(jù)讀取,PID計(jì)算刷新時(shí)鐘2***********************************/
void TIM2_Getsample_Int(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //時(shí)鐘使能
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個(gè)更新事件裝入活動(dòng)的自動(dòng)重裝載寄存器周期的值 計(jì)數(shù)到5000為500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來(lái)作為T(mén)IMx時(shí)鐘頻率除數(shù)的預(yù)分頻值 10Khz的計(jì)數(shù)頻率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位
TIM_ITConfig( TIM2,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能定時(shí)器2更新觸發(fā)中斷
TIM_Cmd(TIM2, ENABLE); //使能TIMx外設(shè)
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占優(yōu)先級(jí)0級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優(yōu)先級(jí)3級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure);
}
//***************TIME2的中斷*******************/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET) //溢出中斷
{
i++;
if(i == 100)
{
i = 0;
count1 = abs(Read_Speed(3)); //讀取脈沖數(shù)(TIM3)
count2 = abs(Read_Speed(4)); //讀取脈沖數(shù)(TIM4)
speed1 = Speed_calculate(count1);
speed2 = Speed_calculate(count2);
/*最初的閉環(huán)控制
PWM1 = Velocity_Control(Target,count1); //速度環(huán)閉環(huán)控制
TIM_SetCompare1(TIM2, PWM1/100);
PWM2 = Velocity_Control(Target,count2); //速度環(huán)閉環(huán)控制
TIM_SetCompare2(TIM2, PWM2/100);
*/
}
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除中斷標(biāo)志位
}
我在主函數(shù)里定時(shí)器初始化為1ms中斷一次,很容易看出讀取脈沖數(shù)的間隔時(shí)間是100ms;
在這里我們就讀取到了編碼器上的脈沖數(shù)了,接下來(lái)我們就進(jìn)入本篇文章最重要的計(jì)算速度的部分!
四、計(jì)算速度(本篇最重要部分)
1.速度計(jì)算原理
?定時(shí)器編碼器模式使用的是四倍頻(具體的編碼器模式還請(qǐng)大家去CSDN上搜搜),所以電機(jī)轉(zhuǎn)一圈的脈沖數(shù)應(yīng)該是11×19×4=836;
假設(shè)編碼器讀取的脈沖數(shù)為x,速度,這里的t等于100ms,相當(dāng)于Speed=p*0.0119617224880383;
這樣就可以寫(xiě)速度計(jì)算函數(shù)了
2. 速度計(jì)算代碼
?注意:得出來(lái)的值一定要是float型的,這樣更加精確!
float Speed_calculate(int y)
{
float value_2;
value_2 = (float)y * 0.0119617224880383; //100ms
return value_2;
}
這個(gè)時(shí)候就可以把這個(gè)函數(shù)寫(xiě)到定時(shí)器中斷函數(shù)里面了,這樣就可以計(jì)算出速度。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-772679.html
這里還是要提醒一下,此函數(shù)計(jì)算出來(lái)的速度的單位是r/s,想要轉(zhuǎn)換成m/s就需要輪子的直徑,大家都會(huì)算,再寫(xiě)一個(gè)計(jì)算函數(shù)罷了。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-772679.html
到了這里,關(guān)于(STM32)PWM輸出控制電機(jī)旋轉(zhuǎn)并且使用編碼器讀取脈沖數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!