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

定时器PWM输出

目录

介绍

PWM占空比

框图

输出比较

通道 1 输出比较功能为例

PWM 输出模式

PWM 边沿对齐模式

hal库代码

标准库代码


介绍

       脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微
处理器的数字输出来对模拟电路进行控制的的技术。

        高级控制定时器 (TIM1 和 TIM8) 和通用定时器在基本定时器的基础上引入了外部引脚,可以实现输入捕获和输出比较功能。高级控制定时器比通用定时器增加了可编程死区互补输出、重复计
数器、带刹车 (断路) 功能,这些功能都是针对工业电机控制方面。主要常用的输入捕获和输出比较功能。

        如果把灯亮看作100%,灯灭看作0%,要实现50%的亮度,可以在某个单位时间里亮灯50%时间、灭灯50%时间,只要这个单位时间够小,由于人眼具有视觉暂留效应,就会感觉整个灯是一直亮着,且亮度只要原来的一半。PWM实质就是GPIO不断翻转输出高、低电平,这个效果可以写代码控制GPIO产生,但这样就会占用CPU, CPU就不方便做其它事情。此时可以利用定时器,设置好翻转时间,让其自动控制GPIO翻转,无需CPU再参与。

PWM占空比

        首先定时器从0开始计数,在0~t1时间段, TIMx_CNT<TIMx_CCR1,输出低电平;在t1~t2时间段, TIMx_CNT>TIMx_CCR1,输出高电平; t2时, TIMx_CNT=TIMx_ARR计数器溢出,重新从0开始,如此循环

        在一个周期内,高电平占整个信号周期的百分比,称之为占空比

框图

框图

输出比较

        输出比较就是通过定时器的外部引脚对外输出控制信号,有冻结、将通道 X(x=1,2,3,4)设置为匹配时输出有效电平、将通道 X 设置为匹配时输出无效电平、翻转、强制变为无效电平、强制变为有效电平、 PWM1 和 PWM2 这八种模式,具体使用哪种模式由寄存器 CCMRx 的位 OCxM[2:0]配置。其中 PWM 模式是输出比较中使用的最多。

通道 1 输出比较功能为例

        灰色阴影部分是输入捕获功能部分,右边没有阴影部分就是输出比较功能部分。首先程序员写 CCR1 寄存器,即写入比较值。这个比较值需要转移到对应的捕获/比较影子寄存器后才会真正生效。什么条件下才能转移?图阴影中可以看到 compare_transfer 旁边的与门,需要满足三个条件: CCR1 不在写入操作期间、 CC1S[1:0] = 0 配置为输出、 OC1PE 位置0(或者 OC1PE 位置 1,并且需要发生更新事件,这个更新事件可以软件产生或者硬件产生)。
        当 CCR1 寄存器的值转移到其影子寄存器后,新的值就会和计数器的值进行比较,它们的
比较结果将会通过输出控制部分影响定时器的输出。

PWM 输出模式

        PWM 输出就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定

PWM 边沿对齐模式

        在递增计数模式下,计数器从 0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后重新从 0开始计数并生成计数器上溢事件

        在边沿对齐模式下,计数器 CNT 只工作在一种模式,递增或者递减模式。这里我们以 CNT 工作在递增模式为例,在中, ARR=8, CCR=4, CNT 从 0 开始计数,当 CNT<CCR 的值时, OCxREF为有效的高电平,于此同时,比较中断寄存器 CCxIF 置位。当 CCR<=CNT<=ARR 时, OCxREF为无效的低电平。然后 CNT 又从 0 开始计数并生成计数器上溢事件,以此循环往复。
 

hal库代码

