单片机大作业
课题名称简易楼道灯电费计价系统
院、系、
自动化与电气工程学院部
专业电气工程及其自动化
班级
姓名
学号
指导教师
1.作业背景
城市居民楼内一般安装有楼道灯,方便夜间居民上下楼,其工作特点是人来灯亮,人走灯灭。
以热释电型楼道灯为例,其基本工作原理是:热释电传感器能检测人体是否进入感应范围,当人体未进入感应范围,即离楼道灯还有一定距离时,传感器输出低电平;当人体进入感应范围,即靠近楼道灯时,传感器输出高电平。
根据传感器的输出,单片机可决定是否点亮楼道灯。
由于楼道灯属本单元全体居民共用,为便于电费结算,现要求设计一套简易楼道灯电费计价系统,系统能自动计算楼道灯在一个月内的总点亮时间,并据此计算出应缴电费额度。
2.作业要求
系统由电源电路、热释电传感器、单片机、按键以及显示器组成,楼道灯供电为220市电,功率2kW(实际灯泡功率一般不会这么大。
考虑到实验演示时间有限,故假设此灯泡功率为该值)。
其中电源采用5V,热释电传感器的输出采用按键按下与否进行模拟,单片机采用51,显示器采用4位数码管,电价按5.86元/千瓦时(实际电价一般为0.58。
考虑到实验演示时间有限,故假设电价为该值),要求电费计算精度精确到0.01元。
用户可用按键查询本月楼道灯总点亮时间(精度0.01小时),以及本月总电费。
3.硬件部分
(1)仿真电路图
(2)实物电路图:
(3)
元器件列表
STC89C52RC 一个
按钮开关3个四位共阳数码管1个12M晶振1个CS9012三极管1个
二极管1个ZS230-25G灯泡1个HK4 100F-DC5V-SHG继电器1个接线端子1个3906PNP三极管4个
电容、电阻若干
(4)电路介绍:
1>起振电路:由一个12M晶振和两个20pF的电容组成,接在单片机STC89C52的18、19脚间,为整个电路提供时钟脉冲,一个机器周期为1us。
2>复位电路:由一个0.1nF的电容和一个100Ω的电阻,电容两端并联一个按钮开关S6组成复位电路,接在单片机第9脚上,按下开关S6,电路复位。
同时,将31脚接至VCC,采用内部存储器。
3>数码管显示电路:采用四位7段共阳数码管
位选线接至P2.0-P2.3,段选线接至P0口。
4>外部中断连线:按钮开关S1控制定时器T0开关状态,按下S1,模拟人来,则控制灯亮;按钮开关S2接至P3.3,控制外部中断INT1,按下S2,数码管显示当月灯亮总时间。
4.软件部分
(1)程序流程图
(2)程序代码: #include <reg52.h> #define SEG P0
//段选线接至P0
#define SCANP P2 //位选线接至P2 sbit LAMP=P1^2; //灯接至P1.2 sbit S1=P3^4; //
开关S1接至P3.4
sbit S2=P3^3;
//开关S2接至P3.3,外部中断INT1,显示时间(h ) #define count 50000
//声明计数值,0.05s
#define TH (65536-count)/256 //声明计数高8位 #define TL (65536-count)%256 //声明计数低8位 char count_T0=0; //计数T0中断次数 char count_T1=0; //计数T1中断次数
void debouncer(void);
void delay1ms(int); //声明动态显示延时x(ms)函数void dispmoney(void); //声明计费显示函数
char code TAB[11]={ 0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90}; char dispm[4]={0,0,0,0};//设置计费显示初值
char dispt[4]={0,0,0,0};//设置计时显示初值
char seconds=0;
char scan=1;
int t=0; // 声明灯在一个月内的总点亮时间t变量
int l=0;
char p=0;
char q=0;
main()
{
IE=0x8e; //允许T0、INT1、T1中断
TMOD=0x11; //T0采用Mode1、T1采用Mode1
TH1=TH;
TL1=TL;
TR1=1; //定时器T1启动
LAMP=1; //设置灯初始为熄灭状态
while(1)
{
if(S1==0) //开关S1若按下,模拟传感器检测到人来
{
debouncer();
if(S1==0)
{
TH0=TH;
TL0=TL;
TR0=1; //定时器T0启动
LAMP=0; //灯点亮
}
}
dispmoney(); //显示电费值
}
}
void T0_30s(void)interrupt 1 //T0定时器中断,计时30s
{
TH0=TH;
TL0=TL;
if(++count_T0==20) //计数溢出次数,20*0.05=1s {
count_T0=0; //重新计数
seconds++;
if(seconds==30) //计数30次,30*1=30s
{
seconds=0; //重新计数
LAMP=1; //设置灯灭
t++; //灯点亮时间加1
TR0=0; //停止T0定时器
}
}
}
void T1_1month(void) interrupt 3 //T1中断,定时1 month {
TH1=TH;
TL1=TL;
if(++count_T1==20) //1s
{
count_T1=0;
l++;
if(l==3600) //1h
{
l=0;
p++;
if(p==24) //1 day
{
p=0;
q++;
if(q==30)//1 month
q=0;
t=0; //灯点亮总时间t清零
}
}
}
}
void disptime(void) interrupt 2 //INT1中断,显示灯当月的总点亮时间{
char j;
int time;
scan=0x01;
for(j=0;j<4;j++)
{
time=t*30/36;
dispt[3]=TAB[time/1000];
dispt[2]=0x7f&TAB[time%1000/100];
dispt[1]=TAB[time%100/10];
dispt[0]=TAB[time%10];
SEG=0xff;
SCANP=~scan;
SEG=dispt[3-j];
delay1ms(2); //延时约2ms,4*2=8ms<16ms,可实现动态显示
scan<<=1;
}
}
void dispmoney(void) //计费显示函数
{
char i;
int money;
scan=0x01;
for(i=0;i<4;i++)
{
money=t*293/30;
dispm[3]=TAB[money/1000];
dispm[2]=0x7f&TAB[money%1000/100];
dispm[1]=TAB[money%100/10];
dispm[0]=TAB[money%10];
SEG=0xff;
SCANP=~scan;
SEG=dispm[3-i];
delay1ms(2);
scan<<=1;
}
}
void debouncer(void) //去抖动函数
{
int k;
for(k=0;k<2400;k++);
}
void delay1ms(int x) //延时x(ms)函数
{
int m,n;
for(m=0;m<x;m++)
for(n=0;n<120;n++);
}
5.仿真调试:
按钮开关S1模拟人来,灯亮后定时30s,灯灭,数码管刷新电费值一次,单位(元),精确到0.01元;按钮开关S2被按下时,数码管显示当月灯亮总时间,单位(小时),精确到0.01小时。
未按下开关
按下开关S1,定时30s开始
30s定时结束,数码管显示当月电费
按下S2,显示当月灯点亮总时间
6.实验总结
通过本次单片机大作业的完成,从刚开始的硬件电路设计,到软件程序的编写,然后经过软件Proteus的仿真调试,接着进行电路板焊接,到最后调试成功,
历时三周左右,让我受益颇多。
其中,也遇到很多的困难,比如元器件型号的
选择、购买,程序各部分单元的组合结构一改再改,还有软件应用的困难等,
但都通过与同学们的讨论、交流最终得以克服。
本人热爱动手实践,喜欢通过
理论的学习后可以将其与实践相结合,通过实践的过程,可以收获的不仅仅的
是短暂的成就感,更多的是对理论知识的深刻理解和对实践应用的不断熟练,
通过这个过程,使自己的专业素养进一步得到培养和锻炼。
总之,凡事预则立,不预则废。
我相信,向着自己追求的方向不断努力的过程是永远的快乐。