当前位置: 首页 > article >正文

蓝桥杯单片机组第十二届省赛第二批次

前言
第十二届省赛涉及知识点:NE555频率数据读取,NE555频率转换周期,PCF8591同时测量光敏电阻和电位器的电压、按键长短按判断。

本试题涉及模块较少,题目不难,基本上准备充分的都能完整的实现每一个功能,并且板子上都能实现,一个恶心的地方就是通过PCF8591只采集一条通道的电压值是没有问题的,但是同时采集两条通道的时候,会出现问题,在另一篇文章已经给出了解决方法:
PCF8591一次测量多个通道导致数值不准确解决方法

附件:蓝桥杯单片机组第十二届省赛第二批次
在这里插入图片描述

一、阅读题目,了解性能需求

可以得出以下信息:

  • 板子上需要将P34与SIGNAL通过跳线帽短接读取NE555产生的频率。
    NE555部分已经详细地讲过如何实现了,可以点击下方传送门查阅:
    传送门:NE555模块

在这里插入图片描述

  • 数码管显示的频率、周期和电压值都是实际值,题目中说到的采集频率和电压只有在LED灯有用。

二、底层函数搭建

1.初始化

Init.h

#ifndef __Init_H__
#define __Init_H__

void Init();

#endif

Init.c

#include <STC15F2K60S2.H>
void Init()
{
	P0 = 0xff;
	P2 = P2 & 0x1f | 0x80;
	P2 &= 0x1f;
	
	P0 = 0x00;
	P2 = P2 & 0x1f | 0xa0;
	P2 &= 0x1f;
}

2.NE555和独立按键

由于NE555是通过P34引脚测量的,所以需要修改独立按键的底层代码。(屏蔽P34)
Key.h

#include <STC15F2K60S2.H>
#ifndef __Key_H__
#define __Key_H__

unsigned char KeyDisp();

#endif

Key.c

#include <STC15F2K60S2.H>

unsigned char KeyDisp()
{
	unsigned char temp = 0;
	
	P44 = 0;
	P42 = 1;
	P35 = 1;
	
	if(P30 == 0)temp = 7;
	if(P31 == 0)temp = 6;
	if(P32 == 0)temp = 5;
	if(P33 == 0)temp = 4;	
	
	return temp;
}

定时器部分

void Timer0_Init(void)		//0毫秒@12.000MHz
{
	TMOD &= 0xF0;			//设置定时器模式
	TMOD |= 0x05;
	TL0 = 0;				//设置定时初始值
	TH0 = 0;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
}

void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1 = 1;				//使能定时器1中断
	EA = 1;
}

void Timer1_Isr(void) interrupt 3
{
	systick++;
	if(++SegPos == 8)
		SegPos = 0;
	SegDisp(SegPos, SegBuf[SegPos], SegPoint[SegPos]);
	if(++Time_1s == 1000)
	{
		Time_1s = 0;
		f = (TH0 << 8) | TL0;
		TH0 = TL0 = 0;
	}
}

2.数码管部分

数码管底层代码引入
Seg.h

#ifndef __Seg_H__
#define __Seg_H__

void SegDisp(unsigned char wela, unsigned char dula, unsigned char point);

#endif

Seg.c

#include <STC15F2K60S2.H>

code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xff, //空
0xbf, //-
0x8e, //F
0xc1, //U
0xc8 //n
};

void SegDisp(unsigned char wela, unsigned char dula, unsigned char point)
{
	P0 = 0xff;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
	
	P0 = (0x01 << wela);
	P2 = P2 & 0x1f | 0xc0;
	P2 &= 0x1f;
	
	P0 = Seg_Table[dula];
	if(point)
		P0 &= 0x7f;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
}

3.Led部分

Led.h

#ifndef __Led_H__
#define __Led_H__

void LedDisp(unsigned char *ucLed);

#endif

Led.c

#include <STC15F2K60S2.H>

