蓝桥杯单片机学习记录6——第12届省赛真题练习

蓝桥杯单片机学习记录6——第12届省赛真题练习

前言

上一篇我们练习了第10届的省赛题,主要是为了练习NE555的使用方法及调试。
这次我们接着来练习第12届的省赛题,这一届的题目也不难,同样用了NE555,主要是复习NE555的使用方法。同时还用到了按键长短触发,在13届的题目里有遇到过,当时并没有解决,但这次我们来实现它。

赛题要求

硬件框图

图1

从这张图我们可以知道这个题目要用到哪些外设,同时也是我们写程序的第一步。
先将硬件程序写好并调试无误,为我们后面写功能要求提供保障,减少debug的时间。

功能要求

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

处于频率显示界面。
LED 指示灯功能开。

设计思路

虽然省赛题不难,但是要完成所有要求也不是那么容易的,主要就是要理清楚功能之间的联系。
题目已经把个个外设的功能要求都罗列出来了,在写的过程中,我们也是按照顺序将这些要求分模块完成,再找到之间的联系拼接起来。
框图在实际的练习过程中我并没有制作,是在写文章的时候临时做的。但我们在做的时候,脑子里应该要有一个大概的框图。

实现代码

这里就不再放框图了,直接看代码吧。重点是主要的功能实现部分,底层的驱动代码就不会放太多了。

main.c

  • 包含头文件及变量
#include <STC15F2K60S2.H>
#include "hardware.h"		//外设底层实现文件
#include "iic.h"

typedef unsigned char u8;
typedef char i8;
typedef unsigned int u32;
typedef int i32;

u32 adc,KeyTick;
u32 NE_f=0,count_f=0,pre_adc=0,pre_f=0;
u8 KeyNum,led,keylong,KeyLock;
u8 Page=0,channel=0x01;
bit VoltFlag=0,LEDFlag=0;
  • main函数
void main()
{
  InitInterrupt();	//定时器中断初始化
  P_Init();			//P0控制外设初始化
  while(1)
  {
    Data_Task();
    Key_Task();
    Logic_Task();
    Display();
  }
}

-定时器中断任务函数

void InitInterrupt(void)
{
  TMOD = 0x16;					//定时器0用于计数器
  TH0 = 0xFF;
  TL0 = 0xFF;
  
  TH1 = (65535 - 49999) / 256;	//定时器1用于定时
  TL1 = (65535 - 49999) % 256;
  
  AUXR |= 0X04;					//定时器2用于定时
  T2L = 0X20;
  T2H = 0XD1;
  AUXR |= 0X10;
  IE2 |=0X04;
  
  ET0 = 1;
  ET1 = 1;
  TR0 = 1;
  TR1 = 1;
  EA = 1;
}
//NE555功能实现
void Timer0() interrupt 1
{
  ++NE_f;
}

void Timer1() interrupt 3
{
  static u8 cnt;
  TH1 = (65535 - 49999) / 256;
  TL1 = (65535 - 49999) % 256;
  
  ++cnt;
  if(cnt >= 20)
  {
    count_f = NE_f;
    NE_f = 0;
    cnt = 0;
  }
}
  • 数据更新函数
void Data_Task(void)
{
  adc = PFC_ADC(channel);	//adc获取数字信号
  adc = adc*100/51;		//将0~255配置为0~500
  KeyNum = Key();		//获取按键值
  Key_Long();			//长按操作
}
  • 按键触发任务函数
void Key_Task(void)
{
  //S4按键功能切换显示页面
  if(KeyNum == 1)
  {
    ++Page;
    if(Page>=3) Page=0;
  }
  //S5按键功能切换电压输出通道
  if(KeyNum == 2)
  {
    VoltFlag = ~VoltFlag;
  }
  //S6按键功能记录当前通道3输出的电压值
  if(KeyNum == 3)
  {
    if(channel == 0x03)
    {
      pre_adc = PFC_ADC(0x03)*100/51;
    }
  }
  //S7按键功能记录当前频率输出值
  if(KeyNum == 4)
  {
    pre_f = count_f;
  }
}
  • 逻辑功能函数
void Logic_Task(void)
{
	//选择电压通道
  if(VoltFlag)  channel = 0x03;
  else channel = 0x01;
  //每次进入电压页面都显示通道1的电压值
  if(Page==1) {VoltFlag=0;channel = 0x01;}
	//长按时间超过1s,标志位翻转,计数复位
  if(KeyTick>=1000)
  {
    LEDFlag = ~LEDFlag;
    KeyTick=0;
  }
  if(LEDFlag)	//标志位为1时,LED显示关闭,为0时,显示打开
  {
    led &= ~0xff;
    LED_Task(led);
  }
  else
  {
    LED_Logic();
  }
  
}
//LED显示逻辑函数
void LED_Logic(void)
{
  if(channel == 0x03)
  {
    if(adc>pre_adc)
      led |= 0x01;
    else
      led &= ~0x01;
  }
  
  if(count_f>pre_f)
    led |= 0x02;
  else
    led &= ~0x02;
  
  if(Page == 0) led |= 0x04;
  else led &= ~0x04;
  if(Page == 1) led |= 0x08;
  else led &= ~0x08;
  if(Page == 2) led |= 0x10;
  else led &= ~0x10;
  
  LED_Task(led);
}
  • 数码管显示函数
void Display(void)
{
  switch(Page)
  {
    case 0:	//频率显示页面
      Nixie(1,20);
    if(count_f>9999)
      Nixie(4,count_f/10000%10);
    else
      Nixie(4,24);
    if(count_f>999)
      Nixie(5,count_f/1000%10);
    else
      Nixie(5,24);
    if(count_f>99)
      Nixie(6,count_f/100%10);
    else
      Nixie(6,24);
    
      Nixie(7,count_f/10%10);
      Nixie(8,count_f%10);
    break;
    case 1:	//周期显示页面
      Nixie(1,21);
      Nixie(7,5);
      Nixie(8,0);
    break;
    case 2:	//电压显示页面
      Nixie(1,22);
      Nixie(2,23);
    if(channel == 0x01)
      Nixie(3,1);
    else if(channel == 0x03)
      Nixie(3,3);
      Nixie(6,adc/100%10+10);
      Nixie(7,adc/10%10);
      Nixie(8,adc%10);
    break;
  }
}

按键长短按触发

按键长按功能的实现我用了定时器2来计时,可以防止与NE555功能冲突,提高长按和频率测量的精度。

void Key_Long(void)
{
  u8 keynumber=0;
  
  if(!P30)   keynumber = 4;
  if(keynumber == 4)
  {
    KeyLock = 1;
    if(KeyTick>10)
    {
      keylong = keynumber;
    }
    else
      keylong = 0;
  }
  else
  {
    KeyLock = 0;
    keylong = 0;
    KeyTick = 0;
  }
}
void Timer2() interrupt 12
{
  if(KeyLock == 1)
    {
      KeyTick++;
    }
    else if(KeyLock == 0)
    {
      KeyTick = 0;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值