资源描述
(完整word版)单片机四位抽奖机
漳州师范学院
电子时钟及抽奖机
姓 名:
学 号:
系 别: 物理与电子信息工程系
专 业: 电子科学与技术
年 级: 09级
指导教师: 白炳良
2012年 5月
目录
1 摘要: 4
2 关键字: 5
3 设计任务 5
3.1 两种抽奖方式 5
3.2 扩展功能 5
4 设计方案 5
4。1 设计思路 5
4。2 方案比较与论证 5
4.3 系统结构框图 6
5 各功能模块设计 6
5.1 显示模块原理 6
5。2 参数计算 7
5。3 独立式按键模块 7
5.4 总系统原理图 8
6 软件设计 9
6.1 I/O口分配 9
6.2 随机数算法 10
6。3 秒产生算法 10
6。4 按键扫描 10
6。5 显示扫描 10
7 流程图 10
10
8 程序清单 14
9 调试要点 29
9。1 硬件调试 29
9。2 软件调试 29
9.3 结果分析及设计工作总结 29
10 参考文献及附件 30
10。1 参考文献 30
10。2 元器件清单 30
11 PCB版图 30
31
1 摘要:
本设计由单片机AT89S52芯片和LED共阳数码管为核心,
辅以必要的电路,构成了一个由单片机控制的四位显示设计,设计制作同步和单步抽奖机,在模式键、启动键,停止键的控制下实现设计集成了时钟、秒表、四位抽奖三种功能于一体.
2 关键字:
AT89S52动态显示 四位抽奖 按键扫描 随机数 秒表
3 设计任务
3.1 两种抽奖方式
3.1.1 按抽奖启动键时,四位数码管以不同的随机数快速滚动显示,按抽奖停止键时,四位随机数停止滚动显示在数码管上。
3.1.2 按抽奖启动键时,个位数码管以随机数快速滚动显示,按抽奖停止键时,个位随机数停止滚动显示在数码管上;用同样的方法来确定十位、百位、千位的随机数。
3.2 扩展功能
电子时钟:电子钟以99时59分59秒为一个计数周期,在显示分秒,时分模块化之间切换。
4 设计方案
4.1 设计思路
本设计需要实现两种方式的抽奖(即四位同时抽和逐位抽奖),因此重点在于由软件产生随机数;而硬件则需由数码管来显示中奖结果以及按键来控制抽奖模式和启动、停止抽奖。系统以AT89S52为核心,主要有显示模块、按键模块和单片机软件控制模块构成。
4.2 方案比较与论证
数码管显示模块:
方案一:单片机输出数据经译码芯片CD4511进行译码后直接驱动数码管,数码管公共端接9012三极管扩流,并通过单片机I/O口控制三极管的选通,实现动态显示。
方案二:有单片机的I/O口直接驱动数码管的段码,数码管的公共端接9012三极管,通过灌电流的方式点亮数码管,也需通过单片机I/O口控制三极管的选通,实现动态显示.
由于所需I/O口由AT98S52可直接提供,无须因为I/O口不够而用CD4511来节省I/O口,方案二又较方案一更容易实惠,所以,我选择方案二。
4.3 系统结构框图
AT89S52单片机在模式键、启动键和停止键的控制下,由P1口输出数据,通过P2。0 、P2。1、P2.2、P2。4进行选通,有数码管显示信息。
系统框图:
图2—3系统总框图
5 各功能模块设计
5.1 显示模块原理
由单片机(AT89S52)的引脚P1口输出中奖号码、时间等数据信息,通过片选信号P2.0 、P2。1、P2.2、P2.4就可在相应的数码管进行显示。当位选信号P2。0为低电平时,P1口送出数据也为低电平就点亮数码管,电流灌进单片机.多位LED显示,为了简化电路,降低成本,将所有位的段选线并联在一起,由一个8位I/O口控制。而共阳极公共端分别接一个9012,由相应的I/O口线控制9012,实现各位数码管的分时选通。段选码,位选码每送入一次后延时10MS,因人的视觉暂留时间为0.1S(100MS),所以每位显示的时间不能超过20MS,并保持延时一段时间,以造成视觉暂留效果,给人看上去每个数码管总在亮.这种方式称为软件扫描方式.电路如(图3-1)所示。
由于采用的是共阳极数码管,所以要让段码点亮需把I/O口置0,例如:段码a到g对应的I/O口是P1。0到P1。6,则要让数码管显示0到6对应的16进值如图所示
图3—1显示电路
P1。6
P1.5
P1.4
P1。3
P1.2
P1.1
P1.0
16进制
0
1
0
0
0
0
0
0
0C0H
1
1
1
1
1
0
0
1
0F9H
2
0
1
0
0
1
0
0
0A4H
3
0
1
1
0
0
0
0
0B0H
4
0
0
1
1
0
0
1
99H
5
0
0
1
0
0
1
0
92H
6
0
0
0
0
0
1
0
82H
图3-2码表
5.2 参数计算
由于I/O口高电平约等于5V,使用灌电流的方式驱动数码管,故选用PNP型三极管9012;数码管能正常工作的段电流为3mA-—10 mA,压降为1。7V,三极管发射极和集电极的压降为0。3V,因此限流电阻的压降为3.0V,所以选用限流电阻的阻值R=470欧。
5.3 独立式按键模块
独立式按键是直接用I/O口线构成的单个按键电路,其特点是每个按键单独占用一根I/O口线,每个按键的工作不会影响其它I/O口线的状态。独立式按键的典型应用如(图3-3)所示。
独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一根I/O口线,因此,在按键较多时,I/O口线浪费较大,但本设计只用到三个按键,顾采用独立式按键电路.
图3—3独立式按键电路
5.4 总系统原理图
单片机(AT89S52)9脚为复位输入端。上电复位,只要RST引脚上有大于二个机器周期以上的高电平,单片机(AT89C2051)即复位。
按键从单片机(AT89S52)的P2。0、P2.1、P2。2、P2。4口接入,当按键被按下时,相应的输入口就会输入低电平0。
单片机(AT89S52)的XTAL1脚、XTAL2脚接一个由12M晶振和10pf组成的振荡电路.为单片机提供相应的时序。
6 软件设计
主程序主要起到一个导向和决策功能,控制程序的走向。本系统在主程序中运用模块化结构,所有控制量集中处理,提高了处理效率,并在RAM建立各控制量的映射,方便各功能模块的编程及修改。运用散转结构,可实现无扰动重入.本设计主要有以下几个模块:时钟模块、四位抽奖模块、逐位抽奖模块。
操作说明:上电复位后进入数码初显示模块;按SW0启动,四位数码管产生四位随机数,按SW0四位随机数停止(操作可重复);按SW1一次进入抽奖2模块;按SW0启动,四位数码管最低位产生随机数,按SW1最低位停止高位启动…按4次SW1后四位数码管均产生随机数,按SW0键停止抽奖(操作可重复);按SW1一次进入时间模块(可循环)。按RET键单片机复位。
6.1 I/O口分配
1、P2.0、P2。1、P2.2、P2。4作为个位、十位、百位、千位数码管片选。
2、P3。0、P3。4、P3.7作为按键接口。
3、P1。0到P1.6作为段码a到g的输出口。
6.2 随机数算法
在随机数模式下,调用库函数stdlib。h ,用 dis_buf[i]=dis_dm[rand()%10] 返回随机数值
6.3 秒产生算法
将定时器0定时5mS,每计数200次为1S。
6.4 按键扫描
直接判断按键的按下与放开,不采用标志位判断.
6.5 显示扫描
显示扫描采用高、低两位分开显示;这样,在进行时钟显示及秒表显示时易于处
7 流程图
N
5ms到?
重新对计数器赋值
调用按键扫描程序
调用显示子程序
调用闪烁子程序
500ms到?
F300cnt=0
取反闪烁标志位
根据msta的值进行散转
数码显示初值
四位数同时抽奖
四位数逐位抽奖
时钟显示分秒
时钟显示时分
Msta=1
Msta=2
Msta=3
Msta=0
Y
Y
N
Msta=0
初始化
Msta=0:
数码显示初值
Esw9?
Esw0?
Esw9?
Msta=1
Msta=2
Msta=3
返回
Msta=1:四位同时抽奖
Esw0?
cj!=cj
Cj=1?
据rand()产生随机数
Esw1?
ESW2?
四位数码管闪烁
返回
Msta=2
Y
Y
Y
Y
N
N
N
N
Y
Y
Y
N
N
N
Msta=2:逐位产生随机数:
Esw2=1?
Msta=3
据pointer转模块
Pointer=0
Esw0?
Jc!=cj
Cj=1?
产生个位随机数
Esw1?
Pointer=1
Y
Y
Y
返回
N
N
N
返回
N
Y
Pointer=1
Esw0?
Jc!=cj
Cj=1?
产生个位随机数
Esw1?
Pointer=2
Y
Y
Y
N
N
N
返回
Pointer=2
Esw0?
Jc!=cj
Cj=1?
产生个位随机数
Esw1?
Pointer=3
Y
Y
Y
N
N
返回
N
N
返回
Pointer=3
Esw0?
Jc!=cj
Cj=1?
产生个位随机数
Esw1?
Pointer=3
Y
Y
Y
N
N
返回
1s到?
F200cnt=200
F200cnt--
Msta=3:
++a
秒个位
a送显
a>9?
10s到?
a=0, ++b
N
Y
N
秒十位
b送显
b>5?
1分到?
b=0, ++c
N
Y
分个位
d送显
c>9?
10分到?
N
Y
c=0, ++d
分十位
d送显
d>5?
1时到?
N
Y
d=0, ++e
时个位
e送显
e>9?
10时到?
N
Y
e=0, ++g
时十位
g送显
g>9?
99时到?
N
Y
g=0
Y
esw1?
Msta=0
按下esw0,转到msta=4,显示小时、分钟
8 程序清单
/*-—--—-———-——-——---———-——-—-—-———-—-—-———————-——
名称:四位抽奖机
编写:张小叶
日期:2012。5.4
平台:AT89S52
-———-----—--———-——--—-——--——---—--—-—-———-—--—--*/
#include<reg52.h>
#include<intrins。h>
#include<stdlib。h>
#define uint unsigned int //宏定义
#define uchar unsigned char //宏定义
#define nop _nop_()
/*--—--——---—-——--————-—-—----——--—-————-—-----——-
端口定义
--—-————-----———-—-—--——--—----———--—-——--———---*/
#define disport P0 // 数据端口
sbit cs0=P2^0;
sbit cs1=P2^1;
sbit cs2=P2^4;
sbit cs3=P2^2;
sbit sw0=P3^0; //独立按键端口
sbit sw1=P3^4;
sbit sw2=P3^7;
/*-—----—--———--—---——---—-—--—-——-——--——————-———-
定义变量
--————---——————-—————-—-—-—--——--—-—-———-—---——-*/
uchar data key; // 定义键值寄存器
uchar bdata ekey; // 定义键沿寄存器
uchar bdata lastkey;
sbit esw0=ekey^0;
sbit esw1=ekey^4;
sbit esw2=ekey^7;
bit flaflag; // 定义闪烁标志
bit f300flag;
bit cj=1;
uchar f300cnt, f200cnt=200,f100cnt; // 闪烁标志
uchar msta,ck=0;
uchar flasta=5;
uchar a,b,c,d,e,g,h;
uchar code dis_dm[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0xfc,0x00,0xf0,0x0f};//显示段码值
uchar dis_buf[]={0xC0,0xC0,0xC0,0xC0,0xff};//显示缓冲
uchar dis_pointer,pointer;//定义显示指针
/*—-—--—--——-—-———-—————------——--————-—
函数声明
——————----—-——--——-——---—-——--—----———-—-———-——-*/
void Disply(); // 显示函数
void Flaply(); //闪烁函数
void KeyScan(); //读键函数
void Init_timer0(); // 定时器初始化
void choujiang_2(); //抽奖方式2
void dianzishizhong(); //电子时钟
void dianzishizhongxiaoshi();
/*——------—---———----------—---—-—-—----——-—----—
主函数
---—-——--———————--—--————-——-—-—--—-—--—-——---—-*/
void main()
{ uint i;
TMOD=0x11; //定时器0工作方式1
SCON=0x00;
TH0=0xec;
TL0=0x78;
TR0=1;
while(1)
{while(!TF0); //5ms?
TF0=0;
TH0=0xec; //定时器初值重设
TL0=0x78;
KeyScan(); //调用键扫描函数,显示函数
Disply();
Flaply();
//if(f300cnt++>=100)
//{f300cnt=0;
// f300flag=!f300flag;
}
if(f100cnt++〉=600)
{f100cnt=0;
ck=1;
}
switch(msta)
{
case 0:
dis_buf[0]=0x90; //数码显示初值
dis_buf[1]=0xC0;
dis_buf[2]=0xA4;
dis_buf[3]=0xA4;
if(esw0)
{ msta=1;}
if(esw1)
{ msta=2;}
if(esw2)
{ msta=3;}
break;
case 1:
if(esw0)
cj=!cj;
if(cj)
{
for(i=0;i〈4;i++) //四位数同时抽奖
dis_buf[i]=dis_dm[rand()%10];
}
f300cnt=100;
f300cnt--;
if(f300cnt==0)
{ if(!cj)
flasta=4; }
// if(esw2)
// { if(!cj)
//flasta=4; }
if(esw1)
msta=2;
break;
case 2:
choujiang_2();
if(esw2)
msta=3;
break;
case 3: // flasta=5;
f200cnt-—;
if(f200cnt==0)
{
dianzishizhong();
f200cnt=200;
}
if(esw1)
{ msta=0;}
if(esw0)
msta=4;
break;
case 4: if(esw0)
msta=3 ;
if(esw1)
msta=0;
// f200cnt=200;
f200cnt——;
if(f200cnt==0)
{ ++a;
if(a〉9)
{a=0;++b;}
if(b〉5)
{b=0;++c;}
if(c〉9)
{c=0;++d;}
if(d〉5)
{d=0;++e;}
if(e〉9)
{e=0;++g;}
if(g〉9)
{g=0;}
dis_buf[0]=dis_dm[c];
dis_buf[1]=dis_dm[d];
dis_buf[2]=dis_dm[e];
dis_buf[3]=dis_dm[g];
f200cnt=200;
}
break;
default:msta=0;
}
}
}
/*-—---—-————----———----—--——-—-—-——-—————--——-—-
抽奖方式2 逐位抽奖
-—-——-—---——--—-—---——---—-————-----—-—————--—--*/
void choujiang_2()
{
switch(pointer)
{ case 0:
if(esw0)
cj=!cj;
if(cj)
dis_buf[0]=dis_dm[rand()%10];
if(esw1)
pointer=1;
break;
case 1:
if(esw0)
cj=!cj;
if(cj)
dis_buf[1]=dis_dm[rand()%10];
if(esw1)
pointer=2;
break;
case 2:
if(esw0)
cj=!cj;
if(cj)
dis_buf[2]=dis_dm[rand()%10];
if(esw1)
pointer=3;
break;
case 3:
if(esw0)
cj=!cj;
if(cj)
dis_buf[3]=dis_dm[rand()%10];
if(esw1)
pointer=0;
break;
default:break;
}
}
/*———————-—--——--—--—---——-——-—————-—--—-—-----—-
电子时钟 分秒
——--—-———-———-——----——-——--———---——---—--———-——-*/
void dianzishizhong()
{
++a;
if(a>9)
{a=0;++b;}
if(b〉5)
{b=0;++c;}
if(c〉9)
{c=0;++d;}
if(d>5)
{d=0;++e;}
dis_buf[0]=dis_dm[a];
dis_buf[1]=dis_dm[b];
dis_buf[2]=dis_dm[c];
dis_buf[3]=dis_dm[d];
}
/*—-—-----——-—-----——----——-—-———--——-————-—-—--—
定时器0初始化函数
--—---———————---—-——---——————-—------—————-—--—-*/
void Init_Timer0(void)
{
TMOD = 0x11; //定时器0工作在方式1
TH0=0xec;
TL0=0x78; //定时器5ms初值
TR0= 1; //开定时器0
}
/*———--—-—-——-—--—----——--——--—---——-——--—---————
键扫描函数
----—-—--———---—-—--———————-—-—---——-—---—-——-——*/
void KeyScan()
{
uchar kbuf,keycnt;
P2=0XFF;
P3=P3|0X91; // 读独立按建
kbuf=P3;
kbuf=(kbuf&0X91)^0X91;
lastkey=kbuf;
if(lastkey!=key) // 键有变化?key为电平,lastkey为前沿
{if(keycnt—-!=0) //键有变,计数到?
{lastkey=key; //放弃不稳定的键
}
}
else
keycnt=0X05; // 重赋去抖值
ekey=(key^lastkey)&lastkey; //键前沿提取
key=lastkey;
}
/*———-——-——---—-——-----———----———---—-——-—-----——
显示函数
--———————-—--—-—-—--—-—-—-—-—---—--—————-—-—-—--*/
void Disply()
{ disport=0xff;
P2=0xff;
switch(dis_pointer) // 根据显示指针,转相应显示位
{
case 0: cs0=0; // 点亮第零位数码管
disport=dis_buf[0];
dis_pointer=1;
if(flaflag)
Flaply();
break; // 点亮第一位数码管
case 1: cs1=0;
disport=dis_buf[1];
dis_pointer=2;
if(flaflag)
Flaply();
break; // 点亮第二位数码管
case 2: cs2=0;
disport=dis_buf[2];
dis_pointer=3;
if(flaflag)
Flaply();
break;
case 3: cs3=0; // 点亮第三位数码管
disport=dis_buf[3];
dis_pointer=0;
if(flaflag)
Flaply();
break;
default:break;
}
}
/*-———-——-——-—----—-—-——--—--—-—-----————-—-———--
闪烁函数
——--——--—--—-——-----——--—-———-—-————-——-——--—---*/
void Flaply()
{
switch(flasta) // 据闪烁状态转相应位
{
case 0: if(f300flag) // 300ms到,关显示
cs0=1;
break;
case 1: if(f300flag)
cs1=1;
break;
case 2: if(f300flag)
cs2=1;
break;
case 3: if(f300flag)
cs3=1;
break;
case 4: if(f300flag) // 300ms到,关显示
cs0=1;
if(f300flag)
cs1=1;
if(f300flag)
cs2=1;
if(f300flag)
cs3=1;
break;
default:break;
}
}
9 调试要点
9.1 硬件调试
1、硬件完成后,检查电路有无短路、断路或虚焊;
2、电路板检查正常后,编一段简单的显示程序,检验显示电路是否正常;
3、若显示电路正常后,则可开始进行程序调试;
4、动态显示时要注意任一时刻只能一个数码管工作;
5、按键对应的I/O口要置为1。
9.2 软件调试
1、软件平台采用WAVE6000;
2、参考的子程序均用WAVE6000进行调试,确保结果正确;(参考的子程序有:二翻十进制转换、拆字)
3、本设计要实现3种功能:时钟、秒表及四位抽奖机;调试时哪个功能不正常,则直接找相应的模块进行调试。
9.3 结果分析及设计工作总结
1、实现功能:正常走时秒表及四位抽奖机。
2、经验:通过本电路的设计使我更进一步了解了单片机89S52系列芯片的强大的功能,进一步熟悉89S52系列单片机的编程指令集的实际应用,再次增强了自己的动手、思考能力,同时也体现了实践和理论相结合的要求。为将来步入社会奠定了基础。
10 参考文献及附件
10.1 参考文献
10.1.1 倪云峰.单片机原理与应用。西安电子科技大学出版.2009
10.1.2 张华林,周小方编著.电子设计竞赛实训教程[M].北京:北京航空航天大学出版社,2007,7
10.2 元器件清单
器件名称
器件型号
数量
器件名称
器件型号
数量
数码管
共阳
4
单片机
AT89S52
1
电解电容
10pF
2
三极管
9012
4
晶振
12MHZ
1
电阻
470欧
9
按键
按键
4
电阻
4K7
5
电解电容
220uf
1
电解电容
220uf
1
7805
1
插槽
10脚
1
-XTAL1(反相器输入端):反相振荡器的放大器输入端和内部时钟工作电路的输入端。多与XTAL2引脚一起连接晶体震荡器使用。若采用外部时钟源驱动器件,XTAL2应不接。
-XTAL2(反相器输出端):反相振荡器的放大器输出端。
11 PCB版图
展开阅读全文