void LedDisp(unsigned char *ucLed)
{
	unsigned char i, temp = 0x00;
	static unsigned char temp_old = 0xff;
	
	for(i = 0; i < 8; i++)
		temp |= (ucLed[i] << i);
	
	if(temp != temp_old)
	{
		P0 = ~temp;
		P2 = P2 & 0x1f | 0x80;
		P2 &= 0x1f;
		temp_old = temp;
	}
}

4.PCF8591部分

注:本篇文章中解决多通道读取采用的是连续读取两次电压值,舍弃第一个电压值的方法。
pcf8591.h

#ifndef __pcf8591_H__
#define __pcf8591_H__

unsigned char AD_Read(unsigned char add);

#endif

pcf8591.c

#include <STC15F2K60S2.H>
#include <intrins.h>

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#define DELAY_TIME	5
sbit scl = P2^0;
sbit sda = P2^1;
//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

unsigned char AD_Read(unsigned char add) 
{
    unsigned char temp;
    I2CStart();
    I2CSendByte(0x90);
    I2CWaitAck();
    I2CSendByte(add);
    I2CWaitAck();

    I2CStart();
    I2CSendByte(0x91);
    I2CWaitAck();
    temp = I2CReceiveByte(); 
    I2CSendAck(1);
    I2CStop();

    // 再次读取
    I2CStart();
    I2CSendByte(0x90);
    I2CWaitAck();
    I2CSendByte(add);
    I2CWaitAck();

    I2CStart();
    I2CSendByte(0x91);
    I2CWaitAck();
    temp = I2CReceiveByte();
    I2CSendAck(1);
    I2CStop();
    return temp;
}

5.main.c

#include <STC15F2K60S2.H>
#include "Init.h"
#include "LED.h"
#include "Key.h"
#include "Seg.h"
#include "pcf8591.h"

/* 变量声明区 */
unsigned char Key_Slow; //按键减速变量 10ms 
unsigned char Key_Val, Key_Down, Key_Up, Key_Old; //按键检测四件套
unsigned int Seg_Slow; //数码管减速变量 500ms
unsigned char Seg_Buf[] = {10,10,10,10,10,10,10,10,10,10};//数码管缓存数组
unsigned char Seg_Pos;//数码管缓存数组专用索引
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};//数码管小数点使能数组
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//LED显示数据存放数组
unsigned int Time_1s, f;

/* 按键处理函数 */
void Key_Proc()
{
	if(Key_Slow) return;
	Key_Slow = 1; //按键减速
	
	Key_Val = Key();
	Key_Down = Key_Val & ~Key_Old;	 
	Key_Up = ~Key_Val & Key_Old;
	Key_Old = Key_Val;
	
}

/* 信息处理函数 */
void Seg_Proc()
{
	if(Seg_Slow) return;
	Seg_Slow = 1; //数码管减速
	
}

/* 其他显示函数 */
void Led_Proc()
{

}

/* 定时器0只用于计数 */
void Timer0_Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;			//设置定时器模式
    TMOD |= 0x05;
	TL0 = 0;				//设置定时初始值
	TH0 = 0;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
}

/* 定时器1用于计时 */
void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
    ET1 = 1;
	EA = 1;
}

/* 定时器1中断服务函数 */
void Timer1_Server() interrupt 3
{
	/* NE555 */
  	if(++Time_1s == 1000)
  	{
		Time_1s = 0;
		f = (TH0 << 8) | TL0;
		TH0 = TL0 = 0;
  	}
}

void main()
{
	Init();
	Timer0_Init();
	Timer1_Init();
	while(1)
	{
		Key_Proc(); 
		Seg_Proc();
		Led_Proc();
	}
}

三、数码管部分

在这里插入图片描述
老样子,定义SegMode变量来控制三个页面,SegMode值为0时为频率显示页面,为1时为周期设置界面,为2时为电压显示界面

在数码管Seg.c底层函数的段码表已经包含F、N、U和-的段码表了

1.频率显示页面

NE555测量频率的上限值是五位数,题目要求七位显示频率数据,要求高位为0熄灭,可以直接默认前两位数码管熄灭,再对后五个数码管进行高位熄灭,高位熄灭的实现逻辑如下:

