STM32--TIM定时器(2)

文章目录

  • 输出比较
  • PWM
  • 输出比较通道
  • 参数计算
  • 舵机简介
  • 直流电机简介
    • TB6612
  • PWM基本结构
  • PWM驱动呼吸灯
  • PWM驱动舵机
  • PWM控制电机

输出比较

输出比较,简称OC(Output Compare)
输出比较的原理是,当定时器计数值与比较值相等或者满足某种特定条件时,比较通道会产生一个输出信号,这个输出信号可以用来触发外部事件,如控制其他外设的操作,或者驱动外部电路
在每个高级定时器和通用定时器都拥有4个输出比较通道。
高级定时器的前3个通道额外拥有死区生成和互补输出的功能。

PWM

我们可以利用输出比较来对外产生一个PWM频率。
PWM(Pulse Width Modulation)脉冲宽度调制是一种常用的控制信号技术。通过改变信号的脉冲宽度来控制电力开关装置的平均功率。在PWM中,周期保持不变,而脉冲的宽度可以根据需要进行调整。
PWM技术广泛应用于电力电子领域,特别是在电机控制和电源调节方面。通过调整PWM信号的占空比(脉冲宽度与周期之比),可以精确地控制输出信号的平均电压或电流。这种控制方式可以实现对电机速度、亮度、电压等参数的精确控制,具有高效率、高精度和低成本的优点。
在这里插入图片描述
频率=1/Ts;占空比=Ton/Ts;分辨率=占空比的变化步距。
我们可以利用输出比较,对输出电平进行一定程度的控制,就能输出PWM频率。

输出比较通道

通用定时器总框图。
在这里插入图片描述

放大效果:
在这里插入图片描述
在比较通道左边,CNT计数器与捕获/比较寄存器中的值进行比较大小,再根据控制器,就会输出一定的电平。
ETRF是定时器的小功能,一般不用到。
REF(rreference)实际上就是指这里信号的高低电平。REF可以映射到主模式的TRGO输出上去;REF的主要去向是去到输出使能电路,它会先走向一个寄存器,如果寄存器输出为0,那么电平将不翻转,保持原样;如果信号为1,REF会通向一个非门取反,也就是高低电平翻转的信号;接着通过使能电路,将有一个寄存器(CC1E)控制;最后到OC1引脚,接到CH1通道上。
输出模式控制器,可以根据自己需求来选择模式:
在这里插入图片描述

参数计算

在这里插入图片描述
红色线表示CCR,也就是比较值;黄色线表示自动装载寄存器中的值(ARR);蓝色线表示计数值CNT;
当CNT<CCR时,输出高电平;当CNT>=CCR时,输出低电平。
这里对应的是PWM模式1的向上计数

PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)

舵机简介

舵机(Servo)是一种常用的电动执行器,通常用于控制机械运动和定位定位。它由一个直流电机、减速装置、位置反馈装置和控制电路组成。
舵机的工作原理是控制电路根据输入信号生成特定的PWM信号,并驱动直流电机和减速装置运转,使输出轴转动到所需的位置。位置反馈装置(常用的是旋转式电位器)会实时监测输出轴的位置,并将信息反馈给控制电路,以便进行修正和精确控制。

SG90使用要求:输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms

在这里插入图片描述
硬件电路:
在这里插入图片描述

直流电机简介

直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转。
直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作。
在这里插入图片描述

TB6612

TB6612是一款双路H桥型的直流电机驱动芯片,常用于控制直流电机的转动方向和速度。它具有高效率、低功耗和高输出等特点,适用于各种电机驱动应用。
TB6612芯片内部集成了H桥驱动电路,可通过控制引脚实现正转、反转、制动和浮动等操作。它可以工作于3.3V或5V逻辑电平,支持PWM输入控制电机速度,并提供过流保护功能,防止电机过载。

硬件电路:
在这里插入图片描述
在这里插入图片描述

PWM基本结构

在这里插入图片描述
通过配置时基单元,,让计时器驱动与CCR比较,在PWM模式1下输出电平最后通向GPIO口。

PWM驱动呼吸灯

接线模式:
在这里插入图片描述
PWM.h

#ifndef __PWM_H__
#define __PWM_H__

void PWM_Init();
void PWM_SetCompare(uint16_t Compare);

#endif

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init()
{
    
    //开启APB1外设开关
    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_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    
    //配置内部时钟TIM2
    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; //自动加载寄存器周期值
    TIM_TimeBaseInitStructure.TIM_Prescaler=1-1; //预分频值
    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=0; //指定要捕获的脉冲值CCR
    TIM_OC1Init(TIM2,&TIM_OCInitStructure);
    //启用TIM2外设控制
    TIM_Cmd(TIM2,ENABLE);


}
//设置CCR比较值
void PWM_SetCompare(uint16_t Compare)
{
    TIM_SetCompare1(TIM2,Compare);
}

对于GPIO口来说,不止是接通了外设,还需要将PWM频率传输给外设,所以使用了复用推挽输出。
输出比较结构体有多个成员,我们这里一些成员不用到,所以先进行结构体初始化,再进行对一些成员的赋值。

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"

