STM32實踐項目(激光炮臺)

剛開始設想做一個上半部分可以上下180°移動,下半部分底座360°移動的激光炮臺。于是便開始了實踐。

所需材料清單:

序號 名稱 數量 備注說明
1 面包板(Breadboard) 2 用于電路搭建和模塊連接
2 杜邦線(公對公、公對母等) 若干 建議準備 30~50 根,方便連接
3 MB-102 電源模塊 2 插在面包板上,提供 3.3V / 5V 電源
4 電池(適配 MB-102) 2 建議 9V 方塊電池或 7.4V 鋰電池
5 SG90 舵機(180° 限位舵機) 1 控制角度在 0°~180°
6 SG90 舵機(360° 連續舵機) 1 可連續旋轉,用作角度模擬+PID控制
7 STM32F103C8T6 開發板 2 最小系統板(Blue Pill)
8 KY-008 激光模塊 1 激光發射模塊(帶限流電阻)
9 HC-05 藍牙模塊 2 一發一收,用于無線通信
10 旋轉編碼器(KY-040 或同類) 2 用于輸入角度,連接 STM32 編碼器接口

主要過程

起初設想用簡單的按鈕控制,而單憑if語句只能實現按鈕按一下舵機角度變化一下,無法實現舵機角度連續性變化。

//uint8_t KeyNum;
//float Angle;//uint8_t i;//int main(void)
//{
//	OLED_Init();
//	Servo_Init();
//	Key_Init();
//	
//	OLED_ShowString(1,1,"Angle:");
//    
//    while (1)
//    {
//       KeyNum=Key_GetNum();
//		if(KeyNum==1)
//		{
//			Angle+=30;
//			if(Angle>180)
//			{
//				Angle=0;
//			}
//		}
//		Servo_SetAngle(Angle);
//		OLED_ShowNum(1,7,Angle,3);
//    }
//}

因此,完善key.c代碼,在原代碼中添加按住一直返回低電平來實現。

// 新增的實時檢測(按住時一直返回)
uint8_t Key_IsPressed(uint8_t keyID)
{if (keyID == 1){return (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);}else if (keyID == 2){return (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);}return 0;
}

而此時又發現新的問題,如何很好的控制轉速。一開始采用的是改變延時速率來提升轉速。但如此一來舵機的穩定性便出現的問題。會發生抖動。

//int main(void)
//{
//    OLED_Init();
//    Servo_Init();
//    Key_Init();
//    
//    OLED_ShowString(1, 1, "Angle:");
//	OLED_ShowString(2, 1, "Angle:");
//    while (1)
//{
//    if (Key_IsPressed(1)) // 如果按鍵1被按住
//    {
//        Angle += 1;
//        if (Angle > 180) Angle = 180;//        Servo_SetAngle(Angle);
//        OLED_ShowNum(1, 7, Angle, 3);
//        Delay_ms(1); // 勻速控制
//    }
//	if (Key_IsPressed(2)) // 如果按鍵1被按住
//    {
//        Angle -= 1;
//        if (Angle < 0) Angle = 0;//        Servo_SetAngle(Angle);
//        OLED_ShowNum(2, 7, Angle, 3);
//        Delay_ms(1); // 勻速控制
//    }
//}

于是加大每一次增加的角度,而延遲秒數不變。

float Angle = 90;     // 初始角度
float lastAngle = -1; // 用于減少 OLED 刷新頻率int main(void)
{OLED_Init();Servo_Init();Key_Init();OLED_ShowString(1, 1, "Angle+ :");Servo_SetAngle(Angle); // 舵機先轉到中位while (1){// 按鍵 1:增加角度(快速)if (Key_IsPressed(1)){Angle += 5;               // 每次增加 5°if (Angle > 180) Angle = 180;Servo_SetAngle(Angle);Delay_ms(15);             // 勻速快速控制}// 按鍵 2:減少角度(快速)if (Key_IsPressed(2)){Angle -= 5;               // 每次減少 5°if (Angle < 0) Angle = 0;Servo_SetAngle(Angle);Delay_ms(15);}// 角度變化才刷新顯示if (Angle != lastAngle){OLED_ShowNum(1, 9, (uint16_t)Angle, 3);lastAngle = Angle;}}
}