unsigned char i = 0;
while(SegBuf[i] == 0)//循环条件:SegBuf[i]不为0时退出
{
	SegBuf[i] = 10;
	if(++i == 7)
		break;
}

数码管实现如下:

void SegProc()
{
	unsigned char i;
	
	switch(SegMode)
	{
		case 0:
			SegPoint[5] = 0;
			SegBuf[0] = 12;
			SegBuf[1] = 10;
			SegBuf[2] = 10;
			SegBuf[3] = f / 10000 % 10;
			SegBuf[4] = f / 1000 % 10;
			SegBuf[5] = f / 100 % 10;
			SegBuf[6] = f / 10 % 10;
			SegBuf[7] = f % 10;
			i = 3;
			while(!SegBuf[i])
			{
				SegBuf[i] = 10;
				if(++i == 7)
					break;
			}
		break;
	}
}

2.周期显示页面

从题目可以得到,显示的周期是频率的倒数,也就是T= 1 f \frac{1}{f} f1,单位为us,而1s = 100 0000us,所以转换周期时要省上10 6 ^6 6。代码实现如下:

case 1:
	T = 1000000 / f;
	SegBuf[0] = 14;
	SegBuf[1] = T / 1000000 % 10;
	SegBuf[2] = T / 100000 % 10;
	SegBuf[3] = T / 10000 % 10;
	SegBuf[4] = T / 1000 % 10;
	SegBuf[5] = T / 100 % 10;
	SegBuf[6] = T / 10 % 10;
	SegBuf[7] = T % 10;
	i = 1;
	while(!SegBuf[i])
	{
		SegBuf[i] = 10;
		if(++i == 7)
			break;
	}
break;

3.电压显示页面

电压读取

这边给出两种方法
方法一:定义float型变量

idata float RD1_100x, RB2_100x;
idata bit ChannelMode;

void ADCProc()
{
	RD1_100x = AD_Read(0x01) / 51.0; 
	RB2_100x = AD_Read(0x03) / 51.0; 
}

void SegProc()
{
	case 2:
		SegBuf[0] = 13;
		SegBuf[1] = 11;
		SegBuf[2] = !ChannelMode ? 1 : 3;
		SegBuf[3] = 10;
		SegBuf[4] = 10;
		SegBuf[5] = !ChannelMode ? RD1_100x % 10 : RB2_100x % 10;
		SegPoint[5] = 1;
		SegBuf[6] = !ChannelMode ? RD1_100x * 10 % 10: RB2_100x * 10 % 10;
		SegBuf[7] = !ChannelMode ? RD1_100x * 100 % 10 : RB2_100x * 100 % 10;
		break;
}

方法二:定义unsigned int型变量接受读取的电压值放大100倍后的值

idata u16 RD1_100x, RB2_100x;
void ADCProc()
{
	RD1_100x = AD_Read(0x01) * 100 / 51; 
	RB2_100x = AD_Read(0x03) * 100 / 51; 
}
void SegProc()
{
	case 2:
		SegBuf[0] = 13;
		SegBuf[1] = 11;
		SegBuf[2] = !ChannelMode ? 1 : 3;
		SegBuf[3] = 10;
		SegBuf[4] = 10;
		SegBuf[5] = !ChannelMode ? RD1_100x / 100 : RB2_100x / 100;
		SegPoint[5] = 1;
		SegBuf[6] = !ChannelMode ? RD1_100x / 10 % 10 : RB2_100x / 10 % 10;
		SegBuf[7] = !ChannelMode ? RD1_100x % 10 : RB2_100x % 10;
	break;
}

4.数码管完整代码:

