分享

[51单片机] 初学者自制的时钟:每行代码都有备注,进来不亏

 一瓢若水 2013-04-13
[51单片机] 初学者自制的时钟:每行代码都有备注,进来不亏
郭天祥老师实验板做的时钟,代码每一行都有备注;非常适合初学者!因为我也是初学者,可以一起交流啊。
所用技术:定时器,矩阵键盘,1602液晶,51单片机,中断,I2C保存时间,串口通信,串口缓冲区(核心),串口协议头(核心),时间缓冲区(核心),定时器复用技术(核心),状态机编程思想(核心),多文件编程技术,预处理技术等等,非常适合初学者。先看大概的,然后你决定要不要下载整个代码。
/*********************************************************
文件名称:shizhong.C  主控芯片STC89C52RC     晶振11.0592MHz
功能描述:时钟(1602IIC,按键,串行接口)
作者日期:田卫卫 / 2013222
    本:V1.1
*********************************************************/
#include"define.H"        //公共头文件,可替代reg52.h
#include"dulikey.h"              //按键头文件:按键扫描、按键服务
#include"LCD1602.h"           //1602液晶头文件
#include"clock.h"          //时钟头文件:初始化时钟、及时钟走时分秒,每秒写I2C保存时间
#include"time.h"           //定时器、延时函数等
#include"sio.h"             //串口初始化、接收、串口服务函数等。
void main()
{     
       sio_init();       //串口初始化函数
       InitTimer0();  //定时器0初始化函数
       ClockInit();    //时钟显示界面初始化
       while(1)
       {
              KeyService(clock);        //调用键盘服务函数
              sio_service();         //调用串口服务函数
              WRclock ();    //调用时钟计时函数
       }            
}
#include"define.H"
#include"clock.h"
#include"time.h"
#include"LCD1602.h"
#include"I2C.h"
#include"dulikey.h"
uchar code clock1[]="I Like Clock";    //液晶第一排
uchar clock[]={23,59,50};    //时间缓冲区
void ClockInit()
{
//    Write(clock,1,3);    //////////////////////////调试初始化用的,把“时:分:秒”写入I2C      
       Delayms(1000);            //上电后等电压稳定
       Read(1,3,clock);     /*I2C器件第1个存储区开始,连续读取3个字节,放入时间缓冲区中*/
       Lcd_init();                           /*LCD1602液晶初始化函数*/
      
       WRLCD();     //把时间缓冲区“时:分:秒”,写在液晶屏上。
       TaskCount[1] = 500;             // TO进中断的次数:500
       TaskMark[1]  = 0;        // 启动此任务的定时器
}
void WRclock ()    //时钟计时程序
{
       if (TaskMark[1] == 1)  //1秒标记,定时器中断2ms*500次;
       {
              clock[2]++;           //+1
              TaskMark[1] = 0;          //1秒标记 清零
              if (clock[2]==60)   // = 60
              {
                     clock[2]=0;            //=60!秒=0
                     clock[1]++;           //+1
                     if (clock[1]==60)   // = 60
                     {
                            clock[1]=0;            //=60!分=0
                            clock[0]++;           //+1
                            if (clock[0]==24)   //= 24
                                   clock[0]=0;            //=24!时=0                 
                     }
              }
              Write(&clock[0],1,3);    //I2C
              WRLCD();     //把时间缓冲区“时:分:秒”,写在液晶屏上。
       }
}
/*********************************************************
文件名称:sio.c           主控芯片:STC89C52RC            晶振11.0592MHz
功能描述:串口程序
函数名称:含串口中断函数!其余函数详见头文件sio.h
作者日期:田卫卫 / 2013221
    本:V1.0
*********************************************************/
#include"define.h"
#include"sio.h"
#include"time.h"
#include"lcd1602.h"
#define T1MS_1200bps   0xe8;     /* (e8,-24,SMOD=0) @1200bps  pcon&=0x7f @11.0592MHz*/
#define T1MS_2400bps   0xf4;     /* (f4,-12,SMOD=0) @2400bps  pcon&=0x7f */
#define T1MS_4800bps   0xfa;     /* (fa, -6,SMOD=0) @4800bps  pcon&=0x7f */
#define T1MS_9600bps   0xfd;     /* (fd, -3,SMOD=0) @9600bps  pcon&=0x7f */
#define T1MS_19k2bps   0xfd;     /* (fd, -3,SMOD=1) @19.2kbps pcon|=0x80 */
#define SIOADDNUM  3     //协议头数;设置为0,可以关闭协议头。
uchar code SIOADD[SIOADDNUM]={0xeb,0x00,0xaa};  //定义串口协议头
uchar inbuf[BUFS];              //串口接收缓冲区
uchar buf = 0;               //统计串口接收到本次数据包的总数量。
/*********************************************************
函数名称:sio_service();
功能描述:串口服务程序,处理串口接收缓冲区inbuf[]的数据。
输入参数:全局变量 buf,TaskMark[0]
包含函数:send(uchar dat);
作者日期:田卫卫 / 2013221
*********************************************************/
void sio_service()
{
       if(TaskMark[0] != 0)     //如果为真,说明收到了数据,而且本次数据包接收已经结束。
       {
              uchar i=0,buf_temp=0;         //串口缓冲区服务程序当前指向位置。
              while (buf_temp < SIOADDNUM)      //协议头处理核心:循环SIOADDNUM次,判断协议头。
              {
                     if (inbuf[buf_temp] == SIOADD)           //协议头处理核心:协议头相同
                     {
                            i++;               //协议头处理核心:指向下一个要判断的协议头
                            buf_temp++;   //协议头处理核心:指向下一个要判断的协议头
                     }
                     else                       //协议头处理核心:协议头错误
                     {
                            buf_temp = 0; //协议头处理核心:清零
                            buf = 0;          //协议头处理核心:清零
                            break;            //协议头处理核心:退出本次循环
                     }                  
              }
              if (buf_temp < buf)
              {
                     if (inbuf[buf_temp]==0 | inbuf[buf_temp]==1)          //判断第4字节是0,还是1;用户可以自定义。
                     {
                            lcdflag = inbuf[buf_temp];    //把串口接收到得第4个字节给LCD显示标记
                            buf_temp++;   //指向下一个串口接收到得元素
                            WRLCD();     //写液晶屏。
                     }
              }
              ES = 0;   //先关中断     
              while (buf_temp < buf)  //协议头,如果相等,才会跑到这儿
              {
                     send(inbuf[buf_temp]);  //调用串口发送函数,把协议头以后所接收到的数据原封不动发给上位机
                     buf_temp++;          //指向下一个要发送的数据
              }
              ES = 1;          //刚才关了中断,现在要打开,以备下次接收。
              TaskMark[0]  = 0;        // 此任务的定时标志清零
              buf = 0;                 //关键:统计串口接收到本次数据包的总数量--清零。
       }
}
/*********************************
函数名:sio_int(sio interrupt)
功能:中断+缓冲区方式接收串口数据,把收到的一个字节放在inbuf[bufnum].
*********************************/
void  sio_int() interrupt 4
{
       ES=0;
       if(RI)        /* RI==1 */
       {  
              if (buf < BUFS)            //小于缓冲区溢出上限,为真可以接收
              {
                     inbuf[buf] = SBUF;       //读串口数据,放入缓冲区中
                     buf++;           //缓冲区指向下一个存放位置。
                     TaskCount[0] = 5;         // 启动一个定时器中断延时
                     TaskMark[0]  = 0;        // 启动此任务的定时器
              }
              else                       //大于或等于缓冲区上限,说明本次接收的数据可能被截掉了:错误!
              {
                     beep = 0;        // 蜂鸣器响;切勿删除:可作为串口稳定性的参考。
              }            
              RI=0;
       }
       ES=1;
}
/*********************************
函数名:send(uchar dat)
功能:向串口发送数据
*********************************/
void send(uchar dat)
{
       SBUF=dat;
       while(!TI);
       TI=0;
}
/*********************************
函数名:sel_bps(select bps)
功能:设置串口波特率
sel为选择通讯速率:
  0=1200,1=2400,2=4800,3=9600,4=19.2k
*********************************/
void sel_bps(uchar sel)
{
     switch(sel)
     {
        case 0:PCON&=0x7f;
               TH1=T1MS_1200bps;   /* T1 use sio */
               TL1=T1MS_1200bps;
               break;
        case 1:PCON&=0x7f;
               TH1=T1MS_2400bps;   /* T1 use sio */
               TL1=T1MS_2400bps;
               break;
        case 2:PCON&=0x7f;
               TH1=T1MS_4800bps;   /* T1 use sio */
               TL1=T1MS_4800bps;
               break;
        case 3:PCON&=0x7f;
               TH1=T1MS_9600bps;   /* T1 use sio */
               TL1=T1MS_9600bps;
               break;
        case 4:PCON|=0x80;
               TH1=T1MS_19k2bps;   /* T1 use sio */
               TL1=T1MS_19k2bps;
               break;
     }
}
/*********************************
函数名:tran_init()(tranmit initialize)
功能:串口初始化
     串口通讯参数初始化
包含子函数:sel_bps
*********************************/
void sio_init()        /* 通讯有关参数初始化 */
{
/* 定时器初始化 */
       TMOD=0x21;  /* T1=MODE2,sio; T0=MODE1,16bit,use time */
       sel_bps(3); /* 选择通讯速率:0=1200,1=2400,2=4800,3=9600,4=19.2k */
/* SCON寄存器设置 */
       SM0=0;
       SM1=1; /* SM0=0 SM1=1,mode1,10bit          */
       SM2=0; /* data int,无校验(TB8=bit_duble) */
       REN=1; /* 允许串口接收 */
       TI=0;  /* 清空发送中断标志位 */
       RI=0;  /* 清空接收中断标志位 */
/* IEIP寄存器设置 */
     PS=1;  /* SIO int high  优先级 */
       ET1=0; /*  定时器1串口中断 */
       ES=1;  /*  串口中断 */
       EA=1;  /*  全局中断 */
       TR1=1; /* 启动 定时器1 */      
}
/*********************************
文件名称:time.C        主控芯片:STC89C52RC
功能描述:延时函数
作者日期:田卫卫 / 2013215
    本:V1.0
*********************************************************/
#include"define.H"
#include"time.h"
#include"dulikey.h"
#include<intrins.h>
uint TaskCount[TASK_NUM];             //定义变量:为定时任务存放定时值;
uchar  TaskMark[TASK_NUM];         //标志位,0表示时间没到,1表示定时的时间到。
/*///////////////////////////////////////////////////////////////////////////////////////
void main(void)
{
       InitTimer0();
}
/////////////////////////////////////////////////////////////////////////////////////////
TaskCount[0] = 20;        // TO进中断的次数:20
TaskMark[0]  = 0;        // 启动此任务的定时器
///////////////////////////////////////////////////////////////////////////////////////*/
void InitTimer0()
{
       TMOD = 0x21;
       TH0 = 0xF8;
       TL0 = 0xcc;
       EA = 1;
       ET0 = 1;
       TR0 = 1;
}
////////////////////////////////////////////////////////////////////////////////////////
void Timer0Int(void) interrupt 1
{
       uchar i;
       TH0 = 0xF8;   //定义为2ms中断一次;中断太频繁效率低,中断太久实时性差。
       TL0 = 0xcc;
       for (i=0; i<TASK_NUM; i++)     //循环检查TASK_NUM的任务。任务定义见头文件。这里是核心知识:定时器复用技术。
       {
              if (TaskCount)
              {
                     TaskCount--;
                     if (TaskCount == 0)          //只有被定时器减的TaskCount,才置标志位!
                     {
                            TaskMark = 0x01;
                     }
              }
       }
       KeyScan();
}
////////////////////////////////////////////////////////////////////////////////////////
void Delayms(uint xms)
{
       uint i,j;
       for(i=0;i<xms;i++)
              for(j=0;j<110;j++);
}
////////////////////////////////////////////////////////////////////////////////////////
/*NOP延时函数,单位 微秒*/
void delay()
{
       _nop_();
       _nop_();
       _nop_();
       _nop_();
       _nop_();
       _nop_();
       _nop_();
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多