PWM实现电机的正反转和调速以及TIM定时器

pwm.c

#include "pwm.h"


/*
PWM --- PA2 --TIM2_CH3
//将电机信号控制一根接GND,一根接在PA2(TIM2_CH3),
输出PWM控制电机快慢
TIM2挂在APB1 定时器频率:84MHZ


*/
void Pwm_Init(void)
{
	GPIO_InitTypeDef  		GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef 		TIM_OCInitStruct;
	
	//2、使能定时器2和相关IO口时钟。
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	//3、使能GPIOA时钟:
	RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA,ENABLE);
	
	
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_2; 						//引脚2
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_AF;       				//复用功能
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;					//速度
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;					//推挽
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;						//上拉
	//4、初始化IO口为复用功能输出。
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	
	
	//5、GPIOF9复用映射到定时器2选择哪个复用功能
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_TIM2); 
	
	//定时器2挂在APB1(42MHZ)  所以定时器频率:84MHZ
	TIM_TimeBaseInitStruct.TIM_Prescaler	= 84-1;  				//84分频  84MHZ/84=1MZ 
	TIM_TimeBaseInitStruct.TIM_Period		= 500-1;				//计数500 用时500us
	TIM_TimeBaseInitStruct.TIM_CounterMode	= TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1;			//分频因子
	//2、初始化定时器,配置ARR,PSC。
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
	
	
	TIM_OCInitStruct.TIM_OCMode			= TIM_OCMode_PWM1;  		//PWM模式1
	TIM_OCInitStruct.TIM_OCPolarity		= TIM_OCPolarity_High;		//极性电平 即输出的有效电平(电机需要的是高电平)
	TIM_OCInitStruct.TIM_OutputState    = TIM_OutputState_Enable; 	//通道使能
	//7、初始化输出比较参数: 0C3通道3
	TIM_OC3Init(TIM2, &TIM_OCInitStruct);
	
	//8、使能预装载寄存器: 
	TIM_OC3PreloadConfig(TIM2, 	TIM_OCPreload_Enable); 
	
	//9、使能自动重装载的预装载寄存器允许位	
	TIM_ARRPreloadConfig(TIM2,ENABLE);
		
	//10、使能定时器。
	TIM_Cmd(TIM2, ENABLE);

}

在这里,使用了TIM定时器,只能说像EXTI外部中断、TIM定时器这些是基础呀~

之前忘了写time.c的总结

以下是利用TIM定时器控制led灯的
/*

定时器4配置流程
	1、使能定时器时钟。
		   RCC_APB1PeriphClockCmd();
	2、初始化定时器,配置ARR,PSC。
		  TIM_TimeBaseInit();
	3、启定时器中断,配置NVIC。
		  NVIC_Init();
	4、设置 TIM4_DIER  允许更新中断
		TIM_ITConfig();
	5、使能定时器。
		  TIM_Cmd();
	6、编写中断服务函数。
		  TIMx_IRQHandler();
		  
		  */

#include "time.h"




/*

定时器TIM3挂APB1总线下,时钟频率:84MHZ

TIM3为16位定时器  最大计数值为:65535

*/
void Time3_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef  		NVIC_InitStruct;//定义结构体名称
	//1、能定时器时钟。
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	
	//1ms产生中断
	TIM_TimeBaseInitStruct.TIM_Prescaler	= 840-1;  				//84分频  84MHZ/840 = 100KHZ  100 000HZ
	TIM_TimeBaseInitStruct.TIM_Period		= 20000-1;				//计数1000 用时200ms
	TIM_TimeBaseInitStruct.TIM_CounterMode	= TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1;			//分频因子
	//2、初始化定时器,配置ARR,PSC。
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
	

	
	//3、启定时器中断,配置NVIC。
	NVIC_InitStruct.NVIC_IRQChannel						= TIM3_IRQn;  	//选择通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 2;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 2; 			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//通道使能	
	//5、配置中断分组(NVIC),并使能中断。
	NVIC_Init(&NVIC_InitStruct);


	//4、设置 TIM3_DIER  允许更新中断
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	//5、使能定时器。
	TIM_Cmd(TIM3, ENABLE);


}




