蓝桥杯单片机第十一届第一场省赛真题讲解

目录

前言

一、题目

 二、上代码

1、按键、数码管、LED、定时器等等模块代码(under)

1.1、under.c

1.2、under.h

2、iic

2.1、iic.c

2.2、iic.h

3、最重要的main来咯

总结


前言

省赛相比与国赛确实要简单不少,但是一些小细节还是得注意

一、题目

这么高清的题目确定不点赞吗哈哈哈,你们的支持是我最大的动力

 

 

 二、上代码

1、按键、数码管、LED、定时器等等模块代码(under)

1.1、under.c

#include <STC15F2K60S2.H>
unsigned char code t_display[]={                       //标准字库
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black  -     H    J    K    L    N    o   P    U     t    G    Q    r   M    y
    0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
    0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1

unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位码
unsigned char code keys_num[2][2]=//键盘的键值,只用了四个按键
{
	12,16,
	13,17,
};
unsigned char P_DIG;
unsigned char DIG1[8]={25,16,16,16,16,16,16,16};
unsigned char DIG2[8]={24,16,16,16,16,16,16,16};
unsigned char DIG3[8]={22,16,16,16,16,16,16,16};
unsigned char *DIG=DIG1;
unsigned char key_num;
unsigned char key_state;
unsigned char LED_state=0x00;//改变这个变量就可直接控制LED
void H138_mode(unsigned char mode)//138译码器选择端口
{
	switch(mode)
	{
		case 4:P2=P2&0X1F|0X80;P2&=0X1F;break;
		case 5:P2=P2&0X1F|0Xa0;P2&=0X1F;break;
		case 6:P2=P2&0X1F|0Xc0;P2&=0X1F;break;
		case 7:P2=P2&0X1F|0Xe0;P2&=0X1F;break;
	}
}
void shumaguan()//数码管的函数
{
	P0=0X00;
	H138_mode(6);
	P0=~t_display[DIG[P_DIG]];
	H138_mode(7);
	P0=T_COM[P_DIG];
	H138_mode(6);
	if(++P_DIG>7)P_DIG=0;
}
void LED()
{
	P0=~LED_state;
	H138_mode(4);
}
void init()//最开始的初始化,关蜂鸣器和LED
{
	P0=0X00;
	H138_mode(5);
	P0=0XFF;
	H138_mode(4);
}
void keys()//矩阵键盘
{
	unsigned char R=255,C=255;//R是行,C是列
	P3=0X0F;
	P4=0X00;
	if(~P3&0x0f)
	{
		if(key_state<255)key_state++;//按键扫描状态,每10ms扫描一次,用来消抖
		if(P33==0)R=0;//先扫描行
		if(P32==0)R=1;
		P3=0XF0;
		P4=0XFF;
		if(P35==0)C=0;//再扫描列
		if(P34==0)C=1;
		if(R!=255&&C!=255)
		{
			key_num=keys_num[R][C];//最后找到最开始的键码值
		}
	}
	else
	{
		key_num=0;
		key_state=0;
	}
}

void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x20;		//设置定时初值
	TH0 = 0xD1;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	EA=ET0=1;
}

1.2、under.h

#ifndef __under_H__
#define __under_H__
void H138_mode(unsigned char mode);
void shumaguan();
void LED();
void init();
void keys();
void Timer0Init(void);

extern unsigned char DIG1[8];//第一个界面显示
extern unsigned char DIG2[8];//第一个界面显示
extern unsigned char DIG3[8];//第一个界面显示
extern unsigned char *DIG;
extern unsigned char key_num;
extern unsigned char key_state;
extern unsigned char LED_state;
#endif

2、iic

2.1、iic.c

一些底层驱动就每贴上来,反正都一样

unsigned char ADC()//AD转换
{
	unsigned char Byte;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x43);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();
	I2CReceiveByte();
	I2CSendAck(0);
	Byte=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return Byte;
}

void write_eeprom(unsigned char address,unsigned char Data)//写入eeprom
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CSendByte(Data);
	I2CWaitAck();
	I2CStop();
}

unsigned char read_eeprom(unsigned char address)//读出eeprom
{
	unsigned char Byte;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	Byte=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return Byte;
}

2.2、iic.h

#ifndef __iic_H__
#define __iic_H__
void write_eeprom(unsigned char address,unsigned char Data);
unsigned char read_eeprom(unsigned char address);

unsigned char ADC();
#endif

