蓝桥杯单片机第八届国赛之定时器扫描、PCA超声波

之前发过一篇关于第八届国赛的博客,里面有题目,当时还留下了第一次参赛能进国赛的憧憬,时隔一个月,小菜牛真回来备战国赛了,感觉蓝桥杯越学习代码写法越灵活,比如这篇第八届和我之前发的一篇第八届国赛的写法大大不同,从代码上来说,就减少了一俩百行;不再使用delay阻塞代码,用定时器扫数码管和按键。 

先添加底层,现在我将底层分为led,key,timer(定时器的声明),以及使用的外设底层如iic等。

先记录一下EEPROM, 本代码里面有关于其的俩种读写方式,分为页和字节读写,页只能是八的整数倍地址写入,这届国赛超声波是10位数组存储,我试过按页写入,只能8位,感觉不如字节方便; .h文件就不添入了。

然后本博客超声波采用的是开发板内部的PCA用作软件定时器(具体参考sonic.c)。主要是为了锻炼,不然到时候串口,频率,超声波都考了,就慌了。

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

#define DELAY_TIME	5

sbit sda=P2^1;
sbit scl=P2^0;

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

void DA_output(uchar dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x40);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

/** 按页写入,第一个入口参数是存储数组,第二个入口参数是地址(8的整数倍,可以是0) 第三个入口参数是存储几个数据 **/
//void EEPROM_Write(uchar *arr, uchar add, uchar num)
//{
//	I2CStart();
//	I2CSendByte(0xa0);
//	I2CWaitAck();
//	I2CSendByte(add);
//	I2CWaitAck();
//	
//	while(num--)
//	{
//		I2CSendByte(*arr++);
//		I2CWaitAck();
//		I2C_Delay(200);
//	}
//	
//	I2CStop();
//}

//void EEPROM_Read(uchar *arr,uchar add,uchar num)
//{
//	I2CStart();
//	I2CSendByte(0xa0);
//	I2CWaitAck();
//	I2CSendByte(add);
//	I2CWaitAck();
//	I2CStart();
//	I2CSendByte(0xa1);
//	I2CWaitAck();
//	
//	while(num--)
//	{
//		*arr++ = I2CReceiveByte();
//		if(num)I2CSendAck(0);	
//		else I2CSendAck(1);	
//	}
//	I2CStop();
//}

/** 字节读写 **/
void EEPROM_Write(uchar add,uchar dat)
{
	EA=0;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
	EA=1;
}

uchar EEPROM_Read(uchar add)
{
	uchar temp;
	EA=0;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	EA=1;
	return temp;
}
key.c
#include <stc15f2k60s2.h>
#include <key.h>

uchar Key_Read(void)
{
	uchar key_num,key_value;
	P3|=0x0f;
	key_num=P3&0x0f;
	switch(key_num)
	{
		case 0x0e: key_value=7; break;
		case 0x0d: key_value=6; break;
		case 0x0b: key_value=5; break;
		case 0x07: key_value=4; break;
		default: key_value=0; break;
	}
	return key_value;
}
led.c
#include <stc15f2k60s2.h>
#include <led.h>

void Led_Disp(uchar addr,uchar enable)
{
	static uchar temp=0x00;
	static uchar temp_old=0xff;
	
	if(enable)
		temp|=0x01<<addr;
	else
		temp&=~(0x01<<addr);
	
	if(temp!=temp_old)
	{
		P2=(P2&0x1f)|0x80;
		P0=~temp;
		P2=0;
		temp_old=temp;
	}
}
timer.c
#include <stc15f2k60s2.h>

void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xFB;		//定时器时钟12T模式
	T2L = 0x18;		//设置定时初值
	T2H = 0xFC;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	EA=1;
	IE2 |= 0x04;
}
sonic.c
#include <stc15f2k60s2.h>
#include <sonic.h>
#include <intrins.h>

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}

sbit TX=P1^0;
sbit RX=P1^1;

void send_wave(void)
{
	uchar i;
	for(i=0;i<8;i++)
	{
		TX=1;
		somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
		TX=0;
		somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
	}
}

uchar sonic(void)
{
	uint time;
	CMOD=0x00;
	CH=CL=0;
	send_wave();
	CR=1;
	while(RX==1&&CF==0);
	CR=0;
	if(CF==0)
	{
		time=CH<<8|CL;
		return (uint)time*0.017;
	}
	else
	{
		CF=0;
		return 0;
	}
	
}
main.c
#include <stc15f2k60s2.h>
#include <key.h>
#include <timer.h>
#include <iic.h>
#include <led.h>
#include <sonic.h>

void Allinit(void);//初始化函数
void Key_Proc(void);//数码管显示函数
void Seg_Proc(void);
void Led_Proc(void);
code uchar tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,
									0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0XBF,0XFF,0x8e};//数码管段选
uchar dis_buf[]={21,21,21,21,21,21,21,21};
uchar key_slow_down;//按键减速						
uint seg_slow_down;//数码管减速
uint Ms_tick;
/*led专用变量*/
xdata hkled[]={0,0,0,0,0,0,0,0};
uchar led_8bit;
bit led_flash_flag;//取反标志位
bit start_led1_flash_flag;//开启标志位
/*DA专用变量*/
uint DA_out;
/*界面显示变量*/
uchar jiemian=0;
/*超声波测量专用变量*/
uchar distance[10]=0;//超声波测量数组
uchar EEPROM_distance[10];//超声波保存数组
uchar distance_index=255; //超声波保存数组索引
bit Mes_mode;//操作
uchar calc_result;//计算结果
bit start_sonic=0; //启动测量
uchar dead_zone=20;//测量盲区
uchar i;//初始化读数据的变量