/*

定时器TIM4挂APB1总线下,时钟频率:84MHZ

TIM4为16位定时器  最大计数值为:65535

*/
void Time4_Init(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef  		NVIC_InitStruct;
	//1、能定时器时钟。
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	
	//1ms产生中断
//	TIM_TimeBaseInitStruct.TIM_Prescaler	= 84-1;  				//84分频  84MHZ/84 = 1MHZ  1us数一个数
//	TIM_TimeBaseInitStruct.TIM_Period		= 1000-1;				//计数1000 用时1ms
//	TIM_TimeBaseInitStruct.TIM_CounterMode	= TIM_CounterMode_Up; 	//向上计数
//	TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1;			//分频因子
//	//2、初始化定时器,配置ARR,PSC。
//	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
	
	//练习3
	
	TIM_TimeBaseInitStruct.TIM_Prescaler	= 8400-1;  				//84分频    84MHZ/8400 = 10KHZ  10000HZ
	TIM_TimeBaseInitStruct.TIM_Period		= 10000-1;				//计数10000 用时1s
	TIM_TimeBaseInitStruct.TIM_CounterMode	= TIM_CounterMode_Up; 	//向上计数
	TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1;			//分频因子
	//2、初始化定时器,配置ARR,PSC。
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);	
	
	//3、启定时器中断,配置NVIC。
	NVIC_InitStruct.NVIC_IRQChannel						= TIM4_IRQn;  	//选择通道
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority	= 2;			//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority			= 2; 			//响应优先级
	NVIC_InitStruct.NVIC_IRQChannelCmd					= ENABLE;		//通道使能	
	//5、配置中断分组(NVIC),并使能中断。
	NVIC_Init(&NVIC_InitStruct);


	//4、设置 TIM4_DIER  允许更新中断
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
	//5、使能定时器。
	TIM_Cmd(TIM4, ENABLE);


}	


//6、编写中断服务函数。1ms
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
	{
	
		//定时器处理事件
		GPIO_ToggleBits(GPIOA,GPIO_Pin_6);
	}
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}


