STM32嵌入式基础开发05-通用定时器TIM2/4输出PWM(5_PWM_Veh)

1 博客内容

      博客内容基于STM32F103 RET6芯片,使用系统通用定时器实现占空比输出。TIM2对于引脚 PA0、PA1、 PA2、PA3,TIM4四个通道对应的 PA6、PA7、 PA8、PA9引脚输出。增加VehcCtrl程序输出电机芯片DRV8848使能(PA15/PC0),通过Debug模式观察PWM输出。

2 主程序(Main.c)


//================================================
//    名称:  Main.c
//    作者:  Morven_X
//    版本:  1.1
//    编制:  2021/01/25 22:10
//    更新:  2021/01/30 23:01
//    功能:  基于STM32F103 RET6芯片,使用通用TIM2/4通道1/2/3/4输出PWM并测试引脚电压
//    简介:  TIM3带输出引脚用于测试电压,TIM2/4通道用于控制电机(Keil 5.28)
//    Email:  morven_xie@163.com
//================================================


# 	include "stm32f10x.h"
#	include "LED1.h"
#	include "Delay.h"
#	include "PWM.h"
#	include "SPI.h"
#	include "VehCtrl.h"


/***************************************************

TIM2通道1/2控制前左轮电机正反转,CCR1>CCR2时正传
TIM2通道3/4控制前右轮电机正反转,CCR3>CCR4时正传

TIM4通道1/2控制后左轮电机正反转,3/4后右轮电机正反转

***************************************************/
int main(void)
{ 
	JTAG_Init();
	Stm32_Clock_Init(9);            //=====系统时钟设置
	Delay_Init();                   //=====延时初始化
	LED_Init();                     //===== LED 连接的硬件接口
	uart_init(72,9600);           	//=====串口1初始化
	
	
	VehCtrl_MotorEn_Int();
	Delay_ms(100);   
	Motor_EN();
	
	PWM_TIM2_Init();                       //TIM2_PWM输出初始化
  PWM_TIM4_Init();                       //TIM4_PWM输出初始化
	Delay_ms(1000);                       //=====延时等待初始化稳定
	PS2_Init();											      //=====ps2驱动端口初始化
	PS2_SetInit();		 							      //=====ps2配置初始化,配置“红绿灯模式”,并选择是否可以修改
	GPIO_SetBits(GPIOC, GPIO_Pin_3);      //设置LED高电平输出
	Delay_ms(100);
	GPIO_ResetBits(GPIOC, GPIO_Pin_3);    //设置LED高电平输出
	Delay_ms(100);
	GPIO_SetBits(GPIOC, GPIO_Pin_3);      //设置LED高电平输出
	while(1)
		{		
			GPIO_SetBits(GPIOC, GPIO_Pin_3);  //设置LED高电平输出
		
			Delay_us(20);   									//延时500毫秒


			TIM_SetCompare1(TIM2,750);        //设置TIM2  CH1占空比输出  PA0
			TIM_SetCompare2(TIM2,0);          //设置TIM2  CH2占空比输出  PA1

			TIM_SetCompare3(TIM2,1000);       //设置TIM2  CH1占空比输出  PA2
			TIM_SetCompare4(TIM2,0);          //设置TIM2  CH2占空比输出  PA3
		
			TIM_SetCompare1(TIM4,0);          //设置TIM4  CH1占空比输出  PB6
			TIM_SetCompare2(TIM4,1500);       //设置TIM4  CH2占空比输出  PB7
			TIM_SetCompare3(TIM4,0);          //设置TIM4  CH3占空比输出  PB8
			TIM_SetCompare4(TIM4,2000);       //设置TIM4  CH4占空比输出  PB9
			
		} 
}


3 PWM头文件(PWM.h)


# ifndef  _PWM_H
# define  _PWM_H
# include "stm32f10x.h"

#define TIM2_Reload_Num_ARR  1999             //自动重装载寄存器值
#define TIM2_Frequency_Divide_PSC   35    	  //TIM时钟预分频值

#define TIM4_Reload_Num_ARR  1999             //自动重装载寄存器值
#define TIM4_Frequency_Divide_PSC   35        //TIM时钟预分频值


void JTAG_Init(void);
void PWM_TIM2_Init(void);                       //TIM2_PWM输出初始化
void PWM_TIM4_Init(void);                       //TIM4_PWM输出初始化

