蓝桥杯单片机第十一届省赛题详细讲解

看之前强烈建议先自己做一遍!!!

演示视频

题目讲解

首先根据系统程序框图来提前调试好各模块部分的功能。比如按键,数码管,PCF8591,AT24C02。
在这里插入图片描述
调试完成之后,可以进一步往下看题目。
在这里插入图片描述
这一部分主要讲解一些功能和要求,看一遍注意一下就行。
然后看数码管显示界面设计。
在这里插入图片描述

uchar tab[]={
    
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0x8c,0xc1,0xc8};//p u n
uchar SMG[8]={
    
    20,20,20,20,20,20,20,20};//初始显示20,全息数码管
uchar SMG_mode=0;//控制数码管模式
uint move=0;//pcf8591的滑动变阻器读取值
int Vp=300; //定义电压参数
int count=13; //定义计数值
void main(void)
{
    
    
	init();
	while(1)
	{
    
    
		move=IIC_read(PCF8591_address,Move_address);//读取滑动变阻器
		move=1.9607*move;//move *(5 /255 *100) 将0-255转换到0-500,便于显示
		if(SMG_mode==0) //数据界面
		{
    
    
			SMG[0]=23;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20;
			SMG[5]=move/100+10;SMG[6]=move%100/10;SMG[7]=move%10;
		}
		else if(SMG_mode==1) //参数界面
		{
    
    
			SMG[0]=22;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20;
			SMG[5]=Vp/100+10;SMG[6]=Vp%100/10;SMG[7]=Vp%10;			
		}
		else if(SMG_mode==2)  //计数界面
		{
    
    
			SMG[0]=24;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; ///不同count对应的数码管显示不同
			if(count<10){
    
    SMG[5]=20;SMG[6]=20;SMG[7]=count;}
			else if(count<100){
    
    SMG[5]=20;SMG[6]=count/10;SMG[7]=count%10;}
			else if(count<1000){
    
    SMG[5]=count/100;SMG[6]=count%100/10;SMG[7]=count%10;}			
		}
		SMG_output();
		Jkey_scan();
	}
}

然后看按键功能,可以发现是矩阵按键的右下角一部分。
在这里插入图片描述
按照相关进行设置即可,需要注意一下按键功能设计要求。

void Jkey_scan(void)
{
    
    
	unsigned char i,key;
	for(i=0x80;i>8;i >>=1)
	{
    
    
		if(i==0x80){
    
    P44=0;P42=1;P3=~i;}
		else if(i==0x40){
    
    P44=1;P42=0;P3=~i;}
		else {
    
    P44=1;P42=1;P3=~i;}
		if(i==0x80){
    
    key=P3;key&=0x7f;}
		else if(i==0x40){
    
    key=P3;key&=0xbf;}
		else {
    
    key=P3;}
		if((key&0x0f)!=0x0f)
		{
    
    
			Delay5ms();
			if((key&0x0f)!=0x0f)
			{
    
    
				switch(key)
				{
    
    
					case 0xdb: //S13
						if(SMG_mode==2) count=0; //计数界面有效,计数值清零
						break;
					case 0xd7: //S12
						if(SMG_mode==0)SMG_mode=1; //模式切换
					else if(SMG_mode==1){
    
    SMG_mode=2;IIC_write(AT24C02_address,0,Vp/10);}//模式切换,保存计数值
					else if(SMG_mode==2)SMG_mode=0; //模式切换						
						break;
					case 0xeb: //S17
						if(SMG_mode==1) Vp-=50; //参数界面按下减5
					if(Vp<0)Vp=500;  //限幅设置
						break;
					case 0xe7: //S16
						if(SMG_mode==1) Vp+=50;//参数界面按下加5
					if(Vp>500)Vp=0;  //限幅设置
						break;						
				}
			}
			while((key&0x0f)!=0x0f)
			{
    
    
				key=P3;SMG_output(); //按下按键不影响数码管显示
			}
		}
	}
}

然后看一下LED功能和初始化。
在这里插入图片描述
在这里插入图片描述

uchar led=0xff;//led变量
bit L1_enable=0;//L1使能
char L3_enable=0; //L3使能
if(move<Vp) L1_enable=1; //当move小于vp开始计时
else {
    
    L1_enable=0;led |=0x01;} //L1熄灭