//6、编写中断服务函数。1ms
void TIM4_IRQHandler(void)
{
	static int num=0;
	if(TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
	{
	if(num == 0)
		{
			GPIO_ResetBits(GPIOA, GPIO_Pin_7);//D31一灭4
			//GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
			num++;
		}else
		{
			if(num == 4)
			{
			   num=0;
			}else
			{
			  num++;
			} 
			GPIO_SetBits(GPIOA, GPIO_Pin_7);//灭
		}
		//定时器处理事件
		//GPIO_ToggleBits(GPIOA,GPIO_Pin_7);
	}
	TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}

就是上两篇说到的,TIM定时器和EXTI外部中断都会用到NVIC和中断服务函数,配置流程差不多。

在PWM中TIM定时器的作用

TIM(定时器)在嵌入式系统中通常用于生成精确的时间延迟、定时触发等功能。

TIM2 被配置为 PWM 模式,用于生成 PWM 信号来控制电机的速度或位置。

具体来说,TIM 定时器的作用包括:

1. 生成定时的基准时钟信号:定时器可以生成一个基于系统时钟的定时信号,用于精确计时。这对于需要精确时间间隔的应用非常有用,比如周期性任务的触发

2. 生成 PWM 信号:定时器可以通过配置输出比较通道,生成 PWM(脉冲宽度调制)信号。PWM 信号的占空比可以通过定时器的参数配置来调整,从而控制电机的转速或位置

3. 产生精确的时间延迟:定时器可以用来产生精确的时间延迟,比如在需要精确控制时序的情况下,比如在通信协议中生成特定的时钟信号。

4. 实现定时触发功能:定时器可以配置为在达到特定时间后触发中断,用于执行定时任务。这对于需要周期性执行的任务非常有用,比如传感器数据的定时采集、周期性数据传输等。

总之,TIM 定时器在嵌入式系统中是非常重要的功能模块,它提供了精确的时间控制能力,可以满足各种定时、PWM 生成、延迟等需求。

在这个代码中,通过配置 TIM2 定时器和相关的输出比较通道,实现了 PWM 信号的生成,用于控制电机。

 

pwm.h

#ifndef __PWM_H
#define __PWM_H
#include "stm32f4xx.h"


void Pwm_Init(void);

#endif

 

main.c

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "pwm.h"



//这是一个主函数
int main(void)
{
	
	u32 count = 0;
	
	//NVIC分组 抢占优先级两位:0~3  响应优先级两位:0~3 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	Delay_Init();
	Led_Init();
	Pwm_Init();
	
	
	//不断改变比较值CCRx,达到不同的占空比效果:
	TIM_SetCompare3(TIM2,499);
	
	
	//GPIO_ToggleBits(GPIOE,GPIO_Pin_14);
	while(1)
	{
		for(count=499; count>200; count -= 20)
		{
			TIM_SetCompare3(TIM2,count);
			delay_s(1);
		}
		
		
		
	}
	
	return 0;
}

反转只需将PA2和GND调换位置,从快速到慢速,或者从慢速到快速只需要更改count的数法。 

README

实现电机的正反转和调速只需要用到PWM和delay相关函数 (pwm.c、pwm.h、delay.c、delay.h还要main.c),其中在PWM中使用了TIM定时器、delay相关函数在上几篇(用systick定时器写的精准延时)。

我所实验成功的电机是这种:

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

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

相关文章

信号处理与分析——matlab记录

一、绘制信号分析频谱 1.代码 % 生成测试信号 Fs 3000; % 采样频率 t 0:1/Fs:1-1/Fs; % 时间向量 x1 1*sin(2*pi*50*t) 1*sin(2*pi*60*t); % 信号1 x2 1*sin(2*pi*150*t)1*sin(2*pi*270*t); % 信号2% 绘制信号图 subplot(2,2,1); plot(t,x1); title(信号x1 1*sin(…

nodejs+vue城市交通管理系统的设计与实现pythonflask-django-php

城市交通管理系统的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品,体验高科技时代带给人们的方便,同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓,iOS相比较起来,…

利用pexpect实现ssh自动登录时命令行无法自动换行问题解决

问题描述 使用python的pexpect模块的pexpect.spawn()进行ssh自动登录时,出现超出一定长度(80个字符)时光标自动切换到本行行首进行覆盖输入的情形 原因 使用spawn时输入窗口大小默认限制为[24,80](可通过spawn类的getwinsize(…

HarmonyOS实战开发-如何使用首选项能力实现一个简单示例。

介绍 本篇Codelab是基于HarmonyOS的首选项能力实现的一个简单示例。实现如下功能: 创建首选项数据文件。将用户输入的水果名称和数量,写入到首选项数据库。读取首选项数据库中的数据。删除首选项数据文件。 最终效果图如下: 相关概念 首选…

人工智能(Educoder)-- 搜索技术 -- 启发式搜索

任务描述 本关任务:八数码问题是在一个33的棋盘上有1−8位数字随机分布,以及一个空格,与空格相连的棋子可以滑动到空格中,问题的解是通过空格滑动,使得棋盘转化为目标状态,如下图所示。 为了简化问题的输…

简单使用Swagger

文章目录 1、介绍2、 使用步骤3、 常用注解 1、介绍 Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。 它的主要作用是: 使得前后端分离开发更加方便,有利于团队协作 接口的文…

数据可视化-ECharts Html项目实战(6)

在之前的文章中,我们学习了如何设置散点图、雷达图。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢数据可视化-ECharts Html项目实战(5&a…

软考96-上午题-【操作系统】-文件目录

一、文件目录 1-1、定义 为了实现“按名存取”,系统必须为每个文件设置用于描述和控制文件的数据结构,它至少要包括:文件名、存放文件的物理地址。 这个数据结构称为:文件控制块(FCB),文件控制块的有序集合称为文件…

flutter3_douyin:基于flutter3+dart3短视频直播实例|Flutter3.x仿抖音

flutter3-dylive 跨平台仿抖音短视频直播app实战项目。 全新原创基于flutter3.19.2dart3.3.0getx等技术开发仿抖音app实战项目。实现了类似抖音整屏丝滑式上下滑动视频、左右滑动切换页面模块,直播间进场/礼物动效,聊天等模块。 运用技术 编辑器&#x…

Web前端Html的表单

表单的关键字: form标签表示一个表单区域 action“后端地址” method“提交数据方式:get/post” input 单行输入框 type“text” 文本 name“定义名称 名字自定义” 向后端提交的键 readonly“readonly” 只读,不可修改,但是可以提交 disab…

Django 三板斧、静态文件、request方法

【一】三板斧 【1】HttpResponse (1)介绍 HttpResponse是Django中的一个类,用于构建HTTP响应对象。它允许创建并返回包含特定内容的HTTP响应。 (2)使用 导入HttpResponse类 from django.http import HttpResponse创…

C++ unordered_set和unordered_map

哈希 1. unordered_set/unordered_map1.1 背景1.2 unordered_set1.2.1 特性1.2.2 常用方法 1.3 unordered_map1.3.1 特性1.3.2 常用方法 2. 哈希2.1概念2.2 哈希冲突2.2.1哈希函数2.2.2 解决哈希冲突2.2.2.1 闭散列2.2.2.2 开散列 1. unordered_set/unordered_map 1.1 背景 之…

Rust并发编程thread多线程和channel消息传递

安全高效的处理并发是 Rust 诞生的目的之一,主要解决的是服务器高负载承受能力。 并发(concurrent)的概念是指程序不同的部分独立执行,这与并行(parallel)的概念容易混淆,并行强调的是"同…

如何理解OSI七层模型?

一、是什么 OSI (Open System Interconnect)模型全称为开放式通信系统互连参考模型,是国际标准化组织 ( ISO ) 提出的一个试图使各种计算机在世界范围内互连为网络的标准框架 OSI将计算机网络体系结构划分为七层,每一层实现各自…

存储随笔原创科普视频首播~

一周之前,存储随笔创建了B站账号。小编利用上个周末休息时间专门研究了B站视频录制的各种方案。发现并没有想象的很容易,先花了很长时间准备了一个PPT,再准备演讲大纲,最终磕磕绊绊完成了首期原创视频录制! 可能不尽如…

PCB布线中晶振电容、电源大小电容、电源电容的设计细节

嵌入式软硬件爱好者 一张手册走天下。嵌入式单片机/Linux/Openwrt/电子电路技术交流分享。//主打一个技术层面的剑走偏锋,直击众人重视和不重视的重点//专注基础,才能走的更远 晶振电容 晶振旁边的电容在电路设计中不是用于滤波的。实际上,…

中国疆域从古至今版图演变,中国历史各个朝代地图大全

一、图片描述 每个朝代都有数十张地图,朝代疆域全图重点区域地图,图片是JPG格式,都是高清地图,行政名称清晰可见,非常适合喜欢历史的朋友。本套历史朝代地图,大小1.32G,18个压缩文件。 二、图…

ShardingSphere水平分表——开发经验(2)

1. 什么场景下分表? 数据量过大或者数据库表对应的磁盘文件过大。 Q:多少数据分表? A:网上有人说1kw,2kw?不准确。 1、一般看字段的数量,有没有包含text类型的字段。我们的主表里面是不允许有t…

C语言数据结构之归并排序

疏雨池塘见 微风襟袖知 目录 归并排序的介绍 基本思想 时间复杂度分析 ⭐归并排序步骤 空间复杂度分析 代码展示 ✨归并排序的非递归 代码展示 总结🔥 归并排序的介绍 归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法&#xff…

项目1-加法计算器

1.创建项目 2.导入前端代码 2.1 static包内 2.2 测试前端代码是否有误 显示成功说明无误 2.3 定义用户接口 请求路径:calc/sum 请求方式:GET/POST 接口描述:计算两个整数相加 请求参数: 参数名类型是否必须备注num1Integer是参与计算的第…