蓝桥杯单片机学习记录4——第11届省赛真题练习2

蓝桥杯单片机学习记录4——第11届省赛真题练习2

前言

上一篇我们练习了第11届的省赛题1,这里我们接着来讲题2。

赛题要求

硬件框图

这一题的难度明显比上一题要难,虽然外设没用多少,但要求是挺多的,更加考验逻辑分析能力。
图1

区别于上一篇的按键,这里用的是JBD矩阵按键。
还有EEPROM和ADC功能。
这里有个有意思的点,虽然省赛会用BTN和JBD的其中一种,但是都只用了4个按键,也算是简单化了吧。

  1. 显示功能
    图2
    图3
  2. 按键功能
    图4
  3. LED 指示灯功能
    图5
  4. 初始状态说明

初始状态上电默认处于数据显示界面,计数值为 0,指示灯 L2 熄灭。
设备上电后,应自动从 E2PROM 内部地址 0 读出数据,并将该数据处理为电压参数 VP。

设计思路

功能逻辑框图

图6

代码实现框图

这里的框图我就不放了,可以参考上一篇的,因为都差不多,都是四线一区的框架。当然,你也可以试着自己去做一个框图,那我也就不多赘述了。

代码分析

main.c

#include <STC15F2K60S2.H>
#include "hardware.h"
#include "iic.h"

bit StateFlag=0,VcntFlag=0,addFlag=0,minusFlag=0;
bit cntFlag=0,romFlag=0,overFlag=0;
u8 KeyNum,led,mode=0,Page=0,Vcnt=0;
u32 adc;	//adc的值是0~500,这样可以方便计算,所以用无符号整型的变量
i32 Vp=300;

void main()
{
  InitIniterrupt();			//定时器初始化
  Initsystem();				//初始化外设,关闭继电器和蜂鸣器
  Vp = AT24C02_Read(0)*10;	//每次上电后都读取EEPROM地址0处的值赋给Vp
  while(1)
  {
    Date_Task();			//数据更新函数
    Key_Task();				//按键任务函数
    Logic_Task();			//逻辑任务函数
    Display();				//数码管显示任务函数
  }
}
  • 定时器中断函数
void InitIniterrupt(void)		
{
  TMOD = 0x01;
  TH0 = (65535 - 10000) / 256;
  TL0 = (65535 - 10000) % 256;
  TR0 = 1;
  ET0 = 1;
  EA = 1;
}
void Timer0() interrupt 1		//10ms中断进入
{
  static u32 cnt;
  TH0 = (65535 - 10000) / 256;
  TL0 = (65535 - 10000) % 256;
  
  if(overFlag)		//当参数电压过大标志位打开时,开始计时
  {
    cnt++;
    if(cnt >= 500)	//5s计时,L1打开,计时复位
    {
      led |= 0x01;	//用或操作可以保留上一个LED状态,使不同的LED逻辑不受干扰
      LED_Task(led);
      cnt = 0;
    }
  }
}
  • 数据更新函数
void Date_Task(void)
{
  KeyNum = MatrixKey();
  adc = ADC_Read(0x03)*5;	//将0~255的电压值转换为0~500的电压值,方便显示
  if(cntFlag)				//当计数标志位打开,计数自加,复位标志位,计数最大值为99
  {
    ++Vcnt;
    cntFlag=0;
    if(Vcnt > 99) Vcnt = 99;
  }
}
  • 按键任务函数
void Key_Task(void)
{
  if(KeyNum == 9)     //S12
  {
    StateFlag = 1;		//状态标志位打开
  }
  if(KeyNum == 10)    //S13
  {
    if(mode==2)   		//为计数页面时
      VcntFlag = 1;		//计数复位标志位打开
  }
  if(KeyNum == 13)    //S16
  {
    if(mode==1)			//为参数页面时
      addFlag = 1;		//加1标志位打开
  }
  if(KeyNum == 14)    //S17
  {
    if(mode==1)
      minusFlag = 1;
  }
}
  • 数码管显示函数
void Display(void)
{
  switch(mode)		//0为数据页面,1为参数页面,2为计数页面
  {
    case 0:
      Nixie(1,16);
      Nixie(6,adc/100%10+10);
      Nixie(7,adc/10%10);
      Nixie(8,adc%10);
    break;
    case 1:
      Nixie(1,17);
      Nixie(6,Vp/100%10+10);
      Nixie(7,Vp/10%10);
      Nixie(8,Vp%10);
    break;
    case 2:
      Nixie(1,18);		//这里题目应该有问题,要求显示N,但是数码管无法显示,这里我显示了H
      Nixie(7,Vcnt/10);
      Nixie(8,Vcnt%10);
    break;
  }
}
  • 逻辑任务函数
//页面状态函数
void Page_State(void)
{
  if(StateFlag)		//状态标志位打开,选择模式
  {
    switch(mode)
    {
      case 0:mode=1;StateFlag=0;break;
      case 1:mode=2;StateFlag=0;break;
      case 2:romFlag=1;mode=0;StateFlag=0;break;	//在退出参数页面时rom标志位打开
    }
  }
}

//LED逻辑函数
void LED_Logic(void)
{
  if(adc < Vp)  overFlag = 1;	//数字电压量小于参数电压时,参数电压过大标志位打开
  else if(adc >= Vp)  {overFlag = 0;led &=~0x01;LED_Task(led);}		//与操作使当前状态的LED复位,不影响其他状态的LED
  
  if(Vcnt % 2)  {led |= 0x02;LED_Task(led);}	//计数为奇数时L2点亮
  else if(Vcnt % 2==0)  {led &= ~0x02;LED_Task(led);}
}
void Logic_Task(void)
{
  Page_State();
  if(adc == Vp)  cntFlag = 1;	//当数字电压量等于参数电压时,计数标志位打开,不等于则关闭
  if(adc != Vp)  cntFlag = 0;
  if(VcntFlag)    //计数清零
  {
    Vcnt = 0;
    VcntFlag = 0;
  }
  if(addFlag)     //Vp+0.5,超过5回0
  {
    Vp = Vp + 50;
    addFlag  = 0;
    if(Vp > 500)  Vp = 0;
  }
  if(minusFlag)   //Vp-0.5,低于0回5
  {
    Vp = Vp - 50;
    minusFlag  = 0;
    if(Vp < 0)  Vp = 500;
  }
  if(romFlag)	//当rom标志位打开时,将参数电压缩小10倍写入EEPROM地址0,复位标志位,因为Vp范围超过255,无符号字符型存不下,所以要缩小
  {
    AT24C02_Wirte(0,Vp/10);
    romFlag = 0;
  }
  LED_Logic();
}

这一篇也是只讲main.c的内容,其余部分不过多介绍。当然,如果有疑问也可以在评论区或私信留言。

小结

这次的真题我也是完成了大部分的要求,其实还有一个计数按错按键的任务要求,我尝试了一下,有点麻烦。若你有不错的想法和思路,欢迎讨论。
好了!到这里我就已经完成了3届的省赛真题了,那么离蓝桥杯比赛也挺近了,真题我还是会接着写,但也不会写太多,主要挑一些没用过的外设写。原因就是省赛题难度真的不是很高,要求使用的外设也就那几个,功能要求的也就那一种框架,只要会了这种框架的模板,再把外设加进去就可以了,至少完成80%的功能要求是轻轻松松的。
最后,如果我的代码和思路对你有帮助,别忘了点赞关注哦 >_< !

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值