STM32嵌入式基础开发03-通用定时器TIM3输出PWM(3_PWM)

1 博客内容

      博客内容基于STM32F103 RET6芯片,使用系统通用定时器实现占空比输出。TIM3四个通道对应的PA6、PA7、PB0、PB1引脚电压输出。程序使用结果使用电压表测试,主要参考B站:正点原子STM32-M3入门初级篇

2 PWM原理

      (1)分频系数71,系统主频72MHz,计算系统计数频率为1MHz,计数运行1次时间是0.000 001s;
      
      (2)ARR向上计数模式从0累加到9共10个数,需要0.000 01s,PWM频率100kHz;
      
      (3)PWM外设初始化选择PMW1模式,即比较输出低,ARR低于CCR1,输出有效电平,即2个有效电平,8个无效电平(空)。输出有效值为20%。而一个CNT计算周期为0.000 1s;
      
      (4)PWM外设初始化TTM比较输出极性高,高电平输出,即PA*输出电压为0.656V(注:GPIO端口高电平一般输出3.3V,电压表读数3.28V)。
在这里插入图片描述

3 主程序(Main.c)


//================================================
//    名称:  Main.c
//    作者:  Morven_X
//    版本:  1.1
//    编制:  2021/01/15 23:10
//    更新:  2021/01/30 22:45
//    功能:  基于STM32F103 RET6芯片,使用通用定时器3通道1/2/3/4输出PWM并测试引脚电压
//    简介:  更新内容增加JTAG禁用,避免带来的输出引脚电压错乱问题(Keil 5.28)
//    Email:  morven_xie@163.com
//================================================

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

int main(void)
{
	LED_Init();
	Delay_Init();
	JTAG_Init();
	PWM_Init(); 

	while(1)
	{
		JTAG_ENable(1);
		GPIO_SetBits(GPIOC, GPIO_Pin_3);   		  //设置高电平输出
	
		TIM_SetCompare1(TIM3,200);                //设置TIM3  CH1占空比输出
		TIM_SetCompare2(TIM3,400);                //设置TIM3  CH2占空比输出
		TIM_SetCompare3(TIM3,600);                //设置TIM3  CH3占空比输出  主板引脚PB0
		TIM_SetCompare4(TIM3,800);                //设置TIM3  CH4占空比输出  主板引脚PB1
	}
}

4 PWM文件(PWM.h)


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

#define TIM3_Reload_Num_ARR  999             //自动重装载寄存器值
#define TIM3_Frequency_Divide_PSC   71     //TIM时钟预分频值

void PWM_Init(void);                       //TIM3_PWM输出初始化

void JTAG_Init(void);
void JTAG_ENable(char JTAG_STA);

#endif

5 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 JTAG_ENable(char JTAG_STA)
{
if(JTAG_STA==0)
{
AFIO->MAPR=0X00000000;
}
else
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //先开启开启AFIO复用时钟
AFIO->MAPR=0X02000000;  //JTAG做普通IO口,但SWD可用
}
return;
}



void PWM_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用于10端口A复位(IOPARST),位0用于AFIO端口A复位(AFIORST)
	//APB1 外设复位寄存器(RCC_APB1_RSTR,32位,用全32为位),偏移地址0x10,复位地址 0x0000 0000。位1用于定时器3复位(TIM3RST)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);   //使能GPIOA外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);   //使能GPIOB外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);    //重映射需开启AFIO时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);    //使能TIM3时钟 
	
	/* 端口(GPIO)设置 */
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6  | GPIO_Pin_7;                //PA6=T3 Ch1,PA7=T3 Ch2
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure);                  //初始化 GPIOA
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1;			//PB0=T3 Ch3,PB1=T3 Ch4
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;        //速度 10MHz
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;          //复用推挽输出
	GPIO_Init(GPIOB,&GPIO_InitStructure);                  //初始化 GPIOB
	
	
	/* TIM时间基数初始化 */
	TIM_TimeBaseSrtructure.TIM_Period= TIM3_Reload_Num_ARR;           //计数器 TIMx_CNT计数 从0累加到ARR次后溢出,设置自动重装载值
	TIM_TimeBaseSrtructure.TIM_Prescaler=TIM3_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(TIM3,&TIM_TimeBaseSrtructure);									  //初始化TIM3的时钟

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

	TIM_Cmd(TIM3, ENABLE);                                            //使能 TIM3
	
//	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);									//设定中断优先级分组0
	
}



6 程序运行结果

6.1 PWM目标状态:

PA6PA7PB0PB1
20%占空比:0.66V40%占空比:1.33V60%占空比:1.98V80%占空比:2.64V

6.2 PWM输出状态

      Debug Analyzer模式调试结果:
在这里插入图片描述

      引脚实测电压:
在这里插入图片描述
      对比电压数据发现PA6和PA7引脚输出结果互调,PB0和PB1引脚输出结果互调,输出与目标不一致。
      20210130更新版本,增加JTAG初始化,输出与目标一致。

7 官方帮助文件校验