的確這樣能讓舵機較好的連續變化,但是按鍵壽命有限,頻繁操作容易損壞。于是換成更加方便順手的旋轉編碼器。其優點也是比較突出的。

優點

操作更直觀:想讓舵機轉多少,就擰多少;比按鍵舒服很多。

分辨率可調:可以設置每格 1° / 5° / 10°,靈活性高。

響應更快:旋鈕快速轉幾格,舵機就能快速到位。

支持連續調節:不像按鈕那樣要一直按著,旋鈕轉動一圈就能從 0° 到 180°。

耐用性更好:旋轉編碼器機械壽命通常比按鍵長。

//main函數中
#include "Encoder.h"
float Angle = 90;     // 初始角度
float lastAngle = -1; // 上一次顯示的角度
int main(void)
{OLED_Init();PWM_Init();Encoder_Init();Servo_SetAngle(Angle); // 初始角度OLED_ShowString(1,1,"Angle:");while(1){int16_t val = Encoder_Get();   // 獲取旋轉增量if(val != 0){Angle += val*5;              // 編碼器每跳一下 → 改變 5°if(Angle < 0) Angle = 0;if(Angle > 180) Angle = 180;Servo_SetAngle(Angle);}if(Angle != lastAngle){OLED_ShowNum(1, 8, (uint16_t)Angle, 3);lastAngle = Angle;}}
}
//編碼器函數
#include "stm32f10x.h"                  // Device header
/*================= 編碼器初始化 =================*/int16_t Encoder_Count; 
void Encoder_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line=EXTI_Line0|EXTI_Line1;EXTI_InitStructure.EXTI_LineCmd=ENABLE;EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;NVIC_Init(&NVIC_InitStructure);
}int16_t Encoder_Get(void)
{int16_t Temp;Temp=Encoder_Count;Encoder_Count=0;return Temp;
}/*================= 編碼器中斷服務函數 =================*/
void EXTI0_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line0)==SET){if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Encoder_Count--;}EXTI_ClearITPendingBit(EXTI_Line0);}
}
void EXTI1_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line1)==SET){if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0){Encoder_Count++;}EXTI_ClearITPendingBit(EXTI_Line1);}
}

但如此一來旋轉編碼器需要旋轉720°舵機才能旋轉180°,如果沒有顯示屏不太好控制,并且旋轉兩圈也比較難操作,就想著能否對應編碼器旋轉360°舵機旋轉180。

1.確定編碼器的分辨率

絕大多數常見機械旋轉編碼器是 20 格/圈(detents),有的高分辨率型號可能是 24、30、32 格。

如果是 20 格/圈:旋轉 360° → 20 次脈沖。

中斷服務函數里 Encoder_Count++ / -- 正好就是在數這些脈沖。

2. 計算換算關系

目標是:

20 格(1 圈) → 180°

那么 每格對應 = 180 ÷ 20 = 9°

如果是 24 格:

24 格(1 圈) → 180°

每格 = 180 ÷ 24 = 7.5°

于是在原有主函數上改遍(我這里的旋轉編碼器是20格的)

#define ENCODER_STEPS_PER_REV 20   // 編碼器分辨率(根據實際修改)
#define SERVO_RANGE_DEG       180  // 舵機可動角度范圍float Angle = 90;     // 初始角度
float lastAngle = -1;while (1)
{int16_t val = Encoder_Get();   // 獲取旋轉的脈沖數if (val != 0){Angle += val * (SERVO_RANGE_DEG / ENCODER_STEPS_PER_REV);if (Angle < 0) Angle = 0;if (Angle > 180) Angle = 180;Servo_SetAngle(Angle);}if (Angle != lastAngle){OLED_ShowNum(1, 8, (uint16_t)Angle, 3);lastAngle = Angle;}
}

3.同理,再加上一個舵機

//#define ENCODER_STEPS_PER_REV 20   // 編碼器一圈脈沖數
//#define SERVO_RANGE_DEG       180  // 舵機行程角度//#include "Encoder.h"
//#include "OLED.h"
//#include "PWM.h"
//#include "Servo.h"//float Angle1 = 90;  // 舵機1初始角度
//float Angle2 = 90;  // 舵機2初始角度//float lastAngle1 = -1;
//float lastAngle2 = -1;//int main(void)
//{
//    OLED_Init();
//    PWM_Init();
//    Encoder_Init();//    Servo1_SetAngle(Angle1); // 初始角度
//    Servo2_SetAngle(Angle2);//    OLED_ShowString(1,1,"Servo1:");
//    OL

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

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