void SegProc()
{
	unsigned char i;
	
	if(Seg_Slow) return;
	Seg_Slow = 1; //数码管减速
	
	switch(SegMode)
	{
		case 0:
			SegPoint[5] = 0;
			SegBuf[0] = 12;
			SegBuf[1] = 10;
			SegBuf[2] = 10;
			SegBuf[3] = f / 10000 % 10;
			SegBuf[4] = f / 1000 % 10;
			SegBuf[5] = f / 100 % 10;
			SegBuf[6] = f / 10 % 10;
			SegBuf[7] = f % 10;
			i = 3;
			while(!SegBuf[i])
			{
				SegBuf[i] = 10;
				if(++i == 7)
					break;
			}
		break;
		
		case 1:
			T = 1000000 / f;
			SegBuf[0] = 14;
			SegBuf[1] = T / 1000000 % 10;
			SegBuf[2] = T / 100000 % 10;
			SegBuf[3] = T / 10000 % 10;
			SegBuf[4] = T / 1000 % 10;
			SegBuf[5] = T / 100 % 10;
			SegBuf[6] = T / 10 % 10;
			SegBuf[7] = T % 10;
			i = 1;
			while(!SegBuf[i])
			{
				SegBuf[i] = 10;
				if(++i == 7)
					break;
			}
		break;
			
		case 2:
			SegBuf[0] = 13;
			SegBuf[1] = 11;
			SegBuf[2] = !ChannelMode ? 1 : 3;
			SegBuf[3] = 10;
			SegBuf[4] = 10;
			SegBuf[5] = !ChannelMode ? RD1_100x / 100 : RB2_100x / 100;
			SegPoint[5] = 1;
			SegBuf[6] = !ChannelMode ? RD1_100x / 10 % 10 : RB2_100x / 10 % 10;
			SegBuf[7] = !ChannelMode ? RD1_100x % 10 : RB2_100x % 10;
		break;
	}
}

四、按键部分

在这里插入图片描述
S4和S5的实现很简单,直接给出代码
S6的功能是任意界面下按下S6后,保存电位器的电压数据到电位器缓存变量中。

idata u16 RD1_100x, RB2_100x;
idata u16 RB2_100x_keep, f_keep;

void KeyProc()
{
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyUp = ~KeyVal & KeyOld;
	KeyOld = KeyVal;
	
	switch(KeyDown)
	{
		case 4:
			if(++SegMode == 3)
			{
				SegMode = 0;
				ChannelMode = 0;
			}
		break;
			
		case 5:
			ChannelMode ^= 1;
		break;
		
		case 6:
			RB2_100x_keep = RB2_100x;
		break;
	}
}

S7的功能是短按保存频率,长按打开/关闭Led
这个也是很常考的点了,也很简单
先定义一个Time_1000ms的unsigned int型变量放入定时器1中定时,当超过1000ms时置为1000(防止长按太久数据溢出),然后在设置一个按下S7的变量idata bit型变量CountFlag,当S7按下,CountFlag置1,定时器开始计时,松开S7,CountFlag置为0,计数值清零

注意:NE555和长按S7都是以定时1s为判断,因此定义变量时不要重复定义!

void KeyProc()
{
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyUp = ~KeyVal & KeyOld;
	KeyOld = KeyVal;
	
	if(KeyDown == 7)
		CountFlag = 1;
	
	if(KeyUp == 7)
	{
		CountFlag = 0;
		if(Time_1000ms >= 1001)
		{
			LedFlag = !LedFlag;
		}
		else
			f_keep = f;
	}
}

void Timer1_Isr(void) interrupt 3
{
	systick++;
	if(++SegPos == 8)
		SegPos = 0;
	SegDisp(SegPos, SegBuf[SegPos], SegPoint[SegPos]);
	if(++Time_1s == 1000)
	{
		Time_1s = 0;
		f = (TH0 << 8) | TL0;
		TH0 = TL0 = 0;
	}
	
	if(CountFlag)
	{
		if(++Time_1000ms >= 1001)
			Time_1000ms = 1001;
	}
	else
		Time_1000ms = 0;
}

按键完整代码

