目录
2.1.2 HC-08蓝牙模块、光强传感器—BH1750、TFT LCD液晶显示屏
2.1.6 模拟教室灯控的LED灯阵电路、按键控制开关、VCC-GND扩展电路
题目
一、.设计任务
设计一个教室灯控系统,要求利用2组红外发射接收对管组成模拟教室出入人员计数系统,使其能够模拟统计教室出入人员计数,并根据在教室中的人数控制灯亮。
二、设计要求
1.基本要求
(1)任何一对红外管能够检测到有人走过,并将计数显示出来;
(2)当障碍物依次从红外发射管1到2走过的时候,人员数加1;
(3)当障碍物依次从红外发射管2到1走过的时候,人员数减1;
(4)当教室里人数为1~3人时,第一排灯亮,当人数为3~10人时,第一、二排灯亮,人数大于10时,三排灯都亮。每排灯为6个LED。
2.发挥部分
(1)光线较强时,只计数,LED灯不亮;
(2)增加数据存储显示功能;
(3)远程控制功能。
摘要
本系统是以STM32F103C8T6单片机作为控制中心,结合HC-08蓝牙模块、TFT LCD液晶显示模块、BH1750光强传感器模块和红外发射接收对管计数模块而成的教室人员计数及灯控系统。其中,控制核心STM32负责对各个模块进行控制与数据处理,BH1750模块负责感应环境光照强度对LED实时控制,红外发射接收对管负责模拟教室人员的进出,获得的实时数据通过TFT LCD液晶屏幕显示出来,并且用串口结合HC-08蓝牙的方式,实现了以本系统为下位机与作为上位机的手机的数据通信,及上位机对LED灯阵的远程操控;此外,本系统还通过EEPROM模块实现了数据存储功能。
关键词:STM32,BH1750,TFT LCD,红外发射接收对管,蓝牙。
1.系统方案
1.1. 蓝牙模块选择
方案一:BT08-B蓝牙模块
BT08-B蓝牙模块是专为智能无线数据传输而打造,遵循 V2.1+EDR蓝牙规范。本模块支持UART接口,并支持SPP蓝牙串口协议具有成本低、体积小、功耗低、收发灵敏 性高等优点,只需配备少许的外围元件就能实现其强大功能。
方案二:HC-08蓝牙模块
ATK-HC08模块,是 ALIENTEK 生成的一款高性能主从一体蓝牙串口模块,可以同各种带蓝牙功能的电脑、蓝牙主机、手机、PDA、PSP 等智能终端配对,该模块支持非常宽的波特率范围:4800~1382400,并且模块兼容 5V 或 3.3V 单片机系统,可以很方便与各种产品进行连接。使用非常灵活、方便。ATK-HC08模块非常小巧(16mm*32mm),模块通过 6 个 2.54mm 间距的排针与外部连接.
最后选择了方案二。
1.2. 感光模块选择
方案一:光敏电阻传感器
光敏电阻模块对环境光线敏感,一般用来检测周围环境的光线的亮度;模块在环境光线暗于设定阈值时,继电器吸合,公共端与常开端接通,当外界环境光线亮于设定阈值时,继电器断开,公共端与常闭端接通;公共端,常开,常闭三个端口相当于一个双控开关,继电器线圈有电时,公共端与常开端导通,无电时,公共端与常闭端导通。
方案二:光照强度传感器
BH1750是一种用于两线式串行总线接口的数字型光强度传感器集成电路。这种集成电路可以根据收集的光线强度数据来调整液晶或者键盘背景灯的亮度。利用它的高分辨率可以探测较大范围的光强度变化。BH1750的内部由光敏二极管、运算放大器、ADC采集、晶振等组成,BH1750引出了时钟线和数据线,单片机通过I2C协议可以与BH1750模块通讯,可以选择BH1750的工作方式,也可以将BH1750寄存器的光照强度数据提取出来。
最后选择了方案二。
1.3. 计数模块选择
方案一:红外发射接收对管
帽颈3/5MM,波长940,红外接收管是黑色,因此给它供电时,看不到光,不像LED那样,通电后就可以发光,也可以看到光。接收头是属于传感器的一类,专接收红外信号,因此,只有接收到红外信号,接收管才能工作。
红外发射管外形与普通LED一样透明无色的,发射管工作时,只发出一点点亮度的红色光,为红外光(红外信号),波长是940。发射管属于传感器的一类,只有配对接收管才能有效工作,一传一感,就是所说的红外对管。
透光率高,折射强无气泡杂质,光照璀璨明亮,耐高温适合在恶劣环境下使用;亮度好发射距离远显示图像清晰无频闪发射稳定均匀,使用寿命长。
方案二:对射式光电传感器
采用槽型对射光电传感器.它由一个红外发光二极管和一个NPN光电三极管组成,槽宽度为5.9mm,只要非透明物体通过槽型即可触发输出TTL低电平。采用施密特触发器去抖动脉冲,非常稳定;工作电压3.3V-5V,数字开关量输出(0和1),两端设有M3固定螺栓孔,方便安装;使用宽电压LM393比较器输出,信号干净,波形好,驱动能力强,超过15mA;广泛用于电机转速检测,脉冲计数,测距离,位置限位等。
最后选择了方案一。
1.4. 液晶显示模块选择
方案一:TFT LCD液晶显示屏
TFT LCD支持8位并行MCU接口和SPI 接口。适合一般51单片机和ARM单片机使用;输入具有双缓冲功能,可获得较高的写入速率和正确的显示效果;16位并行RGB输出接口,可支持8位(256色)显示或16位(65K色)显示;输出时序具有高稳定性,抗干扰能力强;具备2页显示页面,切换不闪烁,编程简单;、支持320×240、640×480、800×600等多种分辨率。
方案二:OLED液晶显示屏
0.96寸OLED屏,支持黑白、黑蓝或者黄蓝双色显示;128x64分辨率,显示效果清晰,对比度高;超大可视角度:大于160°(显示屏中可视角度最大的一种屏幕);宽电压供电(3V~5V),兼容3.3V和5V逻辑电平,无需电平转换芯片;默认为4线制SPI总线,可以选择3线制SPI总线或者IIC总线;超低功耗:正常显示仅为0.06W(远低于TFT显示屏);军工级工艺标准,长期稳定工作;适用于STM32、C51、Arduino、Raspberry Pi以及MSP430平台;提供底层驱动技术支持
最后选择了方案一。
1.5. 数据存储模块选择
AT24C02是一个2K位串行CMOS EEPROM,内部含有256个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24C02有一个8字节页写缓冲器。该器件通过IIC进行操作,有一个专门的功能。AT24C02支持总线协议IIC,总线协议规定任何将数据传送到总线的器件作为发送器。任何从总线接收数据的器件为接收器。数据传送是由产生串行时钟和所有起始停止信号的主器件控制的。主器件和从器件都可以作为发送器或接收器,但由主器件控制传送数据(发送或接收)的模式,由于A0、A1和A2可以组成000~111八种情况,即通过器件地址输入端A0、A1和A2可以实现将最多8个AT24C02器件连接到总线上,通过进行不同的配置进行选择器件。该模块可以实现掉电保护存储功能。
EEPROM模块没有太多选择,首先想到AT24C02,最后也选择了此方案。
2.电路及程序设计
2.1 系统电路设计
2.1.1 STM32引脚设计
2.1.2 HC-08蓝牙模块、光强传感器—BH1750、TFT LCD液晶显示屏
2.1.3 红外发射接收对管
2.1.4 AT24C02芯片、EEPORM插件
2.1.5 12V供电电源、 12V转5V降压电路
2.1.6 模拟教室灯控的LED灯阵电路、按键控制开关、VCC-GND扩展电路
2.2 PCB电路设计
2.3 系统框图+系统功能描述
2.4 红外对射管计数模块程序流程图
3. 测试方案与测试结果
3.1. 测试方案及测试条件
测试条件 测试模块 | 光强传感器—强 | 光强传感器—弱 | 按键控制 | 手机控制 |
LCD显示模块 | 正常 | 正常 | 正常 | 正常 |
蓝牙模块 | 正常 | 正常 | 正常 | 可收发指令 |
EEPORM模块 | 正常 | 正常 | 可清除数据 | 正常 |
LED灯阵 | 不工作 | 工作 | 正常 | 根据指令变化 |
红外对射管计数 | 正常 | 正常 | 正常 | 正常 |
测试条件 测试模块 | 不通过红外管 | 只通过一对红外管 | 快速通过两对红外管 | 缓慢通过两对红外管 |
红外对射管计数 | 不计数 | 不计数 | 小于时间差2计数 | 不计数 |
3.2. 测试结果及分析
经过上述方案的检测,题目要求的功能均已实现,通过改进,系统已有一定的鲁棒性。
4. 设计小结与心得体会
本次校赛以TI杯电子设计大赛的形式,由老师自主命题,学生可以选择自己最擅长的题目参赛,并且组队操作其他的事情(包括设计总体方案、硬件电路、软件设计、焊接、调试等工作)。趣味性强,同时也可以学到很多东西。我们小组在本次比赛中,收获知识的同时,还收获了阅历,收获了成熟,在此过程中,我们通过查找大量资料,请教老师,以及不懈的努力,不仅培养了独立思考、动手操作的能力,在各种其它能力上也都有了提高。更重要的是,通过本次比赛,我们学会了很多学习的方法。而这是日后最实用的,真的是受益匪浅。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。
5. 参考文献
[1]李遥,丁艺涛,潘登,郁金明,郭丙君.基于STM32-手机-Arduino使用HC-08进行蓝牙通讯[J].科技视界,2019(19):53-55.
[2]葛泽勋. STM32之BH1750光照强度模块的研究[D].长春理工大学,2019.
[2]张日欣. STM32系列单片机C语言程序设计与开发[J].软件导刊,2009,8(03):105-107.
6. 附录:源程序
附录A 主程序main.c代码
#include "delay.h"
#include "sys.h"
#include "led.h"
#include "lcd_init.h"
#include "lcd.h"
#include "key.h"
#include "exti.h"
#include "usart.h"
#include "BH1750.h"
#include "EEPROM.h"
int main(void)
{
u8 *light[2]={"弱","强"};
u8 intensity=0;
u8 key=0;
float temp;
float threshold=2000;
u8 test;
delay_init();
LED_Init();//LED初始化
KEY_Init(); //初始化与按键连接的硬件接口
LCD_Init();//LCD初始化
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
LCD_ShowChinese(16,0,"教室灯控系统",RED,WHITE,16,0);
LCD_ShowChinese(16,70,"光照强度:",RED,WHITE,16,0);
LCD_ShowChinese(88,70,light[0],RED,WHITE,16,0);
uart_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
BH1750_Init();/*BH1750初始化,配置GPIO */
Count_Sensor_Init();//计数红外传感器初始化
EXTIX_Init();
if(IIC_Read(0x11)!=2&&IIC_Read(0x22)!=2) //第一次上电初始化
{
IIC_Write(0x01,0);//0x01,初始化num
delay_ms(10);
IIC_Write(0x02,30);//0x02,初始化capacity
delay_ms(10);
IIC_Write(0x03,1);//0x03,初始化threshold
delay_ms(10);
IIC_Write(0x11,2);//只在设备第一次上电时判断
delay_ms(10);
IIC_Write(0x22,2);
delay_ms(10);
}
while(1)
{
num=IIC_Read(0x01);
capacity=IIC_Read(0x02);
threshold=500*IIC_Read(0x03);
LCD_ShowString(0,30," ",WHITE,WHITE,16,0);
LCD_ShowChinese(16,30,"当前人数:",RED,WHITE,16,0);
LCD_ShowIntNum(88,30,num,2,RED,WHITE,16);
LCD_ShowString(104,30," ",WHITE,WHITE,16,0);
LCD_ShowString(0,50," ",WHITE,WHITE,16,0);
LCD_ShowChinese(16,50,"教室容量:",RED,WHITE,16,0);
LCD_ShowIntNum(88,50,capacity,2,RED,WHITE,16);
LCD_ShowString(104,50," ",WHITE,WHITE,16,0);
LCD_ShowString(16,90,"lx",RED,WHITE,16,0);
LCD_ShowChinese(32,90,"阈值:",RED,WHITE,16,0);
LCD_ShowIntNum(72,90,threshold,4,RED,WHITE,16);
temp=Get_Sunlight_Value();//获得当前光照强度,单位lx
if(temp>threshold){
intensity=1;
LCD_ShowChinese(88,70,light[intensity],RED,WHITE,16,0);
}
else{
intensity=0;
LCD_ShowChinese(88,70,light[intensity],RED,WHITE,16,0);
}
delay_ms(1);
times++;
if(times%100==0){
if(i2c_CheckDevice(BH1750Address)==0)
printf("BH1750设备检测正常\r\n");
else printf("BH1750设备检测异常\r\n");
if(i2c_CheckDevice(EEPROMAddress)==0)
printf("EEPROM设备检测正常\r\n");
else printf("EEPROM设备检测异常\r\n");
delay_ms(1);
}
if(times%10==0){
printf("EEPROM_num=%d\n",num);
printf("Sunlight=%0.2f lx\n",temp);
printf("教室容量为%d人,当前教室人数为%d人。\r\n",capacity,num);
delay_ms(1);
}
key =KEY_Scan(1); //得到键值
if(key)
{
switch(key)
{
case KEY1_PRES:
capacity+=1;
if(capacity>40)capacity=0;
LCD_ShowIntNum(88,50,capacity,2,RED,WHITE,16);
IIC_Write(0x02,capacity);break;
case KEY2_PRES:
threshold+=500;
if(threshold>=5000)threshold=0;
IIC_Write(0x03,threshold/500);break;
case KEY3_PRES: //清除EEPROM
IIC_Write(0x11,0);
delay_ms(10);
IIC_Write(0x22,0);
delay_ms(10);break;
}
}else delay_ms(1);
if(bluetooth==0)
{
if(intensity==0)
{
if(num==0){
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",WHITE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",WHITE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
}
if(num>=1 && num<=3){
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",BLUE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",WHITE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
}
if(num>3 && num<=10){
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",BLUE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",BLUE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
}
if(num>10){
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
GPIO_SetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",BLUE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",BLUE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",BLUE,WHITE,16,0);
}
}else{
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",WHITE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",WHITE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
}
delay_ms(1);
}
}
}
附录B HC-08蓝牙模块核心代码
u8 bluetooth=0;//蓝牙开关标志
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 res;
if(USART_GetITStatus(USART1, USART_IT_RXNE))
{
res=USART_ReceiveData(USART1);
// USART_SendData(USART1,res);
switch(res)
{
case 0x01:
bluetooth=1;
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(0,110,"LED_1",WHITE,WHITE,16,0);
LCD_ShowString(44,110,"LED_2",WHITE,WHITE,16,0);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
printf("已进入蓝牙控制!");break;
case 0x02:
bluetooth=0;
printf("已退出蓝牙控制!");break;
case 0x03:
GPIO_SetBits(GPIOB,GPIO_Pin_0);
LCD_ShowString(0,110,"LED_1",BLUE,WHITE,16,0);
printf("已开启第一排灯!");break;
case 0x04:
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
LCD_ShowString(0,110,"LED_1",WHITE,WHITE,16,0);
printf("已关闭第一排灯!");break;
case 0x05:
GPIO_SetBits(GPIOA,GPIO_Pin_6);
LCD_ShowString(44,110,"LED_2",BLUE,WHITE,16,0);
printf("已开启第二排灯!");break;
case 0x06:
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
LCD_ShowString(44,110,"LED_2",WHITE,WHITE,16,0);
printf("已关闭第二排灯!");break;
case 0x07:
GPIO_SetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(88,110,"LED_3",BLUE,WHITE,16,0);
printf("已开启第三排灯!");break;
case 0x08:
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
LCD_ShowString(88,110,"LED_3",WHITE,WHITE,16,0);
printf("已关闭第三排灯!");break;
case 0x09:
capacity++;
LCD_ShowIntNum(88,50,capacity,2,RED,WHITE,16);
printf("当前教室容量为%d人\r\n",capacity);break;
case 0x10://此10非10,也可换为0x0A
capacity--;
LCD_ShowIntNum(88,50,capacity,2,RED,WHITE,16);
printf("当前教室容量为%d人\r\n",capacity);break;
}
}
}
附录C 红外发射接收对射管计数模块核心代码
u8 left=0;
u8 right=0;
int num=0;//教室当前人数
int capacity=30;//教室容量
u16 times=0;
u16 time_left;
u16 time_right;
//外部中断0服务程序
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line12)!=RESET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1)
{
delay_ms(20);//重复检测,减少干扰,提高正确率
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==1)
{
time_left=times;
left=1;
if(right)
{
// printf("此次中断时间戳的差%d\r\n",time_left-time_right);
if(time_left-time_right>2){
left=1;
right=0;
}
else{
if(num>=capacity){
num=capacity;
}else{
num++;
// LCD_ShowIntNum(88,30,num,2,RED,WHITE,16);
IIC_Write(0x01,num);
}
left=0;
right=0;
delay_ms(50);//消抖
}
}
}
}
EXTI_ClearITPendingBit(EXTI_Line12); //清除LINE0上的中断标志位
}
if(EXTI_GetITStatus(EXTI_Line13)!=RESET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==1)
{
delay_ms(20);//重复检测,减少干扰,提高正确率
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_13)==1)
{
time_right=times;
right=1;
if(left)
{
// printf("此次中断时间戳的差%d\r\n",time_right-time_left);
if(time_right-time_left>2){
left=0;
right=1;
}
else{
if(num<=0)num=0;
else num--;
// LCD_ShowIntNum(88,30,num,2,RED,WHITE,16);
IIC_Write(0x01,num);
left=0;
right=0;
delay_ms(50);//消抖
}
}
}
}
EXTI_ClearITPendingBit(EXTI_Line13); //清除LINE0上的中断标志位
}
}