if(count%2!=0) led &=0xfd; //L2点亮//计数值为奇数
else led |=0x02; //L2熄灭
if(L3_enable>=3) led &=0xfb; //L3点亮//无效按键三次
else led |=0x04; //L3熄灭
P2=0X80;P0=led;//点亮

//通过1ms定时器判断5s
uint t=0;
void time0() interrupt 1
{
    
    
	if(L1_enable==1)
	{
    
    
		t++;
		if(t>=5000) //5s
		{
    
    
			t=0;
			led &=0xfe; //超过就点亮
		}
	}
}

最后编写计数值判断程序。
在这里插入图片描述

		if(move>Vp) state=1; //高于时标志位置一
		if((state==1)&&(move<Vp)) {
    
    count++;state=0;}//低于时标志位置0,计数++

完整程序

main.c

#include<stc15f2k60s2.h>
#include"intrins.h"
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int

#define PCF8591_address 0x90
#define Move_address 0x03
#define AT24C02_address 0xA0

void SMG_output(void);
void init(void);
void Delay1ms(void);
void Timer0Init(void);
void Jkey_scan(void);
void Delay5ms(void);
uchar tab[]={
    
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xff,0xbf,0x8c,0xc1,0xc8};//p u n
uchar SMG[8]={
    
    20,20,20,20,20,20,20,20};//初始显示20,全息数码管
uchar SMG_mode=0;//控制数码管模式
uint move=0;//pcf8591的滑动变阻器读取值
int Vp=0; //定义电压参数
int count=0; //定义计数值
uchar led=0xff;//led变量
bit L1_enable=0;//L1使能
char L3_enable=0; //L3使能
bit state=0;//判断计数值标志位
void main(void)
{
    
    
	init(); //初始化开发板
	Timer0Init();//定时器初始化
	Vp=IIC_read(AT24C02_address,0);//读取eeprom
	Vp *=10;//变为100
	while(1)
	{
    
    
		if(move>Vp) state=1; //高于时标志位置一
		if((state==1)&&(move<Vp)) {
    
    count++;state=0;}//低于时标志位置0,计数++
		
		move=IIC_read(PCF8591_address,Move_address);//读取滑动变阻器
		move=1.9607*move;//move *(5 /255 *100) 将0-255转换到0-500,便于显示
		if(SMG_mode==0) //数据界面
		{
    
    
			SMG[0]=23;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20;
			SMG[5]=move/100+10;SMG[6]=move%100/10;SMG[7]=move%10;
		}
		else if(SMG_mode==1) //参数界面
		{
    
    
			SMG[0]=22;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20;
			SMG[5]=Vp/100+10;SMG[6]=Vp%100/10;SMG[7]=Vp%10;			
		}
		else if(SMG_mode==2)  //计数界面
		{
    
    
			SMG[0]=24;SMG[1]=SMG[2]=SMG[3]=SMG[4]=20; ///不同count对应的数码管显示不同
			if(count<10){
    
    SMG[5]=20;SMG[6]=20;SMG[7]=count;}
			else if(count<100){
    
    SMG[5]=20;SMG[6]=count/10;SMG[7]=count%10;}
			else if(count<1000){
    
    SMG[5]=count/100;SMG[6]=count%100/10;SMG[7]=count%10;}			
		}
		if(move<Vp) L1_enable=1; //当move小于vp开始计时
		else {
    
    L1_enable=0;led |=0x01;} //L1熄灭
		if(count%2!=0) led &=0xfd; //L2点亮//计数值为奇数
		else led |=0x02; //L2熄灭
		if(L3_enable>=3) led &=0xfb; //L3点亮//无效按键三次
		else led |=0x04; //L3熄灭
		P2=0X80;P0=led; //点亮
		SMG_output();
		Jkey_scan();
	}
}

//通过1ms定时器判断5s
uint t=0;
void time0() interrupt 1
{
    
    
	if(L1_enable==1)
	{
    
    
		t++;
		if(t>=5000) //5s
		{
    
    
			t=0;
			led &=0xfe; //超过就点亮
		}
	}
}

