STM32f103C8定时器输出PWM波信号

利用stm32高级定时器输出PWM,模拟呼吸灯的效果带刹车功能。由于没有示波器查看输出的pwm波形图,所以本次实验使用普通直流电机模拟的。

本文章为学习笔记,其中有些地方解释的不是那么的好,即本笔记可参考、可借鉴、可指点!


简单介绍:

STM32F103C8T6采用 LQFP48方式封装,一共拥有 37个 I/O引脚,被分为PA(15个)、PB(15个)、PC(3个)、PD(2个)、PE(0个)五个组,所有 I/O接口可以映像到 16个外部中断,并且大部份端口都可以可以兼容5V信号。每个 I/O端口可以接受或输出8mA电流,灌电流则可达到20mA。

STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级
定时器。基本定时器 TIM6 TIM7 是一个 16 位的只能向上计数的定时器,只能定时,没有外部
IO 。通用定时器 TIM2/3/4/5 是一个 16 位的可以向上 / 下计数的定时器,可以定时,可以输出比较,
可以输入捕捉,每个定时器有四个外部 IO 。高级定时器 TIM1/8 是一个 16 位的可以向上 / 下计数
的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定
时器有 8 个外部 IO
 

 用到的相关结构体

typedef struct { 
    uint16_t TIM_Prescaler;       // 预分频器
    uint16_t TIM_CounterMode;     // 计数模式
    uint32_t TIM_Period;          // 定时器周期
    uint16_t TIM_ClockDivision;   // 时钟分频
    uint8_t TIM_RepetitionCounter;// 重复计算器
} TIM_TimeBaseInitTypeDef;

备注:
只要用到了TIM定时器就会用到这个结构体
typedef struct { 
    uint16_t TIM_OCMode;          // 比较输出模式
    uint16_t TIM_OutputState;     // 比较输出使能
    uint16_t TIM_OutputNState;    // 比较互补输出使能
    uint32_t TIM_Pulse;           // 脉冲宽度
    uint16_t TIM_OCPolarity;      // 输出极性
    uint16_t TIM_OCNPolarity;     // 互补输出极性
    uint16_t TIM_OCIdleState;     // 空闲状态下比较输出状态
    uint16_t TIM_OCNIdleState;    // 空闲状态下比较互补输出状态
} TIM_OCInitTypeDef;

备注:
只要需要输出PWM波,就需要这个结构体
typedef struct { 
     uint16_t TIM_OSSRState;       // 运行模式下的关闭状态选择
     uint16_t TIM_OSSIState;       // 空闲模式下的关闭状态选择
     uint16_t TIM_LOCKLevel;       // 锁定配置
     uint16_t TIM_DeadTime;        // 死区时间
     uint16_t TIM_Break;           // 断路输入使能控制
     uint16_t TIM_BreakPolarity;   // 断路输入极性
     uint16_t TIM_AutomaticOutput; // 自动输出使能
} TIM_BDTRInitTypeDef;

备注:
这个是中断PWM输出的结构体,也叫PWM死区控制

直接上代码吧!

头文件里面定义的宏,为什么要这么定义,下面注释有解释

/*****************
根据实验所得,用TIM1(即PA引脚组)输出pwm的时候会影响串口1的通信
所以这里将PWM换至其他组,但会丢弃刹车功能
*****************/
#if 0   //修改这个参数选择TIM1高级定时器还是TIM3通用定时器
	#define TIMX_Config            1
	#define RCC_APBxPeriphClockCmd RCC_APB2PeriphClockCmd
	#define RCC_APB2Periph_GPIOx   RCC_APB2Periph_GPIOA
	#define GPIO_Pin_x 			   GPIO_Pin_11
	#define GPIOx				   GPIOA
	#define RCC_APBxPeriph_TIMx	   RCC_APB2Periph_TIM1
	#define TIMx				   TIM1
	
#else
	#define TIMX_Config            0
	#define RCC_APBxPeriphClockCmd RCC_APB1PeriphClockCmd
	#define RCC_APB2Periph_GPIOx   RCC_APB2Periph_GPIOB
	#define RCC_APBxPeriph_TIMx	   RCC_APB1Periph_TIM3
	#define GPIO_Pin_x 			   GPIO_Pin_1
	#define GPIOx				   GPIOB
	#define TIMx				   TIM3