void KeyProc()
{
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyUp = ~KeyVal & KeyOld;
	KeyOld = KeyVal;
	
	if(KeyDown == 7)
		CountFlag = 1;
	
	if(KeyUp == 7)
	{
		CountFlag = 0;
		if(Time_1000ms >= 1001)
		{
			LedFlag = !LedFlag;
		}
		else
			f_keep = f;
	}
	
	switch(KeyDown)
	{
		case 4:
			if(++SegMode == 3)
			{
				SegMode = 0;
				ChannelMode = 0;
			}
		break;
			
		case 5:
			ChannelMode ^= 1;
		break;
		
		case 6:
			RB2_100x_keep = RB2_100x;
		break;
	}
}

五、Led部分

在这里插入图片描述
Led的实现完全没有难度
直接给出代码

void LedProc()
{
	if(LedFlag == 0)
	{
		ucLed[0] = (RB2_100x > RB2_100x_keep);
		ucLed[1] = (f > f_keep);
		ucLed[2] = (SegMode == 0);
		ucLed[3] = (SegMode == 1);
		ucLed[4] = (SegMode == 2);
		
	}
	else
	{
		ucLed[0] = 0;
		ucLed[1] = 0;
		ucLed[2] = 0;
		ucLed[3] = 0;
		ucLed[4] = 0;
	}
	LedDisp(ucLed);
}

六、完整代码

#include <STC15F2K60S2.H>
#include "Init.h"
#include "LED.h"
#include "Key.h"
#include "Seg.h"
#include "pcf8591.h"

/* 变量声明区 */
typedef unsigned char u8;
typedef unsigned int u16;

idata u8 KeyVal, KeyDown, KeyUp, KeyOld;
idata u8 SegPos;
idata u8 SegMode;

idata u16 f, Time_1s;
idata u16 T;
idata u16 RD1_100x, RB2_100x;
idata u16 RB2_100x_keep, f_keep;
idata u16 Time_1000ms;

pdata u8 SegBuf[8] = {10,10,10,10,10,10,10,10};
pdata u8 SegPoint[8] = {0,0,0,0,0,0,0,0};
pdata u8 ucLed[8] = {0,0,0,0,0,0,0,0};

idata bit ChannelMode;
idata bit CountFlag;
idata bit LedFlag;


/* 按键处理函数 */
void Key_Proc()
{
	if(Key_Slow) return;
	Key_Slow = 1; //按键减速
	
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyUp = ~KeyVal & KeyOld;
	KeyOld = KeyVal;
	
	if(KeyDown == 7)
		CountFlag = 1;
	
	if(KeyUp == 7)
	{
		CountFlag = 0;
		if(Time_1000ms >= 1001)
		{
			LedFlag = !LedFlag;
		}
		else
			f_keep = f;
	}
	
	switch(KeyDown)
	{
		case 4:
			if(++SegMode == 3)
			{
				SegMode = 0;
				ChannelMode = 0;
			}
		break;
			
		case 5:
			ChannelMode ^= 1;
		break;
		
		case 6:
			RB2_100x_keep = RB2_100x;
		break;
	}
}

/* 信息处理函数 */
void Seg_Proc()
{
	unsigned char i;
	
	if(Seg_Slow) return;
	Seg_Slow = 1; //数码管减速
	
	switch(SegMode)
	{
		case 0:
			SegPoint[5] = 0;
			SegBuf[0] = 12;
			SegBuf[1] = 10;
			SegBuf[2] = 10;
			SegBuf[3] = f / 10000 % 10;
			SegBuf[4] = f / 1000 % 10;
			SegBuf[5] = f / 100 % 10;
			SegBuf[6] = f / 10 % 10;
			SegBuf[7] = f % 10;
			i = 3;
			while(!SegBuf[i])
			{
				SegBuf[i] = 10;
				if(++i == 7)
					break;
			}
		break;
		
		case 1:
			T = 1000000 / f;
			SegBuf[0] = 14;
			SegBuf[1] = T / 1000000 % 10;
			SegBuf[2] = T / 100000 % 10;
			SegBuf[3] = T / 10000 % 10;
			SegBuf[4] = T / 1000 % 10;
			SegBuf[5] = T / 100 % 10;
			SegBuf[6] = T / 10 % 10;
			SegBuf[7] = T % 10;
			i = 1;
			while(!SegBuf[i])
			{
				SegBuf[i] = 10;
				if(++i == 7)
					break;
			}
		break;
			
		case 2:
			SegBuf[0] = 13;
			SegBuf[1] = 11;
			SegBuf[2] = !ChannelMode ? 1 : 3;
			SegBuf[3] = 10;
			SegBuf[4] = 10;
			SegBuf[5] = !ChannelMode ? RD1_100x / 100 : RB2_100x / 100;
			SegPoint[5] = 1;
			SegBuf[6] = !ChannelMode ? RD1_100x / 10 % 10 : RB2_100x / 10 % 10;
			SegBuf[7] = !ChannelMode ? RD1_100x % 10 : RB2_100x % 10;
		break;
	}
}

