1

关于投票
篮球计时记分系统

        今年寒假就搞定的,放到Q空间了,忘放到这来大家共享了,今天补上~~~

        算是个人的第一个独立作品吧,耗时一天半,绝对原创!基本能实现NBA记分牌上的功能,至于可靠性方面当然不敢媲美。个人爱好,仅供娱乐!       

        键盘有点多,用到的就六个,两个连中断口的独立键盘,四个矩阵键盘用作调整比分。

原理图:

点击看大图 

万用板制作:

程序如下:

 

/*****************************************************************
题目:篮球比赛计时记分系统
硬件:STC89C52RC、1602LCM液晶屏、六个按键
软件:Keil C
作者:特权
时间:08.02.
*****************************************************************/
#include<reg52.h>    //头文件
#define uchar unsigned char  //宏定义
#define uint unsigned int
sbit S1=P3^2;  //中断0(比赛倒计时开始/暂停)
sbit S2=P3^3;  //中断1(24s倒计时重新开始)
sbit key="P2"^4;  //连接S3、S4、S5、S6(矩阵按键)
sbit key_S3=P2^3; //连接S3
sbit key_S4=P2^2; //连接S4
sbit key_S5=P2^1; //连接S5
sbit key_S6=P2^0; //连接S6
sbit FM="P1"^5;  //蜂鸣器接口
sbit EN="P1"^0;  
sbit RS="P1"^1;
char sec,min,num,time,sec_24s;
uchar hpoint,rpoint;
uchar code table1[]={"H.T 000:000 R.T "};
  //H.T(home team)代表主队,R.T(road team)代表客队,中间是比分
