2.门锁_STM32_舵机设备实现

news2024/9/21 12:24:06

概述

需求来源:

门锁的开启和关闭,就是电机来控制。这里不进行实际门锁机械结构的设计,选择用舵机或者电机转动一定的角度,就代表门锁开启。

舵机开发整体思路:

  1. 使用STM32裸机开发舵机,使得舵机可以实现基本的转动功能
  2. 封装接口,使得主函数调用一个函数,传入指定角度即可控制舵机旋转
  3. 分层硬件与设备,建立一个STM32的硬件控制文件和一个舵机角度算法文件,使得舵机角度控制可以容易的移植到其他的芯片上。
  4. 使用封装好的.c .h文件,将功能再FreeRTOS上实现应用编程(在其他博文中,暂未实现)

代码层级关系:

舵机控制裸机实现

1、舵机控制原理

舵机的型号为sg90,它有3根线:黄色为PWM信号线,红色VCC接3.3v,棕色GND

实物图如下:

舵机转动的角度与PWM信号的高电平时间有关,角度范围为0~180°

该舵机的PWM信号要求为50Hz,高电平时间与角度关系如下:

2、配置STM32的PWM输出

使用STM32CubeMx对STM32进行PWM输出的初始化配置。

这里使用的是STM32F103C8T6的TIM3_CH1作为PWM输出端口,对应引脚为PA6。

分频系数PSC配置为72-1

其余的基本配置为:使用外部晶振8MHz,最终输入到定时器的时钟频率为72MHz

3、编写STM32控制PWM文件

3.1 文件及公式

在KEIL中创建两个文件my_pwm.c和my_pwm.h。这两个文件主要实现硬件的控制,向上提供硬件控制的接口。

代码功能总述:

  • 对PWM进行一些初始化:MyPWM_Init()
  • 将所需频率转换为ARR的值:PWM_FreqToARR()
  • 将所需占空比转换为CCR的值:PWM_DutyToCCR()
  • PWM硬件控制接口:PWM_Set()

重要计算公式:

  • 定时器溢出时间计算公式:

  • 占空比计算公式:

 3.2 .h文件代码实现

该.h文件主要去定义一些宏,方便后面移植代码时的参数修改。

//PWM初始化参数
#define __TIM_F 	72000000U //时钟
#define __PSC 		(72-1)    //分频系数
#define __FREQ		1000      //频率
#define __DUTY      50		  //占空比

3.3 .c文件代码实现

3.3.1 MyPWM_Init()

该函数的作用是对PWM进行一些初始化,让PWM输出1000Hz,占空比为50%的信号。

具体函数实现如下:

/*
 * MyPWM_Init:对PWM进行一些初始化1000Hz-50%
*/
void MyPWM_Init(void){
	
	uint32_t PWM_ARR = 0;
	uint32_t PWM_CCR = 0;
	
	//1.开启TIM3_CH1的PWM通道
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
	//2.将频率、占空比转为ARR、CCR
	PWM_ARR = PWM_FreqToARR(__TIM_F,__FREQ,__PSC);
	PWM_CCR = PWM_DutyToCCR(__DUTY,PWM_ARR);
	//3.写入ARR、CCR寄存器
	__HAL_TIM_SET_AUTORELOAD(&htim3,PWM_ARR);
	HAL_TIM_GenerateEvent(&htim3,TIM_EVENTSOURCE_UPDATE);
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,PWM_CCR);
}
3.3.2 PWM_FreqToARR()

该函数的作用是将所需频率转换为ARR的值。根据的公式就是定时器溢出时间计算公式。

具体代码实现如下:

/*
 * PWM_FreqToARR:将所需频率转换为ARR的值
 * param TIM_F:定时器的时钟频率
 * param Freq:所需要的频率
 * param PSC:分频系数
 * @ret  由频率转换的ARR数值
*/
uint32_t PWM_FreqToARR(uint32_t TIM_F,uint32_t Freq,uint32_t PSC){
	
	uint32_t PWM_ARR = 0;
	
	PWM_ARR = (double)TIM_F/((PSC+1)*Freq) - 1 + 0.5;
	
	return PWM_ARR;
}
3.3.3 PWM_DutyToCCR()

该函数的作用是将所需占空比转换为CCR的值,根据的公式就是占空比计算公式。

具体代码实现如下:

