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

news2025/2/26 5:03:59

前言
第十二届省赛涉及知识点: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.coloradmin.cn/o/2306161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI客服-接入deepseek大模型到微信(本地部署deepseek集成微信自动收发消息)

1.本地部署 1.1 ollama Ollama软件通过其高度优化的推理引擎和先进的内存管理机制&#xff0c;显著提升了大型语言模型在本地设备上的运行效率。其核心采用了量化技术&#xff08;Quantization&#xff09;以降低模型的计算复杂度和存储需求&#xff0c;同时结合张量并行计算&…

华为2025年技术发布会:智能汽车核心技术大爆发

近日&#xff0c;华为在鸿蒙智行尊界技术发布会上发布了多项智能汽车核心技术&#xff0c;涵盖智能驾驶、安全防护、通信系统、座舱交互及电池技术等领域&#xff0c;标志着其从“被动智能”向“自主智能”的战略升级。 以下是核心技术的综合梳理&#xff1a; 六大核心创新 途…

SeaCMS V9海洋影视管理系统报错注入

漏洞背景 SQL 注入攻击是当前网络安全中最常见的一种攻击方式&#xff0c;攻击者可以利用该漏洞访问或操作数据库&#xff0c;造成数据泄露或破坏。通常发生在开发人员未能正确处理用户输入时。 在 SeaCMS V9 中&#xff0c;用户输入&#xff08;如登录、评论、分页、ID 等&a…

vue3父子组件props传值,defineprops怎么用?(组合式)

目录 1.基础用法 2.使用解构赋值的方式定义props 3.使用toRefs的方式解构props (1).通过ref响应式变量&#xff0c;修改对象本身不会触发响应式 1.基础用法 父组件通过在子组件上绑定子组件中定义的props&#xff08;:props“”&#xff09;传递数据给子组件 <!-- 父组件…

Django-Vue 学习-VUE

主组件中有多个Vue组件 是指在Vue.js框架中&#xff0c;主组件是一个父组件&#xff0c;它包含了多个子组件&#xff08;Vue组件&#xff09;。这种组件嵌套的方式可以用于构建复杂的前端应用程序&#xff0c;通过拆分功能和视图&#xff0c;使代码更加模块化、可复用和易于维…

Ollama部署本地大模型DeepSeek-R1-Distill-Llama-70B

文章目录 一、下模二、转模1. 下载转换工具2. 安装环境依赖3. llama.cpp1. 转换脚本依赖2. llama.cpp安装依赖包3. llama.cpp编译安装4. 格式转换 三、Ollama部署1. 安装启动Ollama2. 添加模型3. 测试运行 一、下模 #模型下载 from modelscope import snapshot_download model…

Zabbix问题记录2--踩坑HttpRequest,header添加无效

背景 在试图尝试通过Zabbix接入DeepSeek API的时候&#xff0c;由于使用了HTTP的方式&#xff0c;所以需要使用Zabbix 自带的HttpRequest库进行请求&#xff0c;产生了下面的问题 问题 curl curl -X POST https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completio…

Redis 集群的三种模式:一主一从、一主多从和多主多从

本文记述了博主在学习 Redis 在大型项目下的使用方式&#xff0c;包括如何设置Redis主从节点&#xff0c;应对突发状况如何处理。在了解了Redis的集群搭建和相关的主从复制以及哨兵模式的知识以后&#xff0c;进而想要了解 Redis 集群如何使用&#xff0c;如何正确使用&#xf…

网络工程知识笔记

1. 什么是网络&#xff1f; 网络是由多个节点&#xff08;如计算机、打印机、路由器等&#xff09;通过物理或逻辑连接组成的系统&#xff0c;用于数据的传输和共享。这些节点可以通过有线&#xff08;如以太网&#xff09;或无线&#xff08;如 Wi-Fi&#xff09;方式进行连接…

初识.git文件泄露

