Verilog HDL实现智能药盒
Posted hhh江月
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Verilog HDL实现智能药盒相关的知识,希望对你有一定的参考价值。
Verilog HDL实现智能药盒
一、简介
我们知道,当前,老年人的数量是比较多的,从而导致了照顾老年人成为了一个比较大的社会问题。由于老年人的记忆力相比之前可能是会有所下降的,而且与此同时,由于老年人的子女们也有上班工作等一些其他的生活的需求,所以说,老年人的身边并不是总能有人在陪伴的,这就导致了一些社会性的问题。例如,很多老年人随着年龄的增长,会伴随着健忘的问题。对于老年人来说,在生病的时候,甚至是日常生活中按时吃药都是一个难题。如果需要在不同时间吃不同的药,几乎很难独立完成。而设计实现一个具有计时提醒功能的智能药盒就是为这些老年人所设计的。
我们前面已经说了,其中的问题之一,就是老年人如果生病需要吃药的话,很有可能会由于自己的疏忽,忘记了吃药这件事,而同时身边也没有人来即是的提醒,从而会使得老年人错过正确的吃药的时间,这就有可能对老年人的病情产生一些不利的影响,更严重的话,甚至有可能会带来生命危险的。因此,我们需要制作一种可以自动的提醒老年人进行在设置的时间去吃药的操作的一种智能药盒。这种药盒,我们在设计的时候,可以一次性设定最多三种药的吃药时间,对老年人进行提醒吃药的操作,如果老年人吃过了药,那么提醒的警报就会消失,否则,会一直进行提醒。这样一来就可以在正确的时间来提醒老年人吃药,从而减小了错过吃药的时间的可能性了,更好的保证了老年人的安全与健康。
本实验旨在设计一种模拟的智能药盒,主要功能是进行模拟智能药盒的设定提醒时间以及定时的提醒吃药的功能。也就是说,本实验模拟的药盒可以实现定时的操作,设计的时候由于器件等原因,一次最多可以设置三种药的吃药的时间,然后在启动装置以后,装置就会自动的计时,等达到了某一种药的吃药的时间的时候,系统就会自动提醒吃药啦,吃过药以后,提醒关闭。就这样的一直循环下去,直到人为的关闭系统为止。当系统再一次启动的时候,仍然可以重新设置定时以及后面的提醒工作可以正常的进行。
由于后面内容比较多,这里先来一个现象:
https://www.bilibili.com/video/BV1MY411x7Xw?spm_id_from=333.999.0.0
Verilog HDL实现智能药盒
下面开始正式的项目的制作了啦:
二、代码
1、主文件(主模块的代码)
代码比价多、比较长,但是里面有详细的注释。
module test_little_foot(clk,rst,btn1,btn2,btn3,btn4,btn5,btn6,
rled1, rled2, rled3,rled4,seg_led_1,seg_led_2,
row, col);// row, col 是点阵的设置。
// 进行小脚丫上面的所有的代码的一个整合啦。
output reg [7:0] row;
output reg [7:0] col;
// Dot Matrix.---点阵。
localparam s0 = 3'd0, s1 = 3'd1, s2 = 3'd2, s3 = 3'd3,
s4 = 3'd4, s5 = 3'd5, s6 = 3'd6, s7 = 3'd7;
// 这个状态是进行扫描的时候使用的啦。
// Dot Matrix 显示的时候所需要的控制状态。
reg [12:0] cnt;
always @(posedge clk or negedge rst)
if(!rst) cnt <= 1'b0;
else if(cnt >= 13'd7499) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
reg clk_800hz;
// 扫描的频率是 800 Hz。
always @(posedge clk or negedge rst)
if(!rst) clk_800hz <= 1'b0;
else if(cnt == 13'd7499) clk_800hz <= ~clk_800hz;
// 时钟分频。
else clk_800hz <= clk_800hz;
// 产生扫描的频率哦。
//reg [12:0] cnt;
//always @(posedge clk or negedge rst_n)
// if(!rst_n) cnt <= 1'b0;
// else if(cnt >= 13'd7499) cnt <= 1'b0;
// else cnt <= cnt + 1'b1;
//
//reg clk_800hz;
//always @(posedge clk or negedge rst_n)
// if(!rst_n) clk_800hz <= 1'b0;
// else if(cnt == 13'd7499) clk_800hz <= ~clk_800hz;
// else clk_800hz <= clk_800hz;
//
input clk;
// 时钟信号。
input rst;
// 重置信号,在2.0版本无使用。
input btn1;
// 设置盒子开机。
input btn2;
// 设置三个药箱中具体操作哪一个。
input btn3; // 按下一次,时间加一秒;
input btn4; // 按下一次,时间减一秒。
// 设置时间。
input btn5;
// 设置完毕时间以后,需要有一个按键来开启装置的工作状态。
input btn6;
// 关闭挺提醒的警报的按键。
output rled1;
output rled2;
output rled3;
output rled4;
// 输出四个led灯,前三个是对应于三个药盒,第四个原本要接蜂鸣器,但是小脚丫没有。
reg led1;
reg led2;
reg led3;
reg led4 = 1;
// led4 = 1,表示在没有正式进入工作转态的时候,是处于熄灭的状态。
// 记录在没有正式进入工作状态的时候的信号。
reg led10;
reg led20;
reg led30;
reg led40;
// 记录在工作状态下的时候的信号。
reg times;
// 设置一个数字来判断是否需要进行 counting 置零的操作啦。
reg times0;
// 设置一个数字来判断是否进行了置零的操作了。
wire times_ = times;
// 连线相接。
wire times0_ = times0;
// 连线相接。
output [8:0] seg_led_1;
output [8:0] seg_led_2;
// 数码管的显示。
wire key_pulse1;
wire key_pulse2;
wire key_pulse3;
wire key_pulse4;
wire key_pulse5;
wire key_pulse6;
// 对应于 6 个按键的按键消抖的输出线。
reg state_of_start_or_nor = 0;
// 判断是否开机了。
reg really_start = 0;
// 判断是否进行提醒吃药的功能了。
reg [3:0] location = 1'd0;
// 记录设置时间的时候的位置。
wire clkout1;
wire clkout2;
wire clkout3;
wire clkout4;
// 有四个时钟分频,因此有四个输出。
reg [1:0] led_position = 2'b11;
// 判断是哪一个药盒需要进行闪烁以及蜂鸣器的提醒。
reg [3:0] seg_data_1= 1'd0;
reg [3:0] seg_data_2= 1'd0;
// 记录没有正式工作的时候的数码管对应的需要显示的数字。
reg [3:0] seg_data_10= 1'd0;
reg [3:0] seg_data_20= 1'd0;
// 记录正式开始工作以后的数码管对应的所需要显示的数字。
reg [8:0] seg [10:0];
// 这个是数码管的显示部分内容,我们会在初始化的之后直接给它赋值。
reg [5:0] first_medicine;
reg [5:0] second_medicine;
reg [5:0] third_medicine;
// 存储服药的时间,因为有三个药箱,所以需要三个数据进行寄存。
reg [5:0] counting;
// 计时器的时间的记录,这个是一秒计一次数字。
initial
begin
seg[0] = 9'h3f;
// 对存储器中第一个数赋值9'b00_0011_1111,相当于共阴极接地,DP点变低不亮;
// 7段显示数字 0。
seg[1] = 9'h06;
// 7段显示数字 1。
seg[2] = 9'h5b;
// 7段显示数字 2。
seg[3] = 9'h4f;
// 7段显示数字 3。
seg[4] = 9'h66;
// 7段显示数字 4。
seg[5] = 9'h6d;
// 7段显示数字 5。
seg[6] = 9'h7d;
// 7段显示数字 6。
seg[7] = 9'h07;
// 7段显示数字 7。
seg[8] = 9'h7f;
// 7段显示数字 8。
seg[9] = 9'h6f;
// 7段显示数字 9。
seg[10] = 9'b0_0111_0110;
// 显示H,表示说明是处于关机的状态,为什么是H呢,因为我的名字的首字母是H。
end
initial
begin
first_medicine <= 2'd0;
second_medicine <= 2'd0;
third_medicine <= 2'd0;
// 让初始的三个计数都是零。
counting <= 2'd00;
times <= 0;
times0 <= 0;
end
reg [63:0] mem___;
// 设置点阵什么都不显示的状态。(初始状态,以及已经吃过药的状态。)
initial
begin
mem___=8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000;
// 所有的点都处于熄灭的状态。
end
// Dot Matrix 有关的显示
reg [63:0] mem;
reg [63:0] mem1;
reg [63:0] mem2;
reg [63:0] mem3;
// 开机了,但是没有正式开始工作时的闪烁现象。
initial
begin
// 初始状态。
mem1=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
// 所有的该亮的显示灯都凉亮了。
mem2=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem3=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第三个灯
end
always@(posedge clk)
begin
// 通过时钟信号来控制,高电平的时候灯灭,低电平的时候灯亮,从而实现闪烁。
if(clkout1)
// 频率是 2 Hz
begin
// 熄灭状态。
mem1=8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
mem2=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem3=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000;
// 第三个灯
end
else
begin
// 恢复状态。
mem1=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
mem2=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem3=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第三个灯
end
end
reg [63:0] mem0;
reg [63:0] mem10;
reg [63:0] mem20;
reg [63:0] mem30;
// 正式开始工作的时候的闪烁的现象。
initial
begin
// 初始状态。
mem10=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
mem20=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem30=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第三个灯
end
always@(posedge clk)
begin
// 也是更上面的那个一样的道理。
if(clkout3)
// 这个是 4 Hz 的频率。
begin
// 熄灭状态。
mem10=8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
mem20=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem30=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0000_0000,
8'b0000_0000;
// 第三个灯
end
else
begin
// 恢复状态。
mem10=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第一个灯
mem20=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第二个灯
mem30=8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000,
8'b0000_0000,
8'b0001_1000,
8'b0001_1000;
// 第三个灯
end
end
// 按键消抖,需要给使用到的 6 个按键都进行消抖,这里rst我们暂时没有用到,也许后续扩展的时候会使用。
debounce_button u1 (
.clk (clk),
.rst (rst),
.key (btn1),
.key_pulse (key_pulse1)
);
debounce_button u2 (
.clk (clk),
.rst (rst),
.key (btn2),
.key_pulse (key_pulse2)
);
debounce_button u3 (
.clk (clk),
.rst (rst),
.key (btn3),
.key_pulse (key_pulse3)
);
debounce_button u4 (
.clk (clk),
.rst (rst),
.key (btn4),
.key_pulse (key_pulse4)
);
debounce_button u5 (
.clk (clk),
.rst (rst),
.key (btn5),
.key_pulse (key_pulse5)
);
debounce_button u6 (
.clk (clk),
.rst (rst),
.key (btn6),
.key_pulse (key_pulse6)
);
// 时钟分频,我们需要一些不同的信号,所以需要不同的分频模块。
time_split #(.N(6000000),
.WIDTH(23)) t1 (
.clk(clk),
.rst_n(rst),
.clkout(clkout1));
// 频率为 2 Hz。
time_split #(.N(12000000),
.WIDTH(24)) t2 (
.clk(clk),
.rst_n(rst),
.clkout(clkout2));
// 频率为 1 Hz。
time_split #(.N(3000000),
.WIDTH(22)) t3 (
.clk(clk),
.rst_n(rst),
.clkout(clkout3));
// 频率为 4 Hz。
time_split #(.N(1500000),
.WIDTH(21)) t4 (
.clk(clk),
.rst_n(rst),
.clkout(clkout4));
// 频率为 8 Hz。
// 显示Dot Matrix.
reg [63:0] memory;
reg [2:0] state;
// 确定采用哪一种方法来对Dot Matrix进行显示。
always@(posedge clk)
begin
if(state_of_start_or_nor && ~really_start)
// 开机了,但是没有完全开始工作,这个时候是由 location 来进行决定的。
begin
// location.
case(location)
4'b0000:
// 第一个位置
begin
mem <= mem1;
end
4'b0001:
// 第二个位置
begin
mem <= mem2;
end
4'b0010:
// 第三个位置
begin
mem <= mem3;
end
default:
// 一共只有三个位置,因此这个也就是显示第三个位置
begin
mem <= mem3;
end
endcase
end
if(state_of_start_or_nor && really_start)
// 开机了,而且是完全开始了。
begin
// led_position.
case(led_position)
2'b00:
// 第一个位置
begin
if(btn_true_or_not1)
// 如果吃过药了。
begin
mem0 <= mem___;
end
else
begin
mem0 <= mem10;
end
end
2'b01:
// 第二个位置
begin
if(btn_true_or_not2)
// 如果吃过药了。
begin
mem0 <= mem___;
end
else
begin
mem0 <= mem20;
end
end
2'b10:
// 第三个位置
begin
if(btn_true_or_not3)
// 如果吃过药了。
begin
mem0 <= mem___;
end
else
begin
mem0 <= mem30;
end
end
default:
// 已经吃过了所有的药了。
begin
mem0 <= mem___;
end
endcase
end
memory = state_of_start_or_nor ? (really_start ? mem0 : mem) : mem___verilog HDL 实现十六路彩灯的控制 谢谢大神
verilog hdl中有了posedge和negedge为啥还要用脉冲边沿检测?。
用Verilog来实现d触发器2分频的Verilog hdl程序