C51:感应开盖垃圾桶

目录

一  超声波模块

超声波模块

怎么让它发送波

怎么知道它开始发了

怎么知道接收了返回波

怎么算时间

怎么算距离

 代码:

二 超声波感应自动开盖、 按键开盖

材料:

需求:

双计时器:

三 添加震动开盖(外部中断)

四 最终效果


效果展示: 

基于C52单片机的感应开盖垃圾桶

一  超声波模块

超声波模块

 型号:HC-SR04

接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我们开发板

P1.5 和 P1.6 端口

超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,
计算出模块到前方障碍物的距离。

怎么让它发送波

Trig ,给Trig端口至少10us的高电平

怎么知道它开始发了

Echo信号,由低电平跳转到高电平,表示开始发送波

怎么知道接收了返回波

Echo,由高电平跳转回低电平,表示波回来了

怎么算时间

Echo引脚维持高电平的时间!

波发出去的那一下,开始启动定时器

波回来的拿一下,我们开始停止定时器,计算出中间经过多少时间

怎么算距离

距离 = 速度 (340m/s)* 时间/2

 代码:

设置定时器为初始状态,4行代码,然后利用进制运算换算出时间,再求出距离

    //计算时间
        time = (TH0 * 256 + TL0)*1.085;//us
        
    //计算距离
        dist = time * 0.017;//cm

#include "reg52.h"

sbit Trig = P1^5;
sbit Echo = P1^6;
sbit led1 = P3^7;
sbit led2 = P3^6;

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

void send(){
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}

void Timer0Init(void)		//71毫秒@11.0592MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;
	TL0 = 0;		//设置定时初值
	TH0 = 0;		//设置定时初值
}

void main()
{
	double time;
	double dist;
	
	Timer0Init();	
	
	while(1){
	//发送信号
		send();
		
	//Echo信号,由低电平跳转到高电平,表示开始发送波
		while(Echo == 0);
		TR0 = 1;//开始计时
		
	//Echo,由高电平跳转回低电平,表示波回来了
		while(Echo == 1);
		TR0 = 0;//停止计时
		
	//计算时间
		time = (TH0 * 256 + TL0)*1.085;//us
		
	//计算距离
		dist = time * 0.017;//cm
		
	//根据距离亮灯
		if(dist < 10){
			led1 = 0;
			led2 = 1;
		}else{
			led1 = 1;
			led2 = 0;
		}
		
		TL0 = 0;		//设置定时初值
		TH0 = 0;
	}
}

二 超声波感应自动开盖、 按键开盖

材料:

舵机 超声波模块 蜂鸣器

需求:

检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖

双计时器:

由于舵机和超声波都需要计时器,所以把T0;T1两个计时器分别使用

将上述距离检测定时器T0改为T1;并且封装函数:

#include "reg52.h"

sbit Trig = P1^5;
sbit Echo = P1^6;
sbit led1 = P3^7;
sbit led2 = P3^6;

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

void send(){
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}

void Timer1Init(void)
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x00;		//设置定时初值
}

double dist;
double time;
void getDistance(){
	
//发送信号
	send();
		
//Echo信号,由低电平跳转到高电平,表示开始发送波
	while(Echo == 0);
	TR1 = 1;//开始计时
		
//Echo,由高电平跳转回低电平,表示波回来了
	while(Echo == 1);
	TR1 = 0;//停止计时
		
//计算时间
	time = (TH1 * 256 + TL1)*1.085;//us
		
//计算距离
	dist = time * 0.017;//cm
}

void main()
{
	Timer1Init();	
	
	while(1){
		getDistance();
		
	//根据距离亮灯
		if(dist < 10){
			led1 = 0;
			led2 = 1;
		}else{
			led1 = 1;
			led2 = 0;
		}
		
		TL1 = 0;		//设置定时初值
		TH1 = 0;
	}
}

运行成功。

实现:

将PWM舵机控制的代码与上述代码进行结合

(30条消息) C52:PWM+舵机角度控制_我有在好好学习的博客-优快云博客

 多封装函数,

注意两个定时器配置别冲突了

T0:
    TMOD &= 0xF0; 
    TMOD |= 0x01;

T1:
    TMOD &= 0x0F; 
    TMOD |= 0x10;      
 

#include "reg52.h"
#include <intrins.h>
 
//舵机引脚
sbit sg90_con = P1^1;
//蜂鸣器
sbit buzzer 	= P1^2;
//超声波
sbit Trig 		= P1^5;
sbit Echo 		= P1^6;
//led
sbit led1			= P3^7;
sbit led2 		= P3^6;
//按键
sbit key1			= P2^0;
 
int angle;
int cnt = 0;
 
void Timer0Init()//500微秒;T0
{
//1. 配置定时器0工作模式位16位计时
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;
//2. 给初值,定一个10ms出来
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
//3. 开始计时,定时器"数数"
	TR0 = 1;
	TF0 = 0;
//4. 打开定时器0中断
	ET0 = 1;
//5. 打开总中断EA
	EA = 1;
}

void Timer1Init(void)//测距使用;T1
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x00;		//设置定时初值
}

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