uint8_t led = 0;
TIM_HandleTypeDef g_pwm;
/*计数器CNT从0到CCR, 输出低电平,LED灯亮*计数器CNT从CCR到ARR,输出高电平, LED灯灭*CCR值越小, 占空比越大,灯越暗, CCR值越大,占空比越小,灯越亮, CCR值与亮度成正比*定时器时钟频率为72MHz / 360 = 200kHz。*计算得到每次计数的时间为1 / 200kHz = 5us。*计算定时器的溢出时间可以使用下面的公式:*Tout = ((ARR + 1) / TIM_CLK)= ((2000) / 200000) = 0.01秒 = 10毫秒*/
/*工作参数*/
void tim_pwm_init(uint32_t prescaler, uint32_t period)
{TIM_OC_InitTypeDef pwm_tim;TIM_ClockConfigTypeDef tim_clk_conf;/*72MHz 经过 360 分频后,定时器时钟为 200KHz,即计数器每间隔 5us 计数一次,从 0 计数到 ARR,经历 10ms*/g_pwm.Instance = TIM2;g_pwm.Init.Prescaler = prescaler;/*分频系数  360-1*/g_pwm.Init.Period = period;/*自动重装载值   ARR=2000-1*/g_pwm.Init.CounterMode = TIM_COUNTERMODE_UP;/*向上计数*/g_pwm.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;/*定时器时钟不从 HCLK 分频*/g_pwm.Init.AutoReloadPreload = TIM_AUTOMATICOUTPUT_DISABLE;/*不自动重新装载*/HAL_TIM_PWM_Init(&g_pwm);/*初始化pwm*/tim_clk_conf.ClockSource = TIM_CLOCKSOURCE_INTERNAL;/*选用内部时钟作为定时器时钟源*/HAL_TIM_ConfigClockSource(&g_pwm ,&tim_clk_conf);/*pwm配置*/pwm_tim.OCMode = TIM_OCMODE_PWM1;/*模式1*/pwm_tim.Pulse = led; /*比较值.占空比一半,后面代码再修改*/pwm_tim.OCPolarity = TIM_OCPOLARITY_LOW;/*极性,LED灯对应低电平有效*/pwm_tim.OCFastMode = TIM_OCFAST_DISABLE;/*输出比较快速使能禁止(仅在 PWM1 和 PWM2 可设置*/HAL_TIM_PWM_ConfigChannel(&g_pwm, &pwm_tim, TIM_CHANNEL_2);/*通道2*/HAL_TIM_PWM_Start(&g_pwm, TIM_CHANNEL_2);/*启动中断*/HAL_TIM_PWM_Start_IT(&g_pwm ,TIM_CHANNEL_2 );
}
/*msp初始化*/
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){GPIO_InitTypeDef g_led;__HAL_RCC_GPIOA_CLK_ENABLE();/*使能gpio时钟*/__HAL_RCC_TIM2_CLK_ENABLE();/*使能tim2时钟*/g_led.Pin = GPIO_PIN_1;g_led.Mode = GPIO_MODE_AF_PP;/*复用推挽*/g_led.Pull = GPIO_PULLUP;g_led.Speed = GPIO_SPEED_FREQ_HIGH;/*初始化灯*/HAL_GPIO_Init(GPIOA,&g_led);HAL_NVIC_SetPriority(TIM2_IRQn,0,0);/*配置定时器中断优先级*/HAL_NVIC_EnableIRQ(TIM2_IRQn);/*使能 TIM2 中断*/}
}/*中断函数*/
void TIM2_IRQHandler(void)
{HAL_TIM_IRQHandler(&g_pwm);
}void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){/*修改对应通道的比较寄存器 CCR 的值(占空比)*/__HAL_TIM_SET_COMPARE(&g_pwm , TIM_CHANNEL_2 , led*2000/255);}
}
/*led呼吸灯*/
void pwm_led(void)
{uint8_t flag = 0;/*波形0到255递增,255到0递减*/if(!flag){led=led+1;/*递增*/if(led == 255)flag =1;}else{led=led-1;/*递减*/if(led == 0)flag =0;}HAL_Delay(4);
}

标准库代码