#endif

下面代码解释:但选用高级定时器TIM1的时候,对应的输出引脚是PA11,刹车引脚是PB12;

当选用通用定时器TIM3的时候,对应PWM输出引脚PB1,通用没有刹车功能

关于pwm波输出引脚和刹车中断引脚的初始化
static void TIM_GPIO_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	//PWM输出引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_x;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOx,&GPIO_InitStructure);

#if TIMX_Config
	//死区刹车引脚
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	GPIO_ResetBits(GPIOx,GPIO_Pin_12);
#endif
}

下面代码解释:配置的基本定时器的定时为

ARR+1:自动重装载寄存器的值;其中(ARR+1)为TIM_Period的值
PSC+1:预分频值 ;其中(PSC+1)为TIM_Prescaler的值

一个计数器单次计数的频率:Cnt_CLK=Tclk/(PSC+1)=72M/(PSC+1);周期 T=(PSC+1)/Tclk=(PSC+1)/72M;ARR+1为你需要定时这么多个单次计数频率或周期。

总定时时间: Tout(us) = (重装载值+1)*((预分频值+1) / 内部时钟 ) = (ARR+1)*(PSC+1)/Tclk(单位MHz) ;
即定时器(PWM)一个定时周期 :Tout=(ARR+1)*(PSC+1)/Tclk ;频率f=1/Tout=Tclk/(ARR+1)*(PSC+1) 。

占空比 P=CCR/(ARR+1)=TIM_Pulse/(ARR+1)=TIM_Pulse/TIM_Period。

下面配置的是(ARR+1)=10;(PSC+1)=72;即计算出定时周期为10us 频率为100KHz;
通过TIM_SetCompare1(TIM1, Compare1),来修改占空比的值;则占空比100%的时候Compare1=10;0%占空比的时候Compare1=0。

着重注意:例如 TIM_OC4Init(TIMx, &TIM_OCInitStructure); 初始化的时候,别把通道选错了

关于TIM、pwm、pwm死区等相关配置和初始化
static void TIM_Mode_Config()
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//计时器结构体初始化
	TIM_OCInitTypeDef  TIM_OCInitStructure;//输出比较结构体
	TIM_BDTRInitTypeDef TIM_BDTRInitStructure;//刹车和死区结构体初始化
	
	RCC_APBxPeriphClockCmd(RCC_APBxPeriph_TIMx,ENABLE);
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
	TIM_TimeBaseStructure.TIM_Period=10-1;// 自动重装载寄存器的值ARR
	TIM_TimeBaseStructure.TIM_Prescaler= 72-1;// 时钟预分频值 PSC
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;//不用管
	TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);//初始化
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//选择PWM1模式
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置
	TIM_OCInitStructure.TIM_Pulse = 5;// 设置占空比大小 50%
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;// 输出通道空闲电平极性配置
	TIM_OC4Init(TIMx, &TIM_OCInitStructure);
	TIM_OC4PreloadConfig(TIMx, TIM_OCPreload_Enable);//自动重装载
	
#if TIMX_Config
	TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;//运行模式下的关闭状态选择
    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;//空闲模式下的关闭状态选择
    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;//锁定级别配置
	TIM_BDTRInitStructure.TIM_DeadTime = 11;// 输出比较信号死区时间配置  这里配置的死区时间为152ns 
    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;//刹车功能使能
	TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;//刹车输入检测极性,即外部输入高电平为刹车还是低电平
	TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;//自动输出使能
	TIM_BDTRConfig(TIMx, &TIM_BDTRInitStructure);
#endif

	TIM_Cmd(TIMx, ENABLE);	// 使能计数器
	
#if TIMX_Config
	TIM_CtrlPWMOutputs(TIMx, ENABLE);// 主输出使能,高级定时器才需要配置下面的函数
#endif
}

下面代码解释:下面设置的每次增加的占空比为10%,如果需要更加细致的话,则需要修改上面的TIM相关参数,把每个PWM的分得更加细,这样就可以1%的步进进行调节了。 

