51单片机之智能垃圾桶实战

项目采用51单片机,型号为STC89C52RC,主要为了熟练应用51单片机的功能。

一、项目描述

项目主要是模拟不用手动打开垃圾桶盖,而进行自动操作。自动打开的条件如下:

  • 1、垃圾桶检测到有人靠时自动打开桶盖
  • 2、发生震动时会自动打开
  • 3、可以手动按下按钮打开

二、项目用到的模块如下所示:

  1. HC-SR04(超声波模块)
  2. SG90(舵机模块)
  3. MH-sensor-series(振动传感器)
  4. 蜂鸣器,两个指示灯

三、项目源码

#include "reg52.h"
#include <intrins.h>


sbit pulse = P1^1; // sg90 signal
sbit trig = P1^5; // 超声波trig引脚
sbit echo = P1^6; // 超声波echo引脚

sbit beep = P2^0; // 蜂鸣器
sbit key = P2^1;  // 按钮
sbit vibrateData = P3^2; // 振动do引脚
sbit led2 = P3^6; 
sbit led1 = P3^7; 

int cnt = 0;
int phase = 1;
int vibrate;

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

	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

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

	_nop_();
	i = 2;
	j = 103;
	k = 147;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

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

	i = 2;
	j = 13;
	k = 237;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


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

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

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

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


¶æ»ú/
void sg90Init() {
	Delay300ms();
	TMOD &= 0XF0;
	TMOD |= 0X01;
	TL0 = 0X33;
	TH0 = 0XFE;
	TR0 = 1;
	ET0 = 1;
	EA = 1;
}

/Õñ¶¯/
void initExInt0() {
	IT0 = 0; // µÍµçƽ´¥·¢
	EX0 = 1; // ¿ªÆôÍⲿÖжÏ0
}

/·äÃùÆ÷/
void beep300ms() {
	int n;
	beep = 0;
	for(n=0;n<2;n++)
		Delay150ms();
	beep = 1;
}

/led/
void ledStatusWhenOpend() {
	led1 = 1;
	led2 = 0;
}

void ledStatusWhenClosed() {
	led1 = 0;
	led2 = 1;
}

/³¬Éù²¨/

// Éù²¨Ê¹ÓÃtimer 1
void initTimer1() {
	TMOD &= 0X0F;
	TMOD |= 0X10;
	TL1 = 0;
	TH1 = 0;
}

void uart_init() {
	TMOD &= 0X0F;
	TMOD |= 0X20;
	SCON = 0X40;
	TH1 = 0XFD;
	TL1 = 0XFD;
	TR1 = 1;
}

// ±£³Ö10us¸ßµçƽ
void trigWave() {
	trig = 0;
	trig = 1;
	Delay10us();
	trig = 0;
}

void startUltrasonicWave() {
	trigWave();
	while(echo == 0);
	TR1 = 1;
	while(echo == 1);
	TR1= 0;
}

double getDistance() {
	return (TH1 * 256 + TL1) * 1.085 * 0.017;
}

void main() {
	double distance;
	double lastPhase;
	initExInt0();
	sg90Init();
	initTimer1();
	while(1) {
		Delay200ms();
		startUltrasonicWave();
		distance = getDistance();
		if (distance < 10 || !key || vibrate) {
			ledStatusWhenOpend();
			
			phase = 3;
			if(lastPhase != phase) {
				cnt = 0;
				beep300ms();
				Delay2000ms();
			}  
			
			vibrate  = 0;
		} else {
			ledStatusWhenClosed();
			phase = 1;
			cnt = 0;
			Delay150ms();
		}
		lastPhase = phase;
		TL1 = 0;
		TH1 = 0;
	}
}

void timer0_pwm() interrupt 1 {
	cnt ++;
	TL0 = 0X33;
	TH0 = 0XFE;
	if (cnt < phase) {
		pulse = 1;
	} else {
		pulse = 0;
	}
	if (cnt == 40) {
		pulse = 1;
		cnt = 0;
	}
}

void exteral0() interrupt 0 {
	vibrate = vibrateData;
}
2.1、sg90舵机

      由于51没有引脚输出PWM,故只能使用软件定时器进行模拟。PWM有一个占位比的概念,所谓占空比就是一个脉冲周期内高电平持续的比例

sg90 旋转角度如下所示:

由上可以看出每个角度的高电平持续的时间都是0.5ms的倍数,所以可以用定时器定时0.5ms,那么在一个脉冲周期内需要定时器跑了20 / 0.5 = 40次,当舵机需要转0度时,高电平需要跑0.5 / 0.5 = 1次,同理旋转45度时,高电平需要跑1 / 0.5 = 2次等等。

项目使用51定时器0的模式1,即16位定时器/计数器,TL1、TH1全用。

定时器的原理是在一个机器周期内进行加1的操作。一个机器周期又等于n个时钟周期。

该51单片机使用的晶振频率为11.0592MHz,所以时钟周期为1/11.0592, 51单片机采用的是12T模式,所以单片机的机器周期=12 倍时钟周期,即机器周期为12 / 11.0592≈1.085us。如何定时0.5ms呢

16位定时器最大计数2^16=65536, 定时0.5ms 需要计数为 500 / 1.085 =  461, 那么需要预装 65536 - 461 = 0xFE33,所以TH1 = 0XFE ,TL1 = 0X33;

2.2、超声波

       这个没有什么好说的,按照时序图触发波和接收波就行了。

2.3、按钮

        按钮的监测采用轮询,可能会碰到轻按一下没有反应的状况,是因为按下是没有被检测到。

2.4、振动传感器

        振动传感器利用了定时器1中断,如果采用轮询的方式,灵敏度不如按键,所以采用定时器1中断检测

四、项目总结及遇到的问题

4.1、移位问题
double getDistance() {
    return (TH1 * 256 + TL1) * 1.085 * 0.017;
}

刚开始乘以 256 是利用的左移8位,即<<8, 但是计算的结果一直不正常,排查原因是TH1 是8位的寄存器,所以<<8变成0了,获取的值不正确。这个通过串口打印证实。

4.2、超声波不正常工作

按时序写完之后发现代码不正常运行,最终在main()函数内在启动超声波检测之前延时200ms,得以解决,这个可能和硬件有关,毕竟每个开发板都不可能完成相同。

4.3、物体靠近垃圾桶不动,导致舵机有细微抖动

 这个算软件bug,通过判断舵机当前的和上一次的状态解决

4.4、物体靠近垃圾桶不动,这时触发振动传感器,也会导致舵机抖动

当然只是一个简单的小项目,肯定在功能和体验上还有不完善的地方。

项目演示视频:

垃圾桶

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

俯仰一世_1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值