void Jkey_scan(void)
{
    
    
	unsigned char i,key;
	for(i=0x80;i>8;i >>=1)
	{
    
    
		if(i==0x80){
    
    P44=0;P42=1;P3=~i;}
		else if(i==0x40){
    
    P44=1;P42=0;P3=~i;}
		else {
    
    P44=1;P42=1;P3=~i;}
		if(i==0x80){
    
    key=P3;key&=0x7f;}
		else if(i==0x40){
    
    key=P3;key&=0xbf;}
		else {
    
    key=P3;}
		if((key&0x0f)!=0x0f)
		{
    
    
			Delay5ms();
			if((key&0x0f)!=0x0f)
			{
    
    
				switch(key)
				{
    
    
					case 0xdb: //S13
						L3_enable=0; //正确操作
						if(SMG_mode==2) count=0; //计数界面有效,计数值清零
						break;
					case 0xd7: //S12
						L3_enable=0; //正确操作
						if(SMG_mode==0)SMG_mode=1; //模式切换
					else if(SMG_mode==1){
    
    SMG_mode=2;IIC_write(AT24C02_address,0,Vp/10);}//模式切换,保存计数值
					else if(SMG_mode==2)SMG_mode=0; //模式切换						
						break;
					case 0xeb: //S17
						L3_enable=0; //正确操作
						if(SMG_mode==1) Vp-=50; //参数界面按下减5
					if(Vp<0)Vp=500;  //限幅设置
						break;
					case 0xe7: //S16
						L3_enable=0; //正确操作
						if(SMG_mode==1) Vp+=50;//参数界面按下加5
					if(Vp>500)Vp=0;  //限幅设置
						break;			
					default:
						L3_enable++; //其他按键错误加1
						break;
				}
			}
			while((key&0x0f)!=0x0f)
			{
    
    
				key=P3;SMG_output(); //按下按键不影响数码管显示
			}
		}
	}
}

void SMG_output(void)
{
    
    
	uchar i;
	for(i=0;i<8;i++)
	{
    
    
	P2=(P2&0X1F)|0Xc0;
	P0=(1<<i);
	P2=(P2&0X1F)|0Xe0;
	P0=tab[SMG[i]];
	Delay1ms();
	}
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

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

void init(void)
{
    
    
	P2=(P2&0X1F)|0XA0;
	P0=0X00;
	P2=(P2&0X1F)|0X80;
	P0=0Xff;
	P2=(P2&0X1F)|0Xc0;
	P0=0Xff;
	P2=(P2&0X1F)|0Xe0;
	P0=0Xff;	
}

void Delay5ms()		//@11.0592MHz
{
    
    
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
    
    
		while (--j);
	} while (--i);
}


void Delay1ms(void)		//@11.0592MHz
{
    
    
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
    
    
		while (--j);
	} while (--i);
}

iic.c

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

#define DELAY_TIME 40

void IIC_write(uchar hw_address,uchar reg_address,uchar num)
{
    
    
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);
	IIC_WaitAck();
	IIC_SendByte(num);
	IIC_WaitAck();	
	IIC_Stop();	
}	

uchar IIC_read(uchar hw_address,uchar reg_address)
{
    
    
	uchar num;
	IIC_Start();
	IIC_SendByte(hw_address&0xfe);
	IIC_WaitAck();
	IIC_SendByte(reg_address);	
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(hw_address|0x01);
	IIC_WaitAck();
	num=IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();	
	
	return num;
}

//
void IIC_Delay(unsigned char i)
{
    
    
    do{
    
    _nop_();}
    while(i--);        
}

//
void IIC_Start(void)
{
    
    
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//
void IIC_Stop(void)
{
    
    
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
void IIC_SendAck(bit ackbit)
{
    
    
    SCL = 0;
    SDA = ackbit;  					
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//
bit IIC_WaitAck(void)
{
    
    
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//
void IIC_SendByte(unsigned char byt)
{
    
    
    unsigned char i;

    for(i=0; i<8; i++)
    {
    
    
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//
unsigned char IIC_RecByte(void)
{
    
    
    unsigned char i, da;
    for(i=0; i<8; i++)
    {
    
       
    	SCL = 1;
		IIC_Delay(DELAY_TIME);
		da <<= 1;
		if(SDA) da |= 1;
		SCL = 0;
		IIC_Delay(DELAY_TIME);
    }
    return da;    
}

iic.h

#ifndef _IIC_H
#define _IIC_H

#include "stc15f2k60s2.h"
#include "intrins.h"

#define uchar unsigned char
#define uint unsigned int

sbit SDA = P2^1;
sbit SCL = P2^0;

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 
void IIC_write(uchar hw_address,uchar reg_address,uchar num);
uchar IIC_read(uchar hw_address,uchar reg_address);


#endif

工程文件

工程文件有注释

猜你喜欢

转载自blog.csdn.net/darlingqx/article/details/127678566