/*
 * PWM_DutyToCCR:将所需占空比转换为CCR的值
 * param Duty:所需要的占空比
 * param ARR:定时器的ARR数值
 * @ret  由占空比转换的CCR数值
*/
uint32_t PWM_DutyToCCR(double Duty,uint32_t ARR){
	
	uint32_t PWM_CCR = 0;
	
	PWM_CCR = (double)(ARR+1)*Duty/100 + 0.5;
	
	return PWM_CCR;
}
3.3.4 PWM_Set()

该函数的作用是设置所需PWM输出的频率和占空比参数,这是向上提供的硬件控制接口。

具体函数实现如下:

/*
 *PWM_Set:设置所需PWM输出的频率和占空比参数
 * param Freq:所需要的频率
 * param Duty:所需要的占空比
*/
void PWM_Set(uint32_t Freq,double Duty){
	
	uint32_t PWM_ARR = 0;
	uint32_t PWM_CCR = 0;
	
	//1.将频率、占空比转为ARR、CCR
	PWM_ARR = PWM_FreqToARR(__TIM_F,Freq,__PSC);
	PWM_CCR = PWM_DutyToCCR(Duty,PWM_ARR);
	
	//2.写入ARR、CCR寄存器
	__HAL_TIM_SET_AUTORELOAD(&htim3,PWM_ARR);
	HAL_TIM_GenerateEvent(&htim3,TIM_EVENTSOURCE_UPDATE);
	__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,PWM_CCR);
}

4、编写舵机角度算法

4.1 文件

在KEIL中创建两个文件sg90.c和sg90.h。这两个文件主要是实现舵机角度与硬件接口参数的对接。最终再向上提供一个接口,以便应用层代码的使用。

代码功能总述:

  • 初始化sg90舵机设备:Sg90_Init()
  • 将传入的角度转为占空比:Sg90_AngleToDuty()
  • SG90设备控制接口:Sg90_Control()

4.2 .h文件代码实现

该.h文件主要将舵机设备抽象成一个结构体,以及舵机设备一些固定参数的宏定义

//舵机设备
typedef struct{
	
	int angle;
	int speed;
	
}DevSg90,*PDevSg90;
extern DevSg90 Sg90;  //.c定义的全局变量,设备结构体
extern PDevSg90 pSg90;//.c定义的全局变量,设备结构体指针

//舵机参数
#define SG90_PWM_FREQ 50      //工作的PWM频率50Hz-20ms
#define SG90_MAX_HIGH_TIM 2.5 //最大高电平时间,单位ms
#define SG90_MIN_HIGH_TIM 0.5 //最小高电平时间ms
#define SG90_MAX_ANGLE	  180 //最大转动角度
#define SG90_MIN_ANGLE    0   //最小转动角度

4.3 .c文件代码实现

4.3.1 Sg90_Init()

该函数的作用是初始化sg90舵机设备,设置设备初始角度为0度,速度-1代表任意(后续没编写)

具体代码实现如下:

/*
 * Sg90_Init:初始化sg90舵机设备
 * param pDev:sg90设备指针
 * @ret  -1--err  0--success
*/
int Sg90_Init(PDevSg90 pDev){
	
	//1.参数有效性判断
	if(pDev == NULL){
		printf("pDev is NULL \r\n");
		return -1;
	}
	pDev->angle = 0;
	pDev->speed = -1;//-1代表默认
	return 0;
}
4.3.2 Sg90_AngleToDuty()

该函数的作用是将传入的角度转为占空比。

代码设计思路:

根据" 1.舵机控制原理 "章节可以得知,高电平时间与转度的关系是线性的,因此可以使用归一化的方法去实现高电平时间与转度的转换。

因为硬件接口提供的PWM控制只有频率和占空比两个参数,所以还需要将高电平时间转为占空比的值。根据" 1.舵机控制原理 "章节可以得知,该舵机的PWM控制信号是固定的50Hz,因此使用公式"占空比 = 高电平时间/总周期时间"即可进行转换。

具体代码实现如下:

/*
 * Sg90_AngleToDuty:将传入的角度转为占空比
 * param angle: 需要的角度
 * @ret -1--err  other--转换后的占空比
*/
double Sg90_AngleToDuty(double angle){
	
	double percentAngel = 0;
	double highTime = 0;
	double duty = 0;
	
	//1.参数有效性判断
	if(angle > 180 || angle < 0){
			printf("angle err\r\n");
			return -1;
	}
	//2.开始转换
	percentAngel = angle/(SG90_MAX_ANGLE-SG90_MIN_ANGLE);
	//printf("Debug:percentAngel = %lf\r\n",percentAngel);
	highTime = percentAngel*(SG90_MAX_HIGH_TIM - SG90_MIN_HIGH_TIM)+SG90_MIN_HIGH_TIM;
	duty = highTime/((double)1/SG90_PWM_FREQ*1000)*100;//注意单位换算
	return duty;
}
4.3.3 Sg90_Control()