uint16_t i;

int main()
{
    OLED_Init();
    PWM_Init();
    
    while(1)
    {
        for(i=0;i<=100;i++)
        {
            PWM_SetCompare(i);
            Delay_ms(10);
        }
        for(i=0;i<=100;i++)
        {
            PWM_SetCompare(100-i);
            Delay_ms(10);
        }
    }
}

PWM驱动舵机

OLED函数所取地址

连接方式:
在这里插入图片描述
SYTM32驱动电压只有3.3V,舵机需要5V的驱动电压;

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"


void Servo_Init()
{
    PWM_Init();
}

void Servo_SetAngle(float Angle)
{
    PWM_SetCompare(Angle/180*200+50);
}

Servo.h

#ifndef __SERVO_H__
#define __SERVO_H__

void Servo_Init();
void Servo_SetAngle(float Angle);

#endif

这里的PWM频率是有要求的,所以需要将PWM.c的CNT和ARR进行修改:频率=72M/720/2000=50Hz
在这里插入图片描述
这里的转动度数需要根据占空比来进行计算:
在这里插入图片描述
Key.c

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

void Key_Init(void)
{
	//设置APB2外设时钟开关
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	//对结构体成员的选择
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//结构体初始化
	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;
	}
	if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
		Delay_ms(20);
		KeyNum = 2;
	}
	
	return KeyNum;
}

Key.h

#ifndef __KEY_H_
#define __KEY_H_

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif

main.c

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

PWM控制电机

接线方式:
在这里插入图片描述
Motor.h

#ifndef __MOTOR_H__
#define __MOTOR_H__

void Motor_init();
void Motor_GetSpeed(int8_t Speed);

#endif 

Motor.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"