void main(void)
{
  dead_zone=EEPROM_Read(0x10);
	for(i=0;i<10;i++)
 {
	 EEPROM_distance[i]=EEPROM_Read(i);
 }
	Allinit();
	Timer2Init();
	while(1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

void Allinit(void)
{
	P2=(P2&0x1f)|0xa0;
	P0=0x00;P2=0;
	P2=(P2&0x1f)|0xc0;
	P0=0x00;P2=0;
	P2=(P2&0x1f)|0xe0;
	P0=0xff;P2=0;
	P2=(P2&0x1f)|0x80;
	P0=0xff;P2=0;
}

void Key_Proc(void)
{
	uchar key_temp,key_down,key_up;
	static uchar key_old=0;
	if(key_slow_down)return;
	key_slow_down=1;
	key_temp=Key_Read();
	key_down=key_temp&(key_temp^key_old);
	key_up=~key_temp&(key_temp^key_old);
	key_old=key_temp;
	switch(key_down)
	{
		case 7:
			if(jiemian==0)Mes_mode^=1;
			else if(jiemian==1)
			{
				if(++distance_index==10)distance_index=0;
			}
			else if(jiemian==2)
			{
				dead_zone+=10;if(dead_zone>90)dead_zone=10;
			}
		break;
		case 6:
			if(jiemian==0||jiemian==2)
			{
				jiemian+=2;
				if(jiemian==4)
				{
					jiemian=0;
					EEPROM_Write(0x10,dead_zone);
				}
			}
		break;
		case 5:
			if(jiemian!=2)
			{
				if(++jiemian==2)jiemian=0;
				if(jiemian==1)distance_index=0; //将距离数组索引清零
			}
		break;
		case 4:
			if(jiemian==0)
			{
				start_sonic=1;start_led1_flash_flag=1;Ms_tick=0;led_flash_flag=0;
				if(++distance_index==10)distance_index=0;
			}
		break;
	}
}

void Seg_Proc(void)
{
	uchar i;
	if(seg_slow_down)return;
	seg_slow_down=1;
	if(start_sonic==1){start_sonic=0;distance[distance_index%255]=sonic();} //按下s4一次 测量一次
	if(jiemian==0)
	{
		if(distance_index%255>=1)
		{
			calc_result=Mes_mode?distance[distance_index]+distance[distance_index-1]:distance[distance_index-1];
		}
		dis_buf[0]=Mes_mode;dis_buf[1]=21;
		dis_buf[2]=calc_result/100;dis_buf[3]=calc_result%100/10;dis_buf[4]=calc_result%10;
		dis_buf[5]=distance[distance_index%255]/100;dis_buf[6]=distance[distance_index%255]%100/10;dis_buf[7]=distance[distance_index%255]%10;
		if(dis_buf[2]==0)dis_buf[2]=21;
		
		if(distance_index!=255)//防止第一次上电被篡改EEPROM存储数组【0】的数据
		{
			EEPROM_distance[distance_index%255]=distance[distance_index%255];
			EEPROM_Write(distance_index%255,EEPROM_distance[distance_index%255]);
		}
	}
	else if(jiemian==1)//回显
	{
		dis_buf[0]=(distance_index+1)/10;dis_buf[1]=(distance_index+1)%10;
		dis_buf[2]=dis_buf[3]=dis_buf[4]=21;
		dis_buf[5]=EEPROM_distance[distance_index%255]/100;
		dis_buf[6]=EEPROM_distance[distance_index%255]%100/10;
		dis_buf[7]=EEPROM_distance[distance_index%255]%10;
	}
	else if(jiemian==2)//盲区
	{
		dis_buf[0]=22;
		for(i=0;i<5;i++)
		 dis_buf[5-i]=21;
		dis_buf[6]=dead_zone/10;dis_buf[7]=dead_zone%10;
	}
}

void Led_Proc(void)
{
	if(jiemian==2)hkled[6]=1;
	else if(jiemian==1)hkled[7]=1;
	else hkled[6]=hkled[7]=0;
	hkled[0]=led_flash_flag?1:0;
	if(distance[distance_index]<=dead_zone)
		DA_out=0;
	else
		DA_out=(distance[distance_index]-dead_zone)*0.02*51;
	if(DA_out>255)DA_out=255;
	DA_output(DA_out);
}

void display(void)
{
	static uchar i=0;
	P2=(P2&0x1f)|0xe0;
	P0=0xff;P2=0;
	P0=0x00;
	P2=(P2&0x1f)|0xc0;
	P0=1<<i;P2=0;
	P0=0xff;
	P2=(P2&0x1f)|0xe0;
	P0=tab[dis_buf[i]];P2=0;
	if(++i==8)i=0;
}

void Tim2(void) interrupt 12
{
	display();
	if(++key_slow_down==10)key_slow_down=0;
	if(++seg_slow_down==500)seg_slow_down=0;
	if(++led_8bit==8)led_8bit=0;
	Led_Disp(led_8bit,hkled[led_8bit]);
	if(start_led1_flash_flag==1)//关于led灯的10此0.2s亮灭的计算 用4s去判断
	{
		Ms_tick++;
		if((Ms_tick%200)==0)
		{led_flash_flag^=1;}
		if(Ms_tick==4000)
		{Ms_tick=0;start_led1_flash_flag=0;}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值