3、最重要的main来咯

写得比较详细,而且抖音注释,不懂的可以留言哦

#include <STC15F2K60S2.H>
#include "under.h"
#include "iic.h"
unsigned char time_10ms;//大循环,10ms进入一次,用来键盘消抖
unsigned char time_100ms;//拿来刷新ADC的,100ms读一次数据,要不然有点快
unsigned int time_5s;

unsigned char disp_mode;//界面切换变量
int volt_set;//电压参数变量
unsigned char count;//计数参数

unsigned int ADC_read;//读AD转换的变量

unsigned char void_key;//记录无效按键

bit flag;//计数用的标志位
bit compara_bit;//电压显示与电压参数比较标志位
void main()
{
	init();
	Timer0Init();
	volt_set=read_eeprom(0)*10;//上电读书存入的电压参数
	while(1)
	{
		if(time_10ms>=10)
		{
			time_10ms=0;
			/*input*/		
			keys();
			if(time_100ms>=100)
			{
				time_100ms=0;
				ADC_read=ADC()/255.00*500;//电压扩大100倍,后面好显示
			}
			
			/*process*/
			if(key_num==12&&key_state==2)//界面切换
			{
				disp_mode++;
				disp_mode%=3;
				if(disp_mode==2)//退出参数界面存电压参数
				{
					write_eeprom(0,volt_set/10);
				}
				void_key=0;//key_12整个程序始终有效
			}
			
			if(disp_mode==0)//电压显示界面
			{
				if((key_num==13&&key_state==2)||(key_num==16&&key_state==2)||(key_num==17&&key_state==2))//无效按键
				{
					void_key++;
				}
			}
			
			if(disp_mode==1)//电压参数设置
			{
				if(key_num==16&&key_state==2)//有效按键
				{
					volt_set+=50;
					if(volt_set>500)
					{
						volt_set=0;
					}
					void_key=0;
				}
				if(key_num==17&&key_state==2)//有效按键
				{
					volt_set-=50;
					if(volt_set<0)
					{
						volt_set=500;
					}
					void_key=0;
				}
				if((key_num==13&&key_state==2))//无效按键
				{
					void_key++;
				}
			}
			
			
			if(disp_mode==2)//计数清零设置
			{
				if(key_num==13&&key_state==2)//有效按键
				{
					count=0;
					void_key=0;
				}
				if((key_num==16&&key_state==2)||(key_num==17&&key_state==2))//无效按键
				{
					void_key++;
				}
			}
			
			//判断计数++
			if(ADC_read>volt_set)
			{
				flag=1;
			}
			if(flag==1&&(ADC_read<volt_set))
			{
				count++;
				flag=0;
			}
			
			/*output*/
			/*数码管输出*/
			if(disp_mode==0)//第一个界面
			{
				DIG=DIG1;
				DIG1[5]=ADC_read/100+32;
				DIG1[6]=ADC_read/10%10;
				DIG1[7]=ADC_read%10;
			}
			else if(disp_mode==1)//第二个界面
			{
				DIG=DIG2;
				DIG2[5]=volt_set/100+32;
				DIG2[6]=volt_set/10%10;
				DIG2[7]=volt_set%10;
			}
			else//第三个界面
			{
				DIG=DIG3;
				DIG3[6]=count/10;
				DIG3[7]=count%10;
			}
			
			/**LED输出*/
			if(ADC_read<volt_set)
			{
				compara_bit=1;
			}
			else
			{
				compara_bit=0;
				time_5s=0;
				LED_state&=~0X01;//L1灭
			}
			if(time_5s>=5000)//判断五秒后是否标志位为1
			{
				if(compara_bit==1)
				{
					LED_state|=0X01;//L1亮
				}
			}
			
			if(count%2!=0)//判断是奇数
			{
				LED_state|=0X02;
			}
			else
			{
				LED_state&=~0X02;
			}
			/*判断无效按键*/
			if(void_key>=3)
			{
				LED_state|=0X04;
			}
			else
			{
				LED_state&=~0X04;
			}
			
		}
	}
}
void timer0(void) interrupt 1
{
	time_10ms++;
	time_100ms++;
	if(compara_bit==1)time_5s++;
	shumaguan();
	LED();
}

总结

这里的键盘只用了四个按键,不知道无效按键算不算除了这四个其他的按键,这里值得思索,还有计数值是曲线下降时的时候记一次数。

有不理解的地方欢迎留言哦。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值