第九届蓝桥杯单片机省赛题目解析

本文介绍了一个基于STM32的嵌入式系统开发案例,涉及数码管显示、LED控制、独立按键处理、EEPROM数据存储和ADC模拟输入等功能。通过编程逻辑实现四种运行模式和亮度等级,并利用IIC协议与外部设备交互。同时,详细展示了底层驱动代码和关键函数的实现,如IIC通信、ADC读取和EEPROM写入等。
摘要由CSDN通过智能技术生成

别的话也不多说,一起来看看第九届(2018)的题目吧。

题目

 这次的题目依然还是用到了三大模块(数码管、LED、按键),还用到了EEPROM和模拟输入(ADC),也都是一些常见的外设,只要平常都练习过,也就不难,最重要的还是编程逻辑。

1 数码管显示

数码管有两个界面需要显示一个是设置状态的界面,还有一个是亮度等级界面。设置状态界面由运行模式和流转间隔组成。

2 LED显示

 这次的LED是重点,不仅有四种运行模式还有四个亮度等级。四种运行模式就设置数组,然后循环运行。四个亮度等级就是把ADC 0到255分成四份,在哪个等级,LED就相应的亮多久,这样就会有视觉上的亮度等级,具体看代码。

3 按键模块

 使用的是独立按键,s7是LED的启动和停止,s6定义一个变量mode1,为0时数码管关闭(此时按s4显示亮度等级),为1时显示运行模式1以及流转间隔,为2时运行模式1闪烁按s5或s4进行加减,为3时流转间隔闪烁按s5或s4进行加减。

4 EEPROM

 就是改写底层驱动代码部分(IIC),在运行完加减后把流转间隔保存到其中去,在延时5ms。

5 ADC

 就是改写底层驱动代码部分(IIC)。

IIC.c

#include"IIC.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

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

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);
}

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;    
}

unsigned char Read_AD()
{
	unsigned char temp;
	
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	
	IIC_SendByte(0x03);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	
	temp=IIC_RecByte();
	IIC_Stop();
	
	return temp;
}

void write_eeprom(unsigned char add,unsigned char da)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	
	IIC_SendByte(add);
	IIC_WaitAck();
	
  IIC_SendByte(da);
	IIC_WaitAck();
	
	IIC_Stop();
}

unsigned char Read_eeprom(unsigned char add)
{
	unsigned char da;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
  IIC_SendByte(0xa1);
	IIC_WaitAck();
	da=IIC_RecByte();
	IIC_Stop();
	return da;
} 

IIC.h

#ifndef _IIC_H_
#define _IIC_H_

#include<stc15f2k60s2.h>
#include<intrins.h>

void IIC_Delay(unsigned char i);
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
unsigned char Read_AD();
void write_eeprom(unsigned char add,unsigned char da);
unsigned char Read_eeprom(unsigned char add);

#endif

init.h

#include"init.h"
#include"jm.h"

#define u8 unsigned char 
#define u16 unsigned int
#define state_0 0
#define state_1 1
#define state_2 2
	
static u8 segadder=0,key_state;

extern u8 mode1,a;
	
u8 seg[]={11,11,11,11,11,11,11,11};
u8 tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
u8 key_press,key_num,value;
	
void close_init()   //关闭无关外设
{
	P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
	
	P2=(P2&0x1f)|0xa0;P04=0;P06=0;P2&=0x1f;
	
	P2=(P2&0x1f)|0xc0;P0=0x00;P2&=0x1f;
	
	P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f;
}

void display()    // 数码管显示函数
{
	P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f;
	
	P2=(P2&0x1f)|0xc0;P0=1<<segadder;P2&=0x1f;
	
	P2=(P2&0x1f)|0xe0;P0=tab[seg[segadder]];P2&=0x1f;
	
	if(++segadder==8) segadder=0;
}

u8 read_key()    //独立按键
{
	key_press=P3&0x0f;
	switch(key_state)
	{
		case state_0:
			if(key_press!=0x0f)
				key_state=state_1;
			break;
		case state_1:
			if(key_press!=0x0f)
			{
				if((key_press&0x08)==0)
				{
					if(mode1==0&&a==1)
					{
						jm3();
						a=0;
					}
					key_num=4;
				}
				if((key_press&0x04)==0) key_num=5;
				if((key_press&0x02)==0) key_num=6;
				if((key_press&0x01)==0) key_num=7;
				key_state=state_2;
			}
			else
				key_state=state_0;
			break;
		case state_2:
			if(key_press==0x0f)
			{
				if(mode1==0&&a==0)a=1;
				key_state=state_0;
			}
			break;
	}
	value=key_num;
	key_num=0;
	return value;
}

