单片机_PWM输出原理详解

理论篇
  博主自己的经历告诉我,PWM波的理解和应用确实还是挺重要的,这里专门花一期详细介绍一下

  • 什么是PWM?

  PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码。
  通俗的说,就是控制在一个周期内,控制高电平多长时间,低电平多长时间(前面文章种有说过IO口就只有两种状态,0和1,对应就是0和5V或者0和3.3V)。也就是说通过调节高低电平时间的变化来调节信号、能量等的变化。

  图为周期4毫秒的PWM波形

  • 两个重要的概念,频率、占空比

  频率是指每秒钟信号从高电平到低电平再回到高电平的次数,为一个PWM波周期的倒数。上图中频率=1/(0.003+0.001)=250 HZ
  占空比是指高电平持续时间比一个周期持续的时间。上图中占空比=1/(1+3)=25%,所以可以通过控制占空比,来控制输出的等效电压。
  所以对于方波的话,频率和占空比就确定了一个波。

  • 怎么能产生一个PWM波?

  方法1利用芯片内部模块输出PWM信号,STM32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出! 但是!!!同一个定时器TIM只能产生一个频率的PWM波,你只能改变占空比。 具体例程见一下实战篇STM32部分。
  方法2利用IO口高低电平转变输出PWM信号,比如上图中先把电平置1,维持1ms,然后将电平拉低,维持3ms,再将电平置高,如此循环往复下去,就可以产生一个周期4毫秒占空比为25%的PWM波了。具体方法就是给IO口加一个定时器,用定时器中断来实现及时切换高低电平。 具体历程见以下51单片机部分。

  • 定时器

  要想使用51单片机来产生一路PWM,根据上述的方法2,首先你应该知道什么是定时器?定时器是怎么工作的?

  定时器:和计数器说的是一个东西,因为它既能计时也能计数。定时器的实质是,由机器频率向一个16位寄存器累加,累加满溢出时触发中断。为了产生一个我们想要的时间间隔。比如说1s,所以我们要在这个寄存器里设定一个初值,以至于让它在这个初值上累加可以产生一个1s的倍数。这样我们就得到了稳定的时间间隔。
  这个寄存器分为TH(高八位)和TL(低八位)。所以我们需要把计算好的初值分成两部分分别放入TH和TL。

  过程
  首先,我们通过单片机的晶振频率得知其时钟周期,再尤其乘以12得到机器周期。每一个机器周期在寄存器内+1,直到加满溢出产生中断。

  举例说明
  若单片机频率为12Mhz,其时钟周期就是1/12μs,机器周期为1μs,也就是每1μs寄存器+1。16位的寄存器加到溢出最多需要(2^16)-1=65535μs,溢出也需要一个机器周期,所以总共要65536μs。但这个值太别扭,和我们要的1s没什么关系。我们最好让它记50000μs产生一次中断,所以其初值就设为65536-50000=15536。但我们还要将这个值分别放在高八位和低八位,所以要将这个十进制数,转换为4位十六进制数再分开赋值。十进制计算法:TH = 15536/256; TL = 15536%256;,进制计算问题这里不细讨论。这样的话,每50ms就会产生一次中断。我们只要用程序判断其中断20次就记1s。
  定时器部分摘自:https://www.jianshu.com/p/90ea43a7b4fd

  • PWM的应用

1 输出模拟电压(通过电压的高低来控制如LED的亮度,直流电机的速度等)
  PWM对模拟信号电平进行数字编码的方法,计算机只能输出0或5V的数字电压值而不能输出模拟电压,而我们如果想获得一个模拟电压值(介于0 - 5V的电压值),则需通过使用高分辨率计数器,改变方波的占空比来对一个模拟信号的电平进行编码。电压是以一种连接(1)或断开(0)的重复脉冲序列被夹到模拟负载上去的,连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,只要带宽足够,可以输出任意不大于最大电压值的模拟电压。

  输出电压=(接通时间/脉冲时间)*最大电压值12


   PWM输出等效电压
解释部分引自 http://www.eeworld.com.cn/mcu/article_2018061939827.html

2 控制舵机
  大一大二期间做项目经常用到的一个元件就是舵机,而舵机的控制就是通过一个固定周期但是不同占空比来控制舵机摆角的位置的。
  舵机的控制一般需要一个20ms左右的时基脉冲(频率为50HZ),该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;

