初學者STM32—PWM驅動電機與舵機

?一、簡介

上一節課主要學習了輸出比較和PWM的基本原理和結構,本節課就主要以實踐為主通過STM32最小系統板和驅動器控制舵機和直流電機。

上一節課的坐標?初學者STM32—輸出比較與PWM-CSDN博客

二、舵機

舵機是一種根據輸入PWM信號占空比來控制輸出角度的裝置

輸入PWM信號要求:周期為20ms,對應50Hz,高電平寬度為0.5ms~2.5ms

根據上圖所示,舵機內部是由直流電機驅動的,還有一個控制電路版,PWM輸入某個信號,它就會以某種角度轉動。根據最右邊的圖可知,我們這個舵機是180度的舵機,當給予的PWM脈沖信號不同寬度的時候就會以不同的角度進行旋轉。舵機在很多領域都會用上,比如遙控車的轉彎、機械臂的關節等等。

上圖是舵機的電路結構,主要由三根線組成,電源、地線和PWM信號線

不同顏色的舵機接線:

第一種????????黑色:GND????????紅色:+5V????????黃色:信號線

第二種????????棕色 :GND???????紅色:+5V????????橙色:信號線

三、直流電機驅動

直流電機是一種將電能轉換為機械能的裝置,有兩個電極,當電極正接時,電機正轉,當電極反接時,電機反轉

直流電機屬于大功率器件,GPIO口無法直接驅動,需要配合電機驅動電路來操作

TB6612是一款雙路H橋型的直流電機驅動芯片,可以驅動兩個直流電機并且控制其轉速和方向

我們通過看原理圖:電機接O1和O2,當左上和右下形成兩路推挽電路就會導通驅動電機旋轉,當右上和左下兩路導通的時候電機就以另一個方向旋轉。?

?

上圖為電機的驅動芯片和引腳定義圖。我們可以通過引腳定義圖知道如何輸入信號控制電機。

根據定義圖所示:PWM給與的信號按照一定頻率的高低運行就能實現電機的運行而且還能根據電平的時間實現速讀的變化。

注意:VM必須要和驅動電壓一致? ? ? ? H:高電平? ? ? ? L:低電平

四、PWM控制舵機

時鐘源連接著時基單元,我們通過配置好時基單元后計數器就會根據已經配置好的模式進行輸出控制,前面講過用輸出控制寄存器配置,通過配置好的參考電平,使能時候就可以控制GPIO口輸出相應的PWM了。

但是GPIO控制PWM的時候必須要配置成復用推挽輸出,我們參考下圖復用功能,當我們配置了復用推挽輸出,輸出數據寄存器就會斷開,片上外設就能夠連接上輸出控制然后才能夠輸出PWM波形。

代碼部分

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);	TIM_InternalClockConfig(TIM3);

首先第一步就是打開總線APB1和APB2,TIM3是在APB1中,GPIO在APB2中

配置GPIO,注意這里輸出配置為復用推挽,上面說出了原因

開啟GPIO_Pin_7(TIM3在PA7引腳)(后面要考)

開啟TIM3的時基單元時鐘

	TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;		//分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;		//計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =20000 - 1;		//重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =72 - 1;		//預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0;		//重復計數器的值TIM_TimeBaseInit(TIM3,&TIM_TimeBAseInitStructure);

然后配置時基單元?

這個配置按照平常配置,但是ARR和PSC必須要滿足舵機運行的頻率

PWM頻率:? Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 50Hz

PWM占空比:? Duty = CCR / (ARR + 1)

PWM分辨率:? Reso = 1 / (ARR + 1)

這里設置的是20000的ARR 和 72的PSC,而后面的CCR的值是可變的,我設置為500到2500,這樣占空比就能在0.005~0.025(對應高電平寬度0.5ms~2.5ms)滿足舵機0~180度

	TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高級性TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能端TIM_OCInitStructure.TIM_Pulse=0;	//CCR	TIM_OC2Init(TIM3,&TIM_OCInitStructure);TIM_Cmd(TIM3,ENABLE);

