专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

单片机PWM技术实现呼吸灯和KTV等娱乐场所的灯光闪烁效果

作者:寒竹子   来源:本站原创   点击数:  更新时间:2014年04月15日   【字体:

程序是在51hei单片机开发板上面做的,电路很简单,最小系统+P0的八个led即可.ADDR0和ENLED那是开发板上的led使能电路控制端,如果是你自己做的电路 可以删掉这几个语句.或者不用管他,不会影响程序的运行.

/**
  ************************************************************************************************************
  * @file   :      main.c 
  * @author :      xr
  * @date   :      2014年4月15日20:34:05 - 2014年4月15日22:28:08
  * @version: V1.2.3
  * @brief  :      PWM技术实现呼吸灯和KTV等娱乐场所的灯光闪烁效果 单片机STC89C52RC MCU 晶振 11.0592MHZ
  ************************************************************************************************************
  */
#include <reg52.h>

//74HC138
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//sbit PWMOUT = P0^0;//PWM输出
#define PWMOUT P0   //8个LED小灯同时呼吸

//灯光控制编码(调整PWM的占空比)
unsigned char code PWM_Table[] = {
  1,  3,  8,  11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50,
  53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98, 99
}; //34个占空比

unsigned char heighHR0, heighLR0;//PWM高电平计数初值的高字节和低字节
unsigned char lowHR0, lowLR0;   //PWM低电平计数初值的高字节和低字节
unsigned char thr1, tlr1;       //T1计数初值高字节和低字节
unsigned long PWMCounter = 0;      //PWM设定频率后的对应的所需计数值 UL型

void Initial();
void ConfigPWM(unsigned int fr, unsigned char dc);
void ConfigTimer1(unsigned int xms);

void main(void)
{
Initial();
/**********呼吸灯效果***************/
ConfigPWM(100, 5);//设定PWM的脉冲宽度为100hz,即10ms,占空比为5%,当PWM的脉冲宽度小于100HZ时,形成的是闪烁的灯光效果
ConfigTimer1(50);  //定时50ms调整PWM占空比

/*PWM技术实现KTV等娱乐场所的灯光闪烁效果*/
/***************灯光闪烁****************/
/*
ConfigPWM(10, 5); //PWM脉冲宽度为10HZ,即1ms, 占空比5%
ConfigTimer1(50); //定时20ms调整PWM占空比
*/

while (1);
}

/*初始化*/
void Initial()
{
ADDR3 = 1;
ENLED = 0;//选择LED

ADDR2 = 1;
ADDR1 = 1;
ADDR0 = 0;//选择LEDS6,即流水灯
}

/*使用定时器T0配置PWM*/
void ConfigPWM(unsigned int fr, unsigned char dc) //参数:fr PWM配置的频率,当是100时,即是100HZ,周期是10ms,dc为占空比
{
unsigned long tmp;
unsigned int heigh, low;//分别存放高电平计数值和低电平计数值

tmp = 11059200/12;//一个机器周期的计数频率
PWMCounter = tmp / fr;//一个机器周期计数频率是多少个fr计数频率,即fr频率需要的计数值
heigh = (PWMCounter * dc) / 100;//高电平所需计数值 1/fr周期内高电平计数值
low   = PWMCounter - heigh;//低电平所需计数值  1/fr周期内低电平计数值
heigh = 65536-heigh;       //高电平时定时器需要装入的初值
low   = 65536-low;    //低电平时定时器需要装入的初值

heighHR0 = (unsigned char)(heigh >> 8);
heighLR0 = (unsigned char)heigh;
lowHR0   = (unsigned char)(low >> 8);
lowLR0   = (unsigned char)low;

TMOD &= 0xF0;//清零T0控制位
TMOD |= 0x01;//Timer0方式1,16位可设定定时模式
TH0 = heighHR0;
TL0 = heighLR0;//装入高电平时的初值
PWMOUT = 0xFF;//开始PWM输出高电平
TR0 = 1;//启动定时器T0
ET0 = 1;//开启T0中断
EA  = 1;//开总中断
}

/*配置定时器Timer1,用于定时xms调整PWM的占空比*/
void ConfigTimer1(unsigned int xms)
{
unsigned long tmp;
tmp = 11059200/12;//一个机器周期的计数频率
tmp = (tmp * xms) /1000;//定时xms需要的计数频率(即计数次数)
tmp = 65536-tmp;//定时xms需要装入的计数初值
thr1 = (unsigned char)(tmp >> 8);//取高八位
tlr1 = (unsigned char)tmp;

TMOD &= 0x0F;//清零T1控制位
TMOD |= 0x10;//定时器T1方式1,16位可设定时器
TH1 = thr1;
TL1 = tlr1;
TR1 = 1;//启动timer1
ET1 = 1;//开启定时器T1中断
EA  = 1;//开启总中断
}

/*调整PWM占空比*/
void AdjustPWMdc(unsigned char dc)
{
unsigned int heigh, low;
heigh = (PWMCounter * dc) / 100; //PWM脉冲中高脉冲所需计数值
low   = PWMCounter - heigh;//PWM脉冲中低脉冲所需的计数值
heigh = 65536-heigh;//高脉冲装入计数的初值
low   = 65536-low;  //低脉冲装入计数的初值

/*调整PWM高低脉冲计数初值,来调整PWM的占空比*/
heighHR0 = (unsigned char)(heigh >> 8);
heighLR0 = (unsigned char)heigh;
lowHR0   = (unsigned char)(low >> 8);
lowLR0   = (unsigned char)low;
}

/*定时器Timer0中断服务*/
void Timer0_ISP() interrupt 1
{
//在中断中对PWM的输出电平进行判断,若当前输出是高电平,则开始装入低电平的计数初值,PWM输出低电平
if (PWMOUT)
{
//Timer0装入PWM一个周期中低脉冲的计数初值
TH0 = lowHR0;
TL0 = lowLR0;
PWMOUT = 0x00;//PWM输出低电平
}
else  //否则装入高电平的计数初值,输出高电平
{
//Timer0装入PWM一个周期中高脉冲的计数初值
TH0 = heighHR0;
TL0 = heighLR0;
PWMOUT = 0xFF;//PWM输出高脉冲
}
}

/*定时器Timer1中断服务*/
void Timer1_ISP() interrupt 3
{
//注意:index和dir在每次进入中断后都要使用上一次的值,因此必须定义为静态类型
static unsigned char index = 0;//占空比索引
static bit dir = 0;//方向位,0灯光由亮->暗 1灯光由暗->亮

TH1 = thr1;
TL1 = tlr1;

AdjustPWMdc(PWM_Table[index]);//调用调整PWM占空比函数,调整PWM占空比

if (dir == 0)
{
index++;   //索引++
if (index >= 33)     //34个占空比
{
index = 33;
dir = 1;//改变方向
}
}
else
{
index--; //索引--
if (index == 0)
{
index = 0;
dir = 0;//改变方向
}
}
}

关闭窗口

相关文章