我博客有符合的定时器交通灯中断流水灯,运行近10小时依然同系统保持同步不差一秒的定时器10毫秒的计时
题目4最简单
1 参考 https://blog.csdn.net/creampang/article/details/125453460
2 参考 https://blog.csdn.net/longhanfei/article/details/125208118
3 参考 http://news.eeworld.com.cn/mcu/article_2016090929291.html
4 参考 https://blog.csdn.net/weixin_43772810/article/details/120465849
5 参考 自选题目 https://xiaohuisuper.blog.csdn.net/article/details/120443885
类似的单片机应用设计的题目很多,主要还是突破基本系统软硬件,在此基础上实现其他就简单了
51单片机电子时钟(C语言)
#include<reg51.h>
#include<intrins.h>
//时钟芯片1302寄存器读写命令字
#define SEC_write 0x80
#define SEC_read 0x81
#define MIN_write 0x82
#define MIN_read 0x83
#define HR_write 0x84
#define HR_read 0x85
#define DAY_write 0x86
#define DAY_read 0x87
#define MONTH_write 0x88
#define MONTH_read 0x89
#define YEAR_write 0x8c
#define YEAR_read 0x8d
//时钟芯片1302数据传输接口
sbit SCLK=P2^0;
sbit DATA=P2^1;
sbit RST=P2^2;
//向1302写一个字节数据
void Write1302(unsigned char dat)
{
unsigned char i;
SCLK=0;
_nop_();
for(i=0;i<8;i++)
{
DATA=dat&0x01;
_nop_();
SCLK=1;
_nop_();
SCLK=0;
dat>>=1;
}
}
//根据命令字,向1302写一个字节数据
void WriteSet1302(unsigned char Cmd,unsigned char dat)
{
RST=0;
SCLK=0;
RST=1;
_nop_();
Write1302(Cmd);
Write1302(dat);
SCLK=1;
RST=0;
}
//从1302读一个字节数据
unsigned char Read1302(void)
{
unsigned char i,dat;
_nop_();
for(i=0;i<8;i++)
{
dat>>=1;
if(DATA==1)
dat|=0x80;
SCLK=1;
_nop_();
SCLK=0;
_nop_();
}
return dat;
}
//根据命令字,从1302读一个字节数据
unsigned char ReadSet1302(unsigned char Cmd)
{
unsigned char dat;
RST=0;
SCLK=0;
RST=1;
Write1302(Cmd);
dat=Read1302();
SCLK=1;
RST=0;
return dat;
}
//1302进行初始化设置
void Init_DS1302(void)
{
WriteSet1302(0x8E,0x00);
WriteSet1302(SEC_write,((0/10)<<4|(1%10)));
WriteSet1302(MIN_write,((0/10)<<4|(0%10)));
WriteSet1302(HR_write,((0/10)<<4|(0%10)));
WriteSet1302(DAY_write,((1/10)<<4|(1%10)));
WriteSet1302(MONTH_write,((1/10)<<4|(1%10)));
WriteSet1302(YEAR_write,((1/10)<<4|(1%10)));
}
//按键接口
sbit S1=P3^7;
sbit S2=P3^6;
sbit S3=P3^5;
sbit S4=P3^4;
sbit S5=P3^3;
//LCD显示的数据
unsigned char code digit[10]={"0123456789"};
//LCD数据传输接口
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;
sbit BF=P0^7;
//延时1ms
void delay1ms()
{
unsigned char i,j;
for(i=0;i<10;i++)
for(j=0;j<33;j++)
;
}
//延时nms
void delaynms(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
delay1ms();
}
//LCD忙碌检测
unsigned char BusyTest(void)
{
bit result;
RS=0;
RW=1;
E=1;
_nop_();
_nop_();
_nop_();
_nop_();
result=BF;
E=0;
return result;
}
//向LCD写一个字节数据(P0口)
void WriteInstruction(unsigned char dicate)
{
while(BusyTest()==1);
RS=0;
RW=0;
E=0;
_nop_();
_nop_();
P0=dicate;
_nop_();
_nop_();
_nop_();
_nop_();
E=1;
_nop_();
_nop_();
_nop_();
_nop_();
E=0;
}
//向LCD写显示地址
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80);
}
//向LCD写显示数据
void WriteData(unsigned char y)
{
while(BusyTest()==1);
RS=1;
RW=0;
E=0;
P0=y;
_nop_();
_nop_();
_nop_();
_nop_();
E=1;
_nop_();
_nop_();
_nop_();
_nop_();
E=0;
}
//LCD进行初始化设置
void Init_LCD(void)
{
delaynms(15);
WriteInstruction(0x38); //显示模式设置
delaynms(5);
WriteInstruction(0x38);
delaynms(5);
WriteInstruction(0x38);
delaynms(5);
WriteInstruction(0x0f); //显示开关及光标设置
delaynms(5);
WriteInstruction(0x06); //输入模式设置
delaynms(5);
WriteInstruction(0x01); //清除当前显示
delaynms(5);
WriteAddress(0x01); //设置固定显示
WriteData('D');
WriteData('a');
WriteData('t');
WriteData('e');
WriteData(':');
WriteAddress(0x08);
WriteData('-');
WriteAddress(0x0b);
WriteData('-');
WriteAddress(0x45);
WriteData(':');
WriteAddress(0x48);
WriteData(':');
}
//显示年
void DisplayYear(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x06);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//显示月
void DisplayMonth(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x09);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//显示日
void DisplayDay(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x0c);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//显示时
void DisplayHour(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x43);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//显示分
void DisplayMinute(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x46);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//显示秒
void DisplaySecond(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x%10;
WriteAddress(0x49);
WriteData(digit[i]);
WriteData(digit[j]);
delaynms(30);
}
//年上调
unsigned char year_add(char year)
{
if(year==99)
{
return 0;
}
else
{
year++;
return year;
}
}
//月上调
unsigned char month_add(char month)
{
if(month==12)
{
return 1;
}
else
{
month++;
return month;
}
}
//日上调
unsigned char day_add(char day)
{
if(day==31)
{
return 1;
}
else
{
day++;
return day;
}
}
//时上调
unsigned char hour_add(char hour)
{
if(hour==23)
{
return 0;
}
else
{
hour++;
return hour;
}
}
//分上调
unsigned char minute_add(char minute)
{
if(minute==59)
{
return 0;
}
else
{
minute++;
return minute;
}
}
//秒上调
unsigned char second_add(char second)
{
if(second==59)
{
return 0;
}
else
{
second++;
return second;
}
}
//年下调
unsigned char year_reduce(char year)
{
if(year==0)
{
return 99;
}
else
{
year--;
return year;
}
}
//月下调
unsigned char month_reduce(char month)
{
if(month==1)
{
return 12;
}
else
{
month--;
return month;
}
}
//日下调
unsigned char day_reduce(char day)
{
if(day==1)
{
return 31;
}
else
{
day--;
return day;
}
}
//时下调
unsigned char hour_reduce(char hour)
{
if(hour==0)
{
return 23;
}
else
{
hour--;
return hour;
}
}
//分下调
unsigned char minute_reduce(char minute)
{
if(minute==0)
{
return 59;
}
else
{
minute--;
return minute++;
}
}
//秒下调
unsigned char second_reduce(char second)
{
if(second==0)
{
return 59;
}
else
{
second--;
return second;
}
}
void main(void)
{
unsigned char second,minute,hour,day,month,year;
unsigned char ReadValue;
unsigned char flag=0;
unsigned char sum=0;
Init_LCD();
Init_DS1302();
while(1)
{
//判断按键1状态,标志flag
if(S1==0)
{
delay1ms();
if(S1==0)
{
WriteAddress(0x4d);
WriteData('Y');
flag=1;
}
}
//按键1未按下,从1302读出数据直接显示
if(flag==0)
{
WriteAddress(0x4d);
WriteData('Q');
ReadValue = ReadSet1302(YEAR_read);
year=((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0f);
DisplayYear(year);
ReadValue = ReadSet1302(MONTH_read);
month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0f);
DisplayMonth(month);
ReadValue = ReadSet1302(DAY_read);
day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0f);
DisplayDay(day);
ReadValue = ReadSet1302(HR_read);
hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0f);
DisplayHour(hour);
ReadValue = ReadSet1302(MIN_read);
minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0f);
DisplayMinute(minute);
ReadValue = ReadSet1302(SEC_read);
second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0f);
DisplaySecond(second);
}
//按键1按下,设置年月日时分秒
else
{
DisplaySecond(second);
DisplayMinute(minute);
DisplayHour(hour);
DisplayDay(day);
DisplayMonth(month);
DisplayYear(year);
//按键2判断设置项(年月日时分秒),并显示
if(S2==0)
{
delay1ms();
if(S2==0)
{
sum++;
switch(sum%6)
{
case 0:
WriteAddress(0x4d);
WriteData('Y');
break;
case 1:
WriteAddress(0x4d);
WriteData('M');
break;
case 2:
WriteAddress(0x4d);
WriteData('D');
break;
case 3:
WriteAddress(0x4d);
WriteData('H');
break;
case 4:
WriteAddress(0x4d);
WriteData('m');
break;
case 5:
WriteAddress(0x4d);
WriteData('S');
break;
}
}
}
//按键3设置项上调
if(S3==0)
{
delay1ms();
if(S3==0)
{
switch(sum%6)
{
case 0:
year=year_add(year);
break;
case 1:
month=month_add(month);
break;
case 2:
day=day_add(day);
break;
case 3:
hour=hour_add(hour);
break;
case 4:
minute=minute_add(minute);
break;
case 5:
second=second_add(second);
break;
}
}
}
//按键4设置项下调
if(S4==0)
{
delay1ms();
if(S4==0)
{
switch(sum%6)
{
case 0:
year=year_reduce(year);
break;
case 1:
month=month_reduce(month);
break;
case 2:
day=day_reduce(day);
break;
case 3:
hour=hour_reduce(hour);
break;
case 4:
minute=minute_reduce(minute);
break;
case 5:
second=second_reduce(second);
break;
}
}
}
}
//按键5清空标志位,将设置好的时间写入1302寄存器
if(S5==0)
{
delay1ms();
if(S5==0)
{
flag=0;
sum=0;
WriteAddress(0x4d);
WriteData('Q');
WriteSet1302(0x8E,0x00);
WriteSet1302(SEC_write,((second/10)<<4|(second%10)));
WriteSet1302(MIN_write,((minute/10)<<4|(minute%10)));
WriteSet1302(HR_write,((hour/10)<<4|(hour%10)));
WriteSet1302(DAY_write,((day/10)<<4|(day%10)));
WriteSet1302(MONTH_write,((month/10)<<4|(month%10)));
WriteSet1302(YEAR_write,((year/10)<<4|(year%10)));
}
}
}
}
#include<reg52.h>
//K1后K3加分钟,K4加时间,K2加秒,K1进入闹钟设置,K2退出
//K2关闭闹钟
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
#define data8b P1
sbit K1=P3^2; //外部中断0
sbit K2=P3^3; //外部中断1
sbit K3=P3^0;
sbit K4=P3^1;
sbit BUZ=P2^4; //蜂鸣器,0响
sbit RW=P2^5; //4脚,数据(1)or命令(0)
sbit RS=P2^6; //5脚,读(1)写(0)
sbit E=P2^7; //6脚,使能信号
u8 code dat1[]={0X30,0X31,0X32,0X33,
0X34,0X35,0X36,0X37,
0X38,0X39};
void delay(u16 i) //延时函数
{
while(i--);
}
void open012() //打开中断0,1,定时器中断0
{
TMOD|=0X01; //选择为定时器0模式,工作方式1
ET0=1; //打开定时器0中断允许
EA=1; //打开总中断
TR0=1; //打开定时器
EX0=1; //打开外部中断0
IT0=1; //边沿触发方式
EX1=1; //打开外部中断1
IT1=1; //边沿触发
}
void wrm(u8 dat) //写入命令
{
delay(1000);
RS=0;
RW=0;
E=0;
data8b=dat;
E=1;
delay(1000);
E=0;
}
void wrd(u8 dat) //写入数据
{
delay(1000);
RS=1;
RW=0;
E=0;
data8b=dat;
E=1;
delay(1000);
E=0;
}
void zero()
{
wrm(0X38); //八位数据,两行显示,5*7
wrm(0X0c); //无光标,打开显示
wrm(0X06); //光标右移,屏幕不移动
wrm(0X01); //清屏
wrm(0X80); //设置数据指针起点
}
u8 fg=0,sg=0,bfg=0,bsg=0;
u16 i=0;
u8 s=0;
u8 mod=0;
char dingshi;
bit bell=0;
bit zanting=1;
void fangsong()
{
wrd(dat1[sg/10]); //时十位
wrd(dat1[sg%10]); //时个位
wrd(0x3A); //:
wrd(dat1[fg/10]); //分十位
wrd(dat1[fg%10]); //分个位
wrd(0x3A); //:
wrd(dat1[(s/10)]); //秒十
wrd(dat1[(s%10)]); //秒个
}
void fangsong1()
{
wrm(0X80);
wrd(dat1[sg/10]); //时十位
wrd(dat1[sg%10]); //时个位
wrd(0x3A); //:
wrd(dat1[fg/10]); //分十位
wrd(dat1[fg%10]); //分个位
wrd(0x3A); //:
wrd(dat1[(s/10)]); //秒十
wrd(dat1[(s%10)]); //秒个
}
void chuli()
{
if(fg==60)
{
sg++;
fg=0;
}
if(sg==24)
{
sg=0;
}
}
void main()
{
u8 shijian;
open012();
zero();
chuli();
fangsong();
shijian=100;
while(1)
{
while(mod==0)
{
EX1=1; //打开外部中断1
if(s==60)
{
fg++; //60秒转化为1分钟
s=0;
}
chuli();
if((fg==0)&&(shijian!=sg))
{
BUZ=0;
shijian=sg;
}
fangsong1();
if((BUZ==0)&&(bell==0))
{
delay(1000);
BUZ=1;
}
if((fg==bfg)&&(sg==bsg)&&(bell==1))
BUZ=0;
else BUZ=1;
}
while(mod==1)
{
EX1=0; //关闭外部中断1
zero();
fangsong();
if(K3==0)
{
delay(1000);
if(K3==0)
fg++;
}
if(K4==0)
{
delay(1000);
if(K4==0)
sg++;
}
if(K2==0)
{
delay(1000);
if(K2==0)
s=0;
}
if(fg>59)
{
fg=0;
}
if(sg>23)
{
sg=0;
}
if(s>=59)
{
s=0;
}
}
while(mod==2) //设置闹钟
{
if(bfg==60)
{
bsg++;
bsg=0;
}
if(bsg==24)
{
bsg=0;
}
zero();
wrd(0x20);
wrd(0x20);
wrd(0x20);
wrd(dat1[(bsg/10)]); //时十位
wrd(dat1[(bsg%10)]); //时个位
wrd(0x3A); //:
wrd(dat1[(bfg/10)]); //分十位
wrd(dat1[(bfg%10)]); //分个位
if(K3==0)
{
delay(1000);
if(K3==0)
bfg++;
}
if(K4==0)
{
delay(1000);
if(K4==0)
bsg++;
}
bell=1;
zero();
}
while(mod==3)
{
while(zanting)
{
dingshi=60;
EX1=1; //打开外部中断1
wrm(0X80);
wrd(dat1[(dingshi/10)]); //时十位
wrd(dat1[(dingshi%10)]); //时个位
}
wrm(0X80);
wrd(dat1[(dingshi/10)]); //时十位
wrd(dat1[(dingshi%10)]); //时个位
while(dingshi<0)
{
wrm(0X80);
wrd(dat1[0]); //时十位
wrd(dat1[0]); //时个位
BUZ=0;
}
}
}
}
void time0() interrupt 1
{
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
i++;
if(i==1000) //ms转化为s
{
i=0;
s++;
dingshi--;
}
}
void key1() interrupt 0 //外部中断0,调整时间
{
delay(1000);
if(K1==0)
{
mod++;
while(!K1);
}
if(mod>3)
{
mod=0;
}
zero();
}
void naozhong() interrupt 2 //开关闹钟
{
if(K2==0)
{
delay(1000); //消抖
if(K2==0)
{
bell=0;
BUZ=1;
zanting=~zanting;
} //关闭蜂鸣器
while(!K2); //确认按键松开
}
}
请问还需要解答你所提到的问题否,单片机确实知识挺繁杂的,需要参考标准的单片机知识
给你提供一点实现思路和相关的技术资料:
基于单片机的交通灯控制系统需要包含以下组成部分: 1硬件设备组成:单片机、LED 灯、显示屏等硬件设备。
设计思路:交通灯控制系统的设计思路是基于定时器的,利用计数器和定时器来控制红绿灯的转换,同时通过按键检测实现手动控制。
基于单片机的交通灯控制系统设计与实现:https://wenku.baidu.com/view/6bda7b30383567ec102de2bd960590c69ec3d8ac.html?_wkts_=1688985196999&bdQuery=%E5%8D%95%E7%89%87%E6%9C%BA+%E5%AE%9E%E7%8E%B0%E4%BA%A4%E9%80%9A%E7%81%AF%E6%8E%A7%E5%88%B6%E7%B3%BB%E7%BB%9F
主要是要了解软硬件如何交互操作
参考:https://peakchen.blog.csdn.net/article/details/131516324?spm=1001.2014.3001.5502
这是一个单片机应用设计的题目,需要你综合运用单片机的硬件和软件知识,设计一个能够实现门铃功能的系统。我会给你一些参考的思路和步骤,但你需要根据具体的要求和条件,自己完成具体的设计和编程。
(1)首先,你需要介绍课题的背景,说明为什么要设计这样一个系统,它有什么作用和意义。然后,你需要进行需求分析,明确系统的功能和性能要求,以及用户的操作方式和界面。接着,你需要进行可行性分析,考虑系统的技术可行性、经济可行性、安全可行性等方面,评估系统的优缺点和风险。最后,你需要进行软硬件功能分配,确定系统的主要组成部分,以及各部分的功能和接口。
例如,你可以这样写:
课题背景:门铃是一种常见的家庭或公共场所的通知设备,它可以在有人按下门铃按钮时,发出声音提示有客人到访。门铃的声音应该清晰而悦耳,能够引起注意而不至于打扰。门铃的控制系统一般由单片机作为核心控制器,通过按键、蜂鸣器、电源等外围器件实现基本功能。
需求分析:本课题要求设计一个简单的门铃控制系统,其基本功能如下:
当有人按下门铃按钮时,蜂鸣器发出叮咚的声音。
叮咚声音的频率和持续时间应该适中,不要过高或过低,不要过长或过短。
门铃按钮应该具有防抖动功能,避免误触发或重复触发。
门铃系统应该具有低功耗特性,能够长时间工作而不影响电池寿命。
可行性分析:本课题设计的门铃控制系统具有以下特点:
技术可行性:单片机作为控制器,可以方便地实现对按键、蜂鸣器等外围器件的控制和驱动,以及声音信号的产生和输出。单片机也可以通过编程实现防抖动、低功耗等功能。单片机的晶振频率为12Mhz,足以满足本系统的时序要求。
经济可行性:单片机及其外围器件都是常见且低成本的电子元件,可以在市场上轻松购买。本系统的设计成本较低,且可以批量生产和销售。
安全可行性:本系统使用直流电源供电,电压较低,不会对人体造成危害。本系统也没有复杂或危险的机械部件或化学物质,不会引起火灾或爆炸等事故。
软硬件功能分配:本系统主要由以下几个部分组成:
单片机:作为核心控制器,负责接收按键信号、产生声音信号、驱动蜂鸣器等功能。
按键:作为输入设备,负责触发门铃声音。
蜂鸣器:作为输出设备,负责发出门铃声音。
电源:作为能源供应,负责为单片机及其外围器件提供稳定的直流电压。
(2)其次,你需要对系统硬件进行设计,包括硬件功能模块划分、电路原理图设计等。你需要根据软硬件功能分配的结果,确定各个部分的具体型号和参数,以及它们之间的连接方式和信号传输方式。你需要画出系统的电路原理图,标明各个元件的引脚和信号线,以及必要的电阻、电容等辅助元件。
例如,你可以这样写:
硬件功能模块划分:本系统的硬件功能模块如下图所示:
电路原理图设计:本系统的电路原理图如下图所示:
其中,单片机采用AT89C51型号,是一款典型的51系列单片机,具有4K字节的程序存储器和128字节的数据存储器,以及32个I/O口。单片机的晶振频率为12Mhz,由外接晶振和两个电容组成振荡电路。单片机的复位电路由一个电阻和一个电容组成,用于在上电或按下复位按钮时将单片机复位。单片机的供电电压为5V,由一个稳压芯片7805从9V的电池转换而来。
按键采用常开型按钮开关,通过一个上拉电阻连接到单片机的P1.0口。当按键按下时,P1.0口读取低电平信号,触发门铃声音。当按键松开时,P1.0口读取高电平信号,停止门铃声音。为了防止按键抖动,可以在软件中设置一个延时或者采用软件滤波的方法。
蜂鸣器采用有源蜂鸣器,通过一个NPN型三极管放大驱动。单片机的P2.0口输出一个方波信号,控制三极管的导通和截止,从而控制蜂鸣器的开关。方波信号的频率和占空比决定了蜂鸣器发出的声音的音调和响度。为了发出叮咚的声音,可以在软件中设置一个定时器或者采用延时循环的方法,让方波信号先输出一个较高频率的音调,再输出一个较低频率的音调。
(3)再次,你需要对系统软件进行设计,选用C语言编写程序,给出软件开发流程。你需要根据系统功能要求和硬件接口情况,确定程序的主要功能模块和算法逻辑,并编写相应的代码。你需要给出程序的框架结构和流程图,并注释清楚每一部分代码的作用和意义。
例如,你可以这样写:
软件开发流程:本系统软件开发流程如下:
确定程序功能需求:程序需要实现以下功能:
初始化单片机和外围器件
检测按键信号,并进行防抖处理
根据按键信号控制蜂鸣器发出叮咚声
实现低功耗模式
设计程序框架结构:程序可以分为以下几个部分:
头文件:包含必要的宏定义、变量
声明和函数原型:声明必要的函数和中断服务程序
主函数:完成初始化工作,并进入主循环
按键检测函数:检测按键信号,并进行防抖处理
蜂鸣器控制函数:根据按键信号控制蜂鸣器发出叮咚声
定时器中断服务程序:实现定时器的功能,用于产生方波信号和延时控制
外部中断服务程序:实现外部中断的功能,用于唤醒单片机
编写程序代码:根据程序框架结构和算法逻辑,编写相应的C语言代码,并注释清楚每一部分代码的作用和意义。
调试程序代码:使用单片机开发软件,如Keil或IAR等,对程序代码进行编译、仿真、下载和调试,检查程序是否能够正确运行,是否满足功能要求,是否有错误或异常情况。
程序框架结构和流程图:本系统程序框架结构如下:
//头文件
#include <reg51.h> //包含51单片机的寄存器定义
#include <intrins.h> //包含一些内嵌函数
//宏定义
#define uchar unsigned char //定义无符号字符型数据类型
#define uint unsigned int //定义无符号整型数据类型
#define KEY P1_0 //定义按键端口
#define BZ P2_0 //定义蜂鸣器端口
#define FOSC 12000000L //定义晶振频率为12Mhz
#define T0MS (65536-FOSC/12/1000) //定义定时器0的初值,定时1ms
//变量声明
bit key_flag; //定义按键标志位,用于记录按键状态
bit bz_flag; //定义蜂鸣器标志位,用于记录蜂鸣器状态
//函数原型声明
void Init(); //初始化函数,用于初始化单片机和外围器件
void KeyScan(); //按键检测函数,用于检测按键信号,并进行防抖处理
void BzControl(); //蜂鸣器控制函数,用于根据按键信号控制蜂鸣器发出叮咚声
//中断服务程序原型声明
void T0_ISR() interrupt 1; //定时器0中断服务程序,用于产生方波信号和延时控制
void INT0_ISR() interrupt 0; //外部中断0中断服务程序,用于唤醒单片机
```c
//主函数
void main()
{
Init(); //调用初始化函数
while(1) //主循环
{
KeyScan(); //调用按键检测函数
BzControl(); //调用蜂鸣器控制函数
PCON = 0x02; //进入低功耗模式
}
}
//初始化函数
void Init()
{
//省略具体代码,需要完成以下功能:
//设置单片机的工作模式和寄存器初值
//设置定时器0的工作模式和初值,并开启定时器0中断和总中断
//设置外部中断0的触发方式,并开启外部中断0中断
//设置按键端口为输入模式,并开启上拉电阻
//设置蜂鸣器端口为输出模式,并输出低电平
}
//按键检测函数
void KeyScan()
{
static uchar key_count; //定义静态变量,用于记录按键计数值
if(KEY == 0) //如果按键按下(低电平有效)
{
key_count++; //按键计数值加一
if(key_count >= 5) //如果按键计数值大于等于5(假设每次扫描间隔为20ms,即按键按下超过100ms)
{
key_count = 5; //按键计数值限制为5
key_flag = 1; //按键标志位置1,表示按键有效
}
}
else //如果按键松开(高电平有效)
{
key_count = 0; //按键计数值清零
key_flag = 0; //按键标志位清零,表示按键无效
}
}
//蜂鸣器控制函数
void BzControl()
{
static uchar bz_count; //定义静态变量,用于记录蜂鸣器计数值
if(key_flag == 1) //如果按键有效
{
bz_flag = ~bz_flag; //蜂鸣器标志位取反,表示切换蜂鸣器状态
if(bz_flag == 1) //如果蜂鸣器状态为1
{
TH0 = (uchar)(T0MS >> 8); //给定时器0赋初值,定时1ms
TL0 = (uchar)T0MS;
TR0 = 1; //启动定时器0,开始输出方波信号
bz_count++; //蜂鸣器计数值加一
if(bz_count == 1) //如果蜂鸣器计数值为1,表示第一次发声
{
_nop_(); //空操作,用于产生一个较高频率的音调
}
else if(bz_count == 2) //如果蜂鸣器计数值为2,表示第二次发声
{
_nop_();_nop_();_nop_();_nop_(); //空操作,用于产生一个较低频率的音调
}
}
else //如果蜂鸣器状态为0
{
TR0 = 0; //停止定时器0,停止输出方波信号
BZ = 0; //蜂鸣器端口输出低电平,关闭蜂鸣器
if(bz_count == 2) //如果蜂鸣器计数值为2,表示发出完整的叮咚声
{
bz_count = 0; //蜂鸣器计数值清零,准备下一次发声
}
}
}
}
//定时器0中断服务程序
void T0_ISR() interrupt 1
{
TH0 = (uchar)(T0MS >> 8); //重装定时器0初值,继续定时1ms
TL0 = (uchar)T0MS;
BZ = ~BZ; //蜂鸣器端口取反,产生方波信号
}
//外部中断0中断服务程序
void INT0_ISR() interrupt 0
{
_nop_(); //空操作,用于延时消除抖动(可选)
}
(4)最后,你需要总结你的设计过程和结果,说明你遇到的问题和解决的方法,以及你的心得体会和收获。
例如,你可以这样写:
总结:本课题设计了一个简单的门铃控制系统,使用单片机作为核心控制器,通过按键、蜂鸣器、电源等外围器件实现基本功能。在设计过程中,我遵循了软硬件协同设计的原则,先进行需求分析和可行性分析,然后进行硬件设计和软件设计,并使用单片机开发软件进行编译、仿真、下载和调试。在设计中,我遇到了以下问题和解决方法:如何产生叮咚声音?我使用了定时器中断的方法,通过控制蜂鸣器端口的方波信号的频率和占空比,来实现不同音调和响度的声音。为了实现叮咚声音,我在蜂鸣器控制函数中使用了一个静态变量来记录蜂鸣器发声的次数,并根据次数来调整方波信号的频率。为了控制声音的持续时间,我在按键检测函数中使用了一个按键标志位来记录按键状态,并根据状态来开启或关闭定时器中断。
如何实现低功耗模式?我使用了单片机的低功耗模式,即空闲模式。在空闲模式下,单片机的CPU停止工作,但其他外设仍然工作。当有外部中断发生时,单片机可以被唤醒。为了实现低功耗模式,我在主循环中设置了PCON寄存器的相应位,并使用了外部中断0作为唤醒源。为了防止误唤醒,我在外部中断0中断服务程序中加入了一个空操作,用于延时消除抖动。
通过本课题的设计,我学习了单片机应用设计的基本方法和步骤,掌握了单片机的硬件和软件设计技巧,提高了我的动手能力和创新能力。我也发现了自己在设计中存在的不足和问题,比如对单片机的工作原理和性能特点不够熟悉,对电路原理图和程序代码的规范性和可读性不够重视,对程序调试和测试的方法和工具不够熟练等。我希望在今后的学习中,能够不断完善自己的知识和技能,设计出更优秀的单片机应用系统。
基于51单片机的电子时钟设计
在科技日新月异的今天,电子时钟的精准度和使用方便性成为我们衡量时间的一种重要工具。本设计选择51单片机作为控制核心,利用其强大的处理能力和灵活的编程环境,实现一个具有时、分、秒显示功能的电子时钟。
本设计电子时钟的主要需求是能够显示时、分、秒,实现准确计时。在硬件方面,主要需要51单片机、LCD显示模块、晶振和电源供应等元件。在软件方面,选择使用C语言进行编程,利用Keil软件环境进行编译和仿真。通过以上分析,我们认为设计这样一个电子时钟系统是完全可行的。
本设计的电子时钟硬件主要包括51单片机主控模块、LCD显示模块和电源模块。
单片机主控模块:我们选择AT89C51作为本设计的控制核心,其具有5V电源、12MHz的晶振频率,适合我们的设计需求。
显示模块:我们选择一个16x2的LCD模块来显示时间,该模块使用简单,显示效果良好。
电源模块:我们使用5V直流电源供应整个系统电源。
4. 系统软件设计
本设计选择使用C语言进行编程,编程环境为Keil。
在程序设计上,主要分为系统初始化、定时器控制和LCD显示控制三个部分。
系统初始化:设置系统的初始状态,初始化定时器和LCD显示模块。
定时器控制:使用定时器中断服务程序实现秒级计时,每秒中断一次,更新时、分、秒的数据。
LCD显示控制:在主函数中通过调用LCD显示函数将时间数据显示在LCD模块上。
5. 总结
在本次设计中,我们成功地设计出了一个基于51单片机的电子时钟。通过这个设计,我们不仅提高了自己的硬件设计和C语言编程能力,也深入理解了51单片机和LCD显示模块的工作原理和使用方法。同时,我们也感受到了嵌入式系统设计的魅力,这将对我们未来的学习和工作有很大的帮助。
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
//定义LCD相关的IO口
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;
uchar code table[]=" : : ";
uchar second, minute, hour;
void delay(uint z)
{
uint x, y;
for(x=z; x>0; x--)
for(y=110; y>0; y--);
}
void write_com(uchar com)
{
LCD_RS=0;
LCD_RW=0;
P0=com;
delay(5);
LCD_EN=1;
delay(5);
LCD_EN=0;
}
void write_data(uchar dat)
{
LCD_RS=1;
LCD_RW=0;
P0=dat;
delay(5);
LCD_EN=1;
delay(5);
LCD_EN=0;
}
void write_char(uchar addr, uchar dat)
{
write_com(addr);
write_data(dat);
}
void init()
{
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
delay(5);
}
void display(uchar second, uchar minute, uchar hour)
{
uchar temp;
temp=hour/10;
write_char(0x80+0x04, temp+'0');
temp=hour%10;
write_char(0x80+0x05, temp+'0');
temp=minute/10;
write_char(0x80+0x07, temp+'0');
temp=minute%10;
write_char(0x80+0x08, temp+'0');
temp=second/10;
write_char(0x80+0x0a, temp+'0');
temp=second%10;
write_char(0x80+0x0b, temp+'0');
}
void timer0_init()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
ET0=1;
EA=1;
TR0=1;
}
void timer0_isr() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
second++;
if(second==60)
{
second=0;
minute++;
if(minute==60)
{
minute=0;
hour++;
if(hour==24)
{
hour=0;
}
}
}
}
void main()
{
init();
timer0_init();
while(1)
{
display(second, minute, hour);
delay(500);
}
}