#endif


4 PWM程序(PWM.c)

# include "PWM.h"

void JTAG_Init(void)

{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //先开启开启AFIO复用时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //使能GPIOB外设时钟
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//关闭JTAG,保留SWD(同时关闭SWD,芯片作废)

}


void PWM_TIM2_Init(void)
{
	/* 初始化结构体定义 */
	GPIO_InitTypeDef  GPIO_InitStructure;                 //GPIO初始化结构体
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseSrtructure;      //TIM时间基数初始化结构体
	TIM_OCInitTypeDef	TIM_OCInitStructure;                //TIM输出比较功能结构体
	
	/* 时钟线(RCC)设置 */
	//RCC 为 Reset and Clock Control 时钟配置寄存器
	//APB2 外设复位寄存器(RCC_APB2_RSTR,32位,用低16为位),偏移地址OxOC,复位地址 0x0000 0000。位2用于IO端口A复位(IOPARST),位0用于AFIO端口复位(AFIORST)
	//APB1 外设复位寄存器(RCC_APB1_RSTR,32位,用全32为位),偏移地址0x10,复位地址 0x0000 0000。位0用于定时器2复位(TIM2RST)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //重映射需开启AFIO复用时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);    //使能TIM2时钟 
	


	/* 端口(GPIO)设置 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;   //TIM2 Ch1/2/3/4
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);                  //初始化 GPIOA
	


	
	/* TIM时间基数初始化 */
	TIM_TimeBaseSrtructure.TIM_Period= TIM2_Reload_Num_ARR;           //计数器 TIMx_CNT计数 从0累加到ARR次后溢出,设置自动重装载值
	TIM_TimeBaseSrtructure.TIM_Prescaler=TIM2_Frequency_Divide_PSC;   //设置预分频系数 PSC
	TIM_TimeBaseSrtructure.TIM_ClockDivision=0;                       //采用时钟分割,见库函数。TIM_Clock_Division_CKD定义,查手册 00:Tdts=Tck_int:01:Tdts=2*Tck_int(2分频)
	TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up;        //TIM 向上计数模式溢出
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseSrtructure);									  //初始化TIM2的时钟参数
	
	

	/* TIM外设初始化 */
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;     			        //选择定时器模式:TIM 脉冲宽度调制模式1,模式1为比较低输出。
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;     //比较输出使能
	TIM_OCInitStructure.TIM_Pulse =(TIM2_Reload_Num_ARR+1)*0;         //比较输出脉冲宽度,设置占空比(初始化用),即CCR
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;           //输出极性:TIM输出比较极性高
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);          								  //初始化TIM2  CH1的时钟,下同	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC3Init(TIM2,&TIM_OCInitStructure);
	TIM_OC4Init(TIM2,&TIM_OCInitStructure);


	
	
	/* 初始化CH1/2/3/4 */
	TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
	TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH2 预装载使能
	TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH3 预装载使能
	TIM_OC4PreloadConfig(TIM2,TIM_OCPreload_Enable);                  //CH4 预装载使能
	TIM_ARRPreloadConfig(TIM2,ENABLE);                                //使能 TIMx在ARR上的预装载寄存器

//	TIM_ClearFlag(TIM2,TIM_IT_CC1);
//	TIM_ClearFlag(TIM2,TIM_IT_CC2);
//	TIM_ClearFlag(TIM2,TIM_IT_CC3);
//	TIM_ClearFlag(TIM2,TIM_IT_CC4);
	
	TIM_Cmd(TIM2, ENABLE);                                            //使能 TIM2
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);						 			//设定中断优先级分组0,这个是我自加的
	
}


	


