基于89C51单片机的智能垃圾桶

PWM开发SG90

1. 简介

PWM,英文名Pulse Width Modulation,是脉冲宽度调制缩写,它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。
总结:
脉冲宽度调制
通过占空比编码模拟信号
占空比 一个周期内,高电平占据时长的百分比
在这里插入图片描述

2.如何实现PWM信号输出

1.通过芯片内部模块输出,一般观察手册或者芯片IO口都会标明这个是否是PWM口如下图增强51,STC15w的CPU
在这里插入图片描述
2. 如果没有集成PWM功能,可以通过IO口软件模拟,相对硬件PWM来说精准度略差

3.控制舵机

  1. 什么是舵机
    如下图所示,最便宜的舵机sg90,常用三根或者四根接线,黄色为PWM信号控制
    用处:垃圾桶项目开盖用、智能小车的全比例转向、摄像头云台、机械臂等
    常见的有0-90°、0-180°、0-360°
    在这里插入图片描述
  2. 怎么控制舵机
    向黄色信号线“灌入”PWM信号。
    PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右
    数据:
    0.5ms-------------0度; 2.5% 对应函数中占空比为250
    1.0ms------------45度; 5.0% 对应函数中占空比为500
    1.5ms------------90度; 7.5% 对应函数中占空比为750
    2.0ms-----------135度; 10.0% 对应函数中占空比为1000
    2.5ms-----------180度; 12.5% 对应函数中占空比为1250
    定时器需要定时20ms, 关心的单位0.5ms, 40个的0.5ms,初值0.5m cnt++
    1s = 10ms * 100
    20ms = 0.5ms * 40
  3. 编程实现
    在这里插入图片描述
/*******************************************************
*********舵机黄色信号线接P1.1口,每隔2秒从0度到135度切换********
*************注意:初值不要算错,修改位置两个地方**************
*******************************************************/
#include "reg52.h"
#include<intrins.h> 

sbit sg90_con = P1^1;
int jd;
int cnt = 0;