此图可以表现脉冲宽度(也可以转换成占空比)和舵机摆臂的位置图
3 控制步进电机
  之前在做项目的过程中,一般涉及到精确控制位移的时候,这个时候往复式驱动原件(舵机)就不适合了,所以就会经常用到步进电机。
  步进电机把电脉冲信号变换成角位移以控制转子转动的微特电机。在自动控制装置中作为执行元件。每输入一个脉冲信号,步进电动机前进一步,故又称脉冲电动机。 !!!这里注意一点,直接控制单片机的话是脉冲控制,就是进来一个脉冲信号,步进电机转动一个步进角(一般为1.8°)。所以控制步进电机速度的方式就是通过控制 频率 (占空比一般都是50%)但是!!!现在可以通过接入步进电机驱动板的方式(比如博主之前使用的一款步进电机驱动板Tb6560)细分步进角。比如细分为2,一个脉冲步进电机就转动半个脉冲(0.9°)

PS:这里由于篇幅原因,舵机、步进电机的控制代码就不上传了,网上一搜一大堆,也可以联系博主私法给你喽!


实战篇

  这里使用51和STM32实现呼吸灯的功能,同样原理也可以控制直流电机,舵机是频率一定的情况下控制占空比来控制摆臂的方向,而步进电机是通过控制频率的方式来控制速度。

51部分
  例程使用51单片机将P1.0接一个二极管。运用PWM输出等效模拟电压完成呼吸灯功能。引

unsigned char PWM_COUNT;  //计数
unsigned int  HUXI_COUNT;    //占空比更新时间
unsigned char PWM_VLAUE;    //占空比比对值
bit direc_flag;             //占空比更新方向void timer0_init()
{TMOD=0x02;          //模式设置,00010000,定时器0,工作于模式2(M1=1,M0=0)TH0=0x47;               //定时器溢出值设置,每隔200us发起一次中断。TL0=0X47;TR0=1;                  //定时器0开始计时ET0=1;                  //开定时器0中断EA=1;                       //开总中断PWM_COUNT =0;
}void time0() interrupt 1
{   PWM_COUNT++;HUXI_COUNT++;if(PWM_COUNT == PWM_VLAUE)      //判断是否到了点亮LED的时候LED = 1;                    //点亮LEDif(PWM_COUNT == 10)             //当前周期结束{LED = 0;                    //熄灭LEDPWM_COUNT = 0;              //重新计时}if((HUXI_COUNT == 600) && (direc_flag == 0)){                               //占空比增加10%HUXI_COUNT = 0;PWM_VLAUE++;if(PWM_VLAUE == 9)          //占空比更改方向direc_flag = 1; }if((HUXI_COUNT == 600) && (direc_flag == 1)){                               //占空比减少10%HUXI_COUNT = 0;PWM_VLAUE--;if(PWM_VLAUE == 1)          //占空比更改方向direc_flag = 0; }
}
void main()
{HUXI_COUNT = 0;PWM_COUNT = 0;PWM_VLAUE = 5;direc_flag = 0;LED = 1;            //默认LED熄灭   timer0_init();      //定时器0初始化while(1);
}

  例程部分引自 http://www.eeworld.com.cn/mcu/article_2018061939827.html 有删改

32部分
  转自正点原子库函数手册PWM部分教程
  这里用到了 TIM3 的部分重映射功能(重映射:可以理解成把管脚的外设功能映射到另一个管脚,具体哪个引脚可以映射见参考手册), 例程把 TIM3_CH2 直接映射到了 PB5 上。

//TIM3 PWM 部分初始化
//PWM 输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //①使能定时器 3 时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //①使能 GPIO 和 AFIO 复用功能时钟GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //②重映射 TIM3_CH2->PB5//设置该引脚为复用输出功能,输出 TIM3 CH2 的 PWM 脉冲波形 GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure); //①初始化 GPIO//初始化 TIM3TIM_TimeBaseStructure.TIM_Period = arr; //设置在自动重装载周期值TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //③初始化 TIMx//初始化 TIM3 Channel2 PWM 模式TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择 PWM 模式 2TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高TIM_OC2Init(TIM3, &TIM_OCInitStructure); //④初始化外设 TIM3 OC2TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器TIM_Cmd(TIM3, ENABLE); //⑤使能 TIM3
}int main(void)
{u16 led0pwmval=0;u8 dir=1;delay_init(); //延时函数初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2uart_init(115200); //串口初始化波特率为 115200LED_Init(); //LED 端口初始化TIM3_PWM_Init(899,0); //不分频,PWM 频率=72000/900=80Khzwhile(1){delay_ms(10);if(dir)led0pwmval++;else led0pwmval--;if(led0pwmval>300)dir=0;if(led0pwmval==0)dir=1;TIM_SetCompare2(TIM3,led0pwmval);}
}
//实验现象:我们将看 DS0 不停的由暗变到亮,然后又从亮变到暗。每个过程持续时间大概为 3 秒钟左右。

