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

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

前言

上一篇我们练习了第11届的两道省赛题,都没有什么难度,主要是为了练习AD/DA,DS18B20和AT24C02的使用方法及调试。
这次我们接着来练习第10届的省赛题,这一届的题目也不难,同样用了AD/DA,但这次主要是练习NE555的使用方法。

赛题要求

硬件框图

图1

功能要求

  1. 频率显示界面
    图2
  2. 电压显示界面
    图3
  3. 按键功能
    图4
  4. LED 指示灯功能
    图5
  5. 初始状态说明
  • 初始状态上电默认处于电压测量状态,数码管显示和 LED 指示功能启用。
  • 初始状态上电默认 PCF8591 DAC 芯片输出固定电压值 2.0V。

设计思路

功能逻辑框图

图6

实现代码框图

图7
不管是功能逻辑还是代码框架,逻辑瞬间清晰,知道该干什么了吧!XD

实现代码

main.c

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

static u32 adc,dac;		//模数转换后的值,取值0~500,数模转换的输入值,0~255
u32 NE_f=0, count_f=0,Page=1;	//获取的NE555的频率,页码
u8 Key,led;		//获取的按键,LED的状态量
bit StateFlag=0,VFlag=0,LEDFlag=0,SEGFlag=0;	//状态标志位,电压输出模式标志位,LED显示标志位,数码管显示标志位

void main()
{
  InitInterrupt();	//中断初始化
  P_Init();		//P0控制外设初始化
  while(1)
  {
    Data_Task();
    Key_Task();
    Logic_Task();
    Display();
  }
}
  • NE555
void InitInterrupt(void)
{
  TMOD = 0x16; //0001 0110	定时器0配置为8位自动重装载计数器,定时器1配置为50ms中断一次
    
  TH0 = 0xFF;		//定时器0
  TL0 = 0xFF;
  
  TH1 = (65535 - 49999) / 256;		//定时器1
  TL1 = (65535 - 49999) % 256;
  
  ET0 = 1;
  ET1 = 1;
  TR0 = 1;
  TR1 = 1;
  EA = 1;
}
void Timer0() interrupt 1
{
  NE_f++;	//触发后频率计数加1
}
void Timer1() interrupt 3
{
  static u8 cnt = 0;
  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 = PCF_ADC();		//获取数字量
  adc = adc*100/51;		//调整为0~500
  Key = Get_Key();		//获取键值
}
  • 按键任务函数
void Key_Task(void)		//按下按键后,相应标志位取反
{
  if(Key == 1)
  {
    StateFlag = ~StateFlag;
  }
  if(Key == 2)
  {
    VFlag = ~VFlag;
  }
  if(Key == 3)
  {
    LEDFlag = ~LEDFlag;
  }
  if(Key == 4)
  {
    SEGFlag = ~SEGFlag;
  }
}

-逻辑任务函数

void Logic_Task(void)
{
  if(StateFlag) {Page = 2;}		//页码为频率
  else  {Page = 1;}				//页码为电压
  
  if(VFlag) 					//标志位为1时,数模转换的输入值读取模数转换后的值再转换成模拟量输出
  {
    dac = PCF_ADC();
    DAC(dac);
  }
  else  {DAC(108);}				//固定输出2.0V的模拟量
  
  if(LEDFlag) {led &= ~0x1f;LED_Task(led);}	//当标志位为1时,LED显示熄灭
  else {LED_Logic();}	//为0时,LED显示开启
}

//LED显示逻辑函数
void LED_Logic(void)	//led状态值的操作在上一篇讲过,这里就不解释了
{
  if(StateFlag) {led |= 0x02;led &= ~0x01;}		//频率页面时L2点亮,L1熄灭
  else  {led |= 0x01;led &= ~0x02;}		//电压页面L1点亮,L2熄灭

  if(adc>=350)  {led |= 0x04;}
  else if (adc>=250&&adc<350) {led &= ~0x04;}
  else if (adc>=150&&adc<250) {led |= 0x04;}
  else if (adc<150) {led &= ~0x04;}

  if(count_f>=10000)  {led |= 0x08;}
  else if(count_f>=5000&&count_f<10000) {led &= ~0x08;}
  else if(count_f>=1000&&count_f<5000)  {led |= 0x08;}
  else if(count_f<1000) {led &= ~0x08;}

  if(VFlag) {led |= 0x10;}
  else  {led &= ~0x10;}
  
  LED_Task(led);
}
void LED_Task(u8 led)
{
	P0 = ~led;
	_138_Task(4);	//锁存器操作,可以和我的不一样
	_138_Task(0);
}
  • 数码管显示任务函数
void Display(void)
{
  if(SEGFlag)	//标志位为1,数码管显示熄灭
  {
    Nixie(8,22);
  }
  else if(SEGFlag==0)
  {
      switch(Page)	//1:电压页面,2:频率页面
    {
      case 2:
        Nixie(1,20);
      if(!(count_f/10000%10)) Nixie(4,22);
      else
        Nixie(4,count_f/10000%10);
      
      if(!(count_f/1000%10)&&!(count_f/10000%10)) Nixie(5,22);
      else
        Nixie(5,count_f/1000%10);
      
      if(!(count_f/1000%10)&&!(count_f/100%10)&&!(count_f/10000%10)) Nixie(6,22);
      else
        Nixie(6,count_f/100%10);
      
      if(!(count_f/10%10)&&!(count_f/100%10)&&!(count_f/10000%10)) Nixie(7,22);
      else
        Nixie(7,count_f/10%10);
      
        Nixie(8,count_f%10);
      break;
      case 1:
        Nixie(1,21);
        Nixie(6,(adc/100%10)+10);
        Nixie(7,adc/10%10);
        Nixie(8,adc%10);
      break;
    }
  }
}

AD/DA

//IIC的驱动代码直接拿官方给的,这里不做展示
void DAC(unsigned char dat)	//数字量转换为模拟量
{
  bit Ack;
  IIC_Start();
  IIC_SendByte(0x90);
  Ack = IIC_WaitAck();
  IIC_SendByte(0x40);
  Ack = IIC_WaitAck();
  IIC_SendByte(dat);
  Ack = IIC_WaitAck();
  IIC_Stop();
}
unsigned char PCF_ADC(void)	//模拟量转换为数字量并返回
{
  unsigned char dat;
  bit Ack;
  IIC_Start();
  IIC_SendByte(0x90);
  Ack = IIC_WaitAck();
  IIC_SendByte(0x03);
  Ack = IIC_WaitAck();
  
  IIC_Start();
  IIC_SendByte(0x91);
  Ack = IIC_WaitAck();
  dat = IIC_RecByte();
  IIC_SendAck(1);
  IIC_Stop();
  return dat;
}

小结

这一篇完结以后,蓝桥杯单片机组历届省赛考点我们就差不多都练过了,就剩一个PWM还没练过,那么我也会在下一篇练习PWM。这样,拿个省一就差不多稳了,要考的模块都差不多复习好了,代码框架也就那样,基本没变过。
最后,如果我的代码和思路对你有帮助,别忘了点赞关注哦 >_< !

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值