目录
2.2 演示支持方案(如何利用开发板资源或外接模块,实现功能演示的方案,传感器(或模拟)演示方案)
三、模块设计与实现(介绍本课设钟主要模块的设计思路,实现方法,可以通过流程图,状态图,关键代码,显示效果等多种手段说明)
四、系统集成设计(与其它系统的通信、连接,和相互作用设计,参考结构,根据项目增减)
一、需求分析(从用户角度 UML)
1.1设计内容
本项目设计开发一款手动计分器,用户可通过手动控制改变分值与赛程。
1.2 设计目标
1.数码管0123显示A队分数,数码管4567显示B队分数;
2.裁判按动K1键比赛开始,进行计时;
3.裁判按动K2键比赛中止,计时暂停,再次按动K2,比赛继续,计时正常进行;
4.裁判按动K3键比赛终止,程序复位,分数清零,计时归零;
5.按动S1A队加一分,按动S2加两分;按动S3B队加一分,按动S4加两分;
6.按动S5取消A队上次加分,按动S6取消B队上次加分。
1.3实验平台和工具
平台:Keil;
工具:STC89C52单片机
1.4 设计的功能分析
单片机可以实现计分功能,使用动态数码管,LCD1602,独立按键,矩阵键盘4个模块。动态数码管模块用来记录分数,数码管0123显示A队分数,数码管4567显示B队分数;LCD1602用来显示时间;独立按键用来控制赛程;矩阵键盘用来控制分数的加减。
1.5 设计的非功能性分析
通过本程序的设计可设计出一个手动计分器,应用于实际生活中也是非常建议方便。
二、总体设计
2.1总体方案设计
1.赛程控制
K1:比赛开始;
K2:比赛中止;
K3:比赛终止。
2.分数设置
S1:A队加1分;
S2:A队加2分;
S3:B队加1分;
S4:B队加2分;
S5:A队上一次加分撤销;
S6:B队上一次加分撤销;
K3:两队分数清零。
3.时间显示
时间将显示在LCD1602显示屏上。
K2:时间暂停;
K3:时间清零。
2.2 演示支持方案(如何利用开发板资源或外接模块,实现功能演示的方案,传感器(或模拟)演示方案)
在单片机下载完成后,51单片机的最左边一位数码管显示为8,其他位数码管显示为零,LCD1602显示“Time 00:00”。在按下独立按键K1后,时间显示的秒针位开始计时。按下矩阵键盘的S1,数码管3由0变成1,按下矩阵键盘的S3,数码管7由0变成1,按下矩阵键盘的S2数码管3由1变成3,按下矩阵键盘的S4,数码管7由1变成3,按下S5,数码管3由3变成1,按下S6,数码管7由3变成1。
按下K2,计时停止,分数不清零,再次按动K2,计时继续,矩阵键盘功能正常。按动K3,计时清零,分数清零,再次按动K1,比赛开始,计时与分数从0开始。
2.3 单片机资源分配设计(包括RAM资源分配,I/O资源分配)
没有具体要求
三、模块设计与实现(介绍本课设钟主要模块的设计思路,实现方法,可以通过流程图,状态图,关键代码,显示效果等多种手段说明)
3.1分配按键功能
sbit K1=P3^1; //按键
sbit K2=P3^0; //按键
sbit WS3=P3^2; //按键
sbit SW4=P3^3; //按键
sbit LS138A = P2^2; //定义138译码器的输入A脚由P2.2控制
sbit LS138B = P2^3; //定义138译码器的输入脚B由P2.3控制
sbit LS138C = P2^4; //定义138译码器的输入脚C由P2.4控制
3.2LCD1602相关指令
void write_com(uchar com) //1602液晶写指令
{
rs=0; //写指令
lcden=0; //使能1602
P0=com; //写入指令com
LCD_Delay_us(10); //延时1ms
lcden=1; //使能1602
LCD_Delay_us(20); //延时2ms
lcden=0; //使能1602
}
// 描述:1602液晶写数据
void write_date(uchar date) //1602液晶写数据
{
rs=1; //写数据
lcden=0; //使能1602
P0=date; //写入数据date
LCD_Delay_us(10); //延时1ms
lcden=1; //使能1602
LCD_Delay_us(20); //延时2ms
lcden=0; //使能1602
}
// 描述:指定x,y写入字符函数
void W_lcd(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0){write_com(0x80 + x);} //第一行
else{write_com(0xc0 + x);} //第二行
write_date( Data); //写入数据
}
//指定x,y写入字符串函数
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0){write_com(0x80 + x);} //第一行
else{write_com(0xC0 + x);} //第二行
while (*s) //
{write_date( *s); s++;} //写入数据
}
// 描述:初始化液晶,及画面初始化
void init_lcd(void) //初始化液晶,及画面初始化
{
wela=0; //写液晶
lcden=0; //使能1602
write_com(0x38); //8 位总线,双行显示,5X7 的点阵字符
LCD_Delay_us(100); //延时100us
write_com(0x0c); //开显示,无光标,光标不闪烁
write_com(0x06); //光标右移动
write_com(0x01); //清屏
write_com(0x80); //DDRAM 地址归0
}
3.3动态数码管显示数据
void DIS_SEG(void)//在LED上显示数据
{
dispaly[1]=AA%1000/100;
dispaly[2]=AA%100/10;
dispaly[3]=AA%10;
dispaly[5]=BB%1000/100;
dispaly[6]=BB%100/10;
dispaly[7]=BB%10;
LS138A=0; LS138B=0; LS138C=0;//选择第几位数码管
P0 = tab[dispaly[7]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=0; LS138C=0; //选择第几位数码管
P0 = tab[dispaly[6]];//显示数据
delayms(1);//延时
LS138A=0; LS138B=1; LS138C=0; //选择第几位数码管
P0 = tab[dispaly[5]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=1; LS138C=0;//选择第几位数码管
P0 = 0;//显示数据
delayms(1);//延时
LS138A=0; LS138B=0; LS138C=1; //选择第几位数码管
P0 = tab[dispaly[4]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=0; LS138C=1;//选择第几位数码管
P0 = tab[dispaly[3]];//显示数据
delayms(1);//显示数据
LS138A=0; LS138B=1; LS138C=1;//选择第几位数码管
P0 =tab[dispaly[2]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=1; LS138C=1; //选择第几位数码管
P0 = 0;//显示数据
delayms(1);//延时
}
3.4反转法扫描按键
u8 key_matrix_flip_scan(void)
{
static u8 key_value=0;
KEY_MATRIX_PORT=0x0f;
if(KEY_MATRIX_PORT!=0x0f)
{
delayms(1);
if(KEY_MATRIX_PORT!=0x0f)
{
KEY_MATRIX_PORT=0x0f;
switch(KEY_MATRIX_PORT)
{
case 0x07: key_value=1;break;
case 0x0b: key_value=2;break;
case 0x0d: key_value=3;break;
case 0x0e: key_value=4;break;
}
KEY_MATRIX_PORT=0xf0;
switch(KEY_MATRIX_PORT)
{
case 0x70: key_value=key_value;break;
case 0xb0: key_value=key_value+4;break;
case 0xd0: key_value=key_value+8;break;
case 0xe0: key_value=key_value+12;break;
}
while(KEY_MATRIX_PORT!=0xf0);
}
}
else
key_value=0;
return key_value;
}
四、系统集成设计(与其它系统的通信、连接,和相互作用设计,参考结构,根据项目增减)
没有使用
五、系统测试
5.1 系统测试
5.2 单元测试
1.开始
2.按动K1
3.按动S1
4.按动S2
5.按动S3
6.按动S4
7.按动S5
8.按动S6
9.按动K2
10.再次按动S2
11.按动S3
5.3 非功能性测试
六、系统测试
数码管0一直显示为8,多次调试仍然不行,因为单片机内部某模块正在运行,所以即使修改初始值,数码管0也一直为8。修改数码管上显示两队分数的位数时,S2键功能失效,重新编写扫描键盘的函数后功能恢复。总体来说,本项目功能较为简单,易于实现。
附录1原理图
附录2 源程序清单
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
#define KEY_MATRIX_PORT P1
#define SMG_A_DP_PORT P0
sbit K1=P3^1; //按键
sbit K2=P3^0; //按键
sbit WS3=P3^2; //按键
sbit SW4=P3^3; //按键
sbit LS138A = P2^2; //定义138译码器的输入A脚由P2.2控制
sbit LS138B = P2^3; //定义138译码器的输入脚B由P2.3控制
sbit LS138C = P2^4; //定义138译码器的输入脚C由P2.4控制
uchar code tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x58,0x00,0x40,0x46,0x80,0xb0,0x79,0x5c,0x50};//共阴数码码表 01010000
/* 0 1 2 3 4 5 6 7 8 9 C 无 - + . /. E o r*/
uint AA=0;//A队
uint BB=0;//B队
uint CC=0;//A队备份
uint DD=0;//B队备份
uchar fen=0;//分
uchar miao=0;//秒
uchar ii;//
uchar dispaly[]={0,0,0,0,0,0,0,0,0,0,0,0}; //显示缓冲
//--------LCD1602-------------------
sbit rs = P2^6; //1602液晶
sbit wela = P2^5; //1602液晶
sbit lcden = P2^7; //1602液晶
//************************************************************************/
// 描述: 延时t us函数
//************************************************************************/
void LCD_Delay_us(unsigned int t)
{
while(t--); //t=0,退出
}
//************************************************************************/
// 描述: 延时t ms函数
//************************************************************************/
void LCD_Delay_ms(unsigned int t)
{
unsigned int i,j;
for(i=0;i<t;i++) //执行t次循环
for(j=0;j<113;j++) //执行113次循环
;
}
//************************************************************************/
// 描述: 1602液晶写指令
//************************************************************************/
void write_com(uchar com) //1602液晶写指令
{
rs=0; //写指令
lcden=0; //使能1602
P0=com; //写入指令com
LCD_Delay_us(10); //延时1ms
lcden=1; //使能1602
LCD_Delay_us(20); //延时2ms
lcden=0; //使能1602
}
//************************************************************************/
// 描述:1602液晶写数据
//************************************************************************/
void write_date(uchar date) //1602液晶写数据
{
rs=1; //写数据
lcden=0; //使能1602
P0=date; //写入数据date
LCD_Delay_us(10); //延时1ms
lcden=1; //使能1602
LCD_Delay_us(20); //延时2ms
lcden=0; //使能1602
}
//************************************************************************/
// 描述:指定x,y写入字符函数
//************************************************************************/
void W_lcd(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0){write_com(0x80 + x);} //第一行
else{write_com(0xc0 + x);} //第二行
write_date( Data); //写入数据
}
//指定x,y写入字符串函数
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0){write_com(0x80 + x);} //第一行
else{write_com(0xC0 + x);} //第二行
while (*s) //
{write_date( *s); s++;} //写入数据
}
//************************************************************************/
// 描述:初始化液晶,及画面初始化
//************************************************************************/
void init_lcd(void) //初始化液晶,及画面初始化
{
wela=0; //写液晶
lcden=0; //使能1602
write_com(0x38); //8 位总线,双行显示,5X7 的点阵字符
LCD_Delay_us(100); //延时100us
write_com(0x0c); //开显示,无光标,光标不闪烁
write_com(0x06); //光标右移动
write_com(0x01); //清屏
write_com(0x80); //DDRAM 地址归0
}
//************************************************************************/
// 描述: 延时t ms函数
//************************************************************************/
void delayms(unsigned int t)
{
unsigned int i,j;
for(i=0;i<t;i++) //执行t次循环
for(j=0;j<120;j++) //执行113次循环
;
}
void DIS_SEG(void)//在LED上显示数据
{
dispaly[1]=AA%1000/100;
dispaly[2]=AA%100/10;
dispaly[3]=AA%10;
dispaly[5]=BB%1000/100;
dispaly[6]=BB%100/10;
dispaly[7]=BB%10;
LS138A=0; LS138B=0; LS138C=0;//选择第几位数码管
P0 = tab[dispaly[7]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=0; LS138C=0; //选择第几位数码管
P0 = tab[dispaly[6]];//显示数据
delayms(1);//延时
LS138A=0; LS138B=1; LS138C=0; //选择第几位数码管
P0 = tab[dispaly[5]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=1; LS138C=0;//选择第几位数码管
P0 = 0;//显示数据
delayms(1);//延时
LS138A=0; LS138B=0; LS138C=1; //选择第几位数码管
P0 = tab[dispaly[4]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=0; LS138C=1;//选择第几位数码管
P0 = tab[dispaly[3]];//显示数据
delayms(1);//显示数据
LS138A=0; LS138B=1; LS138C=1;//选择第几位数码管
P0 =tab[dispaly[2]];//显示数据
delayms(1);//延时
LS138A=1; LS138B=1; LS138C=1; //选择第几位数码管
P0 = 0;//显示数据
delayms(1);//延时
}
//************************************************************************/
// 描述: 反转法键盘扫描
//************************************************************************/
u8 key_matrix_flip_scan(void)
{
static u8 key_value=0;
KEY_MATRIX_PORT=0x0f;
if(KEY_MATRIX_PORT!=0x0f)
{
delayms(1);
if(KEY_MATRIX_PORT!=0x0f)
{
KEY_MATRIX_PORT=0x0f;
switch(KEY_MATRIX_PORT)
{
case 0x07: key_value=1;break;
case 0x0b: key_value=2;break;
case 0x0d: key_value=3;break;
case 0x0e: key_value=4;break;
}
KEY_MATRIX_PORT=0xf0;
switch(KEY_MATRIX_PORT)
{
case 0x70: key_value=key_value;break;
case 0xb0: key_value=key_value+4;break;
case 0xd0: key_value=key_value+8;break;
case 0xe0: key_value=key_value+12;break;
}
while(KEY_MATRIX_PORT!=0xf0);
}
}
else
key_value=0;
return key_value;
}
void main()
{ uchar key=0xff; //键值初始化
uchar n=0; //第1个数可以按1-4次
uchar m=4; //第2个数可以按1-4次
uchar x=0;
uchar j=0;
uchar stop=0;
init_lcd(); //1602液晶初始化
TMOD=01;//定时器0,,16位定时方式
TH0=65535-50000/256;//50MS
TL0=65535-50000%256;//50MS
EA=1;
ET0=1;
TR0=0;
EA =1; //开中断
miao=0;fen=0;
AA=0;
BB=0;
stop=0;
while(1)
{
DIS_SEG();//数码管显示
W_lcd(1,0,'T');
W_lcd(2,0,'i');
W_lcd(3,0,'m');
W_lcd(4,0,'e');
W_lcd(5,0,' ');
W_lcd(6,0,fen/10+'0');
W_lcd(7,0,fen%10+'0');
W_lcd(8,0,':');
W_lcd(9,0,miao/10+'0');
W_lcd(10,0,miao%10+'0');
W_lcd(11,0,' ');
if(K1==0)
{
while(!K1){;}
miao=0;fen=0;TR0=1;//开始
}
if(K2==0)
{
while(!K2){;}
if(stop==0){TR0=0;stop=1;}else{TR0=1;stop=0;}//暂停
}
if(WS3==0)
{
// while(!K3){;}
AA=0;BB=0;fen=0;miao=0;TR0=0;//清零
}
key=keycheckdown(); /*动态扫描键盘,返回按键对应值,赋给j key=0到f */
if(0xff!=key) /*若返回值有效,进入内部处理程序*/
{
if(key==1){CC=AA;AA=AA+1;}//加1
if(key==2){CC=AA;AA=AA+2;}//加2
if(key==3){DD=BB;BB=BB+1;}//加1
if(key==4){DD=BB;BB=BB+2;}//加2
if(key==5){AA=CC;}//恢复
if(key==6){BB=DD;}//恢复
do{P1=0xf0;}while(P1!=0xf0); /*等待按键松开*/
}
P0=0X00;
}
}
//1MS 定时器计数
void T0_time() interrupt 1
{
TH0=(65535-50000)/256;//50MS
TL0=(65535-50000)%256;//50MS
ii++;
if(ii==20)//0.5ms*2=1ms
{ii=0;
miao++;
if(miao>59){miao=0;fen++;if(fen>59){fen=59;miao=59;}} //秒倒计时
} //分倒计时
}