写pwm波函数可以调用stm32固件库函数直接生成,也可以通过中断来写pwm波;下面就介绍这两种方法,这里先说一下呼吸灯,其原理就是让LED灯由暗变亮再由亮变暗循环,类似呼吸的效果,亮-暗是一个大周期,而LED灯亮或暗是由其刷新的占空比决定,高电平时间占比长则亮,反之则暗;
stm32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出。关于映射及原理大家可查手册吧,这里不做具体叙述了;个人见解:很多知识用到再仔细研究是节省精力的好办法,工程实验做多了,就会发现有些细微的知识可能一直都不需要了解。
补充一下关于stm32 TIMx的管脚映射,每个定时器的通道都有特定的引脚,其可以通过如下两个函数映射跟换引脚:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIMx, ENABLE); //重映射引脚
GPIO_PinRemapConfig(GPIO_FullRemap_TIMx, ENABLE); //完全重映
但可更换的引脚也是固定的,具体如下表:
下面代码包含软件版本pwm波和固件库函数pwm波,具体如下:
1.编译器IAR8,系统win10;
2.板子:STM32F103C8T6核心板,如下:
3.下载器:ST-LINK/V2仿真下载器;
4.板子上LED对应的引脚是GPIOC, GPIO_Pin_13;在IAR对应的stm32F103X模板DRIVER目录下添加:led.c,led.h,timer.c,timer.h文件,如下:
5.led.c 代码如下:
#include "led.h"
/*LED_G 驱动 GPIO 初始化函数*/
void led_gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //调用GPIO结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //配置RCC时钟,使得引脚使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //设置的引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚模式,推挽式输出
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化引脚
}
6.led.h的代码:
#ifndef _LED_H
#define _LED_H
/*包含相关的头文件*/
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void led_gpio_config(void);//声明,初始化LED对应引脚
#endif
7.timer.c代码:
#include "timer.h"
__IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化
__IO uint32_t TimingDelay2; //计数变量2
u8 breath_pwm_high;
u8 breath_pwm_step;
u8 breath_pwm_flag;
u8 breath_circle;
/*SystemCoreClock / 1000000 ------- 1us*/
/*SystemCoreClock / 100000 ------- 10us*/
/*SystemCoreClock / 10000 ------- 100us*/
/*SystemCoreClock / 1000 ------- 1ms*/
//////////////////////////
//设置系统滴答中断延时程序//
/////////////////////////
void Systick_Init(void)
{
//装载系统时钟中断计数值,系统时钟累计达到72000时候溢出产生中断
if (SysTick_Config(72000))
{
/* Capture error */
while (1);
}
}
//延时计数函数,如果不是0,每个系统滴答中断周期自减
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
//延迟函数,设置为 US
void delay_ms(__IO uint32_t nTime)
{
TimingDelay = nTime;//自减初始值
while(TimingDelay != 0);
}
//中断事件函数,原函数在stm32f10x_it.c里面,复制到这里后要将原位置里的注释掉,不然报错
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
//////////////////////////
//设置定时器中断延时程序//
/////////////////////////
//配置嵌套中断控制器 NVCI
void tim2_nvic_config(void)
{
NVIC_InitTypeDef NVIC_Init_Struct; //调用NVCI结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置组优先级
NVIC_Init_Struct.NVIC_IRQChannel = TIM2_IRQn; //设置定时器 2 中断
NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级
NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 0; //设置子优先级
NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断
NVIC_Init(&NVIC_Init_Struct); //初始化NVIC
}
//定时器初始化配置
void tim2_config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //调用定时器结构体
tim2_nvic_config(); //加载嵌套中断控制器 NVCI
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //配置RCC时钟,使得中断使能
TIM_DeInit(TIM2); //将外设 TIMx 寄存器重设为缺省值,复位寄存器
/*
定时计数计算方法如下:
发生中断时间 = (TIM_Prescaler+1)* (TIM_Period+1)/FLK
以定时 1s 为例 TIM_Period=2000-1, TIM_Prescaler=(36000-1)
FLK=72M
*/
//设置36*10/72000000=0.000005s=5us
TIM_TimeBaseInitStruct.TIM_Prescaler = 36-1; //时钟预先分频数
TIM_TimeBaseInitStruct.TIM_Period = 10-1; //自动重装载寄存器的值
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,向上计数方式
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); //初始化TIM2配置
TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除溢出中断标志
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIM 中断
TIM_Cmd(TIM2,ENABLE); //开启时钟
}
//延时计数函数2,如果不是0,每个系统滴答中断周期自减
void TimingDelay_Decrement2(void)
{
if (TimingDelay2 != 0x00)
{
TimingDelay2--;
}
}
//延迟函数,设置为 US
void delay_us2(__IO uint32_t nTime2)
{
TimingDelay2 = nTime2;//时钟滴答数
while(TimingDelay2 != 0);
}
//装载初始值,及呼吸循环检测
void breath_circle_change()
{
//判断呼吸周期是否到了,上限值代表呼吸周期时间
if(breath_circle>=80)
{
//判断占空比分割点,是否已经超过99%占比
if(breath_pwm_high>99)
{
breath_pwm_flag=1;//添加标记,准备自减
}
//判断占空比分割点,是否小于2%占比
if(breath_pwm_high<2)
{
breath_pwm_flag=0;//添加标记,准备自加
}
//修改占空比,设置自加或自减,当占比低于2%时候自加,否则自减
if(breath_pwm_high<100 && breath_pwm_flag==0)
{
breath_pwm_high++;
}
else
{
breath_pwm_high-=2;//快呼慢吸,自减1的话就是1:1呼吸
//breath_pwm_high--;//快呼慢吸,自减1的话就是1:1呼吸
}
breath_circle=0;//呼吸循环置零,重新装载检测
}
}
//定时器2,中断事件函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//固件库函数,判断是否发生TIM2中断
{
// TimingDelay_Decrement2(); //调用延时计数函数
//呼吸分割步长step
breath_pwm_step++;
//设置步长小于分割点时候点亮灯
if(breath_pwm_step GPIO_SetBits(GPIOC, GPIO_Pin_13); //将PB13设置成高电平 } //设置分割点后,熄灭灯 else if(breath_pwm_step<100) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); //将PB13设置成低电平 } else { breath_pwm_step=0;//置0,重新计数 breath_circle++;//计算呼吸循环,调整分割点 } } TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//标志位清除,固件库函数 } ////////////////////////// ////定时器3,通过固件函数产生PWM波 //////////////////////// //定时器3初始化 void TIM3_Int_Init(u16 arr,u16 psc) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//调用TIM结构体 TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载周期值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIMx // TIM_ClearFlag(TIM3,TIM_FLAG_Update); //清除溢出中断标志 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能或者失能指定的 TIM3 中断 TIM_Cmd(TIM3,ENABLE); //开启时钟 NVIC_InitTypeDef NVIC_InitStructure;//调用NVCI结构体 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //设置定时器 23中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //设置子优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断 NVIC_Init(&NVIC_InitStructure); //初始化NVIC } //定时器3,中断事件函数 void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //固件库函数,判断是否发生TIM3中断 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx 的中断待处理位 // LED1=!LED1; } } //PWM波初始化函数 void TIM3_PWM_Init(u16 arr,u16 psc) { //全部映射,将TIM3_CH2映射到PB5 //根据STM32中文参考手册2010中第第119页可知: //当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1 //当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 //当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 //1.开启时钟,配置引脚复用形式,产生PWM波 GPIO_InitTypeDef GPIO_InitStructure;//GPIO结构体 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC |RCC_APB2Periph_AFIO, ENABLE);//使能GPIO外设及ADIO // GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // 重映射引脚,TIM3_CH2->PB5 // GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);//完全重映 // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5; //TIM_CH1和TIM_CH2,重映射引脚后 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM_CH1和TIM_CH2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO // GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO化G //2.设置通用定时器,分频及初始化 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//调用TIM结构体 TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载周期值
上一篇:STM32通用定时器TIM实现PWM波配置步骤
下一篇:STM32定时器控制led灯亮灭
推荐阅读最新更新时间:2024-11-12 14:20
设计资源 培训 开发板 精华推荐
- ADR291GRUZ-REEL7 2.5V便携式设备稳压器典型应用电路
- LTC1731-4.X 的典型应用 - 单节锂离子线性电池充电器控制器
- 用于 SMPS 的 L6566BTR 多模式控制器的轻载(FF 操作)典型频率折返应用
- 使用具有调节功能的 LT1054CS8 正倍频器的典型应用
- OM13078,LPC54102 传感器处理/运动解决方案的开发板
- MK30X单相电表参考设计
- MPC55xx调试和目标适配器
- 2021电赛H-用电器识别分析装置
- LTM4604AEV 演示板、低电压、4A DC/DC 模块稳压器
- UMFT230XA-02,用于 FT230XQ 全速 USB 2.0 接口的 USB 转 4 位 SPI/FT1248 开发模块
- 看视频赢好礼:泰克MIPI家族介绍和测试方案,迎接未来的测试挑战
- 答题有礼|一起学习 Mentor PCB 手册
- 下载白皮书赢好礼:Multi-Die 系统的早期架构性能和功耗分析
- 下载有礼|是德科技:测试设备如何影响产品质量调研报告
- TE户外照明互连解决方案样片来袭 免费申领进行中!
- 学习 TI E2E 工业设计资料抢楼有礼
- 用“芯”做好表|英飞凌智能手表解决方案
- 有奖直播|相约Keysight World 2019“汽车电子及新能源汽车测试”论坛
- ST SensorTile物联网开发套件来啦!免费申请抢鲜体验等你来~
- 有奖直播报名 | 大联大世平集团&Molex 互联方案为下一代汽车科技赋能