/* 其他显示函数 */
void Led_Proc()
{
	if(LedFlag == 0)
	{
		ucLed[0] = (RB2_100x > RB2_100x_keep);
		ucLed[1] = (f > f_keep);
		ucLed[2] = (SegMode == 0);
		ucLed[3] = (SegMode == 1);
		ucLed[4] = (SegMode == 2);
		
	}
	else
	{
		ucLed[0] = 0;
		ucLed[1] = 0;
		ucLed[2] = 0;
		ucLed[3] = 0;
		ucLed[4] = 0;
	}
	LedDisp(ucLed);
}

/* 定时器0只用于计数 */
void Timer0_Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;			//设置定时器模式
    TMOD |= 0x05;
	TL0 = 0;				//设置定时初始值
	TH0 = 0;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
}

/* 定时器1用于计时 */
void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
    ET1 = 1;
	EA = 1;
}

/* 定时器1中断服务函数 */
void Timer1_Server() interrupt 3
{
	/* NE555 */
  	if(++Time_1s == 1000)
  	{
		Time_1s = 0;
		f = (TH0 << 8) | TL0;
		TH0 = TL0 = 0;
  	}
  	if(CountFlag)
	{
		if(++Time_1000ms >= 1001)
			Time_1000ms = 1001;
	}
	else
		Time_1000ms = 0;
}

void main()
{
	Init();
	Timer0_Init();
	Timer1_Init();
	while(1)
	{
		Key_Proc(); 
		Seg_Proc();
		Led_Proc();
	}
}

本篇文章中的代码已经通过4T测试
在这里插入图片描述

其余模块代码请自行添加到工程中即可运行,本篇文章仅提供一种实现思路,如有模块代码无法实现或者与题目要求相违,请移步评论区指出或私信我,看到会及时回复。
每周会更新两篇模拟赛、省赛或国赛的文章,敬请期待。


http://www.kler.cn/a/560199.html

相关文章:

  • 鸿蒙-验证码输入框的几种实现方式-上
  • HarmonyOS 5.0应用开发——鸿蒙接入高德地图实现POI搜索
  • 智能化客户行为轨迹分析:AI视频监控在大型商场的技术方案
  • [H数据结构] lc1206. 设计跳表(模拟+数据结构+跳表实现+优秀博文)
  • python中的JSON数据格式
  • 【漫话机器学习系列】104.机器学习中的“学习”是什么?(Learning In Machine Learning)
  • 【知识】PyTorch中不同优化器的特点和使用
  • 代码随想录算法训练day63---图论系列7《prim算法kruskal算法》
  • python-leetcode 42.验证二叉搜索树
  • 新型物联网电瓶车充电桩在居民区的应用优势
  • P2889 [USACO07NOV] Milking Time S
  • EasyExcel 实践案例:打印工资条
  • 【NLP 38、激活函数 ④ GELU激活函数】
  • Deepseek引爆AI热潮 防静电地板如何守护数据中心安全
  • 卸载Mysql重装(升级版本)
  • UE5网络通信架构解析
  • ubuntu+aarch64+dbeaver安装【亲测,避坑】
  • 基于 Python 的项目管理系统开发
  • db.session.delete是什么意思
  • 【R包】tidyplots----取代ggplot2的科研绘图利器