STM32F10X PWM配置例程详解,测试无误

发布者:落霞与孤鹜最新更新时间:2018-07-06 来源: eefocus关键字:STM32F10X  PWM配置 手机看文章 扫描二维码
随时随地手机看文章

硬件平台:STM32F10X  PWM模块 + JLink + 示波器

软件平台:Keil 4 

一、基础知识

首先,根据芯片的型号,STM32小容量、中容量产品和STM32F105xx/STM32F107xx的互联型产品,包含一个高级控制定时器(TIM1)。大容量产品的STM32F103xx包含有二个高级控制定时器(TIM1和TIM8)。

一个高级定时器可以输出七路PWM波,而一个通用定时器则最多只能输出四路互补PWM波。

通用定时器和高级定时器相互独立,互不影响,可同时操作。

如果需要的PWM 较多,比如控制六轴的话,可以自行选取不同的定时器,一个不够的话可选两个。

其次,每个通用的定时器一般只有4路通道,每个通道有一个比较寄存器,初始化的时候设置不同的值后,可以生成4路PWM信号,不过这4路的PWM频率相同,占空比可以不一样。 

最后,有任何关于引脚复用、及相关寄存器的具体问题,以相应的数据手册为准。

PWM的实质还是定时器TIMER模块的使用。

二、相应模块

程序涉及的模块有:

RCC:复位及时钟控制模块,用于初始化STM32 USART外设时钟及IO口复用时钟;

GPIO:通用输入输出口复用配置模块;

Delay:利用系统时钟SysTick,也号称“滴答”,写的延时模块;

Led:系统运行提示模块;

Timer:定时器模块配置,PWM配置也在其中。

三:代码

RCC

  #include "Rcc.h"

  

  void RCC_Init(void)

  {  

   ErrorStatus HSEStartUpStatus;

   //定义枚举类型错误状态变量

    

   RCC_DeInit();//复位系统时钟设置

  

   RCC_HSEConfig(RCC_HSE_ON);

   //打开外部高速时钟晶振,使能HSE

   /*RCC_HSE_ON  开

   _off 关  _bypass hse晶振被外部时钟旁路*/

    

   HSEStartUpStatus = RCC_WaitForHSEStartUp();

   /*RCC_WaitForHSEStartUp()返回一个ErrorStatus枚举值,

   success好,error未好*/

  

   if(HSEStartUpStatus == SUCCESS)//HES就绪

   {  

   RCC_HCLKConfig(RCC_SYSCLK_Div1);

   //AHB时钟(HCLK)=系统时钟

  

   RCC_PCLK1Config(RCC_HCLK_Div2);

   //设置低速AHB时钟(APB1)为HCLK的2分频  

    

   RCC_PCLK2Config(RCC_HCLK_Div1);

   //设置高速AHB时钟(APB2)=HCLK时钟

    

   FLASH_SetLatency(FLASH_Latency_2);

   //设置FLASH延时周期数为2

    

   //使能领取指缓存

   FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    

   RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

   //设置PLL时钟源及倍频系数,为HSE的9倍频 8MHz * 9 = 72MHz

   /*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)

   RCC_PLLSource_HSI_Div2   pll输入时钟=hsi/2;

   RCC_PLLSource_HSE_Div1   pll输入时钟 =hse

   RCC_PLLSource_HSE_Div2   pll输入时钟=hse/2

    

   RCC_PLLMul_2  ------_16       pll输入时钟*2---16

   pll输出时钟不得超过72MHZ*/  

    

   RCC_PLLCmd(ENABLE);

   //ENABLE  / DISABLE

    

   while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL输出稳定

   /*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG)  检查指定RCC标志位

   返回SET OR RESET

   RCC_FLAG_HSIRDY  HSI晶振就绪

   RCC_FLAG_HSERDY

   RCC_FLAG_PLLRDY

   RCC_FLAG_LSERDY 

   RCC_FLAG_LSIRDY.......*/  

    

   RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

   //设置PLL为系统时钟源

   /*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource)  设置系统时钟

   RCC_SYSCLKSource_HSI 

   RCC_SYSCLKSource_HSE 

   RCC_SYSCLKSource_PLLCLK  选HSI  HSE PLL 作为系统时钟*/  

    

   while(RCC_GetSYSCLKSource() != 0x08);

   //判断PLL是否是系统时钟

   /*u8 RCC_GetSYSCLKSource(void)  返回用作系统时钟的时钟源

   0x00:HSI   0x04:HSE 0x08:PLL */

   }  

    

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | 

   RCC_APB2Periph_AFIO |

   RCC_APB2Periph_GPIOB , ENABLE);

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

   //U2  U3 时钟在APB1

   //打开GPIO时钟,复用功能,串口1的时钟              

  

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟

   //好奇怪,是因为官方的库函数更新?

   //不是说F10X系列只有一个CAN,而F4有CAN1  CAN2 吗?

   //怎么他的系统配置文件里面是can1?????

    

   RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能

    

   /*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState) 

   enable 或 disable apb2 外设时钟

   RCC_APB2Periph_AFIO  功能复用IO 时钟

   RCC_APB2Periph_GPIOA/B/C/D/E   GPIOA/B/C/D/E 时钟

   RCC_APB2Periph_ADC1/ADC2 ADC1/2 时钟

   RCC_APB2Periph_TIM1 

   RCC_APB2Periph_SPI1

   RCC_APB2Periph_USART1 

   RCC_APB2Periph_ALL 全部APB2外设时钟*/

  }

