目录
前言:
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占空比 |
---|---|
0 | 0% |
1 | 20% |
2 | 40% |
3 | 60% |
4 | 80% |
5 | 100% |
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
以上全部内容,如有疑问评论或私信我。