1. bread88lifa利发国际娱乐论坛/
  2. 综合技术与应用/
    1. 电子论坛综合区
    2. 嵌入式论坛
    3. 电源技术论坛
    4. 硬件设计论坛
    5. 测试测量论坛
    6. 检测技术与质量
    7. EDA设计论坛
    8. 综合技术与应用
    9. 开源硬件
    10. IC设计论坛
    11. 消费电子论坛
    12. 无线通信论坛
    13. 个人版区
    14. 厂商专区
    15. 论坛服务区
    16. 高校联盟
    17. 供求信息发布
  3. 工程资源中心
    1. 电机控制
    2. 智能电网
    3. 光电及显示
    4. 汽车电子技术论坛
    5. 医疗电子论坛
  4. / 应用笔记
  5. / 三组不同的脉冲信号及控制程序
    关闭提示

[设计讨论] 三组不同的脉冲信号及控制程序

[复制链接]
发表于 7 天前   310 查看 1 回复 只看该作者 倒序浏览
分享
本帖最后由 liuyongwangzi 于 2018-6-12 09:56 编辑

PWM是Pulse Width Modulation的缩写,它的中文名字是脉冲宽度调制,一种说法是它利用微处理器的数字输出来对模拟电路进行控制的一种有效的技术,其实就是使用数字信号达到一个模拟信号的效果。这是个什么概念呢?我们一步步来介绍。首先从它的名字来看,脉冲宽度调制,就是改变脉冲宽度来实现不同的效果。
我们先来看三组不同的脉冲信号,如图所示。


图 10-1 PWM 波形


这是一个周期是 10ms,即频率是 100Hz 的波形,但是每个周期内,高低电平脉冲宽度各不相同,这就是 PWM 的本质。在这里大家要记住一个概念,叫做“占空比”。占空比是指高电平的时间占整个周期的比例。比如第一部分波形的占空比是 40%,第二部分波形占空比是 60%,第三部分波形占空比是 80%,这就是 PWM 的解释。
那为何它能对模拟电路进行控制呢?

大家想一想,我们数字电路里,只有 0 和 1 两种状态,比如我们第 2 章学会的点亮 LED 小灯那个程序,当我们写一个 LED = 0;小灯就会长亮,当我们写一个 LED = 1;小灯就会灭掉。当我们让小灯亮和灭间隔运行的时候,小灯是闪烁。
如果我们把这个间隔不断的减小,减小到我们的肉眼分辨不出来,也就是 100Hz 以上的频率,这个时候小灯表现出来的现象就是既保持亮的状态,但亮度又没有 LED = 0;时的亮度高。那我们不断改变时间参数,让 LED = 0;的时间大于或者小于 LED = 1;的时间,会发现亮度都不一样,这就是模拟电路的感觉了,不再是纯粹的 0 和 1,还有亮度不断变化。

大家会发现,如果我们用 100Hz 的信号,如图 10-1 所示,假如高电平熄灭小灯,低电平点亮小灯的话,第一部分波形熄灭 4ms,点亮 6ms,亮度最高,第二部分熄灭 6ms,点亮 4ms,亮度次之,第三部分熄灭 8ms,点亮 2ms,亮度最低。那么用程序验证一下我们的理论,我们用定时器T0 定时改变 P0.0 的输出来实现 PWM,与纯定时不同的是,这里我们每周期内都要重载两次定时器初值,即用两个不同的初值来控制高低电平的不同持续时间。为了使亮度的变化更加明显,程序中使用的占空比差距更大。
#include
sbit PWMOUT = P0^0;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned char HighRH = 0; //高电平重载值的高字节
unsigned char HighRL = 0; //高电平重载值的低字节
unsigned char LowRH = 0; //低电平重载值的高字节
unsigned char LowRL = 0; //低电平重载值的低字节
void ConfigPWM(unsigned int fr, unsigned char dc);
void ClosePWM();
void main(){
unsigned int i;
EA = 1; //开总中断
ENLED = 0; //使能独立 LED
ADDR3 = 1;
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;
while (1){
ConfigPWM(100, 10); //频率 100Hz,占空比 10%
for (i=0; i40000; i++);
ClosePWM();
ConfigPWM(100, 40); //频率 100Hz,占空比 40%
for (i=0; i40000; i++);
ClosePWM();
ConfigPWM(100, 90); //频率 100Hz,占空比 90%
for (i=0; i40000; i++);
ClosePWM(); //关闭 PWM,相当于占空比 100%
for (i=0; i40000; i++);
}
}
/* 配置并启动 PWM,fr-频率,dc-占空比 */
void ConfigPWM(unsigned int fr, unsigned char dc){
unsigned int high, low;
unsigned long tmp;
tmp = (11059200/12) / fr; //计算一个周期所需的计数值
high = (tmp*dc) / 100; //计算高电平所需的计数值
low = tmp - high; //计算低电平所需的计数值
high = 65536 - high + 12; //计算高电平的重载值并补偿中断延时
low = 65536 - low + 12;//计算低电平的重载值并补偿中断延时
HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
HighRL = (unsigned char)high;
LowRH = (unsigned char)(low>>8); //低电平重载值拆分为高低字节
LowRL = (unsigned char)low;
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x01; //配置 T0 为模式 1
TH0 = HighRH; //加载 T0 重载值
TL0 = HighRL;
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
PWMOUT = 1; //输出高电平
}
/* 关闭 PWM */
void ClosePWM(){
TR0 = 0; //停止定时器
ET0 = 0; //禁止中断
PWMOUT = 1; //输出高电平
}
/* T0 中断服务函数,产生 PWM 输出 */
void InterruptTimer0() interrupt 1{
if (PWMOUT == 1){ //当前输出为高电平时,装载低电平值并输出低电平
TH0 = LowRH;
TL0 = LowRL;
PWMOUT = 0;
}else{ //当前输出为低电平时,装载高电平值并输出高电平
TH0 = HighRH;
TL0 = HighRL;
PWMOUT = 1;
}
}