GPIO


  #include "GPIO.h"

  

  void MYGPIO_Init(void)

  {

   GPIO_InitTypeDef GPIO_InitStructure;

   //GPIO_InitStructure初始化结构体为GPIO_InitTypeDef结构

   GPIO_DeInit(GPIOA);

   GPIO_StructInit(&GPIO_InitStructure);

   //函数:指向结构GPIO_InitTypeDef的指针,待初始化

  

   //CAN TX  : A12

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽

   GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO

   //CAN TX  : A111

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入

   GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO

  

   // USART TX :A9

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

   //2、GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz   最高输出速率

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

   /*Mode,工作状态:GPIO_MODE_AIN  ----- 模拟输入

   _IN_FLOATING  ----- 浮空输入

   _IPD  ----- 上拉输出

   _IPU  ----- 上拉输入

   _OUT_OD  ----- 开漏输出

   _OUT_PP  ----- 推挽输出

   _AF_OD  ----- 复用开漏输出

   _AF_PP  ----- 复用推挽输出*/

   GPIO_Init(GPIOA , &GPIO_InitStructure);

  

   // USART RX :A10

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

   //IO浮空输入

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   //初始化

    

   /************pwm2    pa1**********************/

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH2

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

    

  }


Delay


  #include "delay.h"

  

  static u8  fac_us=0; //us延时倍乘数   

  static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数

  

     

  //初始化延迟函数

  //SYSTICK的时钟固定为HCLK时钟的1/8

  //SYSCLK:系统时钟

  void delay_init()

  {

   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟  HCLK/8

   fac_us=SystemCoreClock/8000000; //为系统时钟的1/8 

  

   fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数 

  }    

  

  //延时nus

  //nus为要延时的us数.       

  void delay_us(u32 nus)

  {

   u32 temp;      

   SysTick->LOAD=nus*fac_us; //时间加载    

   SysTick->VAL=0x00;         //清空计数器

   SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数  

   do

   {

   temp=SysTick->CTRL;

   }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器

   SysTick->VAL =0X00;       //清空计数器  

  }

  //延时nms

  //注意nms的范围

  //SysTick->LOAD为24位寄存器,所以,最大延时为:

  //nms<=0xffffff*8*1000/SYSCLK

  //SYSCLK单位为Hz,nms单位为ms

  //对72M条件下,nms<=1864 

  void delay_ms(u16 nms)

  {    

   u32 temp;   

   SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)

   SysTick->VAL =0x00; //清空计数器

   SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数  

   do

   {

   temp=SysTick->CTRL;

   }while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达   

   SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器

   SysTick->VAL =0X00;       //清空计数器      

  } 


Led


  #include "led.h"

  

  //初始化PB12和13为输出口.并使能这两个口的时钟    

  

  void LED_Init(void)

  { 

   GPIO_InitTypeDef  GPIO_InitStructure;

  

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB,PE端口时钟

  

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;  

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz

   GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB

   GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);

  }


Timer


#include "timer.h"

#include "led.h"

 

//定时器3中断服务程序

void TIM2_IRQHandler(void)   //TIM2中断

{

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) 

//检查指定的TIM中断发生与否:TIM 中断源 

//不等于RESET 即为 SET,就是发生了

//(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) 

{

TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  

//清除TIMx的中断待处理位:TIM 中断源 

LED0=!LED0;

}

}

//通用定时器3中断初始化

//这里时钟选择为APB1的2倍,而APB1为36M

//arr:自动重装值。

//psc:时钟预分频数

 

//TIMX   X:1----4

//TIM2 PWM部分初始化 

//PWM输出初始化

//arr:自动重装值

//psc:时钟预分频数

void TIM2_PWM_Init(u16 arr,u16 psc)

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

/*typedef struct 

u16 TIM_Period; 

自动重装寄存器周期的值,0x00000-----0xFFFF

u16 TIM_Prescaler; 

TIMX 时钟频率除数的预分频值  0x0000----0xFFFF

u8 TIM_ClockDivision; 

时钟分割 TIM_CKD_DIV1  T DTS = Tck_tim  

TIM_CKD_DIV2  T DTS = 2Tck_tim 

TIM_CKD_DIV4  T DTS = 4Tck_tim 

u16 TIM_CounterMode; 

计数器模式 TIM_CounterMode_Up  TIM 向上计数模式

TIM_CounterMode_Down   向下计数模式

TIM_CounterMode_CenterAligned1 -----3    中央对齐模式1--3计数模式

} TIM_TimeBaseInitTypeDef;*/

TIM_OCInitTypeDef  TIM_OCInitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

 

//初始化TIM2

TIM_TimeBaseStructure.TIM_Period = arr; 

//设置在下一个更新事件装入活动的自动重装载寄存器 周期的值 就是周期 计数到5000为500ms

