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