**
@蓝桥杯单片机设计第八届国赛超声波测距
题目
提取码:asdf
**
代码:
1、main.c
#include "STC15F2K60S2.H"
#include "key.h"
#include "ultrasonic.h"
#include "iic.h"
#define u8 unsigned char
#define u16 unsigned int
/*
*@
*@ 函 数 声 明 区
*@
*/
void system_init();
void timer_0_init();
void read_save_dat();
void key_processing();
void smg_display(unsigned char what[]);
void led_processing();
void Delay10ms();
/*
*@
*@ 变 量 定 义 区
*@
*/
u8 code smg_duan[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x00,0x40,0x39,0x71};
//0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 灭 - C 01110001
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
/*
test_display[] 是 测距显示的 第一个界面
dat_huixian[] 是 数据回显的 第二个界面
test_deadArray[] 是 盲区
the_distance_4[] 第一个元素没有用,1到4分别对应4次的测量、
smg_buff[] 是数码缓冲数组
key_vaule 是按下按键所返回的值 取值为 4,5,6,7 或者 0(见key.c文件的 void key_btn() )
menu_index 用于界面切换 ,本题共有三个界面要显示 取值为 0 1 2
Dis_index 所以测量的四次结果 yiwei 用于 当测量次数 超过4次,覆盖测量的数据
current_dis 当前测量的距离 last_dis 上一次测量的距离
tes_dead 盲区距离
led1_count 测量完成后,每一秒加一,直到加到6(亮灭三次 共 6s)
count_1000ms 每1ms 从0开始加,加到1000 表示1s到 , 初值为 1000 即 测量完成 led是 先 亮
flag_1s 用于测量完成后,led间隔1s 亮灭的使能控制 finish_En 每次测量完成的标志,
*/
u8 test_display[8] = {22,20,20,20,20,20,20,20} ;
u8 dat_huixian[8] = {20,20,20,20,20,20,20,20} ;
u8 test_deadArray[8] = {23,20,20,20,20,20,20,20};
u8 the_distance_4[5] = {0,0,0,0,0};
u8 smg_buff[8];
u8 key_vaule = 0 ;
u8 menu_index = 0 ;
u8 Dis_index = 1 , yiwei = 0;
u8 current_dis = 0 , last_dis = 0 ;
u8 tes_dead = 20 ;
u8 led1_count = 0 ;
u16 count_1000ms = 1000 ;
bit flag_1s = 0 , finish_En = 0;
/*
*@
*@ 主 程 序
*@
*/
void main()
{
read_save_dat();
system_init();
timer_0_init();
while(1)
{
// 界面0 测量数据 界面
test_display[2] = current_dis / 100; test_display[3] = current_dis / 10 % 10; test_display[4] = current_dis % 10;
test_display[5] = last_dis / 100; test_display[6] = last_dis / 10 % 10; test_display[7] = last_dis % 10;
// 界面1 数据回显
dat_huixian[0] = Dis_index ;
/*
以下的 5 - Dis_index ,关于是否有 5 - 看是想显示第一次测量、第二次测量.......
还是显示 最近一次测量、最近第二次测量............
*/
dat_huixian[5] = the_distance_4[5-Dis_index] / 100 ;dat_huixian[6] = the_distance_4[5-Dis_index] / 10 % 10 ;
dat_huixian[7] = the_distance_4[5-Dis_index] % 10 ;
// 界面2 盲区
test_deadArray[6] = tes_dead / 10; test_deadArray[7] = tes_dead % 10;
}
}
/*
*@
*@ 定 时 器 0 中 断 服 务 子 程 序
*@
*/
void timer_0_processing() interrupt 1
{
static int count_2ms = 0 , count_10ms = 0 ;
count_2ms++; count_10ms++;
if(finish_En == 1)
{
if(count_1000ms >= 1000)
{
led1_count++;
count_1000ms = 0 ;
flag_1s = !flag_1s ;
}
count_1000ms++ ;
}
if(count_2ms == 2)
{
count_2ms = 0 ;
smg_display(smg_buff); // 2ms 扫面一次数码管
led_processing(); // led 显示
}
if(count_10ms == 10) // 10ms 扫描一次按键函数 , 写 DA
{
count_10ms = 0 ;
key_processing();
if(current_dis <= tes_dead )
{
write_dac(0);
}
else
{
if( ( (current_dis - tes_dead)*0.02 + 0.04) * 51 > 255)
{
write_dac(255);
}
write_dac(( (current_dis - tes_dead)*0.02 + 0.04)*51);
}
}
}
/*
*@
*@ 按 键 子 程 序
*@
*/
void key_processing()
{
u8 EEPROM_index = 0 ;
key_vaule = key_btn();
switch(key_vaule)
{
case(4):last_dis = current_dis ; // 将本次数据给上次数据 然后再次测量获得本次数据
current_dis = sonic_wave();
finish_En = 1 ;led1_count = 0 ; // 测量完成 ,相应的控制位 赋值 ,
count_1000ms = 1000 ;
// 实 现 数 据 覆 盖
for(yiwei = 3 ; yiwei > 0 ; yiwei--)
{
the_distance_4[yiwei + 1] = the_distance_4[yiwei] ;
}
the_distance_4[1] = current_dis ;
// 将 数 据 保 存 到 ROM
for(EEPROM_index = 1 ; EEPROM_index < 5 ; EEPROM_index++)
{
write_24c02(EEPROM_index,the_distance_4[EEPROM_index]);
Delay10ms();
}
break;
case(5):if(menu_index == 0)
{
Dis_index = 1 ; // 每次界面从 测量进入回显 ,都从第一个下标开始
menu_index = 1;
}
else if(menu_index == 1)
menu_index = 0 ;
break;
case(6):if(menu_index != 2 )
{
menu_index = 2 ;
}
else
{
menu_index = 0 ;
}
break;
case(7):if(menu_index == 1)
{
Dis_index++;
if(Dis_index == 5)Dis_index = 1 ;
}
if(menu_index == 2)
{
tes_dead += 10 ;
if(tes_dead >= 40)tes_dead = 0 ;
write_24c02(5,tes_dead);
Delay10ms();
}
break;
}
}
/*
*@
*@ 显 示子 程 序
*@
*/
void smg_display(unsigned char what[])
{
static int where = 0 ;
u8 i ;
// 根据当前的界面 匹配相应的段码
for(i = 0 ; i < 8 ; i++)
{
switch(menu_index)
{
case(0):what[i] = ~smg_duan[test_display[i]];break;
case(1):what[i] = ~smg_duan[dat_huixian[i]];break;
case(2):what[i] = ~smg_duan[test_deadArray[i]];break;
}
}
P2 = 0X00 ; P0 = 0 ; P2 = 0XC0;
P2 = 0X00 ; P0 = smg_wei[where] ; P2 = 0XC0 ;
P2 = 0X00 ; P0 = what[where] ; P2 = 0XE0 ;
where++;if(where == 8)where = 0 ;
}
/*
*@
*@ led 指示
*@
*/
void led_processing()
{
if(menu_index == 0)
{
if(led1_count < 6)
{
if(flag_1s == 1)
{
P2 = 0X00 ; P0 = 0Xfe ; P2 = 0X80 ;
}
else
{
P2 = 0X00 ; P0 = 0xff ; P2 = 0X80 ;
}
}
else
{
led1_count = 0 ;
finish_En = 0 ; flag_1s = 0 ;
P2 = 0X00 ; P0 = 0xff ; P2 = 0X80 ;
}
}
else if(menu_index == 1)
{
P2 = 0X00 ; P0 = 0xbf ; P2 = 0X80 ;
}
else
{
P2 = 0X00 ; P0 = 0x7f ; P2 = 0X80 ;
}
}
/*
*@
*@ 初 始 化
*@
*/
void timer_0_init()
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初值
TH0 = 0xD1; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1 ;
EA = 1 ;
}
void system_init()
{
P2 = 0X00 ; P0 = 0XFF ; P2 = 0X80 ;
P2 = 0X00 ; P0 = 0X00 ; P2 = 0XA0 ;
}
void read_save_dat()
{
tes_dead = read_24c02(5);
the_distance_4[1] = read_24c02(1);
the_distance_4[2] = read_24c02(2);
the_distance_4[3] = read_24c02(3);
the_distance_4[4] = read_24c02(4);
}
void Delay10ms() //@12.000MHz
{
unsigned char i, j;
i = 117;
j = 184;
do
{
while (--j);
} while (--i);
}
2 、key.c
#include "key.h"
#define key_state0 0
#define key_state1 1
#define key_state2 2
unsigned char key_btn()
{
static char key_state = key_state0 ;
unsigned char key_press,key_return = 0 ;
if(P33 == 0)key_press = 0X07 ;
else if(P32 == 0)key_press = 0X0b ;
else if(P31 == 0)key_press = 0X0d ;
else if(P30 == 0)key_press = 0X0e ;
else key_press = 0x0f ;
switch(key_state)
{
case(key_state0):if(key_press != 0x0f )
{
key_state = key_state1 ;
}
break;
case(key_state1):if(key_press != 0x0f)
{
if(key_press == 0x07)key_return = 4 ;
if(key_press == 0x0b)key_return = 5 ;
if(key_press == 0x0d)key_return = 6 ;
if(key_press == 0x0e)key_return = 7 ;
key_state = key_state2 ;
}
else
{
key_state = key_state0 ;
}
break;
case(key_state2):if(key_press == 0x0f)
{
key_state = key_state0 ;
}
break ;
}
return key_return ;
}
3 、iic.c
#include "iic.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;
}
void write_24c02(unsigned char adress ,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(adress);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char read_24c02(unsigned char address)
{
unsigned char temp = 0 ;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(address);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_WaitAck();
IIC_Stop();
return temp ;
}
void write_dac(unsigned char dat)
{
unsigned char temp = 0 ;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
4、ultrasonic.c
#include "ultrasonic.h"
#include "intrins.h"
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void send_wave(unsigned char how_many)
{
unsigned char i;
TX = 0 ;
for(i = 0 ; i < how_many ; i++)
{
TX = !TX ;
Delay12us();
}
}
unsigned char sonic_wave()
{
unsigned char DIS ;
AUXR &= 0XBF ; // 1011 1111
TMOD &= 0X0F;
TF1 = 0 ;
TR1 = 0 ;
TH1 = 0 ;
TL1 = 0 ;
ET1 = 0;
send_wave(4);
TR1 = 1 ;
EA = 0 ;
while((RX == 1)&&(TF1 == 0));
TR1 = 0 ;
EA = 1 ;
if(TF1 == 1)
{
TF1 = 0;
DIS = 255;
}
else
{
DIS = ( (TH1<<8) | TL1 )* 0.017 ;
}
return DIS;
}
注:相应的头文件就是把需要用到的函数声明一下,头文件的格式就是
#如果没有定义 xxx
#那就定义 xxx
#include “STC15F2K60S2.H”
包含需要调用的函数
#endif
这里空一行
另外超声波里定义了引脚
见下:
#ifndef _ULTRESONIC_H
#define _ULTRESONIC_H
#include "STC15F2K60S2.H"
sbit TX = P1^0 ;
sbit RX = P1^1 ;
unsigned char sonic_wave();
#endif