.git 文件泄露 当在一个空目录执行 git init 时&#xff0c;Git 会创建一个 .git 目录。 这个目录包含所有的 Git 存储和操作的对象。 如果想备份或复制一个版本库&#xff0c;只需把这个目录拷贝至另一处就可以了 这是一种常见的安全漏洞&#xff0c;指的是网站的 .git 目录…

政安晨【零基础玩转各类开源AI项目】DeepSeek 多模态大模型Janus-Pro-7B,本地部署!支持图像识别和图像生成

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 目录 下载项目 创建虚拟环境 安装项目依赖 安装 Gradio&#xff08;UI&#xff09; 运…

(六)趣学设计模式 之 代理模式!

目录 一、啥是代理模式&#xff1f;二、为什么要用代理模式&#xff1f;三、代理模式的实现方式1. 静态代理2. JDK动态代理3. CGLIB动态代理 四、三种代理的对比五、代理模式的优缺点六、代理模式的应用场景七、总结 &#x1f31f;我的其他文章也讲解的比较有趣&#x1f601;&a…

力扣LeetCode:1656 设计有序流

题目&#xff1a; 有 n 个 (id, value) 对&#xff0c;其中 id 是 1 到 n 之间的一个整数&#xff0c;value 是一个字符串。不存在 id 相同的两个 (id, value) 对。 设计一个流&#xff0c;以 任意 顺序获取 n 个 (id, value) 对&#xff0c;并在多次调用时 按 id 递增的顺序…

鸿蒙开发深入浅出03(封装通用LazyForEach实现懒加载)

鸿蒙开发深入浅出03&#xff08;封装通用LazyForEach实现懒加载&#xff09; 1、效果展示2、ets/models/BasicDataSource.ets3、ets/models/HomeData.ets4、ets/api/home.ets5、ets/pages/Home.ets6、ets/views/Home/SwiperLayout.ets7、后端代码 1、效果展示 2、ets/models/Ba…

DSP芯片C6678的SRIO及其中断跳转的配置

C6678SRIO读写测试门铃中断跳转测试 SRIO简述代码前言SRIO配置原始代码1.使能电源2.初始化SRIO回环修改 3.SRIO测试 Doorbell门铃中断1.初始化中断函数2.中断向量表建立3.中断向量表的链接 本博客基于创龙“678ZH产品线”的SRIO代码&#xff0c;部分参考于网友们的博客&#xf…

2025asp.net全栈技术开发学习路线图

2025年技术亮点‌&#xff1a; Blazor已全面支持WebAssembly 2.0标准 .NET 8版本原生集成AI模型部署能力 Azure Kubernetes服务实现智能自动扩缩容 EF Core新增向量数据库支持特性 ‌ASP.NET 全栈开发关键技术说明&#xff08;2025年视角&#xff09;‌ 以下技术分类基于现…

01 冲突域和广播域的划分

目录 1、冲突域和广播域的划分 1.1、冲突域 1.2、广播域 1.3、对比总结 1.4、冲突域与广播域个数计算例题 2、交换机和路由器的结构 2.1、交换机的结构 2.2、路由器的结构 1、冲突域和广播域的划分 1.1、冲突域 冲突域是指网络中可能发生数据帧冲突的物理范围。当多…

nodejs npm install、npm run dev运行的坎坷之路

1、前面的种种都不说了&#xff0c;好不容易运行起来oap-portal项目&#xff0c;运行idm-ui项目死活运行不起来&#xff0c;各种报错&#xff0c;各种安装&#xff0c;各种卸载nodejs&#xff0c;卸载nvm&#xff0c;重装&#xff0c;都不好使。 2、甚至后来运行npm install会…

大型装备故障诊断解决方案

大型装备故障诊断解决方案 方案背景 在全球航空工业迅猛发展的背景下&#xff0c;我国在军用和民用飞机自主研发制造领域取得了显著成就。尤其是在国家大力支持下&#xff0c;国内飞机制造企业攻克了诸多关键技术难题&#xff0c;实现了从设计研发到生产制造再到售后保障的完整…

反向代理模块kfj

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…