TIM_TimeBaseStructure.TIM_Prescaler =psc; 

//设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 

//设置时钟分割:T DTS = Tck_tim  

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  

//TIM向上计数模式

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 

//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断

 

NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能

NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

 

TIM_Cmd(TIM2, ENABLE);  //使能TIMx外设

//GPIO_PinRemapConfig(GPIO_PartialRemap2_TIM2, ENABLE);   怎么用????

//改变指定管脚的映射  Timer3部分重映射  TIM2_CH2->PB5

//初始化TIM2 Channel2 PWM模式  

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 

//选择定时器模式:TIM脉冲宽度调制模式1

  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 

//比较输出使能

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 

//输出极性:TIM输出比较极性高

//TIM_OCInitStructure.TIM_Pulse = CCR2_Val;

//TIM_Pulse  待装入比较寄存器的脉冲值  0x0000----0xFFFF

TIM_OC2Init(TIM2, &TIM_OCInitStructure);  

//根据T指定的参数初始化外设TIM2 OC2

 

TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  

//使能TIM2在CCR2上的预装载寄存器

//TIM_ARRPreloadConfig(TIM2, ENABLE);

//使能TIM2在ARR上的预装载寄存器

 

TIM_Cmd(TIM2, ENABLE);  //使能TIM2

}


关键字:STM32F10X  PWM配置 引用地址:STM32F10X PWM配置例程详解,测试无误

上一篇:STM32单片机—编码器测速
下一篇:stm32F4编码器测速并通过串口打印--- 程序源码

推荐阅读最新更新时间:2024-03-16 16:07

STM32F10x DMA介绍以及 dma usart数据收发
DMA方式 1. DMA 介绍 Direct memory access (DMA) is used in order to provide high-speed data transfer between peripherals and memory and between memory and memory. Data can be quickly moved by DMA without any CPU action. This keeps CPU resources free for other operations. The DMA controller combines a powerful dual AHB
[单片机]
STM32F10x_ RTC日历
Ⅰ、概述 接着上一篇文章来讲述关于RTC的计数功能,我们以实例RTC日历(读写年、月、日、星期、时、分、秒)来讲述该章节。 STM32F1系列芯片的RTC功能和其他系列(F0、F2、F4等)相比来说,功能要弱一点,原因在于F1系列的RTC日历功能需要我们通过软件进行处理(换算RTC计数值)才能真正实现RTC日历的功能,而其他系列芯片不用这么麻烦,可直接读取日历值。 该文和上一篇文章的区别:1、RTC时钟源选择LSE(外部低速时钟); 2、分频值是32768; 3、读写了RTC_CNT(计数值),用于RTC日历。 本文章提供的实例工程“STM32F10x_RTC日历(LSE)”,其实验效果是: 主函数间隔0.5秒LE
[单片机]
STM32F10x_ RTC日历
STM32F10x 利用环形缓冲区的串口驱动程序
这次讲讲利用串口收发中断来进行串口通讯。STM32 上为每个串口分配了一个中断。也就是说无论是发送完成还是收到数据或是数据溢出都产生同一个中断。程序需在中断处理函数中读取状态寄存器(USART_SR)来判断当前的是什么中断。下面的中断映像图给出了这些中断源是如何汇合成最终的中断信号的。图中也给出了如何控制每一个单独的中断源是否起作用。 另外,Cortex-M3 内核中还有个NVIC,可以控制这里的中断信号是否触发中断处理函数的执行,还有这些外部中断的级别。关于NVIC 可以参考《ARM CortexM3 权威指南》,里面讲解的非常详细。 简单的说,为了开启中断,我们需要如下的代码: NVIC_InitTypeDef N
[单片机]
<font color='red'>STM32F10x</font> 利用环形缓冲区的串口驱动程序
fatfs文件系统移植到STM32F10x
//文件系统与SD卡驱动接口文件diskio.c #include diskio.h #include ffconf.h #include #include MMC_SD.h DSTATUS disk_initialize ( BYTE drv ) { int Status; switch (drv) { case 0 : // Status = MSD0_Init(); Status = SD_Init(); if(Status==0){ return RES_OK; }else{ return STA_NOINIT; } case 1
[单片机]
STM32F0xx_TIM输出PWM配置详细过程
前言 前面我说过STM32的定时器功能很强大,今天就来总结一下它的另外一个“强大”功能:TIM的比较输出功能,输出可调PWM波形。直接调用函数接口“TIM2_CH1_PWM(uint32_t Freq, uint16_t Dutycycle)”传入频率和占空比就能输出指定的波形。 我提供的软件工程直接调用是比较简单就能实现想要的PWM波形。但是,如果你是学习者,建议还是进去函数把每一个细节了解清楚,里面的东西可能对你掌握TIM很有帮助。 ST标准外设库和参考手册、数据手册等都可以在 ST官网 下载,你也可以到我的360云盘下载。关于F0系列芯片的参考手册有多个版本(针对F0不同芯片),但有一个通用版本,就是“STM32F0x12
[单片机]
STM32F0xx_TIM输出<font color='red'>PWM</font><font color='red'>配置</font>详细过程
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved