找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3894|回复: 1
收起左侧

蓝桥杯单片机第八届省赛 程序题解析(完美调试,清晰解析)

[复制链接]
ID:586435 发表于 2020-3-22 21:04 | 显示全部楼层 |阅读模式
本帖最后由 黑夜的星光 于 2020-3-22 21:14 编辑

             Hellow !大家好,今天找个时间把第八届的题也发出来 一起探讨学习一下。自己呢也算做一个的经历笔记吧 (哈哈哈哈)
                                                      试想一下 10年后的自己看到这浅陋的代码,不知道会有什么感慨呢..................(hahaha....隔~)


                                        ps:帖子今天用了 一个粉红的颜色,哈哈哈,看着比较养眼舒服吧,若努力学习的                                                                                                         同学不嫌弃这些代码的话,希望这粉红能一定程度上减缓你们的疲劳



自己在调试的时候呢, 最头大的地方就是DS1302不能读取时间(DS1302驱动代码都没问题)
   原因有二:
                   其一 :自己在上电初始化的函数中,将P22 = 0了,(我做了测试,将其P22 = 1时,可以正常工作) 详细请看代码
                   其二 :开发板是自己焊接的,可能P2引脚有短路的问题存在。
       起初把自己调试的都怀疑人生了   啊哈哈哈。真的很难受。哎..........     最后调试出来的时候又喜悦到了极点

说一下自己对赛题的看法吧,赛题没有太新颖,生疏的考点,整体难度还是不低的。主要是按键的功能标志位的逻辑关系以及对数码管的多工作界面的切换,数码管玩的是真的很....ennenen
     中断不要多做事情,快进快出。一般LED的(指示灯之类的)标志位处理放在中断处理比其他函数内要好很多。先把简单的容易实现的功能调试出      来,最后再去写复杂的逻辑代码。
     写完一个逻辑功能就去编译一下,看一下有没有语法错误,不然等到最后错误太多,调试会复杂很多。然后单独的模块完成后记着上电验证一下,使其逐渐能衔接起来。
   好的算法有时会起到意想不到的好处,多看看一些大佬的算法,以及一些好的思维方式。慢慢积累,对自己的好处也会慢慢变的明显。

以上都是自己的卑鄙拙见,期间也受到了一些大佬的思维启蒙,非常感谢。
  自己多单片机的感悟就是3点 多写 多看 多想。  只有在自己亲自写的时候,才能体会到他们的真正含义,而且要多写,形成自己的逻辑思维;多看别人的优秀的地方,如算法,思维,积累这些,自己学着去消化使用,慢慢变成自己的; 多想想自己编写不出来的地方,想想功能模块之间的联系,怎样做才能使完善,实现想要的结果。


                                                   
     学而不思则罔,思而不学则殆



好了,咱们上题