void pwm_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;/*复用推挽*/GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/*使用内部时钟*/TIM_InternalClockConfig(TIM2);/*初始化定时器*//*PWM频率: frq = CK_PSC/(PSC + 1)/(ARR+1)= 72MHZ/ = 70Mhz/(720-1+1)/(100-1+1) = 1000*PWM占空比:duty = CCR/(ARR+1) = 50/(100-1+1) = 50%*PWM分辨率:reso = 1/(ARR + 1) = 1/(100-1+1)  = 1%*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;/*向上计数*/TIM_TimeBaseInitStruct.TIM_Period = 100-1;/*arr自动重装值*/TIM_TimeBaseInitStruct.TIM_Prescaler = 720-1;/*psc预分频值*/TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;/*重复计数器,高级定时器才有,这里给0*/TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);TIM_OCInitTypeDef TIM_OCInitStruct;TIM_OCStructInit(&TIM_OCInitStruct);/*初始化TIM_OCInitStruct*/TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;              /*输出比较模式*/TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCPolarity_High;     /*输出比较的极性*/TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;/*使能输出*/TIM_OCInitStruct.TIM_Pulse = 0;/*ccr捕获比较寄存器值,后面设置*/TIM_OC2Init(TIM2, &TIM_OCInitStruct);/*使用通道*//*开启Tim*/TIM_Cmd(TIM2,ENABLE);
}void  pwm_set_ccr(void)
{uint8_t i;for(i=0;i<=100;i++)/*从0到100呼吸变亮*/{TIM_SetCompare2(TIM2,i);/*设置定时器通道的捕获比较寄存器(CCR1)的值*/Delay_ms(10);}for(i=0;i<=100;i++)/*从0到100呼吸变暗*/{TIM_SetCompare2(TIM2,100-i);/*设置ccr的值*/Delay_ms(10);}
}

相关文章:

  • uniapp 模仿 Android的Menu菜单栏
  • 开源软件:释放创新的力量,改变数字世界的游戏规则
  • 基于springboot实现学生就业管理系统项目【项目源码+论文说明】计算机毕业设计
  • 绝缘栅双极型晶体管igbt短路如何用自动化软件进行测试?
  • WPS文件恢复怎么做?记得掌握这5个方法!
  • 英飞凌TC3xx-Overlay
  • 多模态论文学习之ALBEF(Align BEfore Fusing)
  • 京东h5st逆向 python代码算法还原逆向分析 h5st代码
  • SpringMVC Day 10 : 拦截器
  • 最小化安装移动云大云操作系统--BCLinux-R8-U2-Server-x86_64-231017版
  • 【嵌入式开发学习】__hex文件、bin文件、axf文件的区别
  • Mybatis—XML配置文件、动态SQL
  • [idea]关于idea开发乱码的配置
  • 从零开始的目标检测和关键点检测(一):用labelme标注数据集
  • LeetCode----1979. 找出数组的最大公约数
  • 【5+】跨webview多页面 触发事件(二)
  • Android单元测试 - 几个重要问题
  • Docker 笔记(2):Dockerfile
  • ECMAScript入门(七)--Module语法
  • HTML中设置input等文本框为不可操作
  • mongodb--安装和初步使用教程
  • mysql中InnoDB引擎中页的概念
  • Objective-C 中关联引用的概念
  • windows下mongoDB的环境配置
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 服务器之间,相同帐号,实现免密钥登录
  • 简单易用的leetcode开发测试工具(npm)
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 深入浅出Node.js
  • 我建了一个叫Hello World的项目
  • 项目实战-Api的解决方案
  • Spring Batch JSON 支持
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (07)Hive——窗口函数详解
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (LeetCode 49)Anagrams
  • (搬运以学习)flask 上下文的实现
  • (办公)springboot配置aop处理请求.
  • (分布式缓存)Redis哨兵
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)nsfocus-绿盟科技笔试题目
  • ***详解账号泄露:全球约1亿用户已泄露
  • .net Stream篇(六)
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [ 蓝桥杯Web真题 ]-Markdown 文档解析
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题
  • [ 网络基础篇 ] MAP 迈普交换机常用命令详解
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [Android]使用Git将项目提交到GitHub