uchar code table2[]={"12:00  SEC-1  24"};
//SEC-X代表第X节比赛,左边是单节比赛倒计时,右边是24秒倒计时
/***1ms延时子程序***/
void delay(int z)  
{
int x;
uchar y;
for(x=z;x>0;x--)
  for(y=110;y>0;y--);
}
/***LCD写指令***/
void write_com(uchar com)
{
RS=0;
P0=com;
delay(5);
EN=1;
delay(5);
EN=0;
}
/***LCD写数据***/
void write_dat(uchar dat)
{
RS=1;
P0=dat;
delay(5);
EN=1;
delay(5);
EN=0;
}
/***初始化程序***/
void init(void)
{
uchar i;
hpoint=0;    //H.T分数初始化
rpoint=0;    //R.T分数初始化
time=0;
TMOD=0x10;    //定时器1初始化
TL1=0x00;
TH1=0x4c;
EA=1;     //开总中断
ET1=1;     //开定时器1
TR1=0;     //定时器1不工作
EX0=1;     //开中断0
EX1=1;     //开中断1
IT0=1;     //中断0为边沿触发
IT1=1;     //中断1为边沿触发
EN=0;
sec=0;
min=12;
num=1;
sec_24s=24;
write_com(0x38);  //LCD设置初始化
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);  //LCD显示初始化
for(i=0;i<16;i++)
{
  write_dat(table1[i]);
}
write_com(0x80+0x40);
for(i=0;i<16;i++)
{
  write_dat(table2[i]);
}
}
/***LCD分数更新***/
void point_lcd(uchar add,uchar dat)
{
write_com(0x80+add);
write_dat(0x30+dat/100);
write_dat(0x30+(dat%100)/10);
write_dat(0x30+dat%10);
}
/***按键检测***/
void keyscan(void)
{
key=0;
if(key_S3==0)     //S3按下H.T分数加一
{
  hpoint++;
  point_lcd(0x04,hpoint);  //分数显示更新
  if(key_S3==0)    //松手检测
  {
   while(key_S3==0);
   delay(20);
  }
}
else if(key_S4==0)    //S4按下H.T分数减一
{
  hpoint--;
  point_lcd(0x04,hpoint);
  if(key_S4==0)
  {
   while(key_S4==0);
   delay(20);
  }
}
else if(key_S5==0)    //S5按下R.T分数加一
{
  rpoint++;
  point_lcd(0x08,rpoint);
  if(key_S5==0)
  {
   while(key_S5==0);
   delay(20);
  }
}
else if(key_S6==0)    //S6按下R.T分数减一
{
  rpoint--;
  point_lcd(0x08,rpoint);
  if(key_S6==0)
  {
   while(key_S6==0);
   delay(20);
  }
}
}
/***比赛倒计时/24s倒计时(同步)***/
void counter_down(void)
{
uchar i;
if(time>=20)     //每1s倒计时做减一操作
{
  sec--;
  sec_24s--;
  write_com(0x80+0x4e);  //24s倒计时显示
  write_dat(0x30+sec_24s/10);
  write_dat(0x30+sec_24s%10);
  if(sec_24s==0)    //24s结束发出3s连续报警
  {
   FM="0";
   delay(3000);
   FM="1";
   sec_24s=24;
  }
  if((sec==0)&&(min==0))  //检测一节比赛是否结束
  {
   TR1=0;     //定时器1暂停
   write_com(0x80+0x44);
   write_dat(0x30);
   num++;
   sec_24s=24;    //24s计时复位
   write_com(0x80+0x4e);  //24s倒计时显示
   write_dat(0x30+sec_24s/10);
   write_dat(0x30+sec_24s%10);
   if(num<5)    //每节结束蜂鸣器发出8s的间断报警
   {
    for(i=80;i>0;i--)
    {
     FM="0";
     delay(500);
     FM="1";
     delay(500);
    }
   }
   if(num==5)    //终场结束,蜂鸣器发出10s的连续警报声
   {
     FM="0";
     delay(10000);
     num="1";
   }
   FM="1";     //蜂鸣器关闭
   write_com(0x80+0x4b); //更新"SEC-?"
   write_dat(0x30+num);
   sec="0";     //倒计时复位
   min="12";
  }
  if(sec==-1)
  {
   sec="59";
   min--;
  }
  write_com(0x80+0x40);  //更新倒计时显示
  write_dat(0x30+min/10);
  write_dat(0x30+min%10);
  write_com(0x80+0x43);
  write_dat(0x30+sec/10);
  write_dat(0x30+sec%10);
  time=0;
}
}
/***主程序***/
void main()
{
init();
while(1)
{
  keyscan();  //分数按键检测
}
}
/***S1按键中断0***/
void exter0() interrupt 0  //比赛时间开始/暂停
{
TR1=~TR1;     //定时器1工作/暂停
if(TR1==1)  //当倒计时工作时,S1按下定时器立即停止工作
{
  PT1=0;
}
else   //倒计时不工作时,S1按下倒计时立即工作
{
  PT1=1;
}
if(S1==0)     //松手检测
{
  while(S1==0)
  {
   counter_down();
  }
  delay(20);
}
}
/***S2按键中断1***/
void exter1() interrupt 2   //24s倒计时重新开始
{
sec_24s=24;
write_com(0x80+0x4e);   //24s倒计时显示
write_dat(0x30+sec_24s/10);
write_dat(0x30+sec_24s%10);
if(S2==0)      //松手检测
{
  while(S2==0)
  {
   counter_down();
  }
  delay(20);
}
}
/***定时器1中断***/
void timer1() interrupt 3   //定时器1中断20次为1s
{
time++;
TL1=0x00;
TH1=0x4c;
counter_down();     //倒计时
}pdf

系统分类: 单片机
用户分类: MCU
标签: 无标签
来源: 原创
发表评论 阅读全文(119) | 回复(0)

0

关于投票
MSP430的时钟问题

MSP430的时钟周期(振荡周期)、机器周期、指令周期之间的关系

通用知识

时钟周期也称为振荡周期:定义为时钟脉冲的倒数(时钟周期就是直接供内部CPU使用的晶振的倒数,例如12M的晶振,它的时钟周期就是1/12us),是计算机中的最基本的、最小的时间单位。在一个时钟周期内,CPU仅完成一个最基本的动作。时钟脉冲是计算机的基本工作脉冲,控制着计算机的工作节奏。时钟频率越高,工作速度就越快。

机器周期:在计算机中,常把一条指令的执行过程划分为若干个阶段,每一个阶段完成一项工作。每一项工作称为一个基本操作,完成一个基本操作所需要的时间称为机器周期。8051系列单片机的一个机器周期由6S周期(状态周期)组成。一个S周期=2个时钟周期,所以8051单片机的一个机器周期=6个状态周期=12个时钟周期。

指令周期:执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期也不同。

专用知识:

430中,一个时钟周期 = MCLK晶振的倒数。如果MCLK8M,则一个时钟周期为1/8us

