基于FPGA婴儿安全监护系统
前言
实时监测车内温湿度数据(DTH11温湿度模块)----实时控制风扇驱动速度(结合温湿度进行控制)-----检测车内是否有人(人体感应模块)------数据显示(数码管模块或者LCD模块)----
当车锁住后,检测车内是否有人----如果有人----蜂鸣器响----LED灯亮------将车内数据通过蓝牙发送到手机上,手机可以通过蓝牙开车锁 app没有 有小程序或者蓝牙app
模块:
一、芯片手册阅读
都属于非常常见的通信协议了,不在进行手册展示了。
其中温湿度模块:单总线通信
蓝牙模块:串口通信
人体感应模块:读取高低电平
数码管模块:译码
二、代码分析
都比较常见了,也不再做仿真了,直接写代码上板,有问题逻辑分析仪进行抓取波形

1.温湿度驱动
参考野火的例程进行修改的,原代码有问题,两次采样间隔太短,造成数据读取卡壳,总需要复位。
c
`timescale 1ns/1ns
module dht11_ctrl
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
inout wire dht11 , //控制总线
output reg [15:0] temp_out , //输出显示的数据
output reg [15:0] humi_out , //输出显示的数据
output reg sign //输出符号位,高电平显示负号
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter S_WAIT_1S = 3'd1 , //上电等待1s状态
S_LOW_18MS = 3'd2 , //主机拉低18ms,发送开始信号状态
S_DLY1 = 3'd3 , //等待20-40us状态
S_REPLY = 3'd4 , //DHT11响应80us状态
S_DLY2 = 3'd5 , //拉高等待80us状态
S_RD_DATA = 3'd6 ; //接收数据状态
parameter T_1S_DATA = 999999 ; //1s时间计数值
parameter T_18MS_DATA = 17999 ; //18ms时间计数值
//reg define
reg clk_1us ; //1us时钟,用于驱动整个模块
reg [4:0] cnt ; //时钟分频计数器
reg [2:0] state ; //状态机状态
reg [20:0] cnt_us ; //us计数器
reg dht11_out ; //总线输出数据
reg dht11_en ; //总线输出使能信号
reg [5:0] bit_cnt ; //字节计数器
reg [39:0] data_tmp ; //读出数据寄存器
reg data_flag ; //数据切换标志信号
reg dht11_d1 ; //总线信号打一拍
reg dht11_d2 ; //总线信号打两拍
reg [31:0] data ; //除校验位数据
reg [6:0] cnt_low ; //低电平计数器
//wire define
wire dht11_fall; //总线下降沿
wire dht11_rise; //总线上升沿
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//当使能信号为1是总线的值为DATA_out的值,为0时值为高阻态
assign dht11 = (dht11_en == 1 ) ? dht11_out : 1'bz;
//检测总线信号的上升沿下降沿
assign dht11_rise = (~dht11_d2) & (dht11_d1) ;
assign dht11_fall = (dht11_d2) & (~dht11_d1) ;
//对dht11信号打拍
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
dht11_d1 <= 1'b0 ;
dht11_d2 <= 1'b0 ;
end
else
begin
dht11_d1 <= dht11 ;
dht11_d2 <= dht11_d1 ;
end
//cnt:分频计数器
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt <= 5'b0;
else if(cnt == 5'd24)
cnt <= 5'b0;
else
cnt <= cnt + 1'b1;
//clk_1us:产生单位时钟为1us的时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
clk_1us <= 1'b0;
else if(cnt == 5'd24)
clk_1us <= ~clk_1us;
else
clk_1us <= clk_1us;
//bit_cnt:读出数据bit位数计数器
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 6'b0;
else if(bit_cnt == 40 )
bit_cnt <= 6'b0;
else if(dht11_fall == 1'b1 && state == S_RD_DATA)
bit_cnt <= bit_cnt + 1'b1;
//状态机状态跳转
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= S_WAIT_1S ;
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA) //上电1s后跳入起始状态
state <= S_LOW_18MS ;
else
state <= S_WAIT_1S ;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
state <= S_DLY1 ;
else
state <= S_LOW_18MS ;
S_DLY1:
if(cnt_us == 10) //等待10us后进入下一状态
state <= S_REPLY ;
else
state <= S_DLY1 ;
S_REPLY: //上升沿到来且低电平保持时间大于70us,则跳转到下一状态
if(dht11_rise == 1'b1 && cnt_low >= 70)
state <= S_DLY2 ;
//若1ms后,dht11还没响应,则回去继续发送起始信号
else if(cnt_us >= 1000)
state <= S_LOW_18MS ;
else
state <= S_REPLY ;
S_DLY2: //下降沿到来且计数器值大于70us,则跳转到下一状态
if(dht11_fall == 1'b1 && cnt_us >= 70)
state <= S_RD_DATA ;
else
state <= S_DLY2 ;
S_RD_DATA: //读完数据后,回到起始状态
if(bit_cnt == 40 )
state <= S_WAIT_1S ;
else
state <= S_RD_DATA ;
default:
state <= S_WAIT_1S ;
endcase
//各状态下的计数器赋值
//cnt_us:每到一个新的状态就让该计数器重新计数
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else
case(state)
S_WAIT_1S:
if(cnt_us == T_1S_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_LOW_18MS:
if(cnt_us == T_18MS_DATA)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_DLY1:
if(cnt_us == 10)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_REPLY:
if(dht11_rise == 1'b1 && cnt_low >= 70)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
//当dht11发送低电平回应时,计算其低电平的持续时间
else if(dht11 == 1'b0)
begin
cnt_low <= cnt_low + 1'b1 ;
cnt_us <= cnt_us + 1'b1 ;
end
//若1ms后,dht11还没响应,则回去继续发送起始信号
else if(cnt_us >= 1000)
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
else
begin
cnt_low <= cnt_low ;
cnt_us <= cnt_us + 1'b1 ;
end
S_DLY2:
if(dht11_fall == 1'b1 && cnt_us >= 70)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
S_RD_DATA:
if(dht11_fall == 1'b1 || dht11_rise == 1'b1)
cnt_us <= 21'd0 ;
else
cnt_us <= cnt_us + 1'b1;
default:
begin
cnt_low <= 7'd0 ;
cnt_us <= 21'd0 ;
end
endcase
//各状态下的单总线赋值
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
else
case(state)
S_WAIT_1S:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_LOW_18MS: //拉低总线18ms
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b1 ;
end
//后面状态释放总线即可,由DHT11操控总线
S_DLY1:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_REPLY:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_DLY2:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
S_RD_DATA:
begin
dht11_out <= 1'b0 ;
dht11_en <= 1'b0 ;
end
default:;
endcase
//data_tmp:将读出的数据寄存在data_tmp中
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data_tmp <= 40'b0;
else if(state == S_RD_DATA && dht11_fall == 1'b1 && cnt_us<=50)
data_tmp[39-bit_cnt] <= 1'b0;
else if(state == S_RD_DATA && dht11_fall == 1'b1 && cnt_us>50)
data_tmp[39-bit_cnt] <= 1'b1;
else
data_tmp <= data_tmp;
//data_out:输出数据显示,按一次按键切换一次数据
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 32'b0;
else if(data_tmp[7:0] == data_tmp[39:32] + data_tmp[31:24] +
data_tmp[23:16] + data_tmp[15:8])
data <= data_tmp[39:8]; //若检验位正确,则数据值有效
else
data <= data;
//temp_out:对数码管显示的湿度和温度进行赋值
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
temp_out <= 16'b0;
else
//温度低四位显示温度小数数据
temp_out <= data[15:8] * 10 + data[3:0];
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
humi_out <= 16'b0;
else
humi_out <= data[31:24] * 10; //湿度小数位为0
//sign:符号位的显示
always@(posedge clk_1us or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sign <= 1'b0;
else if(data[7] == 1'b1 && data_flag == 1'b1)
//当温度低八位最高位为1时,显示负号
sign <= 1'b1;
else
sign <= 1'b0;
endmodule
2.转速等级设置模块
c
//
// Company:
// Engineer:
//
// Create Date: 2025/04/25 11:16:23
// Design Name:
// Module Name: level_monitor
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module level_monitor(
input clk,
input rst_n,
input [15:0] temp_data,
input [15:0] humi_data,
output reg [2:0] fire_level
);
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
fire_level <= 3'd3;
end
else if( humi_data>15'd500)begin
fire_level <= 3'd3;
end
else if( humi_data>=15'd400 && humi_data<=15'd500)begin
fire_level <= 3'd5;
end
else if( humi_data<15'd400)begin
fire_level <= 3'd7;
end
end
endmodule
3.电机转速控制模块
c
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2025/04/13 14:38:54
// Design Name:
// Module Name: motor_control
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module motor_control(
input sys_clk ,
input rst_n,
//signal
input [2:0] fire_level,
output reg Pwm_out
);
parameter cnt20_ms=24'd1000000;
parameter cnt5_ms=24'd250000;
parameter cnt10_ms=24'd500000;
parameter cnt15_ms=24'd750000;
parameter IDLE=4'd0;
parameter OUT=4'd1;
parameter OPEN=4'd2;
reg [3:0] state;
reg [23:0] cnt_max;
reg [23:0] cnt_out;
reg [3:0] cnt_change;
always @(*)begin
case(fire_level)
3:cnt_max=cnt5_ms;
5:cnt_max=cnt10_ms;
7:cnt_max=cnt15_ms;
default:cnt_max=cnt5_ms;
endcase
end
always @(posedge sys_clk or negedge rst_n)begin
if(!rst_n)begin
state<=IDLE;
Pwm_out<=1'b0;
cnt_out<=24'd0;
end
else begin
case(state)
IDLE:begin
state<=OUT;
end
OUT:begin
state<=OUT;
if(cnt_out<cnt_max)begin
Pwm_out<=1'b1;
cnt_out<=cnt_out+1;
end
else if(cnt_out>=cnt_max && cnt_out<cnt20_ms)begin
Pwm_out<=1'b0;
cnt_out<=cnt_out+1;
end
else begin
cnt_out<=24'd0;
end
end
default:state<=IDLE;
endcase
end
end
endmodule
总结
视频演示
基于FPGA的车内婴儿安全监测系统设计(风扇模块、温湿度、蓝牙模块、人体感应检测模块)