void Timer0Init(void)		
{
	AUXR |= 0x80;		
	TMOD &= 0xF0;		
	TL0 = 0xCD;		
	TH0 = 0xD4;		
	TF0 = 0;		
	TR0 = 1;
  EA = 1;
  ET0 = 1;	
}

init.h

#ifndef _INIT_H_
#define _INIT_H_

#include<stc15f2k60s2.h>

void close_init();
void display();
unsigned char read_key();
void Timer0Init(void);





#endif

jm.h

#include"jm.h"
#include"IIC.h"

#define u8 unsigned char 
#define u16 unsigned int
	
extern bit sp,mode_flag,val_flag;      // extern表示此变量是在别处定义的,要在此处引用
extern u8 seg[],mode1,RB2_value;
extern u8 val1,val2,val3,val4,val_count;

u8 mode12[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};  //模式1,2的数组
u8 mode34[]={0x7e,0xbd,0xdb,0xe7};   //模式3,4的数组
u8 mode=1,i=0,j=7,x=0,y=3,mode2=1;

void Delay5ms()
{
	unsigned char i, j;

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

void jm3()      //亮度等级显示函数
{
	seg[0]=11;
	seg[1]=11;
	seg[2]=11;
	seg[3]=11;
	seg[4]=11;
	seg[5]=11;
	seg[6]=10;
	seg[7]=RB2_value;
}

void jm4()    //s4的功能
{
	if(mode1==2)
	{
		if(--mode==0)mode=4;
	}
	if(mode1==3)
	{
		if(mode==1)val1-=10;
		if(val1<=40)val1=40;
		write_eeprom(0x10,val1);
		Delay5ms();
		
		if(mode==2)val2-=10;
		if(val2<=40)val2=40;
		write_eeprom(0x20,val2);
		Delay5ms();
		
		if(mode==3)val3-=10;
		if(val3<=40)val3=40;
		write_eeprom(0x40,val3);
		Delay5ms();
		
		if(mode==4)val4-=10;
		if(val4<=40)val4=40;
		write_eeprom(0x80,val4);
		Delay5ms();
	}
}

void jm5()     //s5的功能
{
	if(mode1==2)
	{
		if(++mode==5)mode=1;
	}
	if(mode1==3)
	{
		if(mode==1)val1+=10;
		if(val1>=120)val1=120;
		write_eeprom(0x10,val1);
		Delay5ms();
		
		if(mode==2)val2+=10;
		if(val2>=120)val2=120;
		write_eeprom(0x20,val2);
		Delay5ms();
		
		if(mode==3)val3+=10;
		if(val3>=12)val3=120;
		write_eeprom(0x40,val3);
		Delay5ms();
		
		if(mode==4)val4+=10;
		if(val4>=120)val4=120;
		write_eeprom(0x80,val4);
		Delay5ms();
	}
}

void jm6()    
{
	if(mode1==0)  //数码管关闭
	{
		seg[0]=11;
		seg[1]=11;
		seg[2]=11;
		seg[3]=11;
		seg[4]=11;
		seg[5]=11;
		seg[6]=11;
		seg[7]=11;
	}
	if(mode1==1)    //显示运行模式1以及流转间隔
	{
		seg[0]=10;
		seg[1]=1;
		seg[2]=10;
		seg[3]=11;
		seg[4]=val1/100;
		seg[5]=val1/10%10;
		seg[6]=val1%10;
		seg[7]=0;
	}
	if(mode1==2)    //运行模式1闪烁
	{
		if(mode_flag==1)
		{
			seg[0]=10;
			seg[1]=mode;
			seg[2]=10;
			seg[3]=11;
			if(mode==1)
			{
				seg[4]=val1/100;
				seg[5]=val1/10%10;
				seg[6]=val1%10;
				seg[7]=0;
			}
			if(mode==2)
			{
				seg[4]=val2/100;
				seg[5]=val2/10%10;
				seg[6]=val2%10;
				seg[7]=0;
			}
			if(mode==3)
			{
				seg[4]=val3/100;
				seg[5]=val3/10%10;
				seg[6]=val3%10;
				seg[7]=0;
			}
			if(mode==4)
			{
				seg[4]=val4/100;
				seg[5]=val4/10%10;
				seg[6]=val4%10;
				seg[7]=0;
			}
		}
		else
		{
			seg[0]=11;
			seg[1]=11;
			seg[2]=11;
			seg[3]=11;
		}	
	}
	if(mode1==3)      //流转间隔闪烁
	{
		if(mode_flag==1)
		{
			if(mode==1)
			{
				seg[4]=val1/100;
				seg[5]=val1/10%10;
				seg[6]=val1%10;
				seg[7]=0;
			}
			if(mode==2)
			{
				seg[4]=val2/100;
				seg[5]=val2/10%10;
				seg[6]=val2%10;
				seg[7]=0;
			}
			if(mode==3)
			{
				seg[4]=val3/100;
				seg[5]=val3/10%10;
				seg[6]=val3%10;
				seg[7]=0;
			}
			if(mode==4)
			{
				seg[4]=val4/100;
				seg[5]=val4/10%10;
				seg[6]=val4%10;
				seg[7]=0;
			}
		}
		else
		{
			seg[4]=11;
			seg[5]=11;
			seg[6]=11;
			seg[7]=11;
		}
	}
}

void jm7()
{
	if(sp==1)   //打开LED
	{
		if(mode2==1&&val_flag==0)
		{	
				P2=(P2&0x1f)|0x80;	
				P0=mode12[i];
				P2&=0x1f;
		}
		if(mode2==1&&val_flag==1)
		{
			val_flag=0;
			if(++i==8)
			{
				i=0;
				mode2=2;
				val_count=0;
			}
		}
    if(mode2==2&&val_flag==0)
		{

				P2=(P2&0x1f)|0x80;
				P0=mode12[j];
				P2&=0x1f;
		}	
		if(mode2==2&&val_flag==1)
		{
			val_flag=0;
			if(--j==-1)
				{
					j=7;
					mode2=3;
					val_count=0;
				}
		}
		if(mode2==3&&val_flag==0)
		{
				P2=(P2&0x1f)|0x80;
				P0=mode34[x];
				P2&=0x1f;	
		}
		if(mode2==3&&val_flag==1)
		{
			val_flag=0;
			if(++x==4)
				{
					x=0;
					mode2=4;
					val_count=0;
				}
		}
		if(mode2==4&&val_flag==0)
		{
				P2=(P2&0x1f)|0x80;
				P0=mode34[y];
				P2&=0x1f;	
		}
		if(mode2==4&&val_flag==1)
		{
			val_flag=0;
			if(--y==-1)
			{
				y=3;
				mode2=1;
				val_count=0;
			}
		}
	}
	else
	{
	  P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
	}
}

jm.h

#ifndef _JM_H_
#define _JM_H_

#include<stc15f2k60s2.h>

void jm3();
void jm4();
void jm5();
void jm6();
void jm7();
void Delay5ms();




#endif

main.c

#include"init.h"
#include"IIC.h"
#include"jm.h"

#define u8 unsigned char 
#define u16 unsigned int
	
extern u8 mode2;
	
u8 a,b,num,mode1=0,RB2=0,RB2_value=0,RB2_count=0,e_count=0;
bit sp=0,mode_flag=0,val_flag=1,e_flag=0;
u16 mode_count=0,val_count=0;
u8 val1=40,val2=40,val3=40,val4=40;
	
void main()
{	
	close_init();
	Timer0Init();
	while(1)
	{
		RB2=Read_AD();
		num=read_key();
		switch(num)
		{
			case 4:
				jm4();
			break;
			case 5:
				jm5();
			break;
			case 6:
				if(++mode1==4)mode1=0;
				a=1;
			break;
			case 7:
				sp^=1;
				b=1;
			break;			
		}
		num=0;
		if(a==1)jm6();
		if(b==1)jm7();
		if(RB2>=0&&RB2<64)RB2_value=1;       //把ADC的值分成四个等级
		if(RB2>=64&&RB2<128)RB2_value=2;
		if(RB2>=128&&RB2<192)RB2_value=3;
		if(RB2>=192&&RB2<=255)RB2_value=4;
		if(e_flag==1)        //读取EEPROM中的值
		{
			e_flag=0;
			val1=Read_eeprom(0x10);
			val2=Read_eeprom(0x20);
			val3=Read_eeprom(0x40);
			val4=Read_eeprom(0x80);
		}
	}
}
	
void Timer0() interrupt 1
{
	display();
	val_count++;
	if(mode1==2||mode1==3)
	{
		if(++mode_count==800)
		{
			mode_count=0;
			mode_flag^=1;
		}
	}
	if((val_count==val1*10)&&mode2==1)
	{
		val_count=0;
		val_flag=1;
	}
	if((val_count==val2*10)&&mode2==2)
	{
		val_count=0;
		val_flag=1;
	}
	if((val_count==val3*10)&&mode2==3)
	{
		val_count=0;
		val_flag=1;
	}
	if((val_count==val4*10)&&mode2==4)
	{
		val_count=0;
		val_flag=1;
	}
	
	if(++RB2_count<=RB2_value) jm7();   //亮度等级越大,LED亮的越久
	else if((RB2_count>RB2_value)&&(RB2_count<=4))
	{
		P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;
	}
	else if(RB2_count>4)RB2_count=0;
	
	if(++e_count==200)
	{
		e_count=0;
		e_flag=1;
	}
}	

最后,有什么写的不好的地方,还希望大家指正,或者有更好的意见和想法都可以讨论。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值