【STC89C51单片机控制舵机的综合应用】

一、项目概述

1、功能描述

超声波模块,震动传感器,按键控制SG90舵机

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

发生震动时,垃圾桶自动开盖并伴随滴一声,
2
秒后关盖

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

2、硬件部分

SG90舵机,超声波模块,震动传感器,蜂鸣器

3、接线说明

舵机(PWM)信号线 —> P1.1(定时器0)
超声波HC-SR04   Trig —> P1.5 、Echo —> P1.6 (定时器1)
震动传感器 —> P3.2(外部中断0)
蜂鸣器 —> P2.0

二、基础参考

【51单片机STC89C52】定时器(中断)控制LED_大头1213

【51单片机STC89C52】IO口模拟PWM控制SG90舵机_大头1213

【51单片机STC89C52】HC-SR04超声波模块测距_大头1213

三、部分代码

1、接线部分

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

2、超声波测距

double get_distance()
{
		double time;
		//定时器数据清零,以便下一次测距
		TH1 = 0;
		TL1 = 0;
	    //1. 让它发送波:给Trig端口至少10us的高电平
		startHC();
		//2. 开始发送波:Echo信号由低电平跳转到高电平
		while(Echo == 0);
		//   开始发送波,启动定时器
		TR1 = 1;
		//3. 接收返回波:Echo信号由高电平跳转回低电平
		while(Echo == 1);
		//   接收返回波,停止定时器
		TR1 = 0;
		//4. 计算时间
		time = (TH1 * 256 + TL1)*1.085;//us为单位
		//5. 距离 = 速度 (340m/s)* 时间/2
		return  (time * 0.017);
}

3、舵机——定时器0中断服务函数

void Time0Handler() interrupt 1
{
	cnt++;  					//统计溢出的次数
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	
	//控制PWM波
	if(cnt < angle){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	
	if(cnt == 40){				//当溢出40次,经过了20ms
		cnt = 0;  				
		sg90_con = 1;
	}		
}

4、震动传感器——外部中断0

打开外部中断

void EX0_Init()
{
	EX0 = 1;//打开外部中断
	IT0 = 0;//低电平触发
}

中断服务函数

void Ex0_Handler() interrupt 0
{
	mark_vibrate = 1;
}

5、开关盖函数

void openDustbin()
{
	char n;
	angle = 3; //90度 1.5ms高电平
	//舵机开盖
	if(angle_bak != angle){
		cnt = 0;
		beep = 0;
		Delay150ms();
        Delay150ms();
		beep = 1;
		Delay2000ms();
	}
	
	angle_bak = angle;
	
}

void closeDustbin()
{
	//关盖
	angle = 1; //0度
	angle_bak = angle;
	cnt = 0;
	Delay150ms();
}

四、整体代码

#include "reg52.h"
#include "intrins.h"

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

char angle;
char angle_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 Timer0Init(void)		//500微秒@11.0592MHz
{
	//AUXR &= 0x7F;		
	TMOD &= 0xF0;	//设置定时器模式16位
	TMOD |= 0x01;	//设置定时器模式
	TL0 = 0x33;		//设置定时初始值0.5ms
	TH0 = 0xFE;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;		//打开定时器0中断
	EA  = 1;		//打开总中断EA
}

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

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

double get_distance()
{
		double time;
		//定时器数据清零,以便下一次测距
		TH1 = 0;
		TL1 = 0;
	    //1. 让它发送波:给Trig端口至少10us的高电平
		startHC();
		//2. 开始发送波:Echo信号由低电平跳转到高电平
		while(Echo == 0);
		//   开始发送波,启动定时器
		TR1 = 1;
		//3. 接收返回波:Echo信号由高电平跳转回低电平
		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()
{
	angle = 1;      //初始角度是0度,0.5ms,溢出1就是0.5ms高电平
	cnt = 0;
	sg90_con = 1;//一开始从高电平开始
}

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

void closeDustbin()
{
	//关盖
	angle = 1; //0度
	angle_bak = angle;
	cnt = 0;
	Delay150ms();
}

void EX0_Init()
{
	EX0 = 1;//打开外部中断
	IT0 = 0;//低电平触发
}

void main()
{
	double dis;
	
	Timer0Init();
	Timer1Init();
	EX0_Init();
	
	initSG90_0();//舵机的初始位置
	
	while(1){
		
		dis = get_distance();//超声波测距
		if(dis < 10 || KEY1 == 0 || mark_vibrate == 1){
			//开盖,灯状态,D5亮
			openStatusLight();
			openDustbin();
			mark_vibrate = 0;
		}else{
			//关盖,灯状态,D5灭
			closeStatusLight();
			closeDustbin();
		}
	}
}

void Time0Handler() interrupt 1
{
	cnt++;  					//统计溢出的次数
	//重新给初值
	TL0 = 0x33;
	TH0 = 0xFE;
	
	//控制PWM波
	if(cnt < angle){
		sg90_con = 1;
	}else{
		sg90_con = 0;
	}
	
	if(cnt == 40){				//当溢出40次,经过了20ms
		cnt = 0;  				
		sg90_con = 1;
	}		
}

void Ex0_Handler() interrupt 0
{
	mark_vibrate = 1;
}

物联沃分享整理
物联沃-IOTWORD物联网 » 【STC89C51单片机控制舵机的综合应用】

发表评论