当前位置: 首页 > news >正文

STM32单片机:基本定时器应用:PWM 生成(STM32L4xx)

STM32的基本定时器的功能比较简单,主要就是提供一个定时器的功能。

本文讨论基本定时器是不是可以实现PWM的功能呢?

其实基本定时器里面是没有PWM功能的,也没有对应的输出引脚。但通过对基本定时器一些寄存器的操作,是可以模拟PWM功能的,只是这个PWM是有软件参与,所以时效性不如硬件上自带的PWM来的高。不过可以通过这个实验来更加深刻理解基本定时器的工作原理。

所谓PWM就是脉宽调制,也就是可以根据需要调整波形的周期和占空比。

为了实现这个功能,需要充分利用自动重新加载寄存器(TIMx_ARR)的预加载功能,也就是通过设置控制寄存器(TIMx_CR1)中的自动重新加载预加载启用位(ARPE=1)来采用预加载方式。

预加载功能的实现过程:就是将(TIMx_ARR)的值加载到影子寄存器后,定时器的计数值(TIMx_CNT)和影子寄存器比较,在此期间可以将新的待加载的值存入(TIMx_ARR),新存入的值不影响当前影子寄存器里面的值,当(TIMx_CNT)计数值达到影子寄存器存储的数值时,会产生更新中断,且自动将刚才存储在(TIMx_ARR)里面待加载的数据加载到影子寄存器,以及将(TIMx_CNT)清0,并重新计数和影子寄存器里面的数据做比较。在此期间可以再次将新的待加载的值存入(TIMx_ARR),如此循环往复。


任务:设计一个波形周期为10ms,高电平时间为2.5ms,低电平时间为7.5ms,通过PA0输出此波形。

使用基本定时器TIM6实现此功能的具体实施步骤如下:

1、  使能TIM6的时钟。

2、  TIM6_CR1.ARPE = 1,TIM6_CR1.URS = 0,TIM6_CR1.UDIS = 0  :允许TIM6_ARR预加载,允许更新,且更新请求的事件源为:定时器溢出,置位TIM6_EGR.UG,通过从模式控制器产生更新。

3、  设置定时器输入时钟的分频系数。

4、  输出高电平:PA0=1

5、  根据定时器时钟频率,计算出维持高电平输出的2.5ms对应的计数值(此处用名称High_CNT表示),并将此值写入(TIM6_ARR),此时这个计数值并没有写入到真正参与比较的影子寄存器,只是缓存在(TIM6_ARR)中,下一步将此值加载到影子寄存器。

6、  TIM6_EGR.UG = 1,将(TIM6_ARR)中的数据加载到影子寄存器,同时将TIM6_CNT清0。

7、  根据定时器时钟频率,计算出维持低电平输出的7.5ms对应的计数值(此处用名称Low_CNT表示),并将此值写入(TIM6_ARR),这个值不影响影子寄存器的值,等到维持高电平的2.5ms时间到达时,产生更新事件,自动将此值(维持低电平的时间的计数值)加载到影子寄存器。

8、  TIM6_SR.TIM_SR_UIF = 0:清除更新中断标志, TIM6_DIER.TIM_DIER_UIE = 1:允许更新中断

9、  TIM6_CR1.CEN = 1: 启动定时器TIM6

10、  NVIC_EnableIRQ(TIM6_DAC_IRQn):开启TIM6更新中断

11、  TIM6中断服务程序:

如果当前PA0=1,表示高电平输出时间结束,因为此前已经将维持低电平输出时间的计数值(Low_CNT)存储到(TIM6_ARR)中了,所以会自动将此值(Low_CNT)加载到影子寄存器(这个无需软件干预,是硬件自动完成的),然后我们可以将维持高电平输出时间的计数值(High_CNT)存入(TIM6_ARR),当低电平输出时间结束后,自动载入维持高电平输出时间的计数值(High_CNT)到影子寄存器。

如果当前PA0=0,表示低电平输出时间结束,因为此前已经将维持高电平输出时间的计数值(High_CNT)存储到(TIM6_ARR)中了,所以会自动将此值(High_CNT)加载到影子寄存器(这个无需软件干预,是硬件自动完成的),然后我们可以将维持低电平输出时间的计数值(Low_CNT)存入(TIM6_ARR),当高电平输出时间结束后,自动载入维持低电平输出时间的计数值(Low_CNT)到影子寄存器。


实现代码:

