STM32F10X PWM配置例程详解,测试无误
2016-01-31 23:42
330 查看
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
GPIO
Delay
Led
Timer
欢迎讨论,共同进步
硬件平台: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 }
欢迎讨论,共同进步
相关文章推荐
- 世间本无传奇
- 函数式编程
- 关于1.11 题后问题的分析
- js 封装ajax
- mycat读写分离与主从切换
- 阿里云 Centos 7 PHP7环境配置 LNMP
- java项目——大数据量的处理
- 从零快速搭建Android项目
- 《VR入门系列教程》之12---转换矩阵
- centos6.5 安装redis-2.8.13.tar.gz
- mycat初次进阶体验
- Interview How to Count Squares
- 《寻找伟大的企业》
- ffmpeg入门(二)
- python科学计算六:scipy矩阵操作
- Android中layout过程详解
- Sublime 40个插件分享
- Tomcat启动常见问题
- MVVM学习初探
- Codeforces 197C (脑洞)