STM32f103入门(7)pwm驱动led驱动舵机驱动直流电机

news2025/1/25 11:08:17

PWM驱动

  • PWM介绍
    • TIM_OC1Init 配置通道
    • TIM_OCStructInit 输出比较参数默认值
    • 输出比较模式 TIM_OCInitstructure
    • 输出比较极性 TIM_OCInitstructure
    • 设置输出使能
    • 以下三个决定了PWM的频率 占空比
    • 初始化通道 TIM_OC1Init(TIM2, &TIM_OCInitstructure);
    • GPIO复用 PWM通道
  • 驱动LED
    • 复用推挽输出
  • 驱动舵机
  • 驱动直流电机

PWM介绍

每个定时器有四个通道,每一个通道都有一个捕获比较寄存器,
将寄存器值和计数器值比较,通过比较结果输出高低电平,实现PWM信号在这里插入图片描述

如图为向上计数:
     定时器重装载值为ARR,比较值CCRx
     t时刻对计数器值和比较值进行比较
     如果计数器值小于CCRx值,输出低电平
     如果计数器值大于CCRx值,输出高电平
 
PWM的一个周期
    定时器从0开始向上计数
    当0-t1段,定时器计数器TIMx_CNT值小于CCRx值,输出低电平
    t1-t2段,定时器计数器TIMx_CNT值大于CCRx值,输出高电平
    当TIMx_CNT值达到ARR时,定时器溢出,重新向上计数...循环此过程
    至此一个PWM周期完成
 
影响因素
    ARR : 决定PWM周期(在时钟频率一定的情况下,当前为默认内部时钟CK_INT)
    CCRx : 决定PWM占空比(高低电平所占整个周期比例)

TIM_OC1Init 配置通道

配置比较函数 一个函数配置一个单元
参数1 定时器 参数2 输出比较参数 ******

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

TIM_OCStructInit 输出比较参数默认值

输出比较参数默认值

void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);

用来配置强制输出模式 = 100%占空比

void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);

用来配置CCR寄存器预装功能

void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

用来单独修改CCR寄存器值的函数(更改占空比)****

void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);

再补充说明一下这个函数仅高级定时器使用在使用高级定时器输出PWM时需要调用这个函数使能主输出否则PWM将不能正常输出

void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);

输出比较模式 TIM_OCInitstructure

TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;
1 冻结模式
2 相等时置有效电平
3 相等时置无效电平
4 相等时电平反转
5 6 pwm1 pwm2
在这里插入图片描述

输出比较极性 TIM_OCInitstructure

TIM_OCInitstructure.TIM_OCPolarity = ;

在这里插入图片描述
1高极性 极性不反转 REF波形直接输出 REF有效时 输出高电平
2 REF有效时 输出低电平

设置输出使能

TIM_OCInitstructure.TIM_OutputNState = TIM_OutputNState_Enable;

以下三个决定了PWM的频率 占空比

TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1; //ARR in时基
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1; //PSC in 时基
TIM_OCInitstructure.TIM_Pulse = ; //CCR 0000~FFFF
在这里插入图片描述

初始化通道 TIM_OC1Init(TIM2, &TIM_OCInitstructure);

GPIO复用 PWM通道

在这里插入图片描述

驱动LED

复用推挽输出

在这里插入图片描述在这里插入图片描述
我们可以看到 pa0的控制权 由输出数据寄存器 跳转到了片上外设
所以 PA0的输出模式改为复用输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

分辨率1% 频率1k 占空比 50% 由公式可得
ARR = 100 - 1
CCR = 50
PSC = 720 - 1
后期可以调 CCR 来控制占空比
0 - 100 分别代表占空比 0 - 100 %

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //打开时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 控制权来自于定时器
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
	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;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
	TIM_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 = 50;		//CCR
	TIM_OC1Init(TIM2, &TIM_OCInitStructure);
	
	TIM_Cmd(TIM2, ENABLE);//启动定时器
}

void pwm_setcompare1(uint16_t Compare)  //实时修改CRR 用来控制PWM占空比
{
	TIM_SetCompare1(TIM2, Compare);
}

驱动舵机

驱动舵机不免驱动一个,多数情况下会驱动多个
那么一个定时器应该如何驱动多个舵机呢
我们可以开通多个通道
在这里插入图片描述在这里插入图片描述

占空比要求一般 0.5ms - 2.5 ms

ARR+1 = 20k
PSC + 1 = 72
CRR = 500 -2500

这里通道设置为2 GPIOA pin2
初始化代码基本不变
main如下

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "sevo.h"

uint16_t i;
float angle=0;
int main(void)
{
	OLED_Init();//Apin 14 15
	sevo_init();//TIM2 ͨµÀ2 PA1
	
	while (1)
	{
		if(angle>180) angle=0;
		sevoangle(angle);
		OLED_ShowNum(1,1,angle,3);//
		angle+=30;
		Delay_ms(1000);
		
	}
}

sevo.c如下

#include "stm32f10x.h"                  // Device header

#include "pwm.h"

void sevo_init(void){
	PWM_Init();
}
void sevoangle(float angle){
	angle=angle/180 * 2000 + 500;
	TIM_SetCompare2(TIM2, angle);
}

实现了1s钟 舵机旋转30度

舵机接口   
1. 5V电压 
2. PWM通道2  这里接PA1 TIM2 通道 2
3. GND

驱动直流电机

在这里插入图片描述

频率越快 蜂鸣器杂音越小 20kHZ psc=32 预分频器= 32
72M / 32 = 20KHZ
CCR = -100 ~ +100 反转 和 正转

由于设备不齐全 只能理论以下了

VM 5v
VCC 3.3v
GND
AO1 正极
AO2 负极
PWMA 接A2 使用的TIM2 通道3
AIN2 GPIO A5
AIN1 GPIO A4
正传 A4=1 A5=0
反转 相反
STBY 3.3v


CCR用来控制速度
 0-100
 但我们输入参数的时候是-100 ~ +100  这是因为我们要区分正传还是反转
 如果为负数 我们就A4=0 A5=1 反之 相反
 如果为负值 我们需要取绝对值 否则CCR会错误

留个作业

旋转编码器来控制舵机 留在这

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

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

相关文章

2022年09月 C/C++(五级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:城堡问题 1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####—#####—#—#####—# 2 # # | # # # # # #—#####—#####—#####—# 3 # | | # # # # # #—#########—#####—#—# 4 # # | | | | # # ############################# (图 1)…

关于git约定式提交IDEA

背景 因为git提交的消息不规范导致被乱喷,所以领导统一规定了约定式提交 官话 约定式提交官网地址 约定式提交规范是一种基于提交信息的轻量级约定。 它提供了一组简单规则来创建清晰的提交历史; 这更有利于编写自动化工具。 通过在提交信息中描述功能…

【算法】递归的概念、基本思想

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

LuatOS 开发指南

NDK 开发 官方教程 官方例程 API 下载软件 下载官方NDK例程压缩包到本地&#xff0c;并解压。可以看到目录如下&#xff1a; doc: 文档教程 env: 编译环境 example: NDK示例 platform: 需要编译的平台&#xff08;air72x/air8xx&#xff09; tools: 其他辅助软件 VSCode 使…

问道管理:成交量买卖公式?

跟着股票商场的如火如荼&#xff0c;人们对于怎么解读和使用成交量进行股票生意的需求日积月累。成交量是指在某一特定时间内进行的股票生意的数量&#xff0c;它是投资者们研判商场状况和制定生意战略的重要指标之一。那么&#xff0c;是否存在一种最厉害的成交量生意公式呢&a…

day31 集合

一、Collection 创建对象 Collection c3 new HashSet(); //元素不可重复 无序 Collection c1 new ArrayList(); //元素可重复 有序collection方法 c.add() 添加引用类型数据 c.addAll() 添加collection对象 c.isEmpty() 判断是否为空 c.clear() 清空所有类容 c.…

深入了解Docker镜像操作

Docker是一种流行的容器化平台&#xff0c;它允许开发者将应用程序及其依赖项打包成容器&#xff0c;以便在不同环境中轻松部署和运行。在Docker中&#xff0c;镜像是构建容器的基础&#xff0c;有些家人们可能在服务器上对docker镜像的操作命令不是很熟悉&#xff0c;本文将深…

xx音乐app逆向分析

目标 看一下评论的请求 抓包 这里使用httpcanary 请求包如下 POST /index.php?rcommentsv2/getCommentWithLike&codeca53b96fe5a1d9c22d71c8f522ef7c4f&childrenidcollection_3_1069003079_330_0&kugouid1959585341&ver10&clienttoken7123ecc548ec46d…

frida动态调试入门02——hook加密函数

说明 frida是一款Python工具可以方便对内存进行hook修改代码逻辑在移动端安全和逆向过程中常用到。 前置知识 frida动态调试入门01——定位关键代码 https://blog.csdn.net/qq_41690468/article/details/132607065 定位函数 关键函数 String code RequestUtil.paraMap(ad…

Linux 指令心法(四)`touch` 创建一个新的空文件

文章目录 命令的概述和用途命令的用法命令行选项和参数的详细说明命令的示例命令的注意事项或提示 命令的概述和用途 touch 是一个用于在 Linux 和 Unix 系统中创建空文件或更改现有文件的访问和修改时间的命令。如果指定的文件不存在&#xff0c;touch会创建一个新的空文件&a…

九、idSpanMap使用基数树代替原本的unordered_map 十、使用基数树前后性能对比

九、idSpanMap使用基数树代替原本的unordered_map 我们原本的idSpanMap用的是STL容器中的unordered_map哈希桶&#xff0c;因为STL的容器本身是不保证线程安全的&#xff0c;所以我们在访问时需要加锁保证线程安全&#xff0c;这也就是我们写的内存池的性能的瓶颈点。因为我做…

【MySQL】基础知识(二)

MySQL基础知识(二) 文章目录 MySQL基础知识(二)01 表操作1.1 创建表1.2 查看所有表1.3 查看指定表的结构1.4 删除表练习 02 CURD2.1 新增2.1.1 指定列插入2.1.2 datetime类型插入 2.2 查询2.2.1 全列查询2.2.2 指定列查询2.2.3 查询字段为表达式2.2.4 别名查询2.2.5 去重2.2.6 …

【Cookie和Session的那些事儿】

&#x1f320;作者&#xff1a;TheMythWS. &#x1f386;专栏&#xff1a;《集合与数据结构》 &#x1f387;座右铭&#xff1a;不走心的努力都是在敷衍自己&#xff0c;让自己所做的选择&#xff0c;熠熠发光。 目录 认识Cookie和Session Cookie Cookie对象的特点 Cookie对…

【算法日志】动态规划刷题:股票买卖附加问题(day42)

代码随想录刷题60Day 目录 前言 含冷冻期的股票买卖最佳时期 含手续费的股票买卖最佳时期 前言 今天的股票买卖问题会附加一些条件&#xff0c;但总体难度不大。 含冷冻期的股票买卖最佳时期 该问题难点在于对几个状态进行解构并写出相应的状态转移方程。 int maxProfit(ve…

每日一博 - 漫谈流控小妙招

文章目录 Pre概述实现方式固定窗口算法&#xff08;计数器法&#xff09;定义实现 滑动窗口算法定义实现 漏桶算法定义实现 令牌桶算法定义实现每秒产生5个令牌应对突发流量平滑预热 网关限流流量整形中间件限流 Pre 深入理解分布式技术 - 限流 并发编程-25 高并发处理手段之…

Revit SDK:AutoParameter 添加参数

前言 这个例子介绍如果往族文件里添加参数。 内容 Revit 的参数&#xff0c;参考官方文档&#xff1a; 这个例子的关键接口&#xff1a; // 通过 FamilyManager 添加参数 FamilyParameter AddParameter(string parameterName, BuiltInParameterGroup parameterGroup, Categ…

【JS案例】JS实现积分抽奖(内附源码)

JS案例实现积分抽奖 &#x1f31f;效果展示 &#x1f31f;HTML结构 &#x1f31f;CSS样式 &#x1f31f;实现思路 &#x1f31f;具体实现 1.定义抽奖次数渲染 2.点击抽奖按钮,实现滚动抽奖效果 3.弹窗处理 &#x1f31f;完整代码 &#x1f31f;写在最后 &#x1f3…

阿里面试经验分享:从被回绝到Offer,详解应聘阿里技术岗位注意事项

本文是《谈谈应聘阿里全流程》的姊妹篇&#xff0c;《谈谈应聘阿里全流程》发布后&#xff0c;收到了很多读者的积极反馈&#xff0c;但其中也反映出读者普遍的困惑&#xff1a;清楚了应聘流程&#xff0c;该如何有针对性地做应聘准备呢&#xff1f;这个问题从正面并不好回答&a…

windows自带远程桌面连接的正确使用姿势

摘要 目前远程办公场景日趋广泛&#xff0c;对远程控制的需求也更加多样化&#xff0c;windows系统自带了远程桌面控制&#xff0c;在局域网内可以实现流程的远程桌面访问及控制。互联网使用远程桌面则通常需要使用arp等内网穿透软件&#xff0c;市场上teamviewer、Todesk、向…

浅探Android 逆向前景趋势~

前段时间&#xff0c;我和朋友偶然间谈起安卓逆向&#xff0c;他问我安卓逆向具体是什么&#xff0c;能给我们带来什么实质性的东西&#xff0c;我也和朋友大概的说了一下&#xff0c;今天在这里拿出来和大家讨论讨论&#xff0c;也希望帮助大家来了解安卓逆向。 谈起安卓逆向…