需要提醒大家的是,由于标准 51 单片机中没有专门的 PWM 模块,所以我们用定时器加中断的方式来产生 PWM,而现在有很多的单片机都会集成硬件的 PWM 模块,这种情况下需要我们做的就仅仅是计算一下周期计数值和占空比计数值然后配置到相关的 SFR 中即可,既使程序得到了简化又确保了 PWM 的输出品质(因为消除了中断延时的影响)。
大家编译下载程序后,会发现小灯从最亮到灭一共 4 个亮度等级。如果我们让亮度等级更多,并且让亮度等级连续起来,会产生一个小灯渐变的效果,与呼吸有点类似,所以我们习惯上称之为呼吸灯,程序代码如下,这个程序用了 2 个定时器 2 个中断,这是我们第一次这样用,大家可以学习一下。我们来试试这个程序,试完了大家一定要能自己把程序写出来,切记。

#include
sbit PWMOUT = P0^0;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
unsigned long PeriodCnt = 0; //PWM 周期计数值
unsigned char HighRH = 0; //高电平重载值的高字节
unsigned char HighRL = 0; //高电平重载值的低字节
unsigned char LowRH = 0; //低电平重载值的高字节
unsigned char LowRL = 0; //低电平重载值的低字节
unsigned char T1RH = 0; //T1 重载值的高字节
unsigned char T1RL = 0; //T1 重载值的低字节
void ConfigTimer1(unsigned int ms);
void ConfigPWM(unsigned int fr, unsigned char dc);
void main(){
EA = 1; //开总中断
ENLED = 0; //使能独立 LED
ADDR3 = 1;
ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;
ConfigPWM(100, 10); //配置并启动 PWM
ConfigTimer1(50); //用 T1 定时调整占空比
while (1);
}
/* 配置并启动 T1,ms-定时时间 */
void ConfigTimer1(unsigned int ms){
unsigned long tmp; //临时变量
tmp = 11059200 / 12; //定时器计数频率
tmp = (tmp * ms) / 1000; //计算所需的计数值
tmp = 65536 - tmp; //计算定时器重载值
tmp = tmp + 12; //补偿中断响应延时造成的误差
T1RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
T1RL = (unsigned char)tmp;
TMOD &= 0x0F; //清零 T1 的控制位
TMOD |= 0x10; //配置 T1 为模式 1
TH1 = T1RH; //加载 T1 重载值
TL1 = T1RL;
ET1 = 1; //使能 T1 中断
TR1 = 1; //启动 T1
}
/* 配置并启动 PWM,fr-频率,dc-占空比 */
void ConfigPWM(unsigned int fr, unsigned char dc){
unsigned int high, low;
PeriodCnt = (11059200/12) / fr; //计算一个周期所需的计数值
high = (PeriodCnt*dc) / 100; //计算高电平所需的计数值
low = PeriodCnt - high; //计算低电平所需的计数值
high = 65536 - high + 12; //计算高电平的定时器重载值并补偿中断延时
low = 65536 - low + 12; //计算低电平的定时器重载值并补偿中断延时
HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
HighRL = (unsigned char)high;
LowRH = (unsigned char)(low>>8); //低电平重载值拆分为高低字节
LowRL = (unsigned char)low;
TMOD &= 0xF0; //清零 T0 的控制位
TMOD |= 0x01; //配置 T0 为模式 1
TH0 = HighRH; //加载 T0 重载值
TL0 = HighRL;
ET0 = 1; //使能 T0 中断
TR0 = 1; //启动 T0
PWMOUT = 1; //输出高电平
}
/* 占空比调整函数,频率不变只调整占空比 */
void AdjustDutyCycle(unsigned char dc){
unsigned int high, low;
high = (PeriodCnt*dc) / 100; //计算高电平所需的计数值
low = PeriodCnt - high; //计算低电平所需的计数值
high = 65536 - high + 12; //计算高电平的定时器重载值并补偿中断延时
low = 65536 - low + 12; //计算低电平的定时器重载值并补偿中断延时
HighRH = (unsigned char)(high>>8); //高电平重载值拆分为高低字节
HighRL = (unsigned char)high;
LowRH = (unsigned char)(low>>8); //低电平重载值拆分为高低字节
LowRL = (unsigned char)low;
}
/* T0 中断服务函数,产生 PWM 输出 */
void InterruptTimer0() interrupt 1{
if (PWMOUT == 1){ //当前输出为高电平时,装载低电平值并输出低电平
TH0 = LowRH;
TL0 = LowRL;
PWMOUT = 0;
}else{ //当前输出为低电平时,装载高电平值并输出高电平
TH0 = HighRH;
TL0 = HighRL;
PWMOUT = 1;
}
}
/* T1 中断服务函数,定时动态调整占空比 */
void InterruptTimer1() interrupt 3{
static bit dir = 0;
static unsigned char index = 0;
unsigned char code table[13] = { //占空比调整表
5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95
};
TH1 = T1RH; //重新加载 T1 重载值
TL1 = T1RL;
AdjustDutyCycle(table[index]); //调整 PWM 的占空比
if (dir == 0){ //逐步增大占空比
index++;
if (index >= 12){
dir = 1;
}
}else{ //逐步减小占空比
index--;
if (index == 0){
dir = 0;
}
}
}