相關文章

不止是夾住,更是“感知”:Contactile GAL2觸覺型夾爪實現自適應抓取

近日&#xff0c;專注于觸覺傳感與智能抓取技術的Contactile推出全新Contactile 觸覺型夾爪 GAL2&#xff0c;這款集成先進傳感技術的雙指夾爪&#xff0c;憑借實時觸覺反饋能力&#xff0c;為多行業智能抓取場景帶來突破性解決方案。 Contactile 觸覺型夾爪GAL2是一款多功能即…

Grafana - 監控磁盤使用率Variables使用

1 查詢prometheus2 編輯grafana dashboard 2.1 配置變量2.2 配置多選2.3 配置legend2.4 優化顯示 1 查詢prometheus 指標名稱描述node_filesystem_size_bytes文件系統總容量node_filesystem_avail_bytes用戶可用空間node_filesystem_files_free剩余inode數量比如我們想看/目…

WindowsAPI|每天了解幾個winAPI接口之網絡配置相關文檔Iphlpapi.h詳細分析10

上一篇&#xff1a;WindowsAPI|每天了解幾個winAPI接口之網絡配置相關文檔Iphlpapi.h詳細分析9 如果有錯誤歡迎指正批評&#xff0c;在此只作為科普和參考。 C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um\iphlpapi.h 文章目錄GetNetworkParams&#xff1a…

算法 --- 分治(歸并)

分治&#xff08;歸并&#xff09; 分治&#xff08;特別是歸并&#xff09;算法適用于解決“整體求解依賴于子問題合并”且子問題相互獨立的題目&#xff0c;其典型特征是能將大規模數據分解、遞歸求解&#xff0c;然后通過合并操作&#xff08;這正是歸并排序中‘歸并’的精…

【程序人生】有夢想就能了不起,就怕你沒夢想

夢想不是遙不可及的星辰&#xff0c;而是需要我們用腳步丈量的路途兩年前的一個夏日&#xff0c;我在日記本上鄭重地寫下&#xff1a;"我要掌握Web開發&#xff0c;能夠獨立構建一個完整的Web應用。"那天是2023年6月8日&#xff0c;當時的我連Java和JavaScript都分不…

前端基礎(四十二):非固定高度的容器實現折疊面板效果

效果展示源碼 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head>…

發票、收據合并 PDF 小程序,報銷上傳 3 秒搞定

每到報銷、報稅、財務整理時&#xff0c;手里是不是總有一堆格式不一的票據&#xff1a; 聊天記錄里的電子發票郵件附件中的 PDF 發票手機相冊里的報銷收據甚至還有零散的紙質票據掃描件 要上傳或交給財務前&#xff0c;還得一個個整理、轉換、排版&#xff0c;既耗時又容易出…

GitHub每日最火火火項目(9.4)

1. bytebot-ai / bytebot 項目名稱&#xff1a;bytebot項目介紹&#xff1a;基于 TypeScript 開發&#xff0c;是一款自托管的 AI 桌面智能體&#xff0c;能通過自然語言命令自動化執行計算機任務&#xff0c;運行在容器化的 Linux 桌面環境中。它借助自然語言處理和 AI 技術&a…

MMORPG 游戲戰斗系統架構

&#x1f30c; MMORPG 游戲戰斗系統架構 引用&#xff1a; 游戲服務器同步技術解析&#xff08;C&#xff09;MMORPG移動同步與反外掛 雖然我已離開游戲行業&#xff0c;轉而與幾位成功的商人共同創業&#xff0c;投身于商用機器人領域&#xff0c;但坦誠地說&#xff0c;游戲…

【數學建模學習筆記】啟發式算法:蒙特卡洛算法

蒙特卡洛模擬入門筆記&#xff1a;從原理到代碼實踐一、什么是蒙特卡洛模擬&#xff1f;蒙特卡洛模擬是一種通過大量隨機實驗來解決復雜問題的方法。簡單說&#xff0c;就是用電腦模擬成千上萬次隨機事件&#xff0c;然后統計結果&#xff0c;以此估算一個問題的答案。舉個生活…

20250904的學習筆記

