仿真图:
芯片/模块的特点:
AT89C52简介:
AT89C52是一款经典的8位单片机,是意法半导体(STMicroelectronics)公司生产的一系列单片机之一。它基于8051内核,并具有许多与其兼容的特性。
AT89C52的主要特点如下:
内部存储器:AT89C52具有8KB的闪存(Flash)存储器,可用于存储用户程序和数据。这些存储器的内容可以通过编程器进行编程和擦除。
RAM存储器:AT89C52配备了256字节的随机存取存储器(RAM),用于暂存数据和程序的变量。
外部扩展性:AT89C52支持多种外部扩展设备的连接,包括外部存储器(如RAM、EEPROM)和外设(如ADC、LCD、UART等),通过外部硬件连接,可以扩展单片机的功能和应用。
通用I/O引脚:AT89C52拥有32个可编程的通用输入/输出引脚,可用于连接外部设备和与其他芯片进行通信。
定时器/计数器:AT89C52内置了3个16位定时器/计数器和一个可编程的串行定时器/计数器。这些计时器/计数器可用于实现定时功能、生成脉冲信号、测量时间间隔等。0
串行通信:AT89C52支持串行通信接口,包括UART(串行异步通信)和SPI(串行外设接口),便于与其他设备进行数据通信和交互。
低功耗模式:AT89C52具有多种低功耗模式,如空闲模式和电源下模式,在不需要执行任务的时候可以将CPU进入低功耗状态以节省能量。
宽电源电压范围:AT89C52的工作电压范围通常为4.0V至5.5V,可以满足大多数应用需求。
HC-SR04特点:
- 非接触式测距:HC-SR04利用超声波技术进行测距,可以在不接触测量目标物的情况下获取距离信息。这种非接触式的特性使得它在许多应用中非常有用。
- 宽测量范围:HC-SR04可以测量的距离范围较广,通常为2厘米到400厘米。这使得它可以满足许多测量需求,从近距离到远距离的测量都可以应对。
- 高精度:HC-SR04测量距离的精度相对较高,可以达到3毫米左右。这对于需要较精确距离测量的应用是非常有益的。
- 易于使用:HC-SR04的使用非常简单,只需要提供一个触发信号,然后等待接收到回波信号,并通过计算来确定距离。它使用简单的电平触发和回波检测机制。
- 快速测量响应:HC-SR04可以快速地对目标进行测量并提供准确的结果。它的测量响应时间通常在几十毫秒的范围内。
- 低功耗:HC-SR04的功耗相对较低,适合在需要长时间运行或使用电池供电的应用中使用。
主程序:
#include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <stdio.h>
#include "delay.h"
//#include "math.h"
#define MANUAL 0
#define AUTO 1
sbit TRIG = P1^0; //出发放超声波
sbit ECHO = P1^1; //检测反馈
sbit LIGHT_FLAG = P1^2;
sbit HIGH_BEAM = P2^2; //远光灯
sbit LOW_BEAM = P2^3; //近光灯
sbit LED_MANUAL = P2^0; //手动模式指示灯
sbit LED_AUTO = P2^1; //自动模式指示灯
sbit KEY_CHANGE = P3^7; //远近光灯切换按键
sbit KEY_SWITCH = P3^6; //关灯按键
sbit KEY_MODE = P3^2; //自动手动切换
bit TrigFlag = 0; //触发标志
unsigned char LEDFlag = 0; //远近光灯标志
float distance = 0; //实际测试距离
bit modeFlag = 0; //手动自动模式变量
bit switchFlag = 0;
bit rekey0;
bit rekey1;
bit rekey2; //按键防止重复变量
void Timer0_Init(); //函数声明
void Timer1_Init();
void KeyProcess();
void main()
{
TRIG = 0;
Timer0_Init(); //定时器0初始化
Timer1_Init();
HIGH_BEAM = 0; //远光灯
LOW_BEAM = 0; //近光灯
LED_MANUAL = 0; //手动指示灯
LED_AUTO = 0; //自动指示灯
DelayS(1);
HIGH_BEAM = 1; //远光灯
LOW_BEAM = 1; //近光灯
LED_MANUAL = 1; //手动灯
LED_AUTO = 1; //自动灯
while (1) //主循环
{
if (TrigFlag == 1)
{
TR0 = 0;
TrigFlag = 0;
TRIG = 1; //启动一次模块 //不可以使用其他终端 容易造成死循环
DelayUs10x(1);
TRIG = 0;
while (!ECHO)
; //当RX为零时等待
TR1 = 1; //开启计数
while (ECHO)
; //当RX为1计数并等待
TR1 = 0;
distance = 1.12 * ((float)TH1 * 256 + TL1) * 17 / 100; //算出来是mm,1.12为系数
TH1 = 0;
TL1 = 0;
TH0 = (65536 - 18432) / 256; //重新赋值 20ms
TL0 = (65536 - 18432) % 256;
TR0 = 1;
}
if (switchFlag == 1)
{
if (modeFlag == AUTO) //自动模式下
{
LED_MANUAL = 1;
LED_AUTO = 0;
if (LIGHT_FLAG == 1) //光照暗
{
if (distance < 300)
{
LOW_BEAM = 0; //近光灯开
HIGH_BEAM = 1; //远光灯关
}
else
{
LOW_BEAM = 1; //近光灯关
HIGH_BEAM = 0; //远光灯开
}
}
else
{
LOW_BEAM = 1; //近光灯关
HIGH_BEAM = 1; //远光灯关
}
}
else
{
LED_MANUAL = 0;
LED_AUTO = 1;
if (LEDFlag == 0)
{
LOW_BEAM = 1; //近光灯关
HIGH_BEAM = 1; //远光灯关
}
else if (LEDFlag == 1)
{
LOW_BEAM = 0; //近光灯开
HIGH_BEAM = 1; //远光灯关
}
else
{
LOW_BEAM = 1; //近光灯关
HIGH_BEAM = 0; //远光灯开
}
}
}
else
{
LOW_BEAM = 1; //近光灯关
HIGH_BEAM = 1; //远光灯关
//指示灯闪烁,有助于判断程序是否运行
LED_MANUAL = 1;
LED_AUTO = 1;
DelayMs(250);
DelayMs(250);
LED_MANUAL = 0;
LED_AUTO = 0;
DelayMs(250);
DelayMs(250);
}
KeyProcess();
}
}
void KeyProcess()
{
if (switchFlag == 1)
{
if (KEY_MODE == 0) //手动自动切换
{
DelayMs(10);
if (KEY_MODE == 0 && rekey0 == 0)
{
rekey0 = 1;
modeFlag = ~modeFlag;
}
} //切换置位对应灯亮
else
{
rekey0 = 0;
}
if (modeFlag == MANUAL) //手动模式下
{
if (KEY_CHANGE == 0) //远光灯切换按键
{
DelayMs(10);
if (KEY_CHANGE == 0 && rekey1 == 0) //远光灯切换按键
{
rekey1 = 1;
if (LEDFlag >= 2)
{
LEDFlag = 1;
}
else
{
LEDFlag++;
}
}
}
else
{
rekey1 = 0;
}
}
}
if (KEY_SWITCH == 0) //切换按键
{
DelayMs(10);
if (KEY_SWITCH == 0 && rekey2 == 0) //切换按键
{
rekey2 = 1;
switchFlag = ~switchFlag;
}
}
else
{
rekey2 = 0;
}
}
void Timer0_Init()
{
TMOD &= 0xF0;
TMOD |= 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0 = (65536 - 18432) / 256; //重新赋值 20ms
TL0 = (65536 - 18432) % 256;
EA = 1; //总中断打开
ET0 = 1; //定时器中断打开
TR0 = 1; //定时器开关打开
}
void Timer1_Init()
{
TMOD &= 0x0F;
TMOD |= 0x10; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH1 = 0;
TL1 = 0;
EA = 1; //总中断打开
ET1 = 1; //定时器中断打开
TR1 = 0; //定时器开关关闭
}
void Timer0_Interrupt() interrupt 1
{
static unsigned int cnt = 0;
TH0 = (65536 - 18432) / 256; //重新赋值 20ms
TL0 = (65536 - 18432) % 256;
cnt++;
if (cnt > 50) //1s定时发出超声波
{
TrigFlag = 1;
cnt = 0;
}
}
void Timer1_Interrupt() interrupt 3
{
TH1 = 0;
TL1 = 0;
}
设计文件: