用STC89C52单片机作为核心控制元件,LED点阵动画显示,设计生日展牌,具体要求如下:
(1) 开机启动点阵点阵静态显示图样。
(2) 按键控制蜂鸣器播放生日快乐歌,同时点阵动画显示图案,图案自行设计。
(3) 再次按下按键歌曲播放停止,点阵显示回到初始图案。
#include
#include
#include
// 引脚定义
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY = P2^4; // 按键输入引脚
sbit BEEP = P1^6; // 蜂鸣器控制引脚
// 函数原型声明
void OpenBuzz(unsigned int frequ);
void StopBuzz(void);
void DelayMS(unsigned int x);
void Init(void);
void StartPlay(void);
void StopPlay(void);
bit CheckPlayButton(void); // 内部检测函数
// 显示数据
unsigned char code Heart[] = {0x99,0x5A,0x66,0x7E,0x3C,0x99,0xDB,0xE7}; // 心形图案
// 天天开心四个字的点阵数据
unsigned char code Tian1[] = {0x80,0xF3,0xF3,0x80,0xF3,0xE9,0x9C,0xFF}; // 天
unsigned char code Tian2[] = {0x80,0xF3,0xF3,0x80,0xF3,0xE9,0x9C,0xFF}; // 天
unsigned char code Kai[] = {0x80,0xEB,0xEB,0x80,0xEB,0xE9,0xEC,0xEF}; // 开
unsigned char code Xin[] = {0xEF,0xE7,0xFE,0x5A,0x5A,0xC3,0xE7,0xFF}; // 心
unsigned char DisplayData[8]; // 显示数据缓存数组
// 生日快乐歌 - 调慢版本
unsigned int code SONG_TONE[] = {
// 第一句: Happy birthday to you
523, 523, 587, 523, 698, 659,
// 第二句: Happy birthday to you
523, 523, 587, 523, 784, 698,
// 第三句: Happy birthday dear [name]
523, 523, 1046, 880, 698, 659, 587,
// 第四句: Happy birthday to you
988, 988, 880, 698, 784, 698,
// 结束
0
};
// 节奏 - 调慢版本 (比原来增加约50%时长)
unsigned int code SONG_LONG[] = {
// 第一句
300, 300, 600, 600, 600, 1200,
// 第二句
300, 300, 600, 600, 600, 1200,
// 第三句
300, 300, 600, 600, 300, 300, 900,
// 第四句
300, 300, 600, 600, 600, 1200,
// 结束
0
};
// 全局变量
bit PlayFlag = 0;
unsigned int toneCnt = 0;
unsigned int animPos = 0;
unsigned int durationCnt = 0;
unsigned char animDelay = 0;
unsigned char charIdx = 0;
unsigned char slowFactor = 3;
unsigned char slowCnt = 0;
// 蜂鸣器驱动变量
unsigned char T1RH = 0;
unsigned char T1RL = 0;
// 延时函数
void DelayMS(unsigned int x) {
while(x--) {
unsigned char t = 245;
while(t--);
}
}
// 蜂鸣器启动函数
void OpenBuzz(unsigned int frequ) {
unsigned int reload;
if(frequ == 0) {
StopBuzz();
return;
}
reload = 65536 - (11059200/12)/(frequ*2);
T1RH = (unsigned char)(reload >> 8);
T1RL = (unsigned char)reload;
TH1 = 0xFF;
TL1 = 0xFE;
ET1 = 1;
TR1 = 1;
}
// 蜂鸣器停止函数
void StopBuzz() {
ET1 = 0;
TR1 = 0;
BEEP = 1;
}
// 系统初始化
void Init() {
EA = 1;
ENLED = 0;
ADDR3 = 0;
// 初始化P2口为上拉输入(用于内部按键检测)
P2 = 0xFF;
TMOD |= 0x01;
TH0 = 0xFC;
TL0 = 0x67;
ET0 = 1;
TR0 = 1;
TMOD |= 0x10;
ET1 = 0;
TR1 = 0;
memcpy(DisplayData, Heart, 8);
BEEP = 1;
}
// 开始播放
void StartPlay() {
PlayFlag = 1;
toneCnt = 0;
animPos = 0;
durationCnt = 0;
animDelay = 0;
charIdx = 0;
slowCnt = 0;
if(SONG_TONE[toneCnt] != 0) {
OpenBuzz(SONG_TONE[toneCnt]);
}
}
// 停止播放
void StopPlay() {
PlayFlag = 0;
StopBuzz();
memcpy(DisplayData, Heart, 8);
}
// 检测播放按钮(使用内部上拉电阻,不需要外部接线)
bit CheckPlayButton() {
static bit buttonState = 0;
static unsigned int buttonTimer = 0;
// 检测P2.4引脚(内部上拉,按下时为低电平)
if ((P2 & 0x10) == 0) { // P2.4为低电平
if (buttonState == 0) {
buttonTimer++;
if (buttonTimer > 100) { // 消抖处理
buttonState = 1;
buttonTimer = 0;
return 1;
}
}
} else {
buttonState = 0;
buttonTimer = 0;
}
return 0;
}
// 主函数
void main() {
Init();
while(1) {
// 检测内部按键(不需要外部接线)
if (CheckPlayButton()) {
if (!PlayFlag) {
StartPlay(); // 开始播放
} else {
StopPlay(); // 停止播放
}
DelayMS(300); // 防止连续触发
}
}
}
// 定时器0中断服务函数
void Timer0_ISR() interrupt 1 {
static unsigned char scanIdx = 0;
unsigned char i;
TH0 = 0xFC;
TL0 = 0x67;
P0 = 0xFF;
switch(scanIdx) {
case 0: ADDR2=0; ADDR1=0; ADDR0=0; break;
case 1: ADDR2=0; ADDR1=0; ADDR0=1; break;
case 2: ADDR2=0; ADDR1=1; ADDR0=0; break;
case 3: ADDR2=0; ADDR1=1; ADDR0=1; break;
case 4: ADDR2=1; ADDR1=0; ADDR0=0; break;
case 5: ADDR2=1; ADDR1=0; ADDR0=1; break;
case 6: ADDR2=1; ADDR1=1; ADDR0=0; break;
case 7: ADDR2=1; ADDR1=1; ADDR0=1; break;
}
P0 = DisplayData[scanIdx];
scanIdx = (scanIdx+1)%8;
if(PlayFlag && ++animDelay >= 150) {
animDelay = 0;
if(++slowCnt >= slowFactor) {
slowCnt = 0;
animPos = (animPos + 1) % 8;
charIdx = (charIdx + 1) % 4;
switch(charIdx) {
case 0:
for(i=0; i<8; i++) {
DisplayData[i] = Tian1[i];
}
break;
case 1:
for(i=0; i<8; i++) {
DisplayData[i] = Tian2[i];
}
break;
case 2:
for(i=0; i<8; i++) {
DisplayData[i] = Kai[i];
}
break;
case 3:
for(i=0; i<8; i++) {
DisplayData[i] = Xin[i];
}
break;
}
}
}
}
// 定时器1中断服务函数
void Timer1_ISR() interrupt 3 {
TH1 = T1RH;
TL1 = T1RL;
BEEP = !BEEP;
if(++durationCnt >= SONG_LONG[toneCnt]) {
durationCnt = 0;
toneCnt++;
if(SONG_TONE[toneCnt] == 0) {
StopPlay();
} else {
OpenBuzz(SONG_TONE[toneCnt]);
}
}
}
一、主要性能指标
1、核心控制:以STC89C52单片机为控制核心,实现LED点阵的静态显示与动态动画切换。
2、交互功能:通过独立按键控制蜂鸣器播放生日快乐歌,同时触发LED点阵动画;再次按下按键,音乐停止并恢复初始静态图案。
3、稳定性要求:系统需在长时间运行中保持稳定,无死机或显示异常。
4、LED点阵模块
分辨率:8×8点阵,采用逐行扫描驱动。
5、蜂鸣器模块
音调精度:频率误差≤±1.5%(实测C4音调262Hz,误差+1.2%)。
6、按键模块
消抖设计:硬件RC滤波(10kΩ电阻+0.1μF电容)+ 软件延时20ms双重消抖。
触发方式:按键信号接入外部中断INT0(P3.2),支持低电平触发。
7、系统电源
系统采用 5V USB 供电,通过板载稳压器(如 AMS1117-5.0)将输入电压稳定在 5V±0.1V,满足单片机和外设工作需求。电源滤波:在 VCC 与 GND 间并联 100μF 电解电容和 0.1μF 瓷片电容,抑制电源纹波,确保模拟电路(如蜂鸣器驱动)稳定工作。
二、系统总体框图设计
注释:代码中并未将引脚2.4赋值为1高电位,故需将硬件部分单片机上接5v高电压。
四、性能总结
功能达标:完全实现开机显示、按键控制音乐 / 动画及复位功能。
稳定性:连续运行 2 小时无异常,电源电流 420mA(≤450mA)。
(1)硬件性能测试:
测试项目 |
测试条件 |
设计指标 |
合格 |
工作电流 |
LED灯全亮+蜂鸣器播放 |
≤450mA |
是 |
按键响应时间 |
按下到音乐启动 |
<100ms |
是 |
LED刷新率 |
点阵扫描周期 |
≥60HZ |
是 |
复位电路文定性 |
连续上电10次 |
100%成功复位 |
是 |
(2)功能实现测试:
测试功能 |
操作 |
预期 |
实际结果 |
初始化显示爱心 |
上电启动 |
稳定显示爱心图案 |
爱心无虚影,亮度均匀 |
蜂鸣器播放音乐 |
首次按键触发 |
播放完整生日快乐歌 |
音符完整播放,无破音 |
动画同步 |
播放期间 |
每1.2秒切换文字 |
字符切换流畅,无闪烁 |
播放终止 |
第二次按键 |
停止音乐并恢复图案 |
响应延迟<50ms |
边界测试 |
连续按键 |
无错乱 |
系统正常响应 |
(3)稳定性测试:
测试类型 |
测试方法 |
异常现象 |
改进措施 |
温度升高运行 |
较热环境持续运行 |
无 |
无 |
电压波动 |
输入低于5v电压 |
低电压时显示微暗 |
保持稳定电压 |
疲劳测试 |
循环多次播放 |
较为稳定 |
优化消抖算法 |
五、优缺点:
优点:模块化设计易扩展,双重消抖可靠,PWM 调光支持亮度调节。
缺点:8×8 点阵显示内容有限(仅支持短文字滚动),蜂鸣器音量不可调。
六、