一、封包與拆包1. 封包&#xff08;Packet Encapsulation&#xff09;封包 是指在發送數據時&#xff0c;將數據從高層協議封裝到低層協議的過程。每經過一層協議&#xff0c;數據都會被加上相應的協議頭&#xff08;有時也會加上協議尾&#xff09;&#xff0c;形成一個新的數…

STM32F4 + RT-Thread 實戰指南:TIM10 硬件定時器驅動開發與 1 秒定時功能實現

目錄前言一、STM32定時器10是個什么定時器&#xff1f;二、工程創建、環境配置三、程序代碼四、運行前言 在rtthread中&#xff0c;STM32F4的定時器10有些驅動并不完整&#xff0c;對比與其它定時器在使用時需要手動的添加一些代碼&#xff0c;我在使用上拆踩了一些坑&#xf…

echarts圖庫

環形圖// 指定圖表的配置項和數據this.option {// tooltip: {// trigger: item// },color: [#FFB32F, #FF5757, #57D5FF, #2FA8FF, #95FFF1], // 扇形區域以及列表顏色legend: {orient:vertical,//文字橫向排itemGap:20,left: left,textStyle:{color: #F3F9FF,// fontSi…

進程(Process)全面概述

進程&#xff08;Process&#xff09;全面概述 本文檔擴展了進程的定義、屬性、生命周期、管理機制及示例&#xff0c;涵蓋 task_struct 結構、進程鏈表、狀態與優先級、fork 函數及其寫時復制示例。 一、進程基本概念 進程&#xff1a;系統進行資源分配和調度的基本單位&#…

Java并發編程:sleep()與wait()核心區別詳解

今天完成了實驗室納新網站的工作&#xff0c;大體功能都已經完善&#xff0c;也和前端測試過了&#xff0c;費了點時間&#xff0c;而且今天大部分時間在看langchain4j的東西&#xff0c;就簡單復習一下八股&#xff0c;等會再復習一下算法題吧在Java并發編程中&#xff0c;sle…

AR眼鏡在智能制造的應用方向和場景用例|阿法龍XR云平臺

AR巡檢在制造業的應用已形成覆蓋設備維護、質量檢測、安全監控和遠程協作四大類別的成熟場景&#xff0c;不同制造領域的實踐各具特色&#xff0c;為行業提供了寶貴參考。在汽車制造領域&#xff0c;AR 巡檢主要應用于生產線設備維護和焊接質量檢測。在汽車廠總裝車間部署 AR 系…

【Linux系統】線程同步

在上一章節中&#xff0c;我們使用互斥量之后&#xff0c;確實解決了數據競爭問題&#xff0c;但出現了新的問題&#xff1a;只有一個線程&#xff08;thread 1&#xff09;在處理所有售票任務。這展示了互斥量的一個局限性&#xff1a;它確保了線程安全&#xff0c;但不保證公…

代碼隨想錄訓練營第三十一天|LeetCode56.合并區間、LeetCode738.單調遞增的數字

56.合并區間 思路&#xff1a;先讓二維數組進行排序&#xff1b; 遍歷數組&#xff0c;定義一個min表示重合區間的左邊界&#xff0c;max表示重合區間的右邊界&#xff1b; 如果當前區間左邊大于max&#xff0c;就證明重合區間斷了&#xff0c;就要對它進行加入ArrayList&am…

【Unity項目經驗分享】實現左右分屏裸眼3D程序

1、實現原理左右分屏原理&#xff0c;左右屏內容左右方向存在些許偏差。通過左右相機&#xff0c;然后左側相機向左側偏移一點3cm&#xff0c;右側相機向右側屏偏移一定3cm&#xff0c;然后將左右相機渲染內容通過RenderTexture渲染到Canvas上面的左右RawImage上面。2、實現具體…

設計軟件啟動失敗?“找不到vcruntime140.dll,無法繼續執行代碼” 場景化解決方案來了

打游戲時&#xff0c;剛加載到登錄界面就因 “找不到 vcruntime140.dll, 無法繼續執行代碼” 閃退&#xff1b;寫代碼時&#xff0c;編譯工具突然報錯中斷工作&#xff1b;做設計時&#xff0c;PS、AE 啟動失敗彈出相同提示 —— 不同場景下的 vcruntime140.dll 錯誤&#xff0…