皮一下,欢迎交流啊! 共同学习,共同进步。

单片机_PWM输出原理详解相关推荐

  1. 矩阵键盘扫描原理详解——单片机

    矩阵键盘扫描原理详解 根据原理图 键盘扫描方法是:行线P10~P13为输出线,列线P14~P17为输入线.一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键 ...

  2. 有刷直流电机工作原理详解

    有刷直流电机工作原理详解 来源:网络整理• 2018-05-10 09:00 • 56380次阅读 有刷直流电机被广泛用于从玩具到按钮调节式汽车坐椅的应用中.有刷直流 (Brushed DC,BDC) ...

  3. DS18B20温度传感器原理详解及例程代码、漏极开路

    [常用传感器]DS18B20温度传感器原理详解及例程代码_Z小旋的博客-CSDN博客_ds18b20温度传感器 传感器引脚及原理图 DS18B20传感器的引脚及封装图如下: DS18B20一共有三个引 ...

  4. 负电压是怎么产生的?负压电路工作原理详解

    负电压是怎么产生的?负压电路工作原理详解 2019-07-29 21:39:29 燚智能物联网知识 简介 在电子电路中我们常常需要使用负的电压,比如说我们在使用运放的时候常常需要给他建立一个负的电压. ...

  5. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  6. python中文编码-python中文编码与json中文输出问题详解

    前言 python2.x版本的字符编码有时让人很头疼,遇到问题,网上方法可以解决错误,但对原理还是一知半解,本文主要介绍 python 中字符串处理的原理,附带解决 json 文件输出时,显示中文而非 ...

  7. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  8. SVM分类器原理详解

    SVM分类器原理详解 标签: svm文本分类java 2015-08-21 11:51 2399人阅读 评论(0) 收藏 举报  分类: 数据挖掘 文本处理(16)  机器学习 分类算法(10)  目 ...

  9. TOPSIS(逼近理想解)算法原理详解与代码实现

    写在前面: 个人理解:针对存在多项指标,多个方案的方案评价分析方法,也就是根据已存在的一份数据,判断数据中各个方案的优劣.中心思想是首先确定各项指标的最优理想值(正理想值)和最劣理想值(负理想解),所 ...

最新文章

  1. 6.微信小程序的如何使用全局属性
  2. yii 执行指定迁移文件_Web 云开发 · 云开发数据库迁移指南
  3. Arm v9的牙膏挤出来了,超大核机器学习性能x2,小核4年来终于更新
  4. php配置email支持_配置php自带的mail功能
  5. php主机转发ipv6,php实现ipv4转换ipv6
  6. 【Python入门】Python列表的11个方法全解
  7. 计算机里硬盘图标,计算机中在硬盘图标下面有个其他里PPS图标肿么删?
  8. python2 dict 乱序_为什么我的python dict变得无序?
  9. Go语言之标志符可见性
  10. DNS(域名系统) 是什么
  11. 怎么用睡袋拉人_宝宝晚上翻身踢被子又着凉了,别再盖被子,给宝宝穿婴儿睡袋吧...
  12. 运维工程师必会的109个Linux命令(1)
  13. Makefile:跟我一起学makefile
  14. FFmpeg API 变更记录
  15. 11月安全回顾:你造吗?短信验证码未必可靠
  16. WebRTC学习资料大全
  17. 某些网站加载的zul文件和zk文件是什么东西
  18. js判断对象上是否含有某个属性
  19. 本地 Git 文件夹显示绿色标识
  20. 使用OAS Validator帮助你规范OpenAPI Spec文档

热门文章

  1. SimpleDateFormat日期转换之12小时和24小时制
  2. 报错集-------docker中删除镜像时报错
  3. petalinux uboot源码怎么打补丁
  4. 齐岳定制1, 8-萘酰亚胺类荧光化合物,基于萘酰亚胺的fluorogenic荧光探针,双光子、内质网ER靶向双光子荧光探针NI-OPD
  5. Gido推出电商快递服务,从中国到越南只需三天
  6. ai描边工具怎么打开_AI的工具栏怎么用快捷键打开?
  7. 关于hadoop集群常见的节点失联问题
  8. ssi 指令 php,SSI 漏洞学习笔记
  9. LKJ国锂科技一场影响人类生活的大变革
  10. 官宣了!大杀四方的 Master 就是阿尔法狗