基於STC51微控制器的霓虹燈
設計要求:
- 使用PWM驅動8個LED燈
- 人眼不能觀察到燈光全滅
- 燈光要有動畫效果
設計概述:
按照設計要求,為了更直觀的說明脈衝寬度調製技術(PWM),所以霓虹燈的動畫效果為流水燈形式。所需要的微控制器晶片為STC89C52,所用的硬體工具是由華清遠見開發的基於STC89C52的智慧小車。該小車配備所需要的LED燈模組,8個LED燈由P1口來控制。STC89C52是一種低功耗,高效能的8位微控制器,是加強版的80C51微控制器,但是與80C51微控制器一樣不具備PWM硬體模組,所以我們需要自己寫一個程式來軟體模擬PWM方波。
PWM是一種方波,可以實現數字訊號控制類比電路,它有兩個重要引數週期或頻率,佔空比。佔空比 = 高電平時間/週期,最小為0%,最大為100%,通過調整佔空比來控制高電平,低電平所佔比例,進而調控LED燈的亮滅與明暗變化。STC89C52中P1口為低電平有效,將P1口置0,LED燈亮,置1燈滅。若將P1口的電平輸出訊號調整成高低電平各佔50%,即在一個週期內高電平,低電平所佔比例都是50%,P1口控制的LED燈將會明暗閃爍。
市面上的許多51微控制器開發板大同小異,都是用P1口控制LED燈,所以在此就不提供智慧小車的原理圖和實物圖。
原始碼:
軟體模擬PWM方波通常利用定時器來實現。
參考程式碼1:
#include <reg52.h>
//定義一個全域性變數pwm,通過對全域性變數的累加來控制PWM的佔空比
unsigned int pwm = 0;
/*
利用定時器和I/O口來輸出PWM方波實現8個LED燈的明暗變化
*/
/*定時器中斷服務函式*/
void Timer0() interrupt 1
{
pwm++;
if(pwm == 500)
{
P1 = 0xfe;//第1盞燈亮
}
else if(pwm == 1000)
{
P1 = 0xff;//第1盞燈滅
}
else if(pwm == 1500)
{
P1 = 0xfd;//第2盞燈亮
}
else if(pwm == 2000)
{
P1 = 0xff;
}
else if(pwm == 2500)
{
P1 = 0xfb;//第3盞燈亮
}
else if(pwm == 3000)
{
P1 = 0xff;
}
else if(pwm == 3500)
{
P1 = 0xf7;//第4盞燈亮
}
else if(pwm == 4000)
{
P1 = 0xff;
}
else if(pwm == 4500)
{
P1 = 0xef;//第5盞燈亮
}
else if(pwm == 5000)
{
P1 = 0xff;
}
else if(pwm == 5500)
{
P1 = 0xdf;//第6盞燈亮
}
else if(pwm == 6000)
{
P1 = 0xff;
}
else if(pwm == 6500)
{
P1 = 0xbf;//第7盞燈亮
}
else if(pwm == 7000)
{
P1 = 0xff;
}
else if(pwm == 7500)
{
P1 = 0x7f;//第8盞燈亮
}
else if(pwm == 8000)
{
P1 = 0xff;
pwm = 0;
}
}
void main()
{
TMOD |= 1<<1; //通過移位運算子"<<"來改變位的狀態
TMOD &= ~(1<<0); //置定時器/計數器的工作方式為方式2
TMOD &= ~(1<<2); //選擇定時工作方式
TMOD &= ~(1<<3); //門控位:由執行控制位TR啟動定時器
TL0 = 156;
TH0 = 156; //100us進入一次中斷,0.1毫秒
ET0 = 1; //定時器0開中斷
EA = 1; //CPU開中斷
TR0 = 1; //啟動定時器0
while(1) //防止程式跑飛
;
}
參考程式碼2:
/*第一個檔案為自定義標頭檔案
此標頭檔案裡宣告pwm_led_ctl函式
*/
#ifndef _LED_H
#define _LED_H
//控制某一盞燈亮
char pwm_led_ctl(unsigned int led_num);
#endif
/*
第二個檔案
此原始檔用於實現pwm_led_ctl函式
*/
#include <reg52.h>
#include "led.h"
//軟體模擬PWM方波,通過變數pwm調控PWM佔空比
char pwm_led_ctl(unsigned int led_num)
{
unsigned int pwm;
for(pwm = 0;pwm <= 2000;pwm++)
{
if(pwm == 1000)
{
P1 &= ~(1<<led_num);//通過移位運算子"<<"逐個點亮LED燈
}
else if(pwm == 2000)
{
P1 |= 1<<led_num;
}
}
return 0;
}
/*
第三個檔案
主函式原始檔
*/
#include <reg52.h>
#include "led.h"
/*定時器中斷服務函式*/
void Timer0() interrupt 1
{
unsigned int i;
for(i=0;i<8;i++)
{
pwm_led_ctl(i);
}
}
void main()
{
TMOD |= 1<<1; //通過移位運算子"<<"來改變位的狀態
TMOD &= ~(1<<0); //置定時器/計數器的工作方式為方式2
TMOD &= ~(1<<2); //選擇定時工作方式
TMOD &= ~(1<<3); //門控位:由執行控制位TR啟動定時器
TL0 = 156;
TH0 = 156; //100us進入一次中斷,0.1毫秒
ET0 = 1; //定時器0開中斷
EA = 1; //CPU開中斷
TR0 = 1; //啟動定時器0
while(1) //防止程式跑飛
;
}