蓝桥杯单片机组国赛13届真题详解(附完整源码.

目录

前言:

真题:

解析:

脉冲:

源码分享:

main.c

configure.c

configure.h

iic.c

iic.h


前言:

               2024年有幸参加国赛,分享一下十三届真题解析。

真题:


解析:

        我利用定时器0和定时器1进行对频率脉冲的处理;用定时器2进行按键、数码管等模块处理;用PCA进行超声波测距(可以节省一个定时器)。

        超声波、DA输出、EEPROM、按键的长按在第十届也有提到,主要是理解逻辑,可传送查看

        传送门:蓝桥杯单片机组国赛第十届(附源码.

脉冲:

               先用定时器0和2进行频率测量,然后根据题意进行PWM脉冲输出,由于要输出1KHz脉冲信号,即一个周期为1毫秒(1/1000=0.001秒),所以定时器1可以设置200us,100us,50us甚至更小,本文用的200us。若频率数据大于频率参数时,输出80%占空比,即pwm_cnt=4,反之pwm_cnt=1     以下相应值对应占空比。

pwm_cnt的值PWM占空比
00%
120%
240%
360%
480%
5100%

 

void Time01init(void)//200微秒
{
	TMOD=0x15;
	TH0=0;TH1=0;
	TH1=0xFF;
	TL1=0x38;
	EA = 1;
	ET1= 1;
	EA = 1;
	TR0=1;
	TR1=1;
}

u8 pwm_cnt = 0;

void Timer1_Routine() interrupt 3
{
	TH1=0xFF;       
	TL1=0x38;
	pwm_cnt++;
	pwm_cnt%=6;
	if(++freqcnt==5000)
	{
		freqcnt=0;
		freq=TH0;
		freq=(freq<<8)|TL0;
		TH0=0;TL0=0;
	}
	if(pwm_cnt<=pwm)    //处理脉冲的输出
	{
		y5c_state |= 0x20;
	}else{
		y5c_state &=~0x20;
	}
	HC138_Init(5,y5c_state);
}

源码分享:

main.c
#include <STC15F2K60S2.H>
#include "configure.h"
#include "iic.h"
//***************************************
sbit tx=P1^0;
sbit rx=P1^1;
u8 smg_down_t=0;//对应各个函数多久运行一次
u8 key_down_t=0;
u8 csb_down_t=0;
u8 sid_down_t=0;
u16 freqcnt;    //频率测量计数
u8 key_old,key_val,key_down,key_up;  
u8 mode=1,modepro=1,modeplus=1;    //界面显示
//****
bit s7=0;
bit old_dist=0;
u16 freq;    //频率测量值
u8 sidu=35;    //湿度的值
u16 distance;    //测量的距离
u8 freq_para=90;    //频率参数
u8 sidu_para=40;    //湿度参数
u8 dist_para=6;    //距离参数
//****
u8 y5c_state=0x00;    //Y5C状态对应值
u8 pwm=1,pwm_cnt=0;   
u8 led_state=0xff;    //Y4C(LED)状态对应值
u8 jdq_cnt=0;
u16 time1s,time100ms;    //计数,处理1s、100ms计时
bit flag1s=0;            //1s标志位
bit state_100ms=0;
bit flag100ms=0;
//**************************************
void led_work()        //LED处理函数
{
	if(mode==1)
	{
		led_state &= 0xFE;
		state_100ms=0;
	}else if(mode==4 && modepro==1){
		state_100ms=1;
		if(flag100ms)
		{
			flag100ms=0;
			if((led_state&0x01)==0x00)
			{
				led_state |= 0x01;
			}else{
				led_state &=~0x01;
			}
		}
	}else{
		led_state |= 0x01;
	}
//***********
	if(mode==2)
	{
		led_state &= 0xFD;
		state_100ms=0;
	}else if(mode==4 && modepro==2){
		state_100ms=1;
		if(flag100ms)
		{
			flag100ms=0;
			if((led_state&0x02)==0x00)
			{
				led_state |= 0x02;
			}else{
				led_state &=~0x02;
			}
		}
	}else{
		led_state |= 0x02;
	}
//*********
	if(mode==3)
	{
		led_state &= 0xFB;
		state_100ms=0;
	}else if(mode==4 && modepro==3){
		state_100ms=1;
		if(flag100ms)
		{
			flag100ms=0;
			if((led_state&0x04)==0x00)
			{
				led_state |= 0x04;
			}else{
				led_state &=~0x04;
			}
		}
	}else{
		led_state |= 0x04;
	}
	if(pwm==4)
	{
		led_state &= 0xF7;
	}else{
		led_state |=~0xF7;
	}
	if(sidu>sidu_para)
	{
		led_state &= 0xEF;
	}else{
		led_state |=~0xEF;
	}
	if(old_dist)
	{
		led_state &= 0xDF;
	}else{
		led_state |=~0xDF;
	}
	HC138_Init(4,led_state);
}
void dist_panduan()    //距离判断函数
{
	if(distance>dist_para*10)
	{
		y5c_state |= 0x10;
		if(!old_dist)
		{
			jdq_cnt++;
			AT24C02_Write(0x00,jdq_cnt);	
			Delay5ms();
		}
		old_dist=1;
	}else{
		old_dist=0;
		y5c_state &=~0x10;
	}
	HC138_Init(5,y5c_state);
}
void freq_panduan()    //频率判断函数->脉冲输出
{
	if(freq>freq_para*100)
	{
		pwm=4;
	}else{
		pwm=1;
	}
	
	HC138_Init(5,y5c_state);
}
void sidu_read()    //湿度读取
{
	u8 temp=0;
	if(sid_down_t) return;
	sid_down_t=1;
	temp = PCF8591_ADchange(0x43);
	sidu = temp/51.0*20;
}
void dac_output()    //DAC输出
{
	float Data;
	u8 temp;
	if(sidu<=sidu_para)
	{
		temp = 51;
	}else if(sidu>=80)
	{
		temp = 255;
	}else{
		Data = 4.0*sidu/(80-sidu_para)+5-320.0/(80-sidu_para);
		temp = Data*51;
	}
	PCF8591_DAchange(temp);
}
void Sendwave()
{
	u8 i;
	for(i=0; i<8; i++)
	{
		tx=0;
		Delay14us();
		tx=1;
		Delay14us();
	}
}
void dist_read()    //测距
{
	u16 time;
	if(csb_down_t)	return;
	csb_down_t=1;
	CMOD=0x00;
	CH=CL=0;
	EA=0;
	Sendwave();
	EA=1;CR=1;
	while(rx&&!CF);
	CR=0;
	if(CF==0)
	{
		time=CH;
		time=(time<<8)|CL;
		distance=time*0.017;
	}else{
		CF=0;
		distance=255;
	}
}
u8 key_read()    //按键相应
{
	u8 temp=0;
	if(P33==0)	temp=4;
	if(P32==0)	temp=5;
	if(P31==0)	temp=6;
	if(P30==0)	temp=7;
	return temp;
}
void key_work()    //按键处理函数
{
	if(key_down_t)	return;
	key_down_t=1;
	key_val = key_read();
	key_down = key_val&(key_old^key_val);
	key_up   = ~key_val&(key_old^key_val);
	key_old  = key_val;
	
	if(key_down==4)
	{
		if(++mode>=5)	mode=1;
		modepro=1;
	}
	if(key_down==5)
	{
		if(mode==4)
		{
			if(++modepro==4)	modepro=1;
		}
	}
	if(key_down==6)		//加
	{
		if(mode==4 && modepro==1)
		{
			freq_para += 5;
			if(freq_para>=125)	freq_para=10;
		}
		if(mode==4 && modepro==2)
		{
			sidu_para += 10;
			if(sidu_para>=70)	sidu_para=10;
		}
		if(mode==4 && modepro==3)
		{
			dist_para += 1;
			if(dist_para>=13)	dist_para=1;
		}
		if(mode==3)
		{
			if(++modepro==3)	modepro=1;
		}
	}
	if(key_down==7)
	{
		s7=1;
		if(mode==4 && modepro==1)
		{
			freq_para -= 5;
			if(freq_para<=5)	freq_para=120;
		}
		if(mode==4 && modepro==2)
		{
			sidu_para -= 10;
			if(sidu_para<=0)	sidu_para=60;
		}
		if(mode==4 && modepro==3)
		{
			dist_para -= 1;
			if(dist_para<=0)	dist_para=12;
		}
		if(mode==1)
		{
			if(++modepro==3)	modepro=1;
		}
	}
	if(key_up==7)
	{
		s7=0;
		time1s=0;
		if(flag1s)
		{
			flag1s=0;
			jdq_cnt=0;
			AT24C02_Write(0x00,jdq_cnt);
			Delay5ms();
		}
	}
}
void smg_work()    //数码管显示函数
{
	if(smg_down_t) return;
	smg_down_t=1;
	//******
	dac_output();
	dist_panduan();
	//******
	if(mode==1)		//频率界面
	{
		smg_data[0]=0x8e;smg_data[1]=0xff;
		smg_data[2]=0xff;
		if(modepro==1)			//HZ
		{
			if(freq>9999) 	smg_data[3]=SMG_NoDot[freq/10000];  else 	smg_data[3]=0xff;
			if(freq>999) 	smg_data[4]=SMG_NoDot[freq/1000%10];else smg_data[4]=0xff;
			if(freq>99) 		smg_data[5]=SMG_NoDot[freq/100%10]; else smg_data[5]=0xff;
			if(freq>9) 		smg_data[6]=SMG_NoDot[freq/10%10];  else 	smg_data[6]=0xff;
			smg_data[7]=SMG_NoDot[freq%10];
		}else if(modepro==2){	//KHZ
			smg_data[3]=0xff;smg_data[4]=0xff;
			if(freq>9999) 	smg_data[5]=SMG_NoDot[freq/10000];   else smg_data[5]=0xff;
			if(freq>999) 	smg_data[6]=SMG_Dot[freq/1000%10];  	else smg_data[6]=SMG_Dot[0];
			if(freq>99) 	smg_data[7]=SMG_NoDot[freq/100%10];  else {smg_data[7]=SMG_NoDot[0];smg_data[6]=0xff;}
		}
	}
	if(mode==2)		//湿度界面
	{
		smg_data[0]=0x89;smg_data[1]=0xff;
		smg_data[2]=0xff;smg_data[3]=0xff;
		smg_data[4]=0xff;smg_data[5]=0xff;
		smg_data[6]=SMG_NoDot[sidu/10];
		smg_data[7]=SMG_NoDot[sidu%10];
	}
	if(mode==3)		//测距界面
	{
		smg_data[0]=0x88;smg_data[1]=0xff;
		smg_data[2]=0xff;smg_data[3]=0xff;
		smg_data[4]=0xff;
		if(modepro==1)
		{
			if(distance>99)smg_data[5]=SMG_NoDot[distance/100];else smg_data[5]=0xff;
			if(distance>9)smg_data[6]=SMG_NoDot[distance/10%10];else smg_data[6]=0xff;
			smg_data[7]=SMG_NoDot[distance%10];
		}else if(modepro==2){
			smg_data[5]=SMG_Dot[distance/100];
			smg_data[6]=SMG_NoDot[distance/10%10];
			smg_data[7]=SMG_NoDot[distance%10];
		}
	}
	if(mode==4)		//参数界面
	{
		smg_data[0]=0x8c;smg_data[2]=0xff;
		smg_data[3]=0xff;smg_data[4]=0xff;
		if(modepro==1)	//频率参数
		{
			smg_data[1]=SMG_NoDot[modepro];
			if(freq_para>99)smg_data[5]=SMG_NoDot[freq_para/100];else smg_data[5]=0xff;
			if(freq_para>9)smg_data[6]=SMG_Dot[freq_para/10%10];else smg_data[6]=SMG_Dot[0];
			smg_data[7]=SMG_NoDot[freq_para%10];
		}
		if(modepro==2)	//湿度参数
		{
			smg_data[1]=SMG_NoDot[modepro];
			smg_data[5]=0xff;
			smg_data[6]=SMG_NoDot[sidu_para/10];
			smg_data[7]=SMG_NoDot[sidu_para%10];
		}
		if(modepro==3)	//距离参数
		{
			smg_data[1]=SMG_NoDot[modepro];
			smg_data[5]=0xff;
			if(dist_para>9)smg_data[6]=SMG_Dot[dist_para/10]; else smg_data[6]=SMG_Dot[0];
			smg_data[7]=SMG_NoDot[dist_para%10];
		}
	}
}
void Time01init(void)//200微秒
{
	TMOD=0x15;
	TH0=0;TH1=0;
	TH1=0xFF;
	TL1=0x38;
	EA = 1;
	ET1= 1;
	EA = 1;
	TR0=1;
	TR1=1;
}
void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xFB;		//定时器时钟12T模式
	T2L = 0x18;		//设置定时初值
	T2H = 0xFC;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	IE2 |= 0x04;
	EA  =1;
}
void system_init()
{
	HC138_Init(4,0xff);
	HC138_Init(5,0x00);
	Time01init();
	Timer2Init();
	
}
void main()
{
	system_init();
	while(1)
	{
		dist_read();
		key_work();
		smg_work();
		sidu_read();
	}
}
void Timer1_Routine() interrupt 3
{
	TH1=0xFF;
	TL1=0x38;
	pwm_cnt++;
	pwm_cnt%=6;
	if(++freqcnt==5000)    //测频率
	{
		freqcnt=0;
		freq=TH0;
		freq=(freq<<8)|TL0;
		TH0=0;TL0=0;
	}
	if(pwm_cnt<=pwm)    //脉冲输出
	{
		y5c_state |= 0x20;
	}else{
		y5c_state &=~0x20;
	}
	HC138_Init(5,y5c_state);
}
void Timer2_Routine() interrupt 12
{
	if(++smg_down_t==10)		smg_down_t=0;
	if(++key_down_t==10)		key_down_t=0;
	if(++csb_down_t==200)	csb_down_t=0;
	if(++sid_down_t==5)		sid_down_t=0;
	if(s7)					time1s++;
	if(state_100ms)			time100ms++;
	if(time100ms==100)
	{
		time100ms=0;
		flag100ms=1;
	}
	if(time1s>=1000)
	{
		flag1s=1;
		time1s=0;
	}
	smg_bit();
	freq_panduan();
	led_work();
}
configure.c
#include <STC15F2K60S2.H>
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;

code u8 SMG_NoDot[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
//1   2   3   4   5   6   7   8   9
code u8 SMG_Dot[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
// 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
u8 smg_data[8]={255,255,255,255,255,255,255,255};

void Delay14us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 38;
	while (--i);
}
void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 59;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}
void HC138_Init(u8 num1,num2)
{
	P2 = P2&0x1f;
	P0 = num2;
	switch(num1)
	{
		case 4: P2=(P2&0x1f)|0x80; break;
		case 5: P2=(P2&0x1f)|0xa0; break;
		case 6: P2=(P2&0x1f)|0xc0; break;
		case 7: P2=(P2&0x1f)|0xe0; break;
	}
	P2 = P2&0x1f;
}
void smg_bit()
{
	static u8 pos=0;
	HC138_Init(7,0xff);
	HC138_Init(6,0x01<<pos);
	HC138_Init(7,smg_data[pos]);
	if(++pos==8)	pos=0;
}
configure.h
#ifndef  __CONFIGURE_H
#define  __CONFIGURE_H

typedef unsigned char u8;
typedef unsigned int u16;

extern code u8 SMG_NoDot[10];
extern code u8 SMG_Dot[10];
extern u8 smg_data[8];

void Delay14us();		//@12.000MHz
void Delay5ms();		//@12.000MHz

void HC138_Init(u8 num1,num2);
void smg_bit();

#endif
iic.c
#include "reg52.h"
#include "intrins.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);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    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;
}

//通过I2C总线发送数据
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;  
}

//从I2C总线上接收数据
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 PCF8591_ADchange(unsigned char Addr)
{
	unsigned char Data;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();	
	IIC_SendByte(Addr);
	IIC_WaitAck();
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	EA=0;
	Data=IIC_RecByte();
	EA=1;
	IIC_SendAck(1);
	IIC_Stop();
	return Data;
}

void PCF8591_DAchange(unsigned char Data)
{
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(0x40);
	IIC_WaitAck();
	IIC_SendByte(Data);
	IIC_WaitAck();
	IIC_Stop();
}
void AT24C02_Write(unsigned char addr,Data)
{
	IIC_Start();
	IIC_SendByte(0xA0);
	IIC_WaitAck();
	IIC_SendByte(addr);
	IIC_WaitAck();
	IIC_SendByte(Data);
	IIC_WaitAck();
	IIC_Stop();
}
iic.h
#ifndef _IIC_H
#define _IIC_H

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 PCF8591_DAchange(unsigned char Data);
unsigned char PCF8591_ADchange(unsigned char Addr);
void AT24C02_Write(unsigned char addr,Data);

#endif

以上全部内容,如有疑问评论或私信我。

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值