呼吸灯效果做出来后,利用这个基本原理,其它各种效果的灯光闪烁都应该可以做出来,大家看到的 KTV 里边那绚丽的灯光闪烁,其实就是采用的 PWM 技术控制的。

标签:PWM 微处理器
举报
版主
发表于 7 天前  
感谢留着分享   请问楼主搞过三相交流电的检测项目吗
回复 点赞 举报
高级模式
您需要登录后才可以回帖 登录 | 注册
关闭

站长推荐 上一条 /9 下一条

快速回复 返回顶部 返回列表
  1. time最新主题
  2. recommend推荐主题
  3. hot热门主题
  4. post 我的帖子
-

推荐专区

技术干货集中营

专家问答

方案交易

用户帮助┃咨询与建议┃版主议事

工程师杂谈

项目|工程师创意

招聘|求职}工程师职场

论坛电子赛事

社区活动专版

发烧友活动

-

嵌入式论坛

ARM技术论坛

Android论坛

Linux论坛

单片机/MCU论坛

MSP430技术论坛

FPGA|CPLD|ASIC论坛

STM32/STM8技术论坛

NXP MCU 技术论坛

PIC单片机论坛

DSP论坛

瑞萨单片机论坛

嵌入式系统论坛

-

电源技术论坛

电源技术论坛

无线充电技术

-

硬件设计论坛

PCB设计论坛

电路设计论坛

电子元器件论坛

控制|传感

总线技术|接口技术

-

测试测量论坛

LabVIEW论坛

Matlab论坛

测试测量技术专区

仪器仪表技术专区

-

EDA设计论坛

multisim论坛

PADS技术论坛

Protel|AD|DXP论坛

Allegro论坛

proteus论坛|仿真论坛

EasyEDA-中国人自已的EDA工具

Orcad论坛

-

综合技术与应用

电机控制

智能电网

光电及显示

工程资源中心

汽车电子技术论坛

医疗电子论坛

-

开源硬件

-

无线通信论坛

无线通信技术专区

天线|RF射频|微波|雷达技术

-

IC设计论坛

芯片测试与失效分析

Mixed Signal/SOC[数模混合芯片设计]

Analog/RF IC设计

设计与制造封装测试

-

厂商专区

TI论坛

TI Deyisupport社区

-

检测技术与质量

电磁兼容(EMC)设计与整改

安规知识论坛

检测与认证

-

消费电子论坛

手机技术论坛

平板电脑/mid论坛

音视/视频/机顶盒论坛

-

电子论坛综合区

聚丰众筹官方社区

新人报道区

聚丰供应链

-

论坛服务区

-

供求信息发布

供需广告

电子展览展会专区

芯片求购|供应发布区

88lifa利发国际娱乐

百度360搜索搜狗搜索