一个机器周期 = 一个时钟周期,即430每个动作都能完成一个基本操作;

一个指令周期 = 16个机器周期,具体根据具体指令而定。

另:指令长度,只是一个存储单位与时间没有必然关系。

MSP430根据型号的不同最多可以选择使用3个振荡器。我们可以根据需要选择合适的振荡频率,并可以在不需要时随时关闭振荡器,以节省功耗。这3个振荡器分别为:

1DCO  数控RC振荡器。它在芯片内部,不用时可以关闭。DCO的振荡频率会受周围环境温度和MSP430工作电压的影响,且同一型号的芯片所产生的频率也不相同。但DCO的调节功能可以改善它的性能,他的调节分为以下3步:a:选择BCSCTL1.RSELx确定时钟的标称频率;b:选择DCOCTL.DCOx在标称频率基础上分段粗调;c:选择DCOCTL.MODx的值进行细调。

2LFXT1  接低频振荡器。典型为接32768HZ的时钟振荡器,此时振荡器不需要接负载电容。也可以接450KHZ~8MHZ的标准晶体振荡器,此时需要接负载电容。

3XT2  450KHZ~8MHZ的标准晶体振荡器。此时需要接负载电容,不用时可以关闭。

低频振荡器主要用来降低能量消耗,如使用电池供电的系统,高频振荡器用来对事件做出快速反应或者供CPU进行大量运算。当然高端430还有锁频环(FLL)FLL+等模块,但是初步不用考虑那么多。

MSP4303种时钟信号:MCLK系统主时钟;SMCLK系统子时钟;ACLK辅助时钟。

1MCLK系统主时钟。除了CPU运算使用此时钟以外,外围模块也可以使用。MCLK可以选择任何一个振荡器所产生的时钟信号并进行1248分频作为其信号源。

2SMCLK系统子时钟。供外围模块使用。并在使用前可以通过各模块的寄存器实现分频。SMCLK可以选择任何一个振荡器所产生的时钟信号并进行1248分频作为其信号源。

3ACLK辅助时钟。供外围模块使用。并在使用前可以通过各模块的寄存器实现分频。但ACLK只能由LFXT1进行1248分频作为信号源。

PUC复位后,MCLKSMCLK的信号源为DCO,DCO的振荡频率默认为800KHZACLK的信号源为LFXT1

MSP430内部含有晶体振荡器失效监测电路,监测LFXT1(工作在高频模式)和XT2输出的时钟信号。当时钟信号丢失50us,监测电路捕捉到振荡器失效。如果MCLK信号来自LFXT1或者XT2,那么MSP430自动把MCLK的信号切换为DCO,这样可以保证程序继续运行。但MSP430不对工作在低频模式的LFXT1进行监测。

为了实现具体的时钟可以设置跟时钟相关的寄存器,在低端430中是DCOCTLBCSCTL1BCSCTL2三个寄存器。而对于高端的430,则要考虑SCFI0SCFQCTLFLL_CTL0FLL_CTL1BTCTL等几个寄存器。具体设置,参看DataSheet

 

 

 

单片机上电后,如果不对时钟系统进行设置,默认800 kHzDCOCLKMCLKSMCLK的时钟源,LFXTl32768 Hz晶体,工作在低频模式(XTS=O)作为ACLK的时钟源。CPU的指令周期由MCLK决定,所以默认的指令周期就是1800 kHz="1"25μs。要得到lμs的指令周期需要调整DCO频率,即MCLK=1 MHz,只需进行如下设置:BCSCTLl=XT20FF+RSEL2

 

    //关闭XT2振荡器,设定DCO频率为1 MHz

 

    DCOCTL=DCO2

 

    //使得单指令周期为lμs

系统分类: 单片机
用户分类: MCU
标签: 无标签
来源: 转贴
发表评论 阅读全文(160) | 回复(0)

0

关于投票
从1602到12864