着重注意:选择通道几,就要对应配置这个函数的x   “TIM_SetCompareX()"

/****************************
函数:uint8_t Motor_PWM_Fun(void)
参数:
功能:通过PWM实现类似呼吸灯效果的输出
说明://TIM_SetCompare1(TIM1, Compare1);//Compare1 范围0~10 自定义
        只要配置好了,即可直接调用该函数
****************************/
uint8_t Motor_PWM_Fun(void)
{
	value=pwm_value;
	if(pwm_value>10)
	{
		if(pwm_value==20)
		{
			pwm_value=0;
			value=0;
		}
		else
		{
			value=10-value%10;
		}
		TIM_SetCompare4(TIMx,value);//Compare1 范围0~10 自定义
	}
	else
	{
				TIM_SetCompare4(TIMx,value);//Compare1 范围0~10 自定义
	}
	sprintf(PWM_value,"\tPWM:value=%d%%\r\n",value*10);
	Usart1_SendString(PWM_value);
	pwm_value++;
	
	return 0;
}

pwm简易模拟呼吸灯

关注显示器上面的PWM的值的变化,对比车轮的转速变化(这里可能看起不明显) 

PWM调速电机

 注意:

STM32F103C8T6拥有 7个定时器:其中 1个用于电机控制的 16位 PWM高级控制定时器、3个 16位通用定时器、2个看门狗定时器(包含独立型的和窗口型)、1个 24位自减型系统嘀嗒定时器。
高级控制定时器 TIM1:TIM1可以被视为分配到 6个通道的三相 PWM发生器,具有带死区插入的互补 PWM输出,还可以用作完整的通用定时器;其四个独立通道可分别用于:输入捕获、输出比较、产生边缘或中心对齐模式的PWM、单脉冲输出。当配置为 16位普通定时器时,与TIM2、TIM3、TIM4具有相同功能;配置为 16位 PWM发生器时,具有0 ~ 100%的全调制能力。
通用定时器 TIM2、TIM3、TIM4:STM32F103C8T6内置有 3个可同步运行的标准定时器,每个定时器都拥有一个 16位自动加载递加/递减计数器、一个 16位预分频器、4个独立通道,每个通道都可用于输入捕获、输出比较、PWM、单脉冲输出,它们还可以通过定时器链接功能与高级控制定时器 TIM1协同工作,从而提供同步或事件链接功能。

STM32F103C8是一款常用的Cortex-M3内核的微控制器芯片,它具有丰富的外设资源,包括多个定时器模块。对于定时器4 (Timer4) 的PWM输出,以下是具体的步骤和代码实现。 1. 首先,需要初始化定时器4的时钟。定时器4使用的是APB1总线时钟,需要将APB1总线时钟使能,并设置合适的分频系数。 RCC_APB1PeriphClockCmd(RCC_APB1Periph_Timer4, ENABLE); // 使能定时器4时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // 启用定时器4外设 2. 进行定时器4的配置,设置相关寄存器的值,包括设置PWM输出的周期和占空比。 TIM_TimeBaseStructure.TIM_Period = 999; // 设置周期值,决定PWM输出的频率 TIM_TimeBaseStructure.TIM_Prescaler = 71; // 设置预分频系数,用于将时钟源除以一定倍数 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分频 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 设置计数模式为向上计数 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 初始化定时器4 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 设置定时器4的PWM模式 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 启用定时器4的输出比较 TIM_OCInitStructure.TIM_Pulse = 500; // 设置占空比,决定PWM信号高电平持续时间 TIM_OC1Init(TIM4, &TIM_OCInitStructure); // 初始化定时器4的通道1 TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable); // 启用定时器4的通道1的预装载功能 3. 最后,需要使能定时器4并启动PWM输出。 TIM_CtrlPWMOutputs(TIM4, ENABLE); // 使能定时器4的PWM输出 TIM_Cmd(TIM4, ENABLE); // 启动定时器4 通过上述步骤和代码,我们可以实现定时器4的PWM输出。其中,周期值和占空比可以根据具体需求进行调整,以得到期望的PWM形。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值