功能:
0.本系统采用STC89C52作为单片机
1.LCD1602液晶实时显示进出计数和当前总数
2.系统设计有四个功能按键,按键可设定总数上限阈值,超过上限,系统将报警
3.报警电路由蜂鸣器和LED组成的声光报警
4.采用DC002作为电源接口可直接输入5V给整个系统供电
5.计数传感器采用的是红外光电传感器,该传感器最远测试距离可达到0.8米,能够满足使用场景
原理图:
PCB :
主程序:
#include <reg52.h> //调用单片机头文件
#define uchar unsigned char //无符号字符型 宏定义 变量范围0~255
#define uint unsigned int //无符号整型 宏定义 变量范围0~65535
#include <intrins.h>
#include <stdio.h>
#define OSC 11059200 //11.0592MHz
// #define OSC 12000000 //12MHz
// 定时器寄存器值预处理
#define BAUDRATE 9600
#define RH_UART (256-((OSC/12/32) / BAUDRATE))
bit flag_500ms;
sbit BEEP = P2^2; //蜂鸣器IO口定义
sbit INFRARED_IN = P2^0; //红外传感器IO口定义
sbit INFRARED_OUT = P2^1; //红外传感器IO口定义
sbit LCD_RS=P2^7; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit LCD_RW=P2^5; //寄存器选择信号 H:数据寄存器 L:指令寄存器
sbit LCD_EN =P2^6; //片选信号 下降沿触发
uchar a_a;
uchar menu_1; //设置参数用
uint num; //计的数
uint jin,chu;
uchar set_num = 10; // 设置预警值
bit oldPinState1 = 0;
bit nowPinState1 = 0;
bit oldPinState2 = 0;
bit nowPinState2 = 0;
bit sendFlag = 1;
void DelayUs10x(unsigned char t)
{
do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (--t);
}
void Timer0_Init()
{
TMOD &= 0xF0; //Timer0 16位装载
TMOD |= 0x01;
TL0 = 0x00; //设置定时初始值
TH0 = 0x4C; //设置定时初始值 50ms
TR0 = 1; //开启T0计时
ET0 = 1; //打开T0中断
EA = 1; //打开总中断
}
void UART0_Init()
{
SCON = 0x50;
TMOD &= 0x0F;
TMOD |= 0x20; //8位自动重装
TH1 = RH_UART;
TL1 = TH1;
ET1 = 0; //禁止T1中断
TR1 = 1; //启动T1计时
//ES = 1; //打开串口中断
EA = 1; //打开总中断
}
void UART0_SendByte(unsigned char dat) //串口发送单字节数据
{
unsigned char time_out;
time_out = 0x00;
SBUF = dat; //将数据放入SBUF中
while ((!TI) && (time_out < 100)) //检测是否发送出去
{
time_out++;
DelayUs10x(2);
} //未发送出去 进行短暂延时
TI = 0; //清除ti标志
}
void UART0_SendStr(unsigned char *str) //发送定长度字符串
{
unsigned char *tmp;
unsigned char cnt = 0;
unsigned char length = 0;
tmp = str;
while (*(tmp++) != '\0')
{
length++;
}
while (cnt < length) //发送长度对比
{
UART0_SendByte(*str); //发送单字节数据
str++; //指针++
cnt++; //下一个++
}
}
/***********************1ms延时函数*****************************/
void delay_1ms(uint q)
{
uint i,j;
for(i=0;i<q;i++)
for(j=0;j<120;j++);
}
/********************************************************************
* 名称 : delay_uint()
* 功能 : 小延时。
* 输入 : 无
* 输出 : 无
***********************************************************************/
void delay_uint(uint q)
{
while(q--);
}
/********************************************************************
* 名称 : write_com(uchar com)
* 功能 : 1602命令函数
* 输入 : 输入的命令值
* 输出 : 无
***********************************************************************/
void write_com(uchar com)
{
LCD_EN=0;
LCD_RS=0;
LCD_RW=0;
P0=com;
delay_uint(25);
LCD_EN=1;
delay_uint(100);
LCD_EN=0;
}
/********************************************************************
* 名称 : write_data(uchar dat)
* 功能 : 1602写数据函数
* 输入 : 需要写入1602的数据
* 输出 : 无
***********************************************************************/
void write_data(uchar dat)
{
LCD_EN=0;
LCD_RS=1;
LCD_RW=0;
P0=dat;
delay_uint(25);
LCD_EN=1;
delay_uint(100);
LCD_EN=0;
}
/***********************lcd1602上显示四位十进制数************************/
void write_sfm4(uchar hang,uchar add,uint date)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
write_data(0x30+date/1000%10);
write_data(0x30+date/100%10);
write_data(0x30+date/10%10);
write_data(0x30+date%10);
}
/***********************lcd1602上显示这字符函数************************/
void write_string(uchar hang,uchar add,uchar *p)
{
if(hang==1)
write_com(0x80+add);
else
write_com(0x80+0x40+add);
while(1)
{
if(*p == '\0') break;
write_data(*p);
p++;
}
}
/***********************lcd1602初始化设置************************/
void init_1602() //lcd1602初始化
{
write_com(0x38);
write_com(0x0c);
write_com(0x06);
delay_uint(1000);
write_string(1,0," Z:0000 ");
write_string(2,0," J:0000 C:0000 ");
write_sfm4(2,3,jin); //显示人数
write_sfm4(1,7,num); //显示人数
write_sfm4(2,11,chu); //显示人数
}
/********************独立按键程序*****************/
uchar key_can; //按键值
void key() //独立按键程序
{
static uchar key_new;
key_can = 20; //按键值还原
P3 |= 0x78;
if((P3 & 0x78) != 0x78) //按键按下
{
delay_1ms(1); //按键消抖动
if(((P3 & 0x78) != 0x78) && (key_new == 1))
{ //确认是按键按下
key_new = 0;
switch(P3 & 0x78)
{
case 0x70: key_can = 1; break; //得到k1键值
case 0x68: key_can = 2; break; //得到k2键值
case 0x38: key_can = 3; break; //得到k3键值
case 0x58: key_can = 4; break; //得到k4键值
}
}
}
else
key_new = 1;
}
/****************按键处理LCD显示函数***************/
void key_with()
{
if(key_can == 1) //设置键
{
menu_1 ++;
if(menu_1 >= 2)
{
menu_1 = 0;
init_1602(); //lcd1602初始化
}
if(menu_1 == 1) //初始化显示
{
write_string(1,0," SET Z Alarm ");
write_string(2,0," ");
write_sfm4(2,6,set_num); //显示人数
}
}
if(menu_1 == 0)
{
if(key_can == 4) //清零
{
num = 0;
jin = 0;
chu = 0;
write_sfm4(2,3,jin); //显示人数
write_sfm4(1,7,num); //显示人数
write_sfm4(2,11,chu); //显示人数
}
}
if(menu_1 == 1)
{
if(key_can == 2)
{
set_num ++ ; // 设置数加
if(set_num > 99)
set_num = 99; //最大加到99
}
if(key_can == 3)
{
set_num -- ; // 设置数减
if(set_num <= 1)
set_num = 1; //最大减到1
}
write_sfm4(2,6,set_num); //显示人数
write_com(0x80+0x40+6); //将光标移动到秒个位
write_com(0x0f); //显示光标并且闪烁
}
BEEP = 0; //打开蜂鸣器
delay_1ms(50);
BEEP = 1; //关闭蜂鸣器
}
/******************红外计数**********************/
void hw_jin_dis() //红外计数
{
nowPinState1 = INFRARED_IN;
if (oldPinState1 == 1 && nowPinState1 == 0) //检测到下降沿
{
delay_1ms(100);
if (INFRARED_IN == 0) //确定低电平
{
jin ++;
if(jin >= 99)
jin = 99;
num = jin - chu; //计算总人数
if(menu_1 == 0)
{
write_sfm4(2,3,jin); //显示人数
write_sfm4(1,7,num); //显示人数
}
}
}
oldPinState1 = nowPinState1;
}
/******************红外计数**********************/
void hw_chu_dis() //红外计数
{
nowPinState2 = INFRARED_OUT;
if (oldPinState2 == 1 && nowPinState2 == 0) //检测到下降沿
{
delay_1ms(100);
if (INFRARED_OUT == 0) //确定低电平
{
if(jin > chu)
chu ++;
if(chu >= 99)
chu = 99;
num = jin - chu; //计算总人数
if(menu_1 == 0)
{
write_sfm4(2,11,chu); //显示人数
write_sfm4(1,7,num); //显示人数
}
}
}
oldPinState2 = nowPinState2;
}
/******************主程序**********************/
void main()
{
unsigned char dis[16];
BEEP = 0; //开机蜂鸣器叫一声
delay_1ms(100);
P0 = P1 = P2 = P3 = 0xff; //初始化IO口
Timer0_Init();
UART0_Init();
init_1602(); //lcd1602初始化
while(1)
{
hw_jin_dis(); //红外计数
hw_chu_dis(); //红外计数
if(menu_1 == 0) //扫描显示倒计时数
{
if(flag_500ms == 1)
{
flag_500ms = 0;
if(num > set_num)
BEEP = ~BEEP; //报警
else
{
BEEP = 1;
}
}
}
if (sendFlag == 1) //定时串口发送信息
{
sendFlag = 0;
sprintf(dis, "Z:%04d\r\n", (uint)num);
UART0_SendStr(dis);
delay_1ms(20);
sprintf(dis, "J:%04d C:%04d\r\n", (uint)jin, (uint)chu);
UART0_SendStr(dis);
}
key(); //按键扫描函数
if(key_can < 10)
{
key_with(); //按键执行函数
}
}
}
/*************定时器0中断服务程序***************/
void Timer0_Intterupt() interrupt 1
{
static unsigned char time50ms = 0;
TL0 = 0x00; //设置定时初始值
TH0 = 0x4C; //设置定时初始值 50ms
time50ms++;
if (time50ms > 100) //5s
{
sendFlag = 1;
time50ms = 0;
}
if (time50ms % 10 == 0)
{
flag_500ms = ~flag_500ms;
}
}