void send(){//发出超声波
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
 
void Delay1500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 11;
	j = 130;
	k = 111;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
//测距功能:
double dist;
double time;
void getDistance(){
//发送信号
	send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
	while(Echo == 0);
	TR1 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
	while(Echo == 1);
	TR1 = 0;//停止计时
//计算时间
	time = (TH1 * 256 + TL1)*1.085;//us
//计算距离
	dist = time * 0.017;//cm
	
	TL1 = 0;		//设置定时初值
	TH1 = 0;
}
 
void Open(){
	//Turn the Lihgt
	led1 = 0;
	led2 = 1;
	//open buzzer
	buzzer = 0;
	//open lid
	angle = 3;//90度
	cnt = 0;
	Delay500ms();
	//close buzzer
	buzzer = 1;
	Delay1500ms();
}

void Close(){
	//Turn the Lihgt
	led1 = 1;
	led2 = 0;
	//close lid
	angle = 1;//0度
	cnt = 0;
}

//================================================
void main()
{	
	Delay500ms();
	
	Timer1Init();
	Timer0Init();
	
	while(1){
		
		getDistance();

	//根据距离亮灯
		if(dist < 10 || key1 == 0){
			
			Open();
		}else{
			
			Close();
		}
	}
}
//=================================================
void Time0Handler() interrupt 1
{
	cnt++; //统计爆表的次数
	
//重新给初值
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	
	if(cnt < angle){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	
	if(cnt == 40){//爆表40次,经过了20ms
		
	cnt = 0; //计算下一次的20ms
	sg90_con = 1;
		
	}
}

三 添加震动开盖(外部中断)

发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
代码相同,但是震动导致的低电平时间很短,不容易被检测到

所以采用中断

 

CPU能响应定时器0中断的条件:需要配置IE寄存器的 bit1: ET0 bit7:EA
1. ET0中断允许要置一 ET0 = 1
2. EA总中断要置一 EA = 1 

 //打开外部中断
EX0 = 1;
//低电平触发
IT0 = 0;

#include "reg52.h"
#include <intrins.h>
 
//舵机引脚
sbit sg90_con = P1^1;
//蜂鸣器
sbit buzzer 	= P1^2;
//超声波
sbit Trig 		= P1^5;
sbit Echo 		= P1^6;
//led
sbit led1		= P3^7;
sbit led2 		= P3^6;
//按键
sbit key1		= P2^0;
//震动传感器,外部中断,这里其实不用定义,插上就行
sbit vibrate	= P3^2;
 
int angle;
int cnt = 0;
char vib_mark = 0;//char省空间
 
void Timer0Init()//500微秒;T0
{
//1. 配置定时器0工作模式位16位计时
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;
//2. 给初值,定一个10ms出来
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
//3. 开始计时,定时器"数数"
	TR0 = 1;
	TF0 = 0;
//4. 打开定时器0中断
	ET0 = 1;
//5. 打开总中断EA
	EA = 1;
}

void Timer1Init(void)//测距使用;T1
{
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0x00;		//设置定时初值
}

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}

void send(){//发出超声波
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
 
void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}



void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void vibrate_EX0_init(){
	//打开外部中断
	EX0 = 1;

	//低电平触发
	IT0 = 0;
}



//测距功能:
double dist;
double time;
void getDistance(){
//发送信号
	send();
//Echo信号,由低电平跳转到高电平,表示开始发送波
	while(Echo == 0);
	TR1 = 1;//开始计时
//Echo,由高电平跳转回低电平,表示波回来了
	while(Echo == 1);
	TR1 = 0;//停止计时
//计算时间
	time = (TH1 * 256 + TL1)*1.085;//us
//计算距离
	dist = time * 0.017;//cm
	
	TL1 = 0;		//设置定时初值
	TH1 = 0;
}
 
void Open(){
	//Turn the Lihgt
	led1 = 0;
	led2 = 1;
	//open buzzer
	buzzer = 0;
	//open lid
	angle = 3;//90度
	Delay500ms();
	//close buzzer
	buzzer = 1;
	
	Delay1000ms();
	//if close lid
	while(dist < 10){
		getDistance();
	}
	Delay500ms();
	vib_mark = 0;
}

void Close(){
	//Turn the Lihgt
	led1 = 1;
	led2 = 0;
	//close lid
	angle = 1;//0度
}

//================================================
void main()
{	
	Delay500ms();
	
	Timer1Init();
	Timer0Init();
	vibrate_EX0_init();
	
	while(1){
		
		getDistance();


	//根据距离亮灯
		if(dist < 10 || key1 == 0 || vib_mark == 1){
			
			Open();
		}else{
			
			Close();
		}
	}
}
//=================================================
void Time0Handler() interrupt 1
{
	cnt++; //统计爆表的次数
	
//重新给初值
	TL0 = 0x33;		//设置定时初值
	TH0 = 0xFE;		//设置定时初值
	
	if(cnt < angle){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	
	if(cnt == 40){//爆表40次,经过了20ms
		
	cnt = 0; //计算下一次的20ms
	sg90_con = 1;
		
	}
}

void EX0_handler() interrupt 0
{
	vib_mark = 1;
	
}

四 最终效果

震动、按钮或者超声波距离检测,触发蜂鸣器饷以及开盖2秒。

两秒后,如果人还一直在检测范围内,就不关盖。

基于C52单片机的感应开盖垃圾桶

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值