然后配置輸出比較的參數,同樣也是用結構體配置的?

TIM_OCPolarity :極性選擇為 高 ,當輸出REF為高電平時就是高電平,反之

然后輸出使能:TIM_OutputState_Enable

CCR:0(后面通過函數自己配置)

最后填入OC2Init中

由于我選擇的是TIM3的通道2(CH2),所以配置的是OC2Init

?上圖是通用定時器的部分結構,OC2Init中的OC2就是CH2通道,當然也可以選擇其他通道,這里只是舉個例子。因為每個通用定時器都能輸出四路PWM。

void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM3,Compare);
}void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

TIM_SetCompare2這個函數也是因為用了OC2通道所以是TIM_SetCompare?2?而不是1或者其他

最后我們通過這個函數來填寫CCR的值,其中Compare是一個變量,在500~2500之間,實現了舵機從0~180度的控制。

五、直流電機的控制

由于直流電機的控制和舵機控制相似,就省略講解,但是也會重點講解時基單元的配置和方向控制

時基單元的配置

	TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;		//分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;		//計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =100 - 1;		//重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =36 - 1;		//預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0;		//重復計數器的值TIM_TimeBaseInit(TIM2,&TIM_TimeBAseInitStructure);

PWM頻率:? Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 20KHz?

為什么要這個頻率呢?因為頻率太低當我們捂住電機的時候會發現有嗚嗚聲,這樣就會產生噪音。我們將頻率提高到20KHz超出了讓人耳能聽到的頻率就不會聽到這個噪音。?

#include "stm32f10x.h"                  // Device header
#include "PWM.h"
void Motor_init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);PWM_Init(); 
}
void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(-Speed);	}
}

GPIO_SetBits置1????????GPIO_ResetBits置0

他們分別連接TB6612的AO1和AO2,當參數speed大于0就是正轉,小于0就是反轉

六、完整代碼(按鍵控制舵機)

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum;
float Angle;
int main(void)
{Key_Init();OLED_Init();Servo_Init();OLED_ShowString(1,1,"Angle:");while(1){KeyNum=Key_GetNum();if(KeyNum == 2){Angle+=30;if(Angle > 180){Angle = 0;}}Servo_SetAngle(Angle);OLED_ShowNum(1,7,Angle,3);}}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"void Servo_Init(void)
{PWM_Init();
}
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

?PWM.c

#include "stm32f10x.h"                  // Device headervoid PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);	TIM_InternalClockConfig(TIM2);		//上電默認是這個內部時鐘TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;		//分頻模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;		//計數模式向上計數TIM_TimeBAseInitStructure.TIM_Period =100 - 1;		//重裝器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =36 - 1;		//預分頻器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0;		//重復計數器的值TIM_TimeBaseInit(TIM2,&TIM_TimeBAseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//高級性TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能端TIM_OCInitStructure.TIM_Pulse=0;		//CCR的值TIM_OC3Init(TIM2,&TIM_OCInitStructure);TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2,Compare);
}

PWM.h?

#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);
#endif

Servo.c?

#ifndef __SERVO_H
#define __SERVO_Hvoid Servo_Init(void);
void Servo_SetAngle(float Angle);#endif

Key.c?

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
void Key_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;GPIO_Init(GPIOB,&GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{uint8_t KeyNum=0; if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)Delay_ms(20);KeyNum=1;}return KeyNum;
}

Key.h?

#ifndef __KEY_H
#define __KEY_Hvoid Key_Init(void);
uint8_t Key_GetNum(void);#endif

這段完整代碼實現的效果:當按鍵按下的時候?舵機運動30度,加滿180度的時候就會重新歸位0度

七、完整代碼(按鍵控制電機速度)

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"
uint8_t KeyNum;
int8_t Speed;
int main(void)
{Key_Init();OLED_Init();Motor_init();OLED_ShowString(1,1,"Speed:");while(1){KeyNum=Key_GetNum();if(KeyNum == 1){Speed+=20;if(Speed>100)Speed=0;}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1,7,Speed,3);}
}

??Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"
void Motor_init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);PWM_Init(); 
}
void Motor_SetSpeed(int8_t Speed)
{if(Speed >= 0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare3(-Speed);	}
}

?Motor.h

#ifndef __MOTOR_H
#define __MOTOR_Hvoid Motor_init(void);
void Motor_SetSpeed(int8_t Speed);#endif

Key.c與Key.h和上面(按鍵控制舵機)的Key函數一樣

最后實現的效果:按鍵每按一次,電機就會以百分之20的比例進行增速最后增到100,再次按下就會歸零。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89695.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89695.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89695.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++中的異常處理機制:try-catch

一、基本概念 異常(Exception):程序執行過程中發生的非正常情況,比如除以零、訪問越界、內存不足等。 異常處理(Exception Handling):對異常情況進行捕獲、分析,并采取補救措施&…

如何從 Windows 11 或 10 遠程訪問 Ubuntu 24.04 或 22.04 桌面

了解如何使用 RDP(遠程桌面協議)從 Windows 11 或 10 遠程連接 Ubuntu 24.04 Noble 或 22.04 LTS Jammy JellyFish 桌面的步驟。 Windows 提供了一個便捷的功能,稱為遠程桌面連接,它使用 RDP 協議來遠程連接 PC。當從 Windows 系統建立遠程桌面連接時,使用起來非常簡單,…

Linux 服務器中,Tab 鍵自動補全功能失效

在 Linux 服務器中,Tab 鍵自動補全功能失效通常與 bash-completion 組件缺失或配置異常有關。以下是解決問題的兩個關鍵 YUM 指令及操作步驟:1. 安裝 bash-completion 組件 sudo yum install -y bash-completion說明: bash-completion 是提供…

SpringBoot服裝推薦系統實戰

