赞
踩
模块不熟悉没关系,下面的描述和代码都很详细;
为了快速做出项目,我们一边介绍项目所需元器件,一边写代码,原理类的东西带过一下。
首先,基本的led1、led2,key1。
#include<reg51.h>
sbit led1 = P3^7; //固定的口
sbit led2 = P3^6; //固定的口
sbit key1 = P2^1; //固定的口
这些口请参考你使用的单片机的原理图,不同单片机不一样
比如我使用的单片机
大家根据自己使用的单片机原理图接对应硬件的引脚。
void led1_ON() //led1亮,led2灭
{
led1 = 1;
led2 = 0;
}
void led2_ON() //led2灭,led2亮
{
led1 = 0;
led2 = 1;
}
这两个点灯函数之后也会用到,用来做为开关垃圾桶的标志。
我使用的是HC-SR04
大家在某宝或者某夕夕上面买就ok了,几块钱。
接线参考:
四个引脚VCC接 5/3.3V,GND 接地。
Trig、Echo 两个引脚随便接没有被占用的引脚,我接的是 P1.5 和 P1.6;
sbit Trig = P1^5; //发生超声波
sbit Echo = P1^6; //接收超声波
超声波测距原理
超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度, 计算出模块到前方障碍物的距离.
配置好引脚后,trig 和 echo 就可以在软件成面,就是通过代码的方式进行操作。
怎么发送和接收超声波呢?
trig = 1
的状态至少10us;大家看着看不懂也没关系,我们有代码
先获取一下延时函数
打开STC-ISP,按照我的操作就ok了
不会用STC-ISP也没关系,直接复制代码一样得
void Delay10us() //@11.0592MHz //发射超声波最短时间
{
unsigned char i;
i = 2;
while (--i);
}
下面是这个器件操作的大头:利用到了定时器/计数器1
定时器/计数器如果不太明白,大家可以参考我之前写的博客:
sbit Trig = P1^5; //发生超声波 sbit Echo = P1^6; //接收超声波 void Timer1Init() // @11.0592MHz { TMOD &= 0x0F; //设置定时器模式 //选择定时器1 TMOD |= 0x10; //与运算,可以参考我另一篇博客(下面会介绍),看不懂也没关系,直接C、V就好 TL1 = 0x00; //设置定时初始值 TH1 = 0x00; //设置定时初始值 //不着急开始计数,寄存器的操作在后面 getDis( )函数 } void startHC() //发射超声波 { Trig = 0; //Trig 硬件层面接好后,软件 sbit 了 一个引脚后,就可以直接赋值; Trig = 1; Delay10us(); //延时10us,//前面介绍过,直接copy Trig = 0; } float getDis() //获得距离 //这里是难点,根据Echo信号的变化来获取距离 { float TIME;//时间 TL1 = 0x00; //设置定时初始值 TH1 = 0x00; //设置定时初始值 startHC(); //准备启动 while(Echo==0); //等待高电平,跳出循环 TR1 = 1; while(Echo==1);//等待低电平,跳出循环 TR1 = 0; TIME = (TH1 * 256 + TL1)* 1.085; //us //340m/s == 340 00cm/1000ms == 34cm/ms == 0.034cm/us == 0.017cm/us //计数器的计数一次最大的时间是71ms,根据公式可以知道,一次计数,超声波最远可以传播12m return TIME * 0.017; //最大12m来回,器件HC-SR04说明书的测量距离是 2cm-4m; }
超声波测距模块就这么一些,在后面我们会在垃圾桶上装一共这样的模块,来检查我们的的手离垃圾桶的距离,通过距离来控制下面我们要讲的舵机,通过舵机控制垃圾桶的开关。
我使用的是SG90
网上都可以买的到的
参考接线
三个引脚VCC接 5V,GND 接地。舵机需要的电压大一点;
PWM信号脚 随便接没有被占用的引脚,我接的是 P1.1;
sbit sg90_con = P1^1; //舵机
怎么控制舵机呢?
通过PWM信号来控制
PWM波的频率不能太高,大约50HZ,即周期=1/频率=1/50=0.02s,20ms左右
0.5ms-------------0度; 2.5% 占空比
1.0ms------------45度; 5.0% 占空比
1.5ms------------90度; 7.5% 占空比
2.0ms-----------135度; 10.0% 占空比
2.5ms-----------180度; 12.5% 占空比
占空比:占空比指的是在一个周期中,高电平状态占整个周期的百分比。
给PWM信号引脚 不同频率的脉冲,便可以调控PWM的占空比;
我们设置20ms为一个周期,0.5ms 为最小单元,定义标识符
int cnt
来计数,没过0.5ms,计数加一cnt++
;这样一来,我们就可以通过标识符来方便的控制舵机旋转角度;
模块参考代码介绍
sbit sg90_con = P1^1; //舵机 int jd,jd_bak; //0.5的倍数 //用jd,和jd_bak 标识符来控制舵机旋转角度,jd指的是(角度),jd_bak指的是(之前的角度) //jd_bak的设置,是为了让使各各模块结合在一起后,舵机更加稳定所做出的操作; int cnt; //计数 void Time0Init() //定时器0来配合舵机PWM操作 @11.0592MHz { //最小时间单元0.5ms(人为设置的) //1. 配置定时器0工作模式位16位计时 TMOD &= 0xF0; //设置定时器模式 //选择定时器1 TMOD |= 0x01; //2. 给初值,定一个0.5出来 TL0=0x33; TH0=0xFE; //3. 开始计时 TR0 = 1; TF0 = 0; //4. 打开定时器0中断 ET0 = 1; //5. 打开总中断EA EA = 1; } void sg90_0_Init() //初始化舵机 { jd = 1; //初始角度是0度(使舵机恢复原始状态),0.5ms,溢出1就是0.5ms,高电平 cnt = 0; sg90_con = 1;//一开始从高电平开始 } void Time0Handler() interrupt 1 //舵机 定时器0-中断 { cnt++; //统计爆表的次数. cnt=1的时候,报表了1 //重新给初值,定时器复位; TL0=0x33; TH0=0xFE; //控制PWM波 if(cnt < jd) //jd是全局变量,比较方便 { sg90_con = 1;//控制舵机PWM信号的高低电平 } else { sg90_con = 0; } if(cnt == 40){//爆表40次,经过了20ms cnt = 0; //40 * 0.5ms = 20ms sg90_con = 1; } }
我用的是SW-18010P
引脚介绍
参考接线
AO口可以,随便接没有被占用的引脚,我是将AO口接在P3.2上
sbit vibrate = P3^2;
为了使程序更加稳定,防高灵敏度误触影响程序运行,我们使用外部中断0,来对震动传感器的触发进行操作
模块参考代码介绍
int make_vibrate = 0; //震动标志位(全局)
void EX0_Init() //外部中断初始化
{
//EA = 1;//因为前面以及打开过 EA 中断总开关了,我们这边就把他省略
EX0 = 1; //打开外部中断0 开关
IT0 = 0; //IT0 = 0时 低电平触发
//IT = 1 的话就是下降言触发
}
void Ex0_Handler() interrupt 0 //震动传感器,外部中断0
{
make_vibrate = 1; //震动 标志位改变,进而影响震动传感器的状态;
}
我使用的是低电平触发的蜂鸣器,都大差不差,随便到某宝买就行。
接线参考
VCC GND就不说了,I/O口,随便接没有被占用的引脚,我将 I/O 接在了P2.3
sbit beep = P2^3; // 蜂鸣器 开盖就响
蜂鸣器比较简单;
接下来我们把上述各种器件整合,写开盖函数,关盖函数,和main函数;
直接上代码
void openDustbin() //开盖 { jd = 3; //90度 1.5ms高电平;根据前面讲得,20ms里面,1.5ms高电平,舵机转90度 if(jd_bak != jd)//当当前设置的角度标志位,与前一个角度标志位不一样时,执行给语句; //目的解决物体一直放在垃圾桶前面时,舵机抽搐的问题。 { cnt = 0; //抽搐的原因 beep = 0; //蜂鸣器响一下 Delay150ms(); //响150ms beep = 1; //蜂鸣器停 Delay1000ms(); //延时1s,开关也要时间 jd_bak = jd;//这一次的角度,变成了下一次的上一次。 } } void closeDustbin() //关盖 { jd = 1; //0度,归位 cnt = 0; //计数的标志位置零 jd_bak = jd;//这一次的角度,变成了下一次的上一次。 Delay150ms(); }
再补几个延时函数
void Delay1000ms() //@11.0592MHz { unsigned char i, j, k; i = 8; j = 1; k = 243; 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 setDis(float distance) //设置想要的距离,物体到达传感器多长距离,触发开盖 { Delay150ms();//这边加一个延时,目的是怕当物体一直在超声波传感器前面时,传感器启动频繁,导致产生过载;让传感器休息一下; if(Dis < distance || key1 == 0 || make_vibrate == 1)//小于10cm 或者按下按键key1 开盖 { led1_ON();//点灯led1,关灯led2,标志,开盖成功! openDustbin();//开盖函数 make_vibrate = 0; //震动传感器的标志位置零,重新开始 } else { led2_ON();//点灯led2,关灯led1,标志,关盖 closeDustbin(); //关盖函数 //make_vibrate = 0; } }
main()
函数中调用这个函数,通过传参便捷调节触发距离;main()
函数int main()
{
Time0Init(); //初始化定时器
Timer1Init();
EX0_Init(); //外部中断 震动传感器
sg90_0_Init(); //舵机的初始化
while(1)
{
Dis = getDis();
setDis(10); //设置开盖距离参数,
}
}
我们用到了定时器0 控制制舵机PWM,定时器1 计算超声波传播路径,外部中断0 结合了震动传感器
#include<reg51.h> sbit led1 = P3^7; //固定的口 sbit led2 = P3^6; //固定的口 sbit key1 = P2^1; //固定的口 sbit Trig = P1^5; //发生超声波 sbit Echo = P1^6; //接收超声波 sbit sg90_con = P1^1; //舵机 sbit vibrate = P3^2; sbit beep = P2^3; // 蜂鸣器 开盖就响 int jd,jd_bak; //0.5的倍数 int cnt; //计数 int make_vibrate = 0; float Dis; //超声波距离 void Delay10us() //@11.0592MHz //发射超声波最短时间 { unsigned char i; i = 2; 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 Delay1000ms() //@11.0592MHz { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } void Timer1Init() //10微秒 //10us 超声波 @11.0592MHz { TMOD &= 0x0F; //设置定时器模式 //选择定时器1 TMOD |= 0x10; TL1 = 0x00; //设置定时初始值 TH1 = 0x00; //设置定时初始值 //不着急开始计数 } void Time0Init() //舵机定时器0 0.5ms @11.0592MHz { //1. 配置定时器0工作模式位16位计时 TMOD &= 0xF0; //设置定时器模式 //选择定时器1 TMOD |= 0x01; //2. 给初值,定一个0.5出来 TL0=0x33; TH0=0xFE; //3. 开始计时 TR0 = 1; TF0 = 0; //4. 打开定时器0中断 ET0 = 1; //5. 打开总中断EA EA = 1; } void sg90_0_Init() { jd = 1; //初始角度是0度,0.5ms,溢出1就是0.5,高电平 cnt = 0; sg90_con = 1;//一开始从高电平开始 } void EX0_Init() { EX0 = 1; IT0 = 0; //低电平触发 //1的话就是下降言触发 } void startHC() //发射超声波 { Trig = 0; Trig = 1; Delay10us(); Trig = 0; } float getDis() //获得距离 { float TIME;//时间 TL1 = 0x00; //设置定时初始值 TH1 = 0x00; //设置定时初始值 startHC(); //准备启动 while(Echo==0); //等待高电平,跳出循环 TR1 = 1; while(Echo==1);//等待低电平,跳出循环 TR1 = 0; TIME = (TH1 * 256 + TL1)* 1.085; //us //340m/s = 340 00cm/1000ms == 34cm/ms == 0.034cm/us == 0.017cm/us return TIME * 0.017;//最大12m来回,器件HC是 2cm-4m } void led1_ON() //亮led1 { led1 = 1; led2 = 0; } void led2_ON() //亮led2 { led1 = 0; led2 = 1; } void openDustbin() //开盖 { jd = 3; //90度 1.5ms高电平 if(jd_bak != jd) { cnt = 0; //抽搐的原因 beep = 0; Delay150ms(); beep = 1; Delay1000ms(); jd_bak = jd; } } void closeDustbin() //关盖 { jd = 1; //0度 cnt = 0; jd_bak = jd; Delay150ms(); } void setDis(float distance) //设置距离 { Delay150ms(); if(Dis < distance || key1 == 0 || make_vibrate == 1)//小于10cm 或者按下按键key1 开盖 { led1_ON(); openDustbin(); make_vibrate = 0; } else { led2_ON(); closeDustbin(); //make_vibrate = 0; } } int main() { Time0Init(); //初始化定时器 Timer1Init(); EX0_Init(); //外部中断 震动传感器 sg90_0_Init(); //舵机的初始化 while(1) { Dis = getDis(); setDis(10); //设置开盖距离参数, } } 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 //震动传感器,外部中断0 { make_vibrate = 1; //震动 标志位改变 }
主要还是大家要注意接线,代码模块还是比较简单的;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。