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

news/2024/6/3 18:31:11 标签: 单片机, stm32, 嵌入式硬件

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定时器写的精准延时)。

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


http://www.niftyadmin.cn/n/5449436.html

相关文章

五分钟快速搭建个人游戏网站(1Panel)

五分钟快速搭建个人游戏网站(1Panel) 环境要求:主流 Linux 发行版本(基于 Debian / RedHat,包括国产操作系统); 如果是Windows OS的可以通过WSL来实现安装。 1 介绍 1Panel 是一个基于 Web 的 L…

手撕A*(效果不太好)

根据这篇博客基于C实现的A*算法&#xff08;链表和二叉堆实现&#xff09;_a*算法是不是必须用到链表?-CSDN博客修改了A*&#xff0c;用优先级队列和unordered_set&#xff0c;但是效果不太好&#xff0c;时间反而增加了&#xff0c;正在探索原因。 #include<vector> #…

探索AI大模型学习:理论基础、技术突破与未来挑战

在当今技术飞速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;大模型学习无疑是推动科技进步和创新的关键力量。AI大模型学习的核心在于通过训练大规模的数据集来提升模型的性能&#xff0c;使之能够更准确、更高效地完成各种任务&#xff0c;从而在多个领域中实现…

Rancher(v2.6.3)——Rancher部署Nginx(单机版)

Rancher部署Nginx详细说明文档&#xff1a;https://gitee.com/WilliamWangmy/snail-knowledge/blob/master/Rancher/Rancher%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3.md#5rancher%E9%83%A8%E7%BD%B2nacos ps&#xff1a;如果觉得作者写的还行&#xff0c;能够满足您的需求&#x…

FMEA由谁主导开发?——FMEA软件

免费试用FMEA软件-免费版-SunFMEA ​关于FMEA到底该由谁主导开发的问题&#xff0c;业界存在不同的看法和实践。 首先&#xff0c;我们需要明确FMEA的目的和作用。FMEA旨在发现产品或过程中的潜在问题&#xff0c;并提出改进措施&#xff0c;以提高产品的可靠性和性能。因此&a…

多线程面试专题

文章目录 多线程的用途线程和进程主要区别实现线程的方式有几种启动线程方法 start()和 run()有什么区别&#xff1f;怎么终止一个线程&#xff1f;如何优雅地终止线程一个线程的生命周期包括以下几种状态线程中的 wait()和 sleep()方法有什么区别&#xff1f;多线程同步有哪几…

在fstab文件中配置UUID方式自动挂载数据盘、swap、目录(**)

linux如何挂在硬盘&#xff0c;自动挂载和手动挂载&#xff08;详细说明&#xff09;https://gitcode.csdn.net/65eedcea1a836825ed7a06f4.html 解决linux重启后磁盘挂载失效的问题 https://blog.csdn.net/sugarbliss/article/details/107033034 linux /etc/fstab 文件详细说…

【MySQL】数据操作语言 (DML) 和 数据定义语言 (DDL)

数据操作语言 (DML) 和 数据定义语言 (DDL) 在数据库管理系统中&#xff0c;DML (Data Manipulation Language) 和 DDL (Data Definition Language) 是两个核心的语言类型&#xff0c;用于管理数据库的数据和结构。本文将深入探讨这两种语言的概念、功能以及通过案例演示它们的…