void Delay2000ms() //@11.0592MHz
{
	unsigned char i, j, k;
	
	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Time0Init()
{
	//1. 配置定时器0工作模式位16位计时
	TMOD = 0x01;
	//2. 给初值,定一个0.5出来
	TL0=0x33;
	TH0=0xFE;
	//3. 开始计时
	TR0 = 1;
	TF0 = 0;
	//4. 打开定时器0中断
	ET0 = 1;
	//5. 打开总中断EA
	EA = 1;
}

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

	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void main()
{
	Delay300ms();//让硬件稳定一下
	Time0Init(); //初始化定时器
	jd = 1; //初始角度是0度,0.5ms,溢出1就是0.5,高电平
	cnt = 0;
	sg90_con = 1;//一开始从高电平开始
	//每隔两秒切换一次角度
	while(1){
		jd = 4; //135度 2ms高电平
		cnt = 0;
		Delay2000ms();
		jd = 1; //0度
		cnt = 0;
		Delay2000ms();
	}
}
void Time0Handler() interrupt 1
{
	cnt++; //统计爆表的次数. cnt=1的时候,报表了1
	//重新给初值
	TL0=0x33;
	TH0=0xFE;
	//控制PWM波
	if(cnt < jd){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	if(cnt == 40){//爆表40次,经过了20ms
		cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s
		sg90_con = 1;
	}
}

超声波测距

1.简介

型号:HC-SR04
接线参考:模块除了两个电源引脚外,还有TRIG,ECHO引脚,这两个引脚分别接我们开发板的P1.5和P1.6端口
在这里插入图片描述
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,
计算出模块到前方障碍物的距离。
怎么让它发送波

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

怎么知道它开始发了

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

怎么知道接收了返回波

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

怎么算时间

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

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

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

怎么算距离

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

2.超声波的时序图

在这里插入图片描述

超声波测距代码实现

#include "reg52.h"
//距离小于10cm,D5亮,D6灭,反之相反现象
sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit Trig = P1^5;
sbit Echo = P1^6;
void Delay10us() //@11.0592MHz
{
	unsigned char i;
	i = 2;
	while (--i);
}
void Time0Init()
{
	TMOD &= 0xF0; //设置定时器模式
	TMOD |= 0x01;
	TH0 = 0;
	TL0 = 0;
	//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}
/*
十进制2左移1位,变成20。相当于乘以10
二禁止1左移1位,变成10(2)。相当于乘以2,左移8位,乘以2的8次方=256;*/
void startHC()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0;
}
void main()
{
	double time;
	double dis;
	Time0Init();
	while(1){
		//1. Trig ,给Trig端口至少10us的高电平
		startHC();
		//2. echo由低电平跳转到高电平,表示开始发送波
		while(Echo == 0);
		//波发出去的那一下,开始启动定时器
		TR0 = 1;
		//3. 由高电平跳转回低电平,表示波回来了
		while(Echo == 1);
		//波回来的那一下,我们开始停止定时器
		TR0 = 0;
		//4. 计算出中间经过多少时间
		time = (TH0 * 256 + TL0)*1.085;//us为单位
		//5. 距离 = 速度 (340m/s)* 时间/2
		dis = time * 0.017;
		if(dis < 10){
			D5 = 0;
			D6 = 1;
		}else{
			D5 = 1;
			D6 = 0;
		}
		//定时器数据清零,以便下一次测距
		TH0 = 0;
		TL0 = 0;
	}
}

感应开关盖垃圾桶代码实现

1.项目概述

功能描述
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
硬件说明
SG90舵机,超声波模块,震动传感器,蜂鸣器
接线说明
舵机控制口 P1.1;超声波Trig接 P1.5 ,Echo接 P1.6 ;蜂鸣器接 P2.0 口; 震动传感器接 P3.2口(外部
中断0)

2.开发步骤

  1. 舵机和超声波代码整合
    舵机用定时器0
    超声波用定时器1
    实现物体靠近后,自动开盖,2秒后关盖
  2. 查询的方式添加按键控制
  3. 查询的方式添加震动控制
  4. 使用外部中断0配合震动控制

3.编程实现

/*
检测靠近时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
发生震动时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
按下按键时,垃圾桶自动开盖并伴随滴一声,2秒后关盖
*/
#include "reg52.h"
#include<intrins.h> 

sbit D5 = P3^7;//根据原理图(电路图),设备变量led1指向P3组IO口的第7口
sbit D6 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
sbit SW1 = P2^1;
sbit Trig = P1^5;
sbit Echo = P1^6;
sbit sg90_con = P1^1;
sbit vibrate = P3^2;
sbit beep = P2^0;

char jd;
char jd_bak;
char cnt = 0;
char mark_vibrate = 0;

void Delay150ms() //@11.0592MHz
{
	unsigned char i, j, k;
	_nop_();
	i = 2;
	j = 13;
	k = 237;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay2000ms() //@11.0592MHz
{
	unsigned char i, j, k;
	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay10us() //@11.0592MHz
{
	unsigned char i;
	i = 2;
	while (--i);
}

void Time0Init()
{
	//1. 配置定时器0工作模式位16位计时
	TMOD &= 0xF0; //设置定时器模式
	TMOD |= 0x01;
	//2. 给初值,定一个0.5出来
	TL0=0x33;
	TH0=0xFE;
	//3. 开始计时
	TR0 = 1;
	TF0 = 0;
	//4. 打开定时器0中断
	ET0 = 1;
	//5. 打开总中断EA
	EA = 1;
}

void Time1Init()
{
	TMOD &= 0x0F; //设置定时器模式
	TMOD |= 0x10;
	TH1 = 0;
	TL1 = 0;
	//设置定时器0工作模式1,初始值设定0开始数数,不着急启动定时器
}

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

double get_distance()
{
	double time;
	//定时器数据清零,以便下一次测距
	TH1 = 0;
	TL1 = 0;
	//1. Trig ,给Trig端口至少10us的高电平
	startHC();
	//2. echo由低电平跳转到高电平,表示开始发送波
	while(Echo == 0);
	//波发出去的那一下,开始启动定时器
	TR1 = 1;
	//3. 由高电平跳转回低电平,表示波回来了
	while(Echo == 1);
	//波回来的那一下,我们开始停止定时器
	TR1 = 0;
	//4. 计算出中间经过多少时间
	time = (TH1 * 256 + TL1)*1.085;//us为单位
	//5. 距离 = 速度 (340m/s)* 时间/2
	return (time * 0.017);
}

void openStatusLight()
{
	D5 = 0;
	D6 = 1;
}

void closeStatusLight()
{
	D5 = 1;
	D6 = 0;
}

void initSG90_0()
{
	jd = 1; //初始角度是0度,0.5ms,溢出1就是0.5,高电平
	cnt = 0;
	sg90_con = 1;//一开始从高电平开始
}

void openDusbin()
{
	char n;
	jd = 3; //90度 1.5ms高电平
	//舵机开盖
	if(jd_bak != jd){
		cnt = 0;
		beep = 0;
		for(n=0;n<2;n++)
			Delay150ms();
		beep = 1;
		Delay2000ms();
	}
	jd_bak = jd;
}

void closeDusbin()
{
	//关盖
	jd = 1; //0度
	if(jd_bak != jd){
		cnt = 0;
		Delay150ms();
	}
	jd_bak = jd;
}
void EX0_Init()
{
	//打开外部中断
	EX0 = 1;
	//低电平触发
	IT0 = 0;
}

void main()
{
	double dis;
	Time0Init();
	Time1Init();
	EX0_Init();
	//舵机的初始位置
	initSG90_0();
	while(1){
		//超声波测距
		dis = get_distance();
		if(dis < 10 || SW1 == 0 || mark_vibrate == 1){//如果小于10厘米,或者sw1按键被按下
			//开盖,灯状态,D5亮
			openStatusLight();
			openDusbin();
			mark_vibrate = 0;
		}else{
			//关盖,灯状态,D5灭
			closeStatusLight();
			closeDusbin();
		}
	}
}

void Time0Handler() interrupt 1
{
	cnt++; //统计爆表的次数. cnt=1的时候,报表了1
	//重新给初值
	TL0=0x33;
	TH0=0xFE;
	//控制PWM波
	if(cnt < jd){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	if(cnt == 40){//爆表40次,经过了20ms
		cnt = 0; //当100次表示1s,重新让cnt从0开始,计算下一次的1s
		sg90_con = 1;
	}
}

void Ex0_Handler() interrupt 0
{
	mark_vibrate = 1;
}
  • 19
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从入门到捕蛇者说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值