该函数的作用是SG90设备控制接口,这是应用层调用控制舵机的代码。

具体的函数实现如下:

/*
 * Sg90_Control:SG90设备控制接口
 * param angle:所需转动的角度
 * @ret  -1--err  0--success
*/
int Sg90_Control(double angle){
	
	double duty = 0;
	
	//1.参数有效性判断
	if(angle > 180 || angle < 0){
			printf("angle err\r\n");
			return -1;
	}
	//printf("Debug:angle=%lf\r\n",angle);
	//2.计算占空比
	duty = Sg90_AngleToDuty(angle);
	//printf("Debug:duty=%lf\r\n",duty);
	//3.调用硬件代码进行控制
	PWM_Set(SG90_PWM_FREQ,duty);
	return 0;
}

5、整体调试

调试代码如下:

MyPWM_Init();				//初始化PWM硬件
Sg90_Init(pSg90);			//初始化舵机设备
pSg90->angle = 180;			//设置转动角度为180°
Sg90_Control(pSg90->angle); //驱动舵机转动

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2106375.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

悟空有枪:玩家解包文件发现《黑神话》有AK47

今日&#xff0c;Reddit的《黑神话》子版的一位玩家分享了本作的全新震撼内容&#xff1a;AK47。据他描述&#xff0c;这是一位中国玩家解包发现的&#xff0c;页面描述十分搞笑&#xff1a;不能化身白衣秀士&#xff0c;捻诀念咒&#xff0c;什么也不会发生&#xff0c;快慢机…

【有啥问啥】抽象语法树(Abstract Syntax Tree, AST)的原理详解

抽象语法树&#xff08;Abstract Syntax Tree, AST&#xff09;的原理详解 引言 在编译器设计、编程语言解析以及静态分析工具中&#xff0c;抽象语法树&#xff08;AST&#xff09;是一个至关重要的概念。AST是一种树状结构&#xff0c;用于表示源代码的抽象语法&#xff0c…

ubuntu 常见问题的收录

在使用过程中&#xff0c;发现ubuntu的问题一点不必windows少。因为每次遇到问题都需要要上网找&#xff0c;所以收集起来之后就会方便一些。 版本体验 24.04&#xff1a;整体的风格大变样&#xff0c;更趋近于“现代化”&#xff1f;反正我是更喜欢了 &#x1f604;。就着风…

PAT.7-1 按格式合并两个链表

题目 解题思路 题目一看是和链表相关的&#xff0c;而且是两个链表&#xff0c;那肯定核心思路和双指针相关了。 我们来一步步拆分问题&#xff1a; 首先我们要把给我们的链表构建出来&#xff0c;所以需要一个Node类&#xff0c;以及一个buildNode的方法。那么输入给我们的是…

CAS理解和说明

目录 1.CAS是什么? 2.CAS的应用场景 2.1 实现原子类 2.2 实现自旋锁 3.CAS的典型问题:ABA问题 1.CAS是什么? CAS:全称compare and swap(比较并交换) 我们假设内存中的原始数据V&#xff0c;旧的预期值A&#xff0c;需要修改的新值B 1.比较A与V是否相等&#xff08;比较…

EmguCV学习笔记 VB.Net 9.2 VideoWriter类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

Android Camera 之 CameraInfo 编码模板(前后置摄像头理解、摄像头图像的自然方向理解)

一、Camera.CameraInfo Camera.CameraInfo 是用于获取设备上摄像头信息的一个类&#xff0c;它提供摄像头的各种详细信息&#xff0c;例如&#xff0c;摄像头的方向、是否支持闪光灯等&#xff0c;以下是它的常用属性 static int CAMERA_FACING_BACK&#xff1a;表示设备的后置…

kubernetes 中 利用yaml文件部署应用

目录 1 用yaml文件部署应用有以下优点 1.1 声明式配置&#xff1a; 1.2 灵活性和可扩展性&#xff1a; 1.3 与工具集成&#xff1a; 2 资源清单参数介绍 2.1 获得资源帮助指令explain 2.2 编写示例 2.2.1 示例1&#xff1a;运行简单的单个容器pod 2.2.2 示例2&#xff1a;运行…