STM32L4xx_timer.h:定时器的寄存器定义

#define TIM1             ((uint32_t)0x40012C00)    // Advanced-control timer 1
#define TIM8             ((uint32_t)0x40013400)    // Advanced-control timer 8#define TIM2             ((uint32_t)0x40000000)    // General-purpose timer 2
#define TIM3             ((uint32_t)0x40000400)    // General-purpose timer 3
#define TIM4             ((uint32_t)0x40000800)    // General-purpose timer 4
#define TIM5             ((uint32_t)0x40000C00)    // General-purpose timer 5#define TIM15            ((uint32_t)0x40014000)    // General-purpose timer 15
#define TIM16            ((uint32_t)0x40014400)    // General-purpose timer 16
#define TIM17            ((uint32_t)0x40014800)    // General-purpose timer 17#define TIM6             ((uint32_t)0x40001000)    // Basic timer 6
#define TIM7             ((uint32_t)0x40001400)    // Basic timer 7#define TIM_CR1(timx)    REG32(timx + 0x00000000)  // TIMx control register 1
#define TIM_CR2(timx)    REG32(timx + 0x00000004)  // TIMx control register 2
#define TIM_SMCR(timx)   REG32(timx + 0x00000008)  // TIMx slave mode control register
#define TIM_DIER(timx)   REG32(timx + 0x0000000C)  // TIMx DMA/Interrupt enable register
#define TIM_SR(timx)     REG32(timx + 0x00000010)  // TIMx status register
#define TIM_EGR(timx)    REG32(timx + 0x00000014)  // TIMx event generation register
#define TIM_CCMR1(timx)  REG32(timx + 0x00000018)  // TIMx capture/compare mode register 1
#define TIM_CCMR2(timx)  REG32(timx + 0x0000001C)  // TIMx capture/compare mode register 2
#define TIM_CCER(timx)   REG32(timx + 0x00000020)  // TIMx capture/compare enable register
#define TIM_CNT(timx)    REG32(timx + 0x00000024)  // TIMx counter
#define TIM_PSC(timx)    REG32(timx + 0x00000028)  // TIMx prescaler
#define TIM_ARR(timx)    REG32(timx + 0x0000002C)  // TIMx auto-reload register
#define TIM_RCR(timx)    REG32(timx + 0x00000030)  // TIMx repetition counter register
#define TIM_CCR1(timx)   REG32(timx + 0x00000034)  // TIMx capture/compare register 1
#define TIM_CCR2(timx)   REG32(timx + 0x00000038)  // TIMx capture/compare register 2
#define TIM_CCR3(timx)   REG32(timx + 0x0000003C)  // TIMx capture/compare register 3
#define TIM_CCR4(timx)   REG32(timx + 0x00000040)  // TIMx capture/compare register 4
#define TIM_BDTR(timx)   REG32(timx + 0x00000044)  // TIMx break and dead-time register
#define TIM_DCR(timx)    REG32(timx + 0x00000048)  // TIMx DMA control register
#define TIM_DMAR(timx)   REG32(timx + 0x0000004C)  // TIMx DMA address for full transfer
#define TIM_OR1(timx)    REG32(timx + 0x00000050)  // TIMx option register 1
#define TIM_CCMR3(timx)  REG32(timx + 0x00000054)  // TIMx capture/compare mode register 3
#define TIM_CCR5(timx)   REG32(timx + 0x00000058)  // TIMx capture/compare register 5
#define TIM_CCR6(timx)   REG32(timx + 0x0000005C)  // TIMx capture/compare register 6
#define TIM_OR2(timx)    REG32(timx + 0x00000060)  // TIMx option register 2
#define TIM_OR3(timx)    REG32(timx + 0x00000064)  // TIMx option register 3

dev_tim6.c: 定时器TIM6初始化,以及TIM6中断服务程序

