1、系列目錄
- 基本計時實驗
- 輸入捕獲實驗(實驗3的基礎)
- 電容按鍵檢測實驗
- 輸出PWM實驗
- PWM驅動無刷電機實驗
2、程式設計分析
本次我們采用按鍵控制無刷電機的轉速,實驗本質是通過按鍵中斷改變CCR的值,從而使PWM的占空比跟隨按鍵改變,將PWM信號輸入電調,最終實作對無刷電機的控制,
3、實驗用具
- 正點原子STM32F1精英板
- 新西達30A無刷電調
- A2212 1000KV無刷電機
4、程式設計分析
程式設計可以分為三大塊:
- 定時器、按鍵配置
- 電機控制程式
- 按鍵中斷服務函式
1、定時器、按鍵的配置:
定時器選擇TIM4,因為TIM4的四個通道引腳剛好都在板子上,并且不需要重定義埠,比較方便,四個通道分別為PB6、7、8、9,
原子的板子上總共有KEY0(PE4),KEY1(PE3),KEY_UP(PA0)三個按鍵,剛好可以配置為加速鍵(KEY1)、減速鍵(KEY0)、剎車鍵(PA0),
2、電機控制程式:
根據按鍵,改變寫入CCR暫存器的值,CCR/ARR的比值及為輸出PWM的占空比,直接通過TIMx->CCR1 = x;寫入CCR的值,這是暫存器變成的一種方法,可以直接給CCR暫存器賦值,很好用,
3、按鍵中斷函式,這里可以設定兩個變數ccr_val和add_val,ccr_val代表輸出占空比5%的PWM的CCR的值,電調通過5%-10%的PWM信號控制電機0-100%的轉速,所以占空比最高為10%的PWM,add_val是每次按鍵增加或者減少的CCR,最后寫入暫存器的CCR=ccr_val+add_val,
電機控制流程
電路連接——開發板上電,電機上電——電調校對油門——按鍵——電機啟動
如果不理解電調校對油門以及相關操作,點擊這里
5、代碼示例,很多思想一看程式就明白
1、TIM初始化
//MOT_GPIO PB6,7,8,9
#define MOT_GPIO GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9
#define MOT_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define MOT_GPIO_CLK RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO
#define MOT_TIM TIM4
#define MOT_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define MOT_TIM_CLK RCC_APB1Periph_TIM4
/** TIM4定時器基礎配置
* 功能:
* 入口引數:arr;psc
* 回傳值:無
*/
void PWM_TIM_GPIO_Config(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
MOT_GPIO_APBxClock_FUN(MOT_GPIO_CLK,ENABLE);
MOT_TIM_APBxClock_FUN(MOT_TIM_CLK,ENABLE);
//PB6,7,8,9 配置
GPIO_InitStructure.GPIO_Pin = MOT_GPIO;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//TIM5基礎配置
//計時器時鐘 = APB總線時鐘/分頻因子
// psc
TIM_TimeBaseStructure.TIM_Period = arr;//重裝載值/最大計數值
TIM_TimeBaseStructure.TIM_Prescaler = psc;//預分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(MOT_TIM,&TIM_TimeBaseStructure);
}
/** PWM 配置
* 功能:配置四路PWM控制電機,后期可擴展為電機解鎖程式
* 入口引數:無
* 回傳值:無
*/
void PWM_OC_Config(u16 ccr)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = ccr;
//前左電機 CCR1 PB6
TIM_OC1Init(MOT_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR1上的預裝載暫存器
//前右電機 CCR2 PB7
TIM_OC2Init(MOT_TIM, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR2上的預裝載暫存器
//后左電機 CCR3 PB8
// TIM_OC3Init(MOT_TIM, &TIM_OCInitStructure);
// TIM_OC3PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR3上的預裝載暫存器
//后右電機 CCR4 PB9
TIM_OC4Init(MOT_TIM, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR4上的預裝載暫存器
TIM_ARRPreloadConfig(MOT_TIM, ENABLE); //使能MOT_TIM在ARR上的預裝載暫存器
TIM_Cmd(MOT_TIM, ENABLE); //使能MOT_TIM外設
}
void PWM_Config(void)
{
PWM_TIM_GPIO_Config(2000,720-1);
PWM_OC_Config(200);
}
2、電機驅動,實驗初期先不需要考慮各個CCR的準確值,后期加入PID之后可以通過PID精確控制每個電機
/*****************************************************
* 通過按鍵中斷方式控制電機轉速
(優先級 KEY0和KEY1屬于不同操作,優先級KEY0>KEY1(減速>加速))
*滿油門 CCR 200 10%
*零油門 CCR 100 5%
* KEY0 (PE4) 減速 [0,20]次
* KEY1 (PE3) 加速 [0,20]次
* KEY_UP (PA0) 剎車 CCR=5%
*現階段控油門轉速僅有五個等級,后期按比例增加,按等比例分配為 100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180
*其中KEY_UP僅用作電調初始化,初始CCR=200(10%),KEY_UP為CCR=100(5%),可以做緊急剎車使用
*
*
2021年1月31日10:13:03
*
**************************************************************/
#include "bsp_motor.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "led.h"
#include "beep.h"
/** 電機控制程式
* 功能:控制四個通道的CCR
* 入口引數:ccr1,ccr2,ccr3,ccr4
* 回傳值:無
* 注:取值[0,0xFFFF]
*/
void MOT_Control(u16 ccr1,u16 ccr2,u16 ccr3,u16 ccr4)
{
TIM4->CCR1 = ccr1;
TIM4->CCR2 = ccr2;
TIM4->CCR3 = ccr3;
TIM4->CCR4 = ccr4;
}
3、按鍵中斷服務函式,通過這個函式控制CCR的改變
(1)中斷配置
/** 按鍵中斷配置
* 功能:配置三個按鍵的中斷設定
* 入口引數:無
* 回傳值:無
*/
static void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);//加速鍵PE3
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//減速鍵PE4
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//停止鍵PA0
EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4 | EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
static void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
//加速鍵PE3
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//減速鍵PE4
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//停止鍵PA0
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void KEY_EXTI_Config(void)
{
EXTI_Config();
NVIC_Config();
EXTI_ClearFlag(EXTI_Line0);
EXTI_ClearFlag(EXTI_Line3);
EXTI_ClearFlag(EXTI_Line4);
}
(2)中斷服務函式
u16 ccr_val = 100;//5%的CCR,起始狀態
int add_val = 0;//每次按鍵CCR增加的值
int a =0;
//實際設定寫入的CCR=ccr_val+add_val
/** 按鍵中斷服務函式
* 功能:根據不同的按鍵設定不同的CCR的值
* 入口引數:無
* 回傳值:無
*/
//加速
void EXTI3_IRQHandler(void)
{
delay_ms(10);
if(EXTI_GetITStatus(EXTI_Line3) != RESET)
{
if(KEY1 == 1)
{
add_val += 5;
LED1 = !LED1;
if(add_val<81)//最高允許加速到80%
{
MOT_Control(ccr_val+add_val,ccr_val+add_val,ccr_val+add_val,ccr_val+add_val);
printf("3CCR = %d\r\n",TIM_GetCapture1(TIM4));
}
else
{
BEEP;
add_val = 80;
}
}
EXTI_ClearITPendingBit(EXTI_Line3);
}
}
//減速
void EXTI4_IRQHandler(void)
{
delay_ms(10);
if(EXTI_GetITStatus(EXTI_Line4) != RESET)
if(KEY0 == 1)
{
add_val -=5;
printf("%d\r\n",add_val);
LED0 = !LED0;
if(add_val > -1)
{
MOT_Control(ccr_val+add_val,ccr_val+add_val,ccr_val+add_val,ccr_val+add_val);
printf("4CCR = %d\r\n",TIM_GetCapture1(TIM4));
}
else
{
BEEP;
add_val = 0;
printf("add_val已歸零,add_val = %d\r\n",add_val);
}
}
EXTI_ClearITPendingBit(EXTI_Line4);
}
//停止
void EXTI0_IRQHandler(void)
{
delay_ms(10);
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
if(KEY1 == 1)
{
BEEP = !BEEP;
MOT_Control(ccr_val,ccr_val,ccr_val,ccr_val);
printf("0CCR = %d\r\n",TIM_GetCapture1(TIM4));
}
printf("剎車成功\r\n");
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
6、實驗現象

可以看到加速成功,綠色LED燈閃爍,電機速度加快,

串口輸出CCR,ccr_val和add_val正常,
7、總結
PWM控制無刷電機的使用在顯示中非常廣泛,還可以控制步進電機、伺服電機,現在的高精度加工制造產業都脫離不了伺服電機,所以先學習好PWM控制無刷電機這種簡單的控制,才能為以后打好基礎,后期我將會把四旋翼無人機的設計上傳,本節課的控制電機實驗就是無人機所需要使用的電機控制程式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/255289.html
標籤:其他
上一篇:Raspberry Pi Pico實踐系列3-基于PyCharm和MicroPython的樹莓派Pico擴展介面使用與控制編程實踐
下一篇:JAVA方法多載