7.1 官方标准外设库下载及使用

      官方标准外设库,这里称为帮助文件,ST意法半导体:STM32F10x标准外设库官方下载地址 ,使用方法如下:
在这里插入图片描述

7.2 PWM输出新程序及结果

      调用官方程序,其功能与我写的代码一致,TIM3 Channel1 (PA6)= 50%、TIM3 Channel2 (PA7) = 37.5%、 TIM3 Channel3(PB0)= 25%、TIM3 Channel4(PB1) = 12.5%。

/**
  ******************************************************************************
  * @file    TIM/PWM_Output/main.c 
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"

/** @addtogroup STM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup TIM_PWM_Output
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;
uint16_t CCR1_Val = 333;
uint16_t CCR2_Val = 249;
uint16_t CCR3_Val = 166;
uint16_t CCR4_Val = 83;
uint16_t PrescalerValue = 0;

/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);

/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured, 
       this is done through SystemInit() function which is called from startup
       file (startup_stm32f10x_xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f10x.c file
     */     
       
  /* System Clocks Configuration */
  RCC_Configuration();

  /* GPIO Configuration */
  GPIO_Configuration();

  /* -----------------------------------------------------------------------
    TIM3 Configuration: generate 4 PWM signals with 4 different duty cycles:
    The TIM3CLK frequency is set to SystemCoreClock (Hz), to get TIM3 counter
    clock at 24 MHz the Prescaler is computed as following:
     - Prescaler = (TIM3CLK / TIM3 counter clock) - 1
    SystemCoreClock is set to 72 MHz for Low-density, Medium-density, High-density
    and Connectivity line devices and to 24 MHz for Low-Density Value line and
    Medium-Density Value line devices

    The TIM3 is running at 36 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
                                                  = 24 MHz / 666 = 36 KHz
    TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
    TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
    TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
    TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
  ----------------------------------------------------------------------- */
  /* Compute the prescaler value */
  PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
  /* Time base configuration */
  TIM_TimeBaseStructure.TIM_Period = 665;
  TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  TIM_OC1Init(TIM3, &TIM_OCInitStructure);

  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel2 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel3 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR3_Val;

  TIM_OC3Init(TIM3, &TIM_OCInitStructure);

  TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);

  /* PWM1 Mode configuration: Channel4 */
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = CCR4_Val;

  TIM_OC4Init(TIM3, &TIM_OCInitStructure);

  TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);

  TIM_ARRPreloadConfig(TIM3, ENABLE);

  /* TIM3 enable counter */
  TIM_Cmd(TIM3, ENABLE);

  while (1)
  {}
}

/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void RCC_Configuration(void)
{
  /* TIM3 clock enable */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  /* GPIOA and GPIOB clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
                         RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
}

/**
  * @brief  Configure the TIM3 Ouput Channels.
  * @param  None
  * @retval None
  */
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

#ifdef STM32F10X_CL
  /*GPIOB Configuration: TIM3 channel1, 2, 3 and 4 */
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);	

#else
  /* GPIOA Configuration:TIM3 Channel1, 2, 3 and 4 as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
#endif
}

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  while (1)
  {}
}

#endif

/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

      官方程序结果PA6和PA7引脚输出结果互调,PB0和PB1引脚输出结果互调,同样输出与目标不一致。不纠结于程序,判断程序的写法没有问题(排查为JTAG初始化问题,已更新)。

  • 7
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用STM32生成PWM控制舵机左转右转,需要进行以下步骤: 1. 配置GPIO口为PWM输出模式。 2. 初始化定时器,设置PWM频率和占空比。 3. 根据舵机的需要,设置左转和右转的占空比。 4. 在程序,通过改变PWM占空比的值,控制舵机的转动。 下面是一个简单的示例程序,可以通过改变PWM占空比的值控制舵机的左转和右转: ``` #include "stm32f10x.h" #define PWM_FREQ 50 // PWM频率,单位Hz #define PWM_PERIOD (72000000/PWM_FREQ/1000) // PWM周期,单位us #define SERVO_LEFT_DUTY (PWM_PERIOD/20) // 左转占空比,单位us #define SERVO_RIGHT_DUTY (PWM_PERIOD/10) // 右转占空比,单位us void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void TIM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1; TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_Cmd(TIM3, ENABLE); } void Servo_Left(void) { TIM_SetCompare1(TIM3, SERVO_LEFT_DUTY); } void Servo_Right(void) { TIM_SetCompare1(TIM3, SERVO_RIGHT_DUTY); } int main(void) { GPIO_Config(); TIM_Config(); while(1) { Servo_Left(); delay_ms(1000); Servo_Right(); delay_ms(1000); } } ``` 在这个程序,GPIO口PA7被配置为PWM输出模式,使用定时器TIM3生成PWM信号。左转和右转的占空比分别为PWM周期的1/20和1/10。在程序,控制舵机左转和右转的函数通过改变PWM占空比来实现。函数的delay_ms()函数用于延时,可以使用其他方式实现延时。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值