//-------------------------------------------------------------------------------------------------
// 初始化TIM6: 基本定时器, 产生PWM波形(高电平时间为2.5ms,低电平时间为7.5ms), 通过PA0输出此波形
//
// 时钟源:  APB1-PCLK1 = 18.432MHz【80 MHz Max】
//
// RCC_CFGR_PPRE1 的分频系数  = 1 时  CLK = APB1-PCLK1
// RCC_CFGR_PPRE1 的分频系数 != 1 时  CLK = APB1-PCLK1 * 2
// 因为: 本系统 RCC_CFGR_PPRE1 的分频系数 = RCC_CFGR_PPRE1_DIV4 , 不等于1
// 所以: CLK = APB1-PCLK1 * 2 = 18.432MHz * 2 = 36.864MHz
//-------------------------------------------------------------------------------------------------
void DEV_TIM6_Init(void)
{// 允许TIM6时钟RCC_APB1ENR1 |= RCC_APB1ENR1_TIM6EN;// TIM_CR1.ARPE = 1, TIM_CR1.URS = 0, TIM_CR1.UDIS = 0TIM_CR1(TIM6) = 0;TIM_CR1(TIM6) |= TIM_CR1_ARPE;// 定时器时钟 = 输入时钟 / (PSC+1) = 36.864MHz / 18 = 2.048 MHzTIM_PSC(TIM6) = 17;// PA0 = 1DEV_GPIO_BitSet(GPIOA, GPIO_PIN_0);// 定时2.5ms的计数值 = 2500 us * 2.048 MHz = 5120TIM_ARR(TIM6) = 5120;// 产生更新事件,将当前TIM_ARR内的数据写入影子寄存器,同时将TIM_CNT清0。TIM_EGR(TIM6) |= TIM_EGR_UG;// 定时7.5ms的计数值 = 7500 us * 2.048 MHz = 15360TIM_ARR(TIM6) = 15360;// 清除更新中断标志TIM_SR(TIM6) = 0;// 允许更新中断TIM_DIER(TIM6) = 0;TIM_DIER(TIM6) |= TIM_DIER_UIE;// 启动TIM6计数器TIM_CR1(TIM6) |= TIM_CR1_CEN;// 开TIM6中断NVIC_EnableIRQ(TIM6_DAC_IRQn);
}//-----------------------------------------------------------------------------
// TIM6中断服务程序
//-----------------------------------------------------------------------------
void TIM6_DAC_IRQHandler(void)
{// 清除更新中断标志TIM_SR(TIM6) = 0;if (GPIO_IDR(GPIOA) & BIT0){TIM_ARR(TIM6) = 5120;           DEV_GPIO_BitClr(GPIOA, GPIO_PIN_0);}   else{TIM_ARR(TIM6) = 15360;          DEV_GPIO_BitSet(GPIOA, GPIO_PIN_0);}   
}

运行结果:

http://www.dtcms.com/a/469367.html

相关文章:

  • 驱动开发-Linux启动
  • 【力扣】hot100系列(三)链表(二)(多解法+时间复杂度分析)
  • 初学者小白复盘14之——指针(3)
  • word和wps下分别设置签名或图片背景透明色的方法
  • 适合户外探险、物流、应急、工业,五款三防智能手机深度解析
  • Java 在 Word 文档中插入图片
  • Python 处理 Word 文档中的批注(添加、删除)
  • 做一个什么网站好软件推广联盟
  • 480元做网站昆明网
  • 使用 openpyxl 生成 excel 折线图
  • Java-idea编辑器中Jar方式打包启动
  • vim 编辑中,临时挂起编辑器进程,返回到终端命令行
  • 基于 Reactor 模式的 HTTP 协议扩展实现
  • 2025 FastExcel在Java的Maven项目的导出和导入,简单易上手,以下为完整示例
  • 做的好点的外贸网站有哪些网站建设实训指导书
  • 【Linux】Centos 8 默认OpenSSH 升级OpenSSH9.8【升级其他OpenSSH版本通用】
  • 【Nginx开荒攻略】深度解析基于域名的虚拟主机配置:从域名解析到实战部署
  • 互联网网站样式坪山建设网站建站
  • 全链路智能运维中的业务影响度评估与资源动态优化机制
  • 微信小程序学习(五)
  • Jmeter接口的负载测试概念
  • Linux-CentOS 7 上安装 MySQL 8.0.43(保姆级教程)
  • 视频分辨率4K,比特率50000kbps,电脑播放时卡顿的原因
  • 使用aspx做电影网站网站建设专用术语
  • Linux内核网络优化:两个网络调优解决方案
  • day7_vite 啊哈哈啊哈哈哈哈哈
  • 化妆品产品的自建网站哟哪些能想到的域名都被注册了
  • 网络协议的零拷贝 和 操作系统的零拷贝异同
  • Apache Drill:一款开源的分布式SQL查询引擎
  • 八年磨一剑:中品维度如何用“分布式电商”为商家打开增长新通路?