05:定时器生成频率不同的波形
定时器生成频率不同的波形
- 1、蜂鸣器的使用
- 2、PWM波形
- 2.1、占空比
- 2.2、平均电压
- 2.3、实验
1、蜂鸣器的使用
实验:通过定时器生成不同的波形,让蜂鸣器发出叮咚的声音
在700Hz的电平信号下,蜂鸣器发出叮的声响,在500Hz的电平信号下,蜂鸣器发出咚的声响
700Hz的电平信号的周期T ≈ 1.42ms,500Hz的电平信号周期T = 2ms
综上:需要产生700Hz的电平信号,即每隔0.71ms电平翻转一次即可。需要产生500Hz的电平信号,即每隔1ms电平翻转一次即可。
将定时器T0的定时为100us,则定时到了10次后让电平翻转,则就产生了周期为2ms的电平。
①Time.c文件的代码如下:
#include "Time.h"
sbit GPIO1_0 = P1^0;
/**
* 定时器T0的初始化,且开启中断
*/
void Time0It_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值 */
// TH0 = ((65536 - 100) >> 8);
// TL0 = (65536 - 100) & 0x00FF; //定时100us
// TH0 = ((65536 - 250) >> 8);
// TL0 = (65536 - 250) & 0x00FF; //定时250us
TH0 = ((65536 - 500) >> 8);
TL0 = (65536 - 500) & 0x00FF; //定时500us
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1;
/* 开启中断 */
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数
*/
static unsigned int Period2ms = 0;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
// TH0 = ((65536 - 100) >> 8);
// TL0 = (65536 - 100) & 0x00FF; //定时100us
// TH0 = ((65536 - 250) >> 8);
// TL0 = (65536 - 250) & 0x00FF; //定时250us
TH0 = ((65536 - 500) >> 8);
TL0 = (65536 - 500) & 0x00FF; //定时500us
Period2ms++; //定时时间到执行+1
if(Period2ms == 2) //定时1ms到了
{
GPIO1_0 = ~GPIO1_0; //让电平翻转
Count10 = 0;
}
}
②main.c文件的代码如下:
#include "Time.h"
void main(void)
{
Time0It_Init();
while(1)
{
}
}
综上:定时周期越小,误差就越大
同理:将定时器T0的定时为100us,定时到了7.1次后让电平翻转,则就产生周期为1.42ms的电平。
实验:通过定时器生成不同700Hz和500Hz的电平信号,信号都分别持续5ms
①Time.c文件的代码如下:
#include "Time.h"
sbit GPIO1_0 = P1^0;
/**
* 定时器T0的初始化,且开启中断
*/
void Time0It_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时100us */
TH0 = ((65536 - 100) >> 8);
TL0 = (65536 - 100) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1;
/* 开启中断 */
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数
*/
static unsigned int Period = 0;
static unsigned int Count = 0;
static unsigned int Flag = 0;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
TH0 = ((65536 - 100) >> 8);
TL0 = (65536 - 100) & 0x00FF;
Count++;
Period++; //每隔0.1ms执行+1
if(Count == 50) //5ms到了
{
Count = 0;
Flag = !Flag; //改变状态
}
switch(Flag)
{
case 0: //
if(Period == 10) //定时1ms到了
{
GPIO1_0 = ~GPIO1_0; //让电平翻转
Period = 0;
}
break;
case 1:
if(Period == 7) //定时0.7ms到了
{
GPIO1_0 = ~GPIO1_0; //让电平翻转
Period = 0;
}
break;
default:break;
}
}
②main.c文件的代码如下:
#include "Time.h"
void main(void)
{
Time0It_Init();
while(1)
{
}
}
综上:使用51单片机的定时器生成不同频率的波形存在太大的误差
2、PWM波形
下图是一张典型的pwm波形图,信号从高电平>>低电平>>高电平,称为一个脉冲周期T。
而1s内经历的周期数称为频率 f(HZ),f=1/T。例如周期为0.02s,频率就是50HZ
2.1、占空比
一个脉冲周期内高电平维持时间在整个周期中所占的比值
例如:一个脉冲周期为10ms的pwm波形图,第一个周期高电平为7ms(占空比70%);第二个周期高电平为4ms(占空比40%)
2.2、平均电压
假设高电平为5V,根据"面积等效原理
第一个周期平均电压为5V×70%=3.5V
第二个周期平均电压为5V×40%=2V
2.3、实验
实验:
使用定时器T0生成一个频率为50Hz,占空比为70%的信号。
频率为50Hz,则周期T = 20ms,而占空比为70%,则信号的高电平持续时间t = 14ms,信号的低电平持续时间t = 6ms。
将定时器T0的周期时间设置为1ms即可
①Time.c文件的代码如下:
#include "Time.h"
sbit GPIO1_0 = P1^0;
/**
* 定时器T0的初始化,且开启中断
*/
void Time0It_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1;
/* 开启中断 */
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数
*/
static unsigned int PWM_Cnt = 0;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
PWM_Cnt++; //每隔1ms执行+1
if(PWM_Cnt == 20) //20ms到了
{
PWM_Cnt = 0;
}
if(PWM_Cnt < 14) //14ms还没有到
{
GPIO1_0 = 1; //输出高电平
}
if(PWM_Cnt >= 14) //14ms到了
{
GPIO1_0 = 0; //变为低电平
}
}
②main.c文件的代码如下:
#include "Time.h"
void main(void)
{
Time0It_Init();
while(1)
{
}
}
改进代码如下:
①Time.c文件的代码如下:
#include "Time.h"
sbit GPIO1_0 = P1^0;
/**
* 定时器T0的初始化,且开启中断
*/
void Time0It_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1;
/* 开启中断 */
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数
*/
static unsigned int PWM_Cnt = 0;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
TH0 = ((65536 - 1000) >> 8);
TL0 = (65536 - 1000) & 0x00FF;
PWM_Cnt++; //每隔1ms执行+1
if(PWM_Cnt == Period)//周期到了
{
PWM_Cnt = 0;
}
if(PWM_Cnt < (Period * PWM_Duty)/100)
{
GPIO1_0 = 1; //输出高电平
}
if(PWM_Cnt >= (Period * PWM_Duty)/100)
{
GPIO1_0 = 0; //变为低电平
}
}
②Time.h文件的代码如下:
#ifndef __Time_H
#define __Time_H
#include <reg51.h> //包含51头文件,里面全是寄存器地址>
//使用宏定义占空比,方便修改
/* 宏定义周期T = 20ms*/
#define Period 20
/* 占空比70% */
#define PWM_Duty 70
sbit GPIO1_0 = P1^0;
void Time0It_Init(void);
#endif
③main.c文件的代码如下:
#include "Time.h"
void main(void)
{
Time0It_Init();
while(1)
{
}
}