void PWM_TIM4_Init(void)
	{
	/* 初始化结构体定义 */
	GPIO_InitTypeDef  GPIO_InitStructure;                 //GPIO初始化结构体
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseSrtructure;      //TIM时间基数初始化结构体
	TIM_OCInitTypeDef	TIM_OCInitStructure;                //TIM输出比较功能结构体
	
	/* 时钟线(RCC)设置 */
	//RCC 为 Reset and Clock Control 时钟配置寄存器
	//APB2 外设复位寄存器(RCC_APB2_RSTR,32位,用低16为位),偏移地址OxOC,复位地址 0x0000 0000。位2用于IO端口A复位(IOPARST),位0用于AFIO端口复位(AFIORST)
	//APB1 外设复位寄存器(RCC_APB1_RSTR,32位,用全32为位),偏移地址0x10,复位地址 0x0000 0000。位2用于定时器4复位(TIM2RST)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //使能GPIOB外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //重映射需开启AFIO复用时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);    //使能TIM4时钟 
		
		
	/* 端口(GPIO)设置 */
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;   //TIM4 Ch1/2/3/4
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOB,&GPIO_InitStructure);                  //初始化 GPIOB
	
	

	TIM_TimeBaseSrtructure.TIM_Period= TIM4_Reload_Num_ARR;           //计数器 TIMx_CNT计数 从0累加到ARR次后溢出,设置自动重装载值
	TIM_TimeBaseSrtructure.TIM_Prescaler=TIM4_Frequency_Divide_PSC;   //设置预分频系数 PSC
	TIM_TimeBaseSrtructure.TIM_ClockDivision=0;                       //采用时钟分割,见库函数。TIM_Clock_Division_CKD定义,查手册 00:Tdts=Tck_int:01:Tdts=2*Tck_int(2分频)
	TIM_TimeBaseSrtructure.TIM_CounterMode=TIM_CounterMode_Up;        //TIM 向上计数模式溢出
	TIM_TimeBaseInit(TIM4,&TIM_TimeBaseSrtructure);									  //初始化TIM4的时钟参数

	/* TIM外设初始化 */
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;     			        //选择定时器模式:TIM 脉冲宽度调制模式1,模式1为比较低输出。
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;     //比较输出使能
	TIM_OCInitStructure.TIM_Pulse =(TIM2_Reload_Num_ARR+1)*0.5;         //比较输出脉冲宽度,设置占空比(初始化用),即CCR
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;           //输出极性:TIM输出比较极性高
	
	
	TIM_OC1Init(TIM4,&TIM_OCInitStructure);          								  //初始化TIM4  CH1的时钟,下同	
	TIM_OC2Init(TIM4,&TIM_OCInitStructure);
	TIM_OC3Init(TIM4,&TIM_OCInitStructure);
	TIM_OC4Init(TIM4,&TIM_OCInitStructure);
	
	
	/* 初始化CH1/2/3/4 */	
	TIM_OC1PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH1 预装载使能,功能在ARR和CCR1改变时,等他们计数完一个周期再修改
	TIM_OC2PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH2 预装载使能
	TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH3 预装载使能
	TIM_OC4PreloadConfig(TIM4,TIM_OCPreload_Enable);                  //CH4 预装载使能
	TIM_ARRPreloadConfig(TIM4,ENABLE);                                //使能 TIMx在ARR上的预装载寄存器
	
	TIM_Cmd(TIM4, ENABLE);                                            //使能 TIM2
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);						 			//设定中断优先级分组1,这个是我自加的
}
	

}



5 VehCtrl头文件(VehCtrl.h)

#ifndef  _VehCtrl_H
#define  _VehCtrl_H

# include "stm32f10x.h"

void VehCtrl_MotorEn_Int(void);
void Motor_EN(void);

#endif

6 VehCtrl程序(VehCtrl.c)


# include "stm32f10x_gpio.h"
#	include "VehCtrl.h"

void VehCtrl_MotorEn_Int(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //使能C口GPIO时钟
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     			//选择推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;									//指定引脚PC0,MotEn2
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;					//设置输出速率50MHz//
	GPIO_Init(GPIOC,&GPIO_InitStruct);										//初始化外设GPIOC寄存器
	GPIO_ResetBits(GPIOC, GPIO_Pin_0);
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能A口GPIO时钟
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;     			//选择推挽输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;									//指定引脚PA15,MotEn1
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;					//设置输出速率50MHz
	GPIO_Init(GPIOA,&GPIO_InitStruct);										//初始化外设GPIOA寄存器
	GPIO_ResetBits(GPIOA, GPIO_Pin_15);
	
}


void Motor_EN(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_15);                     //PA15_MotorAB_EN
	GPIO_SetBits(GPIOC, GPIO_Pin_0);                      //PC0_MotorAB_EN
}

#endif

6 输出结果

      留意视频中小车状态与Debug Mode状态显示非同步。

在这里插入图片描述

>> 更多相关内容,点击Morven_Xie博客概览

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值