二叉树 - 最大二叉树

654. 最大二叉树 方法一 /*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val (valundefined ? 0 : val)* this.left (leftundefined ? null : left)* this.right (rightundefined ? null : right)* }*/ /*** param…

java整合Redission

1.maven仓库查询Redisson并倒入项目 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.35.0</version> </dependency> 2.配置文件&#xff08;采用yml配置方式&…

江协科技STM32学习- P9 OLED调试工具

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

2024年9月5日历史上的今天大事件早读

1885年9月5日 左宗棠病逝福州 1894年9月5日 中国古文字学家容庚出生 1905年9月5日 在中国土地上进行的日俄战争结束 1919年9月5日 可口可乐公司成立 1929年9月5日 上海沙逊大厦落成 1937年9月5日 最大一次纳粹集会在纽伦堡举行 1939年9月5日 汪伪政权设立特务组织“七十六…

vue3安装sass时报错:Embedded Dart Sass couldn‘t find the embedded compiler executable

vue3安装sass&#xff1a; npm install sass --save-dev 引用 <template><div class"c1"><h1>hello</h1></div> </template> <style lang"scss">.c1{background-color:red;h1{color:yellow;}} </style>报…

通信算法之230: 5G随机接入PRACH及长度计算

在介绍超远覆盖特性之前&#xff0c;先需了解一下终端接入网络的基本过程。在任何情况下&#xff0c;终端同网络建立通信&#xff0c;都需通过RACH(随机接入信道)向网络发送一个报文来向系统申请一条信令信道&#xff0c;这就是随机接入的过程。根据3GPP 5G R15标准&#xff0c…

如何禁止 Ubuntu 内核更新 ?

更新系统对于保持它的安全和运行是很重要的&#xff0c;然而有时您可能希望停止内核的更新。如果您需要保持系统稳定&#xff0c;或者特定软件在某个内核版本上运行得最好&#xff0c;那么这将非常有用。 在本指南中&#xff0c;我们将向您展示如何在 Ubuntu 中阻止内核更新。…

基于 Konva 实现Web PPT 编辑器(二)

动画系统 为了实现演示中复杂的动画效果&#xff0c;使用 Animation 类统一管理&#xff1b;切换动画通过 css animation 实现&#xff0c;并且是应用在 konvajs-content 上&#xff0c;动画则通过 gsap 实现&#xff0c;应用在 Konva.Node 上&#xff0c;实现思路如下&#xf…

win12R2安装.NET Framework 3.5

一丶安装原因 因此插件的缺失, 有些软件或系统不支持安装. 二丶安装步骤 1丶下载.NET Framework 3.5 点击插件下载, 提取码: 1995, 下载完成之后解压到想要安装的位置上. 2丶打开 服务器管理器 3丶点击: 管理 -> 添加角色和功能 4丶点击下一步到服务器角色, 选择web服…

SQL的高级查询练习知识点(day24)

目录 1 学习目标 2 基础查询 2.1 语法 2.2 例子 3 条件查询 3.1 含义 3.2 语法 3.3 条件表达式 3.3.1 条件运算符 3.3.2 例子 3.4 逻辑表达式 3.4.1 逻辑运算符 3.4.2 例子 3.5 模糊查询 3.5.1 概述 3.5.2 例子 4 DISTINCT关键字 4.1 含义 4.2 例子 5 总结…

代码随想录算法训练营第五十天 | 98. 所有可达路径

目录 98. 所有可达路径 思路 图的存储 邻接矩阵 邻接表 深度优先搜索 1.确认递归函数&#xff0c;参数 2.确认终止条件 3.处理目前搜索节点出发的路径 方法一&#xff1a; 邻接矩阵写法 方法二&#xff1a;邻接表写法 98. 所有可达路径 题目链接&#xff1a;卡码网题…

2024年第十五届蓝桥杯青少组国赛撞期GESP认证、放弃那个?

昨天蓝桥杯青少组官网发布了速查|第十五届蓝桥杯大赛青少组省赛成绩查询&#xff0c;首先恭喜2024年蓝桥杯青少组省赛一等奖的同学晋级蓝桥杯大赛青少组国赛&#xff0c;蓝桥杯青少组国赛的时间为2024年9月7日&#xff0c;CCF GESP编程能力等级认证也在同一天开始&#xff0c;同…