控制/MCU
一、主要功能
(1)自动采集光照和声音数据;
(2)根据声音分贝值及光线强弱自动控制路灯开关;
(3)路灯开启,人走后3秒自动关闭。
二、使用方法
系统运行后,LCD1602显示采集的光线强度值与声音分贝值,当声音分贝数大于45表示有人经过,此时根据光线强度值来判断是否开启路灯,若光线强度值小于1000,这表示光线暗,打开路灯,否则关闭。若路灯开启后,声音分贝数小于45表示人离开,此时路灯开启3秒后自动关闭。
若光线值小于1000,表示光线暗,声音分贝值小于45表示无人,此时路灯依然关闭。
三、硬件资源
51单片机核心模块、PCF8591 ADC/DAC模块、LCD1602模块、路灯控制开关模块、光敏传感器和声音传感器模块。
四、软件设计
主要代码(部分)
代码如下:
#include
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit rs=P2^6; //数据命令选择
sbit rw=P2^5; //读写选择
sbit e=P2^7; //使能
sbit scl=P2^1; //PCF8591时钟
sbit sda=P2^0; //数据线
sbit relay=P3^6; //路灯控制开关
uint8 num[]="0123456789";
uint8 d1[7]="Light: ";
uint8 d2[7]="Sound: ";
uint16 ad[5];
uint8 dsok;
uint8 miao;
void delay(uint16 i) //延时函数,大约10us
{
while(i--);
}
void wrc(uint8 c) //LCD写命令函数
{
delay(1000);
rs=0;
rw=0;
e=0;
P0=c;
e=1;
delay(10);
e=0;
}
void wrd(uint8 dat) //LCD写数据函数
{
delay(1000);
rs=1;
rw=0;
e=0;
P0=dat;
e=1;
delay(10);
e=0;
rs=0;
}
void init() //LCD初始化函数
{
delay(1000);
wrc(0x38);
wrc(0x38);
wrc(0x38);
wrc(0x06);
wrc(0x0c);
wrc(0x01);
}
void time0init() //定时器0初始化
{
TMOD=0X01;
TH0=0XFC;
TL0=0X18; //1ms
// TR0=1;
ET0=1;
EA=1;
}
void iicinit() //IIC初始化函数
{
sda=1;
scl=1;
}
void iicstart() //开始信号
{
sda=1;
scl=1;
delay(10);
sda=0;
delay(10);
scl=0;
delay(10);
}
void iicstop() //停止信号
{
sda=0;
scl=1;
delay(10);
sda=1;
delay(10);
sda=0;
delay(10);
}
void ack() //应答信号
{
sda=1;
scl=0;
delay(2);
sda=0;
delay(2);
scl=1;
delay(10);
scl=0;
delay(2);
sda=1;
delay(5);
}
void noack() //非应答信号
{
sda=0;
scl=0;
delay(2);
sda=1;
delay(2);
scl=1;
delay(10);
scl=0;
delay(2);
sda=0;
delay(5);
}
void iicwrbyte(uint8 dat) //IIC写字节函数
{
uint8 i;
scl=0;
for(i=0;i<8;i++)
{
if(dat&0x80)
{
sda=1;
}
else
{
sda=0;
}
dat<<=1;
scl=1;
delay(10);
scl=0;
delay(10);
}
sda=1;
delay(10);
}
uint8 iicread() //IIC读数据函数
{
uint8 i,dat;
scl=0;
sda=1;
for(i=0;i<8;i++)
{
dat<<=1;
if(sda==1)
{
dat|=0x01;
}
scl=1;
delay(10);
scl=0;
delay(10);
}
return dat;
}
void pcf8591wrbyte(uint8 channel) //IIC在对应通道写数据
{
iicinit();
iicstart();
iicwrbyte(0x90); //pcf8591写数据 1001 A2A1A0 R/W
ack();
iicwrbyte(channel|0x40); //通过打开通道channelX,模拟输出使能打开
noack();
iicstop();
}
uint8 pcf8591read() //读取该通道的数据
{
uint8 dat;
iicinit();
iicstart();
iicwrbyte(0x90);
ack();
iicstart();
iicwrbyte(0x91); // pcf8591读数据 1001 A2A1A0 R/W
ack();
dat=iicread();
noack();
iicstop();
return dat;
}
void pcf8591dac(uint8 value) //DA转换
{
iicinit();
iicstart();
iicwrbyte(0x90);
ack();
iicwrbyte(0x40); //不需要打开通道channelX,模拟输出使能打开
ack();
iicwrbyte(value);
noack();
iicstop();
}
void display() //显示函数
{
float v,v1;
uint8 i;
pcf8591wrbyte(0); //电位器转换
ad[0]=pcf8591read(); //读取第一次之前的那次数据
delay(10);
pcf8591wrbyte(1); //电位器转换
ad[0]=pcf8591read(); //读取第一次之前的那次数据
delay(10);
pcf8591wrbyte(2); //电位器转换
ad[1]=pcf8591read(); //读取第一次之前的那次数据
delay(10);
v=ad[0]*0.01953;//将电位器的数据转换成电压值 0.01953
v=v*1000;//取3位有效数值
ad[0]=v;
v1=ad[1]*0.01953;//将电位器的数据转换成电压值 0.01953
v1=v1*1000;//取3位有效数值
ad[1]=v1/100;
wrc(0x00+0x80);
for(i=0;i<7;i++)
{
wrd(d1[i]);
}
wrd(num[ad[0]/1000]);
wrd(num[ad[0]%1000/100]);
wrd(num[ad[0]%1000%100/10]);
wrd(num[ad[0]%1000%100%10]);
wrc(0x40+0x80);
for(i=0;i<7;i++)
{
wrd(d2[i]);
}
wrd(num[ad[1]/10]);
wrd(num[ad[1]%10]);
wrd('d');
wrd('b');
ad[4]=ad[0];
pcf8591dac(ad[4]/2);//将数字量转换为模拟量由pcf8591的AOUT输出
}
void data_change() //数据比较函数
{
if(ad[0]<1000&&ad[1]>45&&dsok==0) //当光照强度检测低于1000并且声音大于45分贝的时候亮灯
{
relay=0;
TR0=1; //打开定时器0
}
if(dsok==1)
{
relay=1;
dsok=0;
}
}
void main() //主函数
{
init(); //LCD初始化
time0init(); //定时器0初始化
while(1)
{
display(); //显示函数
data_change(); //数据比较函数
}
}
void tim0() interrupt 1
{
static uint16 n;
TH0=0XFC;
TL0=0X18;//1ms
n++;
if(n==1000) //定时1秒
{
n=0;
miao++;
if(miao==3)
{
miao=0;
dsok=1;
TR0=0;
}
}
}
五、实验现象
全部0条评论
快来发表一下你的评论吧 !