从1602到12864

    1602LCM也是跟着教程手把手的学的,只能显示简单的ASCII,两行X16,刚开始一直就用它和DS12CR887搭配做万历年用,加上温度,感觉挺不错的。但是怎么说得找个显示汉字的玩玩才够味,于是请来了12864,就是128*64个点阵的液晶屏。比1602大一倍,整个就一封辨率超低的MP4屏模样。可以显示的就4X8个字,刚开始的硬件连接就费尽周折,找卖家要全了资料对着电路图本想就着试验板用杜邦线连上就能用,可以半天不亮,好是郁闷,最后才找出更本原因:杜邦线好像不太好使,反正是接不通。那就索性自己焊到别的板子上得了。        焊好后,程序没费多久,能显示字了,但是坐标死活不对,一会这一会那像捉迷藏,指令几个换过来换过去还是老样子,最后总算还是让我找到正确的指令了,算是能让它乖乖的在任意位置显示了。但是接下来的画图可让我郁闷了好久,给的产品资料里说得很笼统,什么X轴Y轴的哪是哪都分不清,GOOGLE上一阵搜,好容易有型号差不多的,看了程序也半天没明白,但是依别人的程序倒也能画出别人的图,但是自己的图自己用软件将BMP图片转成16进制代码后却怎么也不对,好像有那只兔子有点轮廓,但就是不完全一样。那两天折腾的够呛先扔一边了去了,回过头来再研究的时候,给参考程序的作者发个了E-MEIL,回了,但是还不太明白,最后搜到了坐标的比较详细的地址说明,然后仔细的把自己的图分析了下,发现应该是反了。就把转化图片时原先从低到高取点改成了从高到低取,啊哈,一上电,0H,YEAR!兔兔出啦了!那叫一个兴奋
系统分类: 单片机
用户分类: MCU
标签: 无标签
来源: 无分类
发表评论 阅读全文(98) | 回复(0)

0

关于投票
从1-Wire到IIC

从1-Wire到IIC

      DS18B20用的是1-Wire通信协议,外表上看就像三极管一样,但是别小看这家伙了,一个要7元,三极管才几毛,技术含量不一样。18B20的三个管脚,一个接正,一个接负,另一个当然就是用于通信了,故谓之1-Wire,写程序的时候都是MCU利用单线先发信号,然后18B20响应,再然后开始传数据,大体就是这样,一个字节8bit的数据要送8次,因为一条线一次只能送一次嘛,这算是很典型的串行通信了,一条线全搞定,确实很省资源,但是话说回来,硬件成本的降低必将导致程序复杂度的上升。这一位一位传输,是收还是发,什么时候收什么时候发,理清思路了还是蛮容易的。      

       再说这IIC,前阵子跟着教程学了AT24C02的操作,很典型的IIC通信,就是实现读写的基本操作,那时候只是听完,自己动手写了一遍,似懂非懂,反正照葫芦画瓢。今天收到MAXIM寄来的DS1337(实时时钟,上次操作的是DS12887,并口传输的),兴致一起就想写程序,也是一个IIC总线的,硬件挺简单,一正一负,再接三条到I/O口(SCL/SDA/INTA),还有两个脚要接晶振。苦就苦在申请样片的时候没注意哪种型号集成晶振,结果申请了个不带的,手头又没有32.768KHZ的无奈掉。但是想闲着也是闲着,先写了程序再说,这算是我第一次把15页的英文资料从头到尾看了一遍,算是看懂了,因为之前对IIC有所了解,半猜着也能把意思都弄明白,这一遍算是理论上吧IIC吃透了吧。挺不容易的,程序也是从头到尾自己写下来的,感觉应该大体就是那样,但还有待于硬件焊上验证一下。      IIC——一个时钟SCL脚,一个数据SDA,至于INTA是用于芯片内的闹钟时间到了发中断信号用的。也就是说,IIC是用两条线来传输数据,比起1-Wire省点事。写/读的时候也是要一个bit一个bit的那么来。MCU控制SDA先来一个下降沿,说明准备工作了,然后SCL要拉低,每当SCL 低时SDA换下一位数据,SCL 高时,锁存数据,8位完了接收方发个低电平表示应答,然后再传,直至要结束传输,SCA在SCL高时来个上升沿完事。所谓IIC,传输时MCU先送的8bit一个字节前7位是地址,最后一位0/1表示MCU是读还是写数据,第二个字节传输需要读写的数据地址,第三个字节才是数据。基本的流程就是这个样子,理顺了还是不难

系统分类: 单片机
用户分类: MCU
标签: 无标签
来源: 无分类
发表评论 阅读全文(102) | 回复(1)
总共 , 当前 /