8DF@%P3H`JUC35OL5R9H@[R.png



OE(KS[_9P4C0YDI910M@S4N.png





代码如下

main.c文件

/*****************************************************************************************************************************************
蓝桥杯第八届省赛习题


【细节提示】:在ds1302.c文件中定义了 有符号的数据变量 char Inittime[],以及必须在ds1302.h文件中进行 extern 全局的调用声明
【主要难点】:数码管的工作界面的切换,按键对工作标志位的使能以及互不干扰
【代码说明】:不同的代码编写都有其高效的地方和一些功能需复杂实现的地方,要合理看待      
                 本题中:   多处使用了  P2 = (P2 & 0xFF) | 0x04; (对DS1302的工作使能)。
                                                                            我调试的很长时间,ds1302一直不能工作。加上这句代码后(P22 = 1),一切都好了。
      【不知道是不是我开发板的问题,你要是使用的话,可以去掉这句代码测试一下】
                       
******************************************************************************************************************************************/
#include "ds18b20.h"
#include "ds1302.h"
#include "smg.h"

#define uchar unsigned
#define uint  unsigned
       
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;

uchar flag_S7 = 0;               //S7功能选择位
uchar flag_S6 = 0;               //S6功能选择位
uchar flag_S5 = 0;               //S5功能选择位
uchar flag_S4 = 0;               //S4功能选择位

bit flag_Clock = 0;              //闹钟响起标志位
bit flag_led = 0;                //L1闪烁标志位,用于闹钟重置恢复闪烁状态 【0-led闪烁开始标志;1-led闪烁停止标志】
bit flag_1s = 0;                 //时钟设置状态下1s闪烁标志位 【0是亮,1是灭】

uchar temp;                      //读取温度变量
char Clock_date[] = {0,0,0};     //闹钟数据

void KeyScan();                  //按键检测
void SMGdisplay();                                                   //数码管显示                                               
void ConfigTime0();              //配置定时器0
void Detection_Clock();          //检测闹钟
void Close_Clock();              //关闭闹钟
void ZSD_L1();                   //闹钟指示灯
void dateStyle();                //闹钟,时钟数据转换函数





void main()
{   
          Init_waise();
          ConfigTime0();
    InitDS1302();
          while(1)
                {         
      if(flag_S7 == 0)        R_time();                                  
                         KeyScan();
                         SMGdisplay();
                         Detection_Clock();
                }
}




/*********************************************************************************************
【函数】 数码管显示界面切换函数
【功能】 负责按键使能切换数码管显示状态
【小难点】 在时钟设置期间,使操作位1s间隔闪烁。在中断或者S7按键中做好标志位即可(本代码在中断)
*********************************************************************************************/
void SMGdisplay()
{
   if(flag_S7 >= 0 && flag_S6 == 0 && flag_1s == 0)       Time(Inittime[2],Inittime[1],Inittime[0]);
         else if(flag_S7 == 1 && flag_1s == 1)                  SetTime(0xFF, 0xFF, Inittime[1]/10,Inittime[1]%10, Inittime[0]/10, Inittime[0]%10);
         else if(flag_S7 == 2 && flag_1s == 1)                  SetTime(Inittime[2]/10,Inittime[2]%10, 0xFF, 0xFF, Inittime[0]/10, Inittime[0]%10);
         else if(flag_S7 == 3 && flag_1s == 1)                  SetTime(Inittime[2]/10,Inittime[2]%10, Inittime[1]/10, Inittime[1]%10, 0xFF, 0xFF);
         else if(flag_S7 == 0 && flag_S6 > 0)                   Time(Clock_date[2],Clock_date[1],Clock_date[0]);
}

/*********************************************************************************************************************************
【函数】 按键检测函数
【功能】 按下按键触发相应工作标志位
【优化】 在按键弹起等待while(S? == 0)期间优化了对应数码管功能,使数码管不会再按键按下弹起期间闪烁或抖动
【算法】 使用的对按键功能选择位的处理  加4为0(详见S6)
【额外说明】对按键的工作使能位的操作以及对数码管多状态的选择切换是本赛题中的最大的难点,一定要理清好功能之间的逻辑关系
*********************************************************************************************************************************/
void KeyScan()
{
   if(S7 == 0)
         {
            delay(200);          
                  if(S7 == 0 && flag_S6 == 0 && flag_Clock == 0)
                        {
                                 flag_S7 ++;
                                 if(flag_S7 >3)  
                                 {
                                          flag_S7 = 0;
                                    flag_1s = 0;
                                 }                                         
                        }while(S7 == 0)
                        {
                                 if(flag_S6 == 0)       Time(Inittime[2],Inittime[1],Inittime[0]);
                                 else if(flag_S6 > 0)   Time(Clock_date[2],Clock_date[1],Clock_date[0]);
                        }
                        Close_Clock();
         }
         
         if(S6 == 0)
         {
            delay(200);
                  if(S6 == 0 && flag_S7 == 0 && flag_Clock == 0)
                        {
                                 flag_S6 ++;
                                 flag_S6 &= 0x03;    //加4为0
                        }while(S6 == 0)
                        {
                           if(flag_S6 == 0)       Time(Inittime[2],Inittime[1],Inittime[0]);
                                 else if(flag_S6 > 0)   Time(Clock_date[2],Clock_date[1],Clock_date[0]);
                        }
                        Close_Clock();
         }
         
         if(S5 == 0)
         {
            delay(200);
                  if(S5 == 0 && flag_Clock == 0)
                        {  
                                 if(flag_S7)
                                 {
                                    switch(flag_S7)
                                                {
                                                         case 1: Inittime[2] ++;   break;
                                                         case 2: Inittime[1] ++;   break;
                                                         case 3: Inittime[0] ++;   break;
                                                         default: break;
                                                }
                                 }
                                 else if(flag_S6)
                                 {
                                    switch(flag_S6)
                                                {
                                                         case 1: Clock_date[2] ++;  break;
                                                         case 2: Clock_date[1] ++;  break;
                                                         case 3: Clock_date[0] ++;  break;
                                                         default: break;
                                                }
                                 }
                                 dateStyle();
                                 InitDS1302();
                        }while(S5 == 0)
                        {
                           if(flag_S6 == 0)        Time(Inittime[2],Inittime[1],Inittime[0]);
                                 else if(flag_S6 > 0)   Time(Clock_date[2],Clock_date[1],Clock_date[0]);
                        }
                  Close_Clock();
         }
         
         if(S4 == 0)
         {
                                delay(200);
                                if(S4 == 0)
                                {
                                                 if(flag_S7)
                                                 {
                                                                        switch(flag_S7)
                                                                        {
                                                                                  case 1: Inittime[2] --;   break;
                                                                                  case 2: Inittime[1] --;   break;
                                                                                  case 3: Inittime[0] --;   break;
                                                                                  default: break;
                                                                        }
                                                 }
                                                 else if(flag_S6)
                                                 {
                                                                  switch(flag_S6)
                                                                  {
                                                                                        case 1: Clock_date[2] --;  break;
                                                                                        case 2: Clock_date[1] --;  break;
                                                                                        case 3: Clock_date[0] --;  break;
                                                                                        default: break;
                                                                  }
                                                 }
                                                 dateStyle();
                                                 InitDS1302();                                 
                                }while(S4 == 0)
                                {
                                                 if(flag_S7 == 0 && flag_S6 == 0 && flag_Clock == 0)
                                                 {
                                                                    temp = rd_temperature();   //温度读取
                                                                    Wendu_SMG(temp);
                                                                    R_time();                  //防止在长按S4情况下导致闹钟失效
                                                                    Detection_Clock();
                                                 }
                                                 else if(flag_S6 == 0)        Time(Inittime[2],Inittime[1],Inittime[0]);
                                                 else if(flag_S6 > 0)         Time(Clock_date[2],Clock_date[1],Clock_date[0]);
                                }
                                Close_Clock();
                }
}

/**********************************************************************************************************
【函数】      闹钟,时钟数据转换函数
【功能】      当 时 设置时间大于23h时,使其等于0;小于0时,使其等于23;分,秒同理
【额外说明】  不加的话,时间更改会出现24小时,62分钟或秒的情况            ———相当于对时间按键设置的优化
**********************************************************************************************************/
void dateStyle()
{     
      if(Inittime[2] > 23)                      Inittime[2] = 0;
      else if(Inittime[2] < 0)                        Inittime[2] = 23;
                        else if(Inittime[1] >= 60)    Inittime[1] = 0;
      else if(Inittime[1] < 0)                        Inittime[1] = 59;
                        else if(Inittime[0] >= 60)    Inittime[0] = 0;
      else if(Inittime[0] < 0)                  Inittime[0] = 59;
       
            if(Clock_date[2] > 23)              Clock_date[2] = 0;
      else if(Clock_date[2] < 0)                Clock_date[2] = 23;
                        else if(Clock_date[1] >= 60)  Clock_date[1] = 0;
      else if(Clock_date[1] < 0)                Clock_date[1] = 59;
                        else if(Clock_date[0] >= 60)  Clock_date[0] = 0;
      else if(Clock_date[0] < 0)                Clock_date[0] = 59;  
}

/******************************************************************************
【函数】 闹钟检测函数
【功能】 在main函数时刻检测闹钟,闹钟到触发闹钟使能标志位,使闹钟打开
******************************************************************************/
void Detection_Clock()
{
     if(Inittime[2]==Clock_date[2] && Inittime[1]==Clock_date[1] && Inittime[0]==Clock_date[0])
                 {
                                         flag_Clock = 1;
                                         flag_led = 1;
                                         Selest573(5);
                                         P0 = 0x40;
                                         Selest573(0);
                                         P0 = 0xFF;
                 }
}

/********************************************************************
【函数】 闹钟关闭函数
【功能】 闹钟响起时 按下任意按键触发闹钟使能标志位,使闹钟关闭
********************************************************************/
void Close_Clock()
{
   if(flag_Clock == 1)
         {
                                flag_Clock = 0;
                                Selest573(5);
                                P0 = 0x00;
                                Selest573(0);
                                P0 = 0xFF;
         }
}

/*********************************************************
【函数】L1指示灯函数
【功能】每隔0.2s L1 闪烁一次
*********************************************************/
void ZSD_L1()
{   
          static uchar t = 0;
          static uint t_5s = 0;
    if( flag_led == 1)  
                {
                                 t++;
                                 t_5s++;
                                 if(t_5s > 2500)
                                 {
                                                  t_5s = 0;
                                                  t = 200;
                                                  flag_led = 0;                                 
                                 }
                                 
                                 if(t/100 == 1)       //每0.2s到
                                 {  
                                                        Selest573(0);
                                                        P0 = 0xFF;
                                                        Selest573(4);
                                                        P0 = 0xFE;
                                                        Selest573(0);
                                                        P0 = 0xFF;
                                                        P2 = (P2 & 0xFF) | 0x04;                                 
                                 }
                                 else if(t/100 == 2)
                                 {
                                                        t = 0;
                                                        Selest573(0);
                                                        P0 = 0xFF;
                                                        Selest573(4);
                                                        P0 = 0xFF;
                                                        Selest573(0);
                                                        P2 = (P2 & 0xFF) | 0x04;
                                 }                                 
                }
}

/*********************************************************************
【函数】:定时器0初始化函数,中断函数
【功能】:2ms中断一次,控制L1指示灯闪烁,控制处于设置的时间闪烁
【晶振】:11.0592MHz
*********************************************************************/
void ConfigTime0()
{
    AUXR |= 0x80;                //定时器时钟1T模式
                TMOD &= 0xF0;                //设置定时器模式
                TL0 = 0x9A;                  //设置定时初值
                TH0 = 0xA9;                  //设置定时初值
                TF0 = 0;                    //清除TF0标志
       
          EA = 1;
          ET0 = 1;
                TR0 = 1;                   //定时器0开始计时
       
}

void InterruptTime0() interrupt 1
{
         static uchar t_1s = 0;
         if(flag_S7)
         {
                                t_1s ++;
                                if(t_1s / 500 == 1)        flag_1s = 1;     //1s到,熄灭数码灭
                                else if(t_1s / 500 == 2)                    //2s到,数码管显示正常
                                {  
                                          t_1s = 0;
                                    flag_1s = 0;
                                }                                       
         }
         
         if(flag_S7 == 0 && flag_S6 == 0)
         {
              flag_1s = 0;
         }

         
    ZSD_L1();           //指示灯闪烁5s关闭
}





剩余篇幅链接如下;



第八届.zip (70.77 KB, 下载次数: 60)

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:463607 发表于 2022-4-4 21:40 | 显示全部楼层
楼主说话好有趣,代码已经下载下来准备好好学习下了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表