Spring Boot 服裝推薦系統實例 以下是基于Spring Boot實現的服裝推薦系統的30個實例代碼示例,涵蓋核心功能和實現方法。 用戶注冊與登錄功能 @RestController @RequestMapping("/api/auth") public class AuthController {@Autowiredprivate UserService userSer…

WIN10系統優化篇(一)

你是否疑惑為什么別人家的電腦運行速度飛快,而自己的卻卡頓難用?其實,很多時候 Windows 系統可以通過簡單的優化措施來提升使用體驗。本文根據項目實戰多年對 Win10 優化經驗,將幫你找出系統卡頓的原因,并給出針對性的…

Flutter狀態管理篇之ChangeNotifier基礎篇(一)

目錄 前言 一、什么是ChangeNotifier 二、ChangeNotifier 的基本用法 三、結合Flutter UI 使用 四、結合 Provider 的高級用法 五、ChangeNotifier 的優勢與注意事項 5.1 優勢 5.2 注意事項 六、與 ValueNotifier 的比較 七、實際應用場景 八、總結 前言 在 Flutter…

react17更新哪些新特性

React 17 是一個“無新特性”的發布版本,它的主要目標是為未來的 React 版本打好基礎,同時改善與舊版本共存和升級的體驗。雖然沒有引入新的開發者 API,但它在內部做了很多重要的改進。以下是 React 17 的核心更新內容和特性:&…

Unity 常見數據結構分析與實戰展示 C#

Unity 常見數據結構分析與實戰展示 提示:內容純個人編寫,歡迎評論點贊,來指正我。 文章目錄Unity 常見數據結構分析與實戰展示1. 引言2. Unity 數據結構概述3. 常見數據結構1. 數組(Array)2. 列表(List&…

【Linux網絡編程】應用層協議 - HTTP

目錄 初識HTTP協議 認識URL HTTP協議的宏觀格式 Socket封裝 TcpServer HttpServer 整體設計 接收請求 web根目錄與默認首頁 發送應答 完善頁面 HTTP常見Header HTTP狀態碼 HTTP請求方法 cookie與session Connection 抓包 初識HTTP協議 應用層協議一定是基于…

技術演進中的開發沉思-36 MFC系列: 對話框

MFC這個章節里,不能忽視的是對話框的開發。如果把 MFC 程序比作一棟辦公樓,那對話框就是「會客室」—— 它是程序與用戶面對面交流的地方:用戶在這里輸入數據,程序在這里展示信息,彼此的互動都從這個空間開始。今天圍繞…

(李宏毅)deep learning(五)--learning rate

一,關于learning rate的討論:(1)在梯度下降的過程中,當我們發現loss的值很小的時候,這時我們可能以為gradident已經到了local min0(低谷),但是很多時候,loss很小并不是因…

pytorch:tensorboard和transforms學習

tensorboard:可視化數據 在anaconda安裝: pip install tensorboard2.12.0最好使用這個版本 不然后面調用會報錯 因為版本過高的原因 然后還碰到了安裝的時候 安裝到C盤去了 但是我用的虛擬環境是在E盤:此時去C盤把那些新安裝的復制過來就好了 附錄我C盤的…

常用的100個opencv函數

以下是OpenCV中最常用的100個函數及其作用與注意事項的全面整理,按功能模塊分類,結合官方文檔與工業實踐優化排序。各函數均標注Python(cv2)和C(cv::)命名,重點參數以加粗突出: &…

【C++】紅黑樹,詳解其規則與插入操作

各位大佬好,我是落羽!一個堅持不斷學習進步的大學生。 如果您覺得我的文章有所幫助,歡迎多多互三分享交流,一起學習進步! 也歡迎關注我的blog主頁: 落羽的落羽 一、紅黑樹的概念與規則 紅黑樹是一種更加特殊的平衡二…

Camera相機人臉識別系列專題分析之十七:人臉特征檢測FFD算法之libhci_face_camera_api.so 296點位人臉識別檢測流程詳解

【關注我,后續持續新增專題博文,謝謝!!!】 上一篇我們講了: 這一篇我們開始講: Camera相機人臉識別系列專題分析之十七:人臉特征檢測FFD算法之libhci_face_camera_api.so 296點位人臉識別檢測流程詳解 目錄 一、背景 二、:FFD算法libhci_face_camera_api.s…

PostgreSQL 16 Administration Cookbook 讀書筆記:第7章 Database Administration

編寫一個要么完全成功要么完全失敗的腳本 事務(transaction)可以實現all or nothing。不過這里指的是psql的-和--single-transaction選項。可以實現transaction wrapper: 此選項只能與一個或多個 -c 和/或 -f 選項組合使用。它會導致 psql 在…

DeepSeekMath:突破開源語言模型在數學推理中的極限

溫馨提示: 本篇文章已同步至"AI專題精講" DeepSeekMath:突破開源語言模型在數學推理中的極限 摘要 數學推理由于其復雜且結構化的特性,對語言模型構成了重大挑戰。本文介紹了 DeepSeekMath 7B,該模型在 DeepSeek-Code…

實體類序列化報錯:Caused by: java.lang.NoSuchMethodException: com.xx.PoJo$Item.<init>()

原實體類代碼EqualsAndHashCode(callSuper true) Data public class Pojo extends BaseBean {private static final long serialVersionUID -4291335073882689552L;ApiModelProperty("")private Integer id;......private List<Item> list;AllArgsConstructo…

基于單片機病床呼叫系統/床位呼叫系統

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 該系統是以單片機STM32F103為核心的基于無線網絡的醫院病房呼叫系統&#xff0c;分為從機和主機兩…

[黑馬頭條]-登錄實現思路

需求分析在黑馬頭條項目中&#xff0c;登錄有兩種方式&#xff1a;一種是用戶輸入賬號密碼后登錄&#xff0c;這種方式登陸后的權限很大&#xff0c;可以查看&#xff0c;也可以進行其他操作&#xff1b;另一種方式就是用戶點擊不登錄&#xff0c;以游客的身份進入系統&#xf…