void Motor_init()
{
    //设置APB2外设时钟开关
	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_GetSpeed(int8_t Speed)
{
    if(Speed>=0)
    {
        GPIO_SetBits(GPIOA,GPIO_Pin_5);
        GPIO_ResetBits(GPIOA,GPIO_Pin_4);
        PWM_SetCompare(Speed);
    }
    else
    {
        GPIO_SetBits(GPIOA,GPIO_Pin_4);
        GPIO_ResetBits(GPIOA,GPIO_Pin_5);
        PWM_SetCompare(-Speed);
    }
}


PWM的占空比作为速度的调节,两个接口的正反接作为方向的控制。
对于电机驱动电路所接引脚,需要进行GPIO口的初始化;
当输入速度为负时,将接口上引脚进行电平翻转,读者可以进行尝试,怎么接为正,怎么接为负;对于小于0的速度,需要加上符号变成正数。

main.c

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

飞凌嵌入式与您相约艾睿电子技术解决方案展

艾睿电子公司将在深圳主办年度“技术解决方案展”&#xff0c;2023 年展示会将以“启航未来&#xff0c;携手共进”为主题&#xff0c;汇聚百家电子/半导体大厂、制造商、供应商、方案公司及创科公司&#xff0c;展示最前沿的产品和领先技术解决方案&#xff0c;如何能驱动人、…

微服务-Nacos(配置管理)

配置更改热更新 在Nacos中添加配置信息&#xff1a; 在弹出表单中填写配置信息&#xff1a; 配置获取的步骤如下&#xff1a; 1.引入Nacos的配置管理客户端依赖&#xff08;A、B服务&#xff09;&#xff1a; <!--nacos的配置管理依赖--><dependency><groupId&…

render和h函数的使用

// 如果没有配置项&#xff0c;则可以省略不写 {}h("div", [h(h-tooltip, // 在tooltip中进行改造// ----- h-tooltip 的配置项 -----Start{props: {placement: "top-start",// content: 提示内容,transfer: true},style: {overflow: hidden,text-overflow…

阿里巴巴面试高频题:JVM内存模型通俗解释!

大家好&#xff0c;我是你们的小米&#xff0c;今天我要和大家一起来探讨一个热门话题——JVM内存模型&#xff01;作为计算机科班出身的小米&#xff0c;一直对技术充满热情&#xff0c;喜欢和大家分享各种有趣的知识。最近在准备阿里巴巴的面试时&#xff0c;遇到了一个非常有…

RestTemplate

RestTemplate介绍 RestTemplate是Spring提供的用于访问RESTful服务的客户端&#xff0c;RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。RestTemplate默认依赖JDK提供http连接的能力&#xff08;HttpURLConnection&#xff09;&#xff0c;…

docker-php扩展

生成扩展骨架 环境&#xff1a;docker-compose、php74 1.本地要有一份 php-src git clone https://github.com/php/php-src.git cd php-src git checkout PHP-7.4.52.\www\php-src\ext可以看到有一个 ext_skel.php 文件 3.通过ext_skel.php脚本创建了一个hello扩展&#xf…

SpringBoot复习:(51)默认情况下DataSource是怎么创建出来的,是什么类型的?

DataSource是通过DataSourceAutoConfiguration创建的&#xff0c;这个类代码如下&#xff1a; 可以看到DataSourceAutoConfiguration有个静态内部类PooledDataSourceConfiguration,在这个类上有个Import注解&#xff0c;导入了DataSourceConfiguration.Hikari这个类&#xff0…

数据结构——链表详解

链表 文章目录 链表前言认识链表单链表结构图带头单循环链表结构图双向循环链表结构图带头双向循环链表结构图 链表特点 链表实现(带头双向循环链表实现)链表结构体(1) 新建头节点(2) 建立新节点(3)尾部插入节点(4)删除节点(5)头部插入节点(6) 头删节点(7) 寻找节点(8) pos位置…

Unknown tree updater grow_gpu_histb报错

报错显示&#xff1a;由于xgboost的问题而报错 报错显示&#xff1a;Unknown tree updater grow_gpu_histb 原因是 XGBoost 在尝试使用 GPU 加速时无法识别指定的树更新器。也就是当前xgboost版本中没有grow_gpu_histb组件&#xff0c;所以需要安装正确的版本。 经搜索&#…

银河麒麟服务器v10 sp1 .Net6.0 上传文件错误

上一篇&#xff1a;银河麒麟服务器v10 sp1 部署.Net6.0 http https_csdn_aspnet的博客-CSDN博客 .NET 6之前&#xff0c;在Linux服务器上安装 libgdiplus 即可解决&#xff0c;libgdiplus是System.Drawing.Common原生端跨平台实现的主要提供者&#xff0c;是开源mono项目。地址…

ios swift5 collectionView 瀑布流(两列)

文章目录 1.瀑布流1.1 demo地址1.2 记得把部署的最低版本由8改成11,13甚至更高。不然编译会报错 2.动态计算图片和文字的高度 1.瀑布流 1.1 demo地址 CollectionViewWaterfallLayout - github 1.2 记得把部署的最低版本由8改成11,13甚至更高。不然编译会报错 2.动态计算图片和…

问道管理:机器人概念走势活跃,新时达涨停,拓斯达、丰立智能等大涨

机器人概念17日盘中走势活跃&#xff0c;到发稿&#xff0c;拓斯达大涨18%&#xff0c;昊志机电涨近16%&#xff0c;丰立智能涨超13%&#xff0c;步科股份、优德精细涨超10%&#xff0c;新时达涨停&#xff0c;天玑科技、兆龙互联、中大力德涨逾9%。 消息面上&#xff0c;8月16…

设计模式

本文主要介绍设计模式的主要设计原则和常用设计模式。 一、UML画图 1.类图 2.时序图 二、设计模式原则 1.单一职责原则 就是一个方法、一个类只做一件事&#xff1b; 2.开闭原则 就是软件的设计应该对拓展开放&#xff0c;对修改关闭&#xff0c;这在java中体现最明显的就…

spring详解

spring是于2003年兴起的一款轻量级的&#xff0c;非侵入式的IOC和AOP的一站式的java开发框架&#xff0c;为简化企业级应用开发而生。 轻量级的&#xff1a;指的是spring核心功能的jar包不大。 非侵入式的&#xff1a;业务代码不需要继承或实现spring中任何的类或接口 IOC&…

Spring5学习笔记—AOP编程

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Spring专栏 ✨特色专栏&#xff1a; M…

国企的大数据岗位方向的分析

现如今大数据已无所不在&#xff0c;并且正被越来越广泛的被应用到历史、政治、科学、经济、商业甚至渗透到我们生活的方方面面中&#xff0c;获取的渠道也越来越便利。 今天我们就来聊一聊“大屏应用”&#xff0c;说到大屏就一定要聊到数据可视化&#xff0c;现如今&#xf…

eclipse 导入项目js报错问题

eclipse 导入项目后会出现项目中的js文件报错&#xff08;红叉&#xff09;&#xff0c;如下图所示&#xff0c;有时候报错的文件很多&#xff0c;需要集中处理。 解决办法&#xff1a; 右键项目名称》Properties》MyEclipse》JavaScript》Include Path&#xff0c;在右侧选择“…

linux 文件权限识别及其修改

一、文件权限认识 在 Linux 系统中&#xff0c;一切皆文件&#xff0c;目录也是一种文件形式叫目录文件&#xff0c;它们的属性主要包含&#xff1a;索引节点(inode)&#xff0c;类型、权限属性、链接数、所归属的用户和用户组、最近修改时间等内容。 如下为根目录下目录&…

基于OpenCV的人脸识别和模型训练系统(万字详解)

前言 我们身边的人脸识别有车站检票&#xff0c;监控人脸&#xff0c;无人超市&#xff0c;支付宝人脸支付&#xff0c;上班打卡&#xff0c;人脸解锁手机。 人脸检测是人脸识别系统组成的关键部分之一&#xff0c;其目的是检测出任意给定图片中的包含的一个或多个人脸&#…

网络通信原理IP头部格式(第四十二课)

字段作用解析:1)版本: 指的IP地址的版本 (IPv4 或 IPV6)2)首部长度: 次数据包的首部长度一共是多少,没有加可选项3)优先级与服务类型:表示****数据包是否需要优选传递4)总长度: 表示的是整个数据包的大小,也就****是首部+数据5)标识符、标志、段偏移量:的作用将拆开的…