2023年马上就要过去,希望2024年会越来越好,根据自己学的内容来实现一些我的idea。
最开始的构思是这样的,“2024”用数码管来输出然后中文的“新年快乐”用点阵来实现,但是点阵是动态的截图不好看,就想干脆用LCD1602输出英文的新年快乐算了,这样就只需要一个AT89C51就行了,还剩下五根引脚,想起来过年我印象中听过最多的歌是“好运来”就想增加一个蜂鸣器来播放好运来歌曲,大致的构思出的原理图如下,实验所需器件在代码后面。
首先是对2024的输出,这个就是输出他的BCD码。这个网络标号最开始就是C0在上面,输出的时候发现不对,然后就反过来标记,算是蒙对的。
#include<reg51.h>
void main(void){
while(1){
//2024 0010 0000 0010 0100
P1=0x20;
P3=0x24;
}
}
用LCD 1602输出我们没必要重新书写代码,只需要修改之后的代码即可。顺便对输出“2024”部分封装成函数。字符型液晶显示器LCD 1602的显示控制(Keil+Proteus)_1602液晶显示电路在keli中名称-CSDN博客https://blog.csdn.net/weixin_64066303/article/details/134224776
#include<reg51.h>
#include<intrins.h> //包含_nop_()空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int
#define out P0
sbit RS=P2^0;//位变量
sbit RW=P2^1;//位变量
sbit E=P2^2;//位变量
//函数声明部分
void lcd_initial(void);//LCD初始化函数
void check_busy(void);//检查忙标志位函数
void write_command(uchar com);//写命令函数
void write_data(uchar dat);//写数据函数
void string(uchar ad,uchar *s);//显示字符串
void delay(uint);//延时
void print_LED();//输出“2024”的数码管
void main(void){
lcd_initial();//对LCD初始化
while(1){
print_LED();
string(0x81,"Happy New Year");//显示第一行的字符
string(0xC1,"peace happiness");//显示第二行的字符
delay(100);//延时
write_command(0x01);//清屏
delay(100);//延时
}
}
//延时
void delay(uint j){
uchar i=250;
for(;j>0;j--){
while(--i);
i=249;
while(--i);
i=250;
}
}
//检查忙标志
void check_busy(void){
uchar dt;
do{
dt=0xff;//dt为变量单元,初值为0xff
//RS=0,E=1时才可以读忙标志位
E=0;
RS=0;
RW=1;
E=1;
dt=out;//out为P0口,P0口的状态送入dt中
}while(dt&0x80);//如果忙标志位BF=1,继续循环检测,等待BF=0
E=0;//BF=0,LCD 1602不忙,结束检测
}
//写命令
void write_command(uchar com){
check_busy();
//按规定RS和E同时为0时,才可以写命令
E=0;
RS=0;
RW=0;
out=com;//将命令com写入P0口
E=1;//写命令时,E应为正脉冲,即正跳变,所以前面先置E=0
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,LCD 1602开始执行命令
delay(1);//延时,等待硬件反应
}
//写数据
void write_data(uchar dat){
check_busy();//检测忙标志位BF=1则等待,若BF=0,则可对LCD 1602写入命令
E=0;//按规定写数据时,E应为正脉冲,所以先置E=0
//按规定RS=1和RW=0时,才可以写入数据
RS=1;
RW=0;
out=dat;//将数据”dat“从P0口输出,即写入LCD 1602
E=1;//E产生正跳变
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,写数据操作结束
delay(1);
}
//液晶显示器初始化函数
void lcd_initial(void){
write_command(0x38);//8位两行显示,5*7点阵字符
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x0C);//开整体显示,光标关,无闪烁
_nop_();//空操作1个机器周期,等待硬件反应
//write_command(0x05);//光标右移
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x01);//清屏
delay(1);
}
//输出显示字符串
void string(uchar ad,uchar *s){
write_command(ad);
while(*s>0){
write_data(*s++);//输出字符串,且指针增1
delay(100);
}
}
void print_LED(){//输出“2024”的数码管
//2024 0010 0000 0010 0100
P1=0x20;
P3=0x24;
}
先找到“好运来”的音乐简谱,然后带入之前的代码中。
单片机实验(三)-CSDN博客https://blog.csdn.net/weixin_64066303/article/details/134624276
#include<reg51.h>
#include<intrins.h> //包含_nop_()空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int
#define out P0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36
#define ClockSpeed 12000000 //时钟频率,Hz
#define SongSpeed 240 //ms,八分音符
sbit beepIO = P2^7; //定义蜂鸣器IO口
uchar freq_select;
//音阶频率表
unsigned int code freq_table[]={0,61714 ,61928 ,62131 ,62322 ,62502 ,62673 ,62833 ,62985 ,63128 ,63263 ,63391 ,63511, //低音
63628 ,63731 ,63835 ,63928 ,64021 ,64103 ,64185 ,64260 ,64331 ,64400 ,64463 ,64524, //中音
64580 ,64633 ,64684 ,64732 ,64777 ,64820 ,64860 ,64898 ,64934 ,64968 ,65000 ,65030 //高音
};
//好运来
uchar code song[]={
//叠个千纸鹤 再系个红腰带
M6,3, M6,1, H1,1, H1,1, M6,3, M6,1, M5,1, M3,1, M5,1, H1,1, M6,2, 0,2,
//愿善良的人们 天天好运来.你
M6,1, H1,1, H1,1, H1,1, H1,2, M5,2, M6,1, M5,1, M2,1, M5,1, M3,3, M2,1,
//勤劳生活美,你健康春常在
M3,1, M2,1, M1,1, M3,1, M2,3, M3,1, M6,1, M5,1, M3,1, M6,1, M6,1, M5,3,
//你一生的忙碌为了笑逐颜开。
M6,1, H1,1, H1,3, M6,1, H2,1, H2,1, H2,1, H1,1, M6,2, M5,1, H1,1, M6,4, M6,3,
//好运来,祝你好运来,好运
M6,2, H3,3, H2,1, H2,2, H1,1, M6,1, M5,2, H1,2, M6,4, M6,2, H2,2,
//带来了喜和爱。好运
H1,2, M6,1, M5,1, M2,2, M5,1, M6,1, M5,1, M3,3, M3,2, M6,3, M5,1,
//来,我们好运来,迎着好运来
M6,2, M6,1, M5,1, M6,2, H2,3, H1,1, H2,4, H1,3, H1,1, H1,1, H2,1,
//兴旺发达通四海。
H3,1, H3,1, H2,1, H1,1, M5,2, H1,3, M6,1, M6,2,
40
};
sbit RS=P2^0;//位变量
sbit RW=P2^1;//位变量
sbit E=P2^2;//位变量
//函数声明部分
void lcd_initial(void);//LCD初始化函数
void check_busy(void);//检查忙标志位函数
void write_command(uchar com);//写命令函数
void write_data(uchar dat);//写数据函数
void string(uchar ad,uchar *s);//显示字符串
void delay(uint);//延时
void print_2024();//输出“2024”的数码管
void print_HappyNewYear();//输出“新年快乐”的LCD 1602
void timer0_initial();//初始化定时器0的状态
void delay_ms(unsigned int x); //音乐延时函数
void main(void){
uchar select;
timer0_initial();//对定时器T0进行初始化
lcd_initial();//对LCD初始化
print_2024();
print_HappyNewYear();
while(song[select]!= 40) //判断歌曲是否结束
{
freq_select=song[select];
if(freq_select) //判断是否是休止符0
{
select++;
delay_ms(song[select]*SongSpeed);
TR0 = 0; //关闭蜂鸣器一段时间再打开,模拟按键抬手动作。
delay_ms(10);
TR0 = 1;
select++;
}else{
TR0 = 0;
select++;
delay_ms(song[select]*SongSpeed);
TR0 = 1;
select++;
}
}
}
//延时
void delay(uint j){
uchar i=250;
for(;j>0;j--){
while(--i);
i=249;
while(--i);
i=250;
}
}
//检查忙标志
void check_busy(void){
uchar dt;
do{
dt=0xff;//dt为变量单元,初值为0xff
//RS=0,E=1时才可以读忙标志位
E=0;
RS=0;
RW=1;
E=1;
dt=out;//out为P0口,P0口的状态送入dt中
}while(dt&0x80);//如果忙标志位BF=1,继续循环检测,等待BF=0
E=0;//BF=0,LCD 1602不忙,结束检测
}
//写命令
void write_command(uchar com){
check_busy();
//按规定RS和E同时为0时,才可以写命令
E=0;
RS=0;
RW=0;
out=com;//将命令com写入P0口
E=1;//写命令时,E应为正脉冲,即正跳变,所以前面先置E=0
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,LCD 1602开始执行命令
delay(1);//延时,等待硬件反应
}
//写数据
void write_data(uchar dat){
check_busy();//检测忙标志位BF=1则等待,若BF=0,则可对LCD 1602写入命令
E=0;//按规定写数据时,E应为正脉冲,所以先置E=0
//按规定RS=1和RW=0时,才可以写入数据
RS=1;
RW=0;
out=dat;//将数据”dat“从P0口输出,即写入LCD 1602
E=1;//E产生正跳变
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,写数据操作结束
delay(1);
}
//液晶显示器初始化函数
void lcd_initial(void){
write_command(0x38);//8位两行显示,5*7点阵字符
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x0C);//开整体显示,光标关,无闪烁
_nop_();//空操作1个机器周期,等待硬件反应
//write_command(0x05);//光标右移
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x01);//清屏
delay(1);
}
//输出显示字符串
void string(uchar ad,uchar *s){
write_command(ad);
while(*s>0){
write_data(*s++);//输出字符串,且指针增1
delay(100);
}
}
void print_2024(){//输出“2024”的数码管
//2024 0010 0000 0010 0100
P1=0x20;
P3=0x24;
}
void print_HappyNewYear(){//输出“新年快乐”的LCD 1602
string(0x81,"Happy New Year");//显示第一行的字符
string(0xC1,"peace happiness");//显示第二行的字符
delay(50);//延时
//write_command(0x01);//清屏
}
void timer0_initial()//初始化定时器0的状态
{
beepIO = 0;
TH0 = 0xFD;
TL0 = 0x09;
TMOD = 0x01; //选择定时器0,工作方式1
ET0 = 1; //允许定时器0中断
EA = 1; //CPU开放中断
TF0 = 0; //溢出标志位清0
TR0 = 1; //开启定时器0
}
void BeepTimer0() interrupt 1 //中断函数
{
beepIO = !beepIO; //蜂鸣器IO口高低电平转换
TH0 = freq_table[freq_select]/256 ;
TL0 = freq_table[freq_select]%256 ;
}
void delay_ms(unsigned int x) //音乐延时函数
{
uchar t;
while(x--) for(t=0;t<120;t++);
}
本来觉得影响不大的,但是忽略了音乐的播放是需要延迟来表示每一个音的节拍,所以就把lcd清屏取消了,让他就一直显示这个,目前的话就是一轮之后会重新从主函数开始,而且LCD输出的时候他会发出其他的声音。
所以又继续完善了一下
#include<reg51.h>
#include<intrins.h> //包含_nop_()空函数指令的头文件
#define uchar unsigned char
#define uint unsigned int
#define out P0
#define L1 1
#define L1_ 2
#define L2 3
#define L2_ 4
#define L3 5
#define L4 6
#define L4_ 7
#define L5 8
#define L5_ 9
#define L6 10
#define L6_ 11
#define L7 12
#define M1 13
#define M1_ 14
#define M2 15
#define M2_ 16
#define M3 17
#define M4 18
#define M4_ 19
#define M5 20
#define M5_ 21
#define M6 22
#define M6_ 23
#define M7 24
#define H1 25
#define H1_ 26
#define H2 27
#define H2_ 28
#define H3 29
#define H4 30
#define H4_ 31
#define H5 32
#define H5_ 33
#define H6 34
#define H6_ 35
#define H7 36
#define ClockSpeed 12000000 //时钟频率,Hz
#define SongSpeed 240 //ms,八分音符
sbit beepIO = P2^7; //定义蜂鸣器IO口
uchar freq_select;
//音阶频率表
unsigned int code freq_table[]={0,61714 ,61928 ,62131 ,62322 ,62502 ,62673 ,62833 ,62985 ,63128 ,63263 ,63391 ,63511, //低音
63628 ,63731 ,63835 ,63928 ,64021 ,64103 ,64185 ,64260 ,64331 ,64400 ,64463 ,64524, //中音
64580 ,64633 ,64684 ,64732 ,64777 ,64820 ,64860 ,64898 ,64934 ,64968 ,65000 ,65030 //高音
};
//好运来
uchar code song[]={
//叠个千纸鹤 再系个红腰带
M6,3, M6,1, H1,1, H1,1, M6,3, M6,1, M5,1, M3,1, M5,1, H1,1, M6,2, 0,2,
//愿善良的人们 天天好运来.你
M6,1, H1,1, H1,1, H1,1, H1,2, M5,2, M6,1, M5,1, M2,1, M5,1, M3,3, M2,1,
//勤劳生活美,你健康春常在
M3,1, M2,1, M1,1, M3,1, M2,3, M3,1, M6,1, M5,1, M3,1, M6,1, M6,1, M5,3,
//你一生的忙碌为了笑逐颜开。
M6,1, H1,1, H1,3, M6,1, H2,1, H2,1, H2,1, H1,1, M6,2, M5,1, H1,1, M6,4, M6,3,
//好运来,祝你好运来,好运
M6,2, H3,3, H2,1, H2,2, H1,1, M6,1, M5,2, H1,2, M6,4, M6,2, H2,2,
//带来了喜和爱。好运
H1,2, M6,1, M5,1, M2,2, M5,1, M6,1, M5,1, M3,3, M3,2, M6,3, M5,1,
//来,我们好运来,迎着好运来
M6,2, M6,1, M5,1, M6,2, H2,3, H1,1, H2,4, H1,3, H1,1, H1,1, H2,1,
//兴旺发达通四海。
H3,1, H3,1, H2,1, H1,1, M5,2, H1,3, M6,1, M6,2,
40
};
sbit RS=P2^0;//位变量
sbit RW=P2^1;//位变量
sbit E=P2^2;//位变量
//函数声明部分
void lcd_initial(void);//LCD初始化函数
void check_busy(void);//检查忙标志位函数
void write_command(uchar com);//写命令函数
void write_data(uchar dat);//写数据函数
void string(uchar ad,uchar *s);//显示字符串
void delay(uint);//延时
void timer0_initial();//初始化定时器0的状态
void delay_ms(unsigned int x); //音乐延时函数
void print_2024();//输出“2024”的数码管
void print_HappyNewYear();//输出“新年快乐”的LCD 1602
void main(void){
print_2024();//输出“2024”的数码管
print_HappyNewYear();//输出“新年快乐”的LCD 1602
//其他的都静态输出即可
while(1){
uchar select=0;//每次重新初始化
timer0_initial();//对定时器T0进行初始化
while(song[select]!= 40) //判断歌曲是否结束
{
freq_select=song[select];
if(freq_select) //判断是否是休止符0
{
select++;
delay_ms(song[select]*SongSpeed);
TR0 = 0; //关闭蜂鸣器一段时间再打开,模拟按键抬手动作。
delay_ms(10);
TR0 = 1;
select++;
}else{
TR0 = 0;
select++;
delay_ms(song[select]*SongSpeed);
TR0 = 1;
select++;
}
}
}
}
//延时
void delay(uint j){
uchar i=250;
for(;j>0;j--){
while(--i);
i=249;
while(--i);
i=250;
}
}
//检查忙标志
void check_busy(void){
uchar dt;
do{
dt=0xff;//dt为变量单元,初值为0xff
//RS=0,E=1时才可以读忙标志位
E=0;
RS=0;
RW=1;
E=1;
dt=out;//out为P0口,P0口的状态送入dt中
}while(dt&0x80);//如果忙标志位BF=1,继续循环检测,等待BF=0
E=0;//BF=0,LCD 1602不忙,结束检测
}
//写命令
void write_command(uchar com){
check_busy();
//按规定RS和E同时为0时,才可以写命令
E=0;
RS=0;
RW=0;
out=com;//将命令com写入P0口
E=1;//写命令时,E应为正脉冲,即正跳变,所以前面先置E=0
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,LCD 1602开始执行命令
delay(1);//延时,等待硬件反应
}
//写数据
void write_data(uchar dat){
check_busy();//检测忙标志位BF=1则等待,若BF=0,则可对LCD 1602写入命令
E=0;//按规定写数据时,E应为正脉冲,所以先置E=0
//按规定RS=1和RW=0时,才可以写入数据
RS=1;
RW=0;
out=dat;//将数据”dat“从P0口输出,即写入LCD 1602
E=1;//E产生正跳变
_nop_();//空操作1个机器周期,等待硬件反应
E=0;//E由高电平变为低电平,写数据操作结束
delay(1);
}
//液晶显示器初始化函数
void lcd_initial(void){
write_command(0x38);//8位两行显示,5*7点阵字符
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x0C);//开整体显示,光标关,无闪烁
_nop_();//空操作1个机器周期,等待硬件反应
//write_command(0x05);//光标右移
_nop_();//空操作1个机器周期,等待硬件反应
write_command(0x01);//清屏
delay(1);
}
//输出显示字符串
void string(uchar ad,uchar *s){
write_command(ad);
while(*s>0){
write_data(*s++);//输出字符串,且指针增1
delay(100);
}
}
void timer0_initial()//初始化定时器0的状态
{
beepIO = 0;
TH0 = 0xFD;
TL0 = 0x09;
TMOD = 0x01; //选择定时器0,工作方式1
ET0 = 1; //允许定时器0中断
EA = 1; //CPU开放中断
TF0 = 0; //溢出标志位清0
TR0 = 1; //开启定时器0
}
void BeepTimer0() interrupt 1 //中断函数
{
beepIO = !beepIO; //蜂鸣器IO口高低电平转换
TH0 = freq_table[freq_select]/256 ;
TL0 = freq_table[freq_select]%256 ;
}
void delay_ms(unsigned int x) //音乐延时函数
{
uchar t;
while(x--) for(t=0;t<120;t++);
}
void print_2024(){//输出“2024”的数码管
//2024 0010 0000 0010 0100
P1=0x20;
P3=0x24;
}
void print_HappyNewYear(){//输出“新年快乐”的LCD 1602
lcd_initial();//对LCD初始化
string(0x81,"Happy New Year");//显示第一行的字符
string(0xC1,"peace happiness");//显示第二行的字符
delay(50);//延时
//write_command(0x01);//清屏
}
器件名称 | Proteus关键字 |
红色共阴极数码管 | 7SEG-BCD |
蓝色共阴极数码管 | 7SEG-BCD-BLUE |
绿色共阴极数码管 | 7SEG-BCD-GRN |
51单片机 | AT89C51 |
复位按钮 | BUTTON |
电容 | CAP |
电解电容 | CAP-ELEC |
晶体振荡器 | CRYSTAL |
字符型LCD 1602显示器 | LM016L |
滑动变阻器 | POT-HG |
电阻 | RES |
排阻 | RESPACK-8 |
蜂鸣器 | SPEAKER |
好运来
本来构思的是看自己学的都可以如何祝大家新年快乐,目前只用到了单片机的知识。