寒假在家一起练项目4小脚丫
本项目基于包含Lattice版本的小脚丫FPGA综合训练板(STEP-MXO2)制作了包括整点报时,调整时间,温度监测的电子钟,并可以与电脑数据互传。
标签
FPGA
张乙凡
更新2021-03-04
904

 一,项目要求

基于包含Lattice版本的小脚丫FPGA综合训练板(STEP-MXO2)完成以下基本功能:

1.实现一个可定时时钟的功能,用小脚丫FPGA核心模块的4个按键设置当前的时间,OLED显示数字钟的当前时间,精确到分钟即可,到整点的时候比如8:00,蜂鸣器报警,播放音频信号,持续30秒;

2.实现温度计的功能,小脚丫通过板上的温度传感器实时测量环境温度,并同时间一起显示在OLED的屏幕上;

3.定时时钟整点报警的同时,将温度信息通过UART传递到电脑上,电脑上能够显示当前板子上的温度信息,要与OLED显示的温度值一致;

4.PC收到报警的温度信号以后,将一段音频文件(自己制作,持续10秒钟左右)通过UART发送给小脚丫FPGA,蜂鸣器播放收到的这段音频文件,OLED屏幕上显示的时间信息和温度信息都停住不再更新;

5.音频文件播放完毕,OLED开始更新时间信息和当前的温度信息

二,项目图片展示

原理图:

FhPOmDahAXYuOZDZhPRSUItHMwZM

实物图:

Fuc60vhu5KmIslC5WGTxJs1qOWTt

串口助手图:

Ftbw_EiSWAnNXiF5jLp-SKjg0NGX

资源占用:

FvOr9UeBtIRWiKMiQezGxsZR3NO1

三,部分代码展示:

  1.top模块是顶层模块,是实现各个功能的控制中心,通过在top模块里调用各个模块功能并进行组合调用,从而实现完整的功能。

module top(
input clk,

input hour,       //时钟
input minj,
input mins,
input rst_n,
input uart_input, //uart
input uart_on,
inout tone_en,
inout one_wire,

output uart_output, 
output beeper 
output oled_csn, //oled
output oled_rst, 
output oled_dcn, 
output oled_clk, 
output oled_dat,
);

wire[15:0] d_out;
wire[3:0] temp1 
wire[3:0] temp2
wire[3:0] temp3
wire[3:0] temp4
wire[3:0] hour1
wire[3:0] hour2
wire[3:0] min1
wire[3:0] min2
wire[3:0] sec1
wire[3:0] sec2
wire flag;

//温度模块
DS18B20Z DS18B20Z_v1(
.clk_in(clk),
.rst_n_in(rst_n),
.one_wire(one_wire),
.data_out(d_out)
);


//OLED显示
OLED12832 OLED12832_v1(
.clk(clk),
.rst_n(rst_n),

.temp1(temp1),
.temp2(temp2),
.temp3(temp3),
.temp4(temp4),

.hour1(hour1),
.hour2(hour2),
.min1(min1),
.min2(min2),
.sec1(sec1),
.sec2(sec2),

.oled_clk(oled_clk),
.oled_csn(oled_csn),
.oled_dat(oled_dat),
.oled_dcn(oled_dcn),
.oled_rst(oled_rst)
);


wire clk_1h;

clk_1h clk_1h_v1(
.clk(clk),
.rst(rst_n),
.clkout(clk_1h)
);

//时钟
clock clock_v1(
.clk1(clk_1h),
.rst_n(rst_n),

.mins(mins),
.minj(minj),
.hour(hour),

.flag(flag),

.hour1(hour1),
.hour2(hour2),
.min1(min1),
.min2(min2),
.sec1(sec1),
.sec2(sec2)
);

//串口
uartfa uartfa_v1(
.clk_in(clk),
.uart_sw(uart_on),

.temp1(temp1),
.temp3(temp3),
.temp4(temp4),

.hour1(hour1),
.hour2(hour2),
.min1(min1),
.min2(min2),
.sec1(sec1),
.sec2(sec2),

.uart_output(uart_output)
);

wire[7:0] d_uart;

uartshou uartshou_v1(
.clk(clk),
.rst_n(rst_n),
.uart_input(uart_input),
.uart_en(uart_en),
.uart_data(d_uart)
);

//蜂鸣器
beeper beeper_v1(
.clk(clk),
.clk_1h(clk_1h),
.rst_n(rst_n),
.tone_en(tone_en),

.min1(min1),
.min2(min2),
.sec1(sec1),

.uart_en(uart_en),
.uart_data(d_uart),

.trflag(flag),
.beeper(beeper)
);
endmodule

二,时间按键控制模块模块:

begin
if(hour2_q > 0)
hour2_q <= hour2_q - 1;
else//five_now = 0
begin
if(hour1_q == 2) 
begin
hour2_q <= 9;
hour1_q <= 1;
end
else if(hour1_q == 1)
begin
hour2_q <= 9;
hour1_q <= 0;
end 
else//if(six_now == 0)
begin
hour2_q <= 3;
hour1_q <= 2;
end
end
end

3'b101://分钟增加
begin
if(min2_q > 0)
min2_q <= min2_q - 1;
else
begin
min2_q <= 9;
if(min1_q> 0)
min1_q <= min1_q - 1;
else
min1_q<= 5;
end
end
default://分钟减少
begin
if(min2_q < 9)
min2_q <= min2_q + 1;
else
begin
min2_q <= 0;
if(min1_q < 5)
min1_q <= min1_q + 1;
else
min1_q <= 0;
end
end
endcase
end
end

三:温度模块

温度模块使用电子森林的模板

module temperature
(
input clk_in, 
input rst_n_in, 
inout one_wire, 
output reg [15:0] data_out 
);
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam INIT = 3'd2;
localparam WRITE = 3'd3;
localparam READ = 3'd4;
localparam DELAY = 3'd5;

reg [2:0] cnt;
reg one_wire_buffer;
reg [3:0] cnt_main;
reg [7:0] data_wr;
reg [7:0] data_wr_buffer;
reg [2:0] cnt_init;
reg [19:0] cnt_delay;
reg [19:0] num_delay;
reg [3:0] cnt_write;
reg [2:0] cnt_read;
reg [15:0] temperature;
reg [7:0] temperature_buffer;
reg [2:0] state = IDLE;
reg [2:0] state_back = IDLE;

reg clk_1mhz;
reg [2:0] cnt_1mhz;
always@(posedge clk_in or negedge rst_n_in) begin
if(!rst_n_in) begin
cnt_1mhz <= 3'd0;
clk_1mhz <= 1'b0;
end else if(cnt_1mhz >= 3'd5) begin
cnt_1mhz <= 3'd0;
clk_1mhz <= ~clk_1mhz; 
end else begin
cnt_1mhz <= cnt_1mhz + 1'b1;
end
end

always@(posedge clk_1mhz or negedge rst_n_in) begin
if(!rst_n_in) begin
state <= IDLE;
state_back <= IDLE;
cnt <= 1'b0;
cnt_main <= 1'b0;
cnt_init <= 1'b0;
cnt_write <= 1'b0;
cnt_read <= 1'b0;
cnt_delay <= 1'b0;
one_wire_buffer <= 1'bz;
temperature <= 16'h0;
end else begin
case(state)
IDLE:begin 
state <= MAIN; 
state_back <= MAIN;
cnt <= 1'b0;
cnt_main <= 1'b0;
cnt_init <= 1'b0;
cnt_write <= 1'b0;
cnt_read <= 1'b0;
cnt_delay <= 1'b0;
one_wire_buffer <= 1'bz;
end
MAIN:begin 
if(cnt_main >= 4'd11) cnt_main <= 1'b0;
else cnt_main <= cnt_main + 1'b1;
case(cnt_main)
4'd0: begin state <= INIT;
end 
4'd1: begin data_wr <= 8'hcc;state <= WRITE;
end 
4'd2: begin data_wr <= 8'h44;state <= WRITE;
end 
4'd3: begin num_delay <= 20'd750000;state <= DELAY;state_back <= MAIN;
end 
4'd4: begin state <= INIT; 
end 
4'd5: begin data_wr <= 8'hcc;state <= WRITE; 
end 
4'd6: begin data_wr <= 8'hbe;state <= WRITE; 
end 
4'd7: begin state <= READ;
end 
4'd8: begin temperature[7:0] <= temperature_buffer;
end 
4'd9: begin state <= READ; 
end 
4'd10: begin temperature[15:8] <= temperature_buffer; 
end 
4'd11: begin state <= IDLE;data_out <= temperature; 
end 
default: state <= IDLE;
endcase
end
INIT:begin 
if(cnt_init >= 3'd6) cnt_init <= 1'b0;
else cnt_init <= cnt_init + 1'b1;
case(cnt_init)
3'd0: begin one_wire_buffer <= 1'b0; 
end 
3'd1: begin num_delay <= 20'd500;state <= DELAY;state_back <= INIT; 
end 
3'd2: begin one_wire_buffer <= 1'bz; 
end 
3'd3: begin num_delay <= 20'd100;state <= DELAY;state_back <= INIT;
end 
3'd4: begin if(one_wire) state <= IDLE; else state <= INIT;
end 
3'd5: begin num_delay <= 20'd400;state <= DELAY;state_back <= INIT; 
end 
3'd6: begin state <= MAIN;
end
default: state <= IDLE;
endcase
end
WRITE:begin 
if(cnt <= 3'd6) begin 
if(cnt_write >= 4'd6) begin cnt_write <= 1'b1; cnt <= cnt + 1'b1;
end
else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt; 
end
end else begin
if(cnt_write >= 4'd8) begin cnt_write <= 1'b0; cnt <= 1'b0;
end
else begin cnt_write <= cnt_write + 1'b1; cnt <= cnt;
end
end

case(cnt_write)

4'd0: begin data_wr_buffer <= data_wr; 
end

4'd1: begin one_wire_buffer <= 1'b0;
end 
4'd2: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE;
end
4'd3: begin one_wire_buffer <= data_wr_buffer[cnt]; 
end 
4'd4: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE;
end 
4'd5: begin one_wire_buffer <= 1'bz;
end 
4'd6: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; 
end 
//back to main
4'd7: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE;
end 
4'd8: begin state <= MAIN; 
end 
default: state <= IDLE;
endcase
end
READ:begin 
if(cnt <= 3'd6) begin 
if(cnt_read >= 3'd5) begin cnt_read <= 1'b0; cnt <= cnt + 1'b1; 
end
else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt;
end
end else begin
if(cnt_read >= 3'd6) begin cnt_read <= 1'b0; cnt <= 1'b0; 
end
else begin cnt_read <= cnt_read + 1'b1; cnt <= cnt;
end
end
case(cnt_read)

3'd0: begin one_wire_buffer <= 1'b0; 
end 
3'd1: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; 
end 
3'd2: begin one_wire_buffer <= 1'bz;
end 
3'd3: begin num_delay <= 20'd5;state <= DELAY;state_back <= READ;
end 
3'd4: begin temperature_buffer[cnt] <= one_wire;
end 
3'd5: begin num_delay <= 20'd60;state <= DELAY;state_back <= READ; 
end 
//back to main
3'd6: begin state <= MAIN;
end 
default: state <= IDLE;
endcase
end
DELAY:begin 
if(cnt_delay >= num_delay) begin 
cnt_delay <= 1'b0;
state <= state_back; 
end else cnt_delay <= cnt_delay + 1'b1;
end
endcase
end
end

assign one_wire = one_wire_buffer;

endmodule

4.蜂鸣器乐谱设定代码。

这里我选用了天空之城这首音乐,虽然有点跑调。

parameter TIME = 3000000;
parameter 
//低音
L1 = 16'd22935, 
L2 = 16'd20428,
L3 = 16'd18203, 
L4 = 16'd17181, 
L5 = 16'd15305, 
L6 = 16'd13635, 
L7 = 16'd12147,
//中音
M1 = 16'd11464, 
M2 = 16'd10215, 
M3 = 16'd9100, 
M4 = 16'd8589, 
M5 = 16'd7652, 
M6 = 16'd6817, 
M7 = 16'd6073,
//高音
H1 = 16'd5740, 
H2 = 16'd5107, 
H3 = 16'd4549, 
H4 = 16'd4294, 
H5 = 16'd3825, 
H6 = 16'd3408, 
H7 = 16'd3036;

assign beeper = beep; //输出
assign trflag = tr;

reg[16:0]count,count_end,count_end1;
reg[23:0]count1;
reg[7:0]state;
always@(posedge clk) 
begin
if(tone_en && min1 == 0 && min2 == 0 && sec1 < 3)
begin
count <= count + 1'b1; 
if(count == count_end)
begin 
count <= 17'h0; 
beep <= !beep; 
end
end
else if(tone_en && !tr)
begin
count <= count + 1'b1; 
if(count == count_end1) 
begin 
count <= 17'h0; 
beep <= !beep; 
end
end
end

//设定乐谱为音乐天空之城
always @(posedge clk) 
begin
if(count1 < TIME) 
count1 = count1 + 1'b1;
else 
begin
count1 = 24'd0;
if(state == 8'd63)
state = 8'd0;
else
state = state + 1'b1;
case(state)
8'd0:count_end=M6; 
8'd1:count_end=M7;

8'd2:count_end=H1;
8'D3:count_end=M7;
8'D4:count_end=H1;
8'D5:count_end=H3;

8'D6:count_end=M7;
8'D7:count_end=M3;
8'D8:count_end=M3;

8'D9:count_end=M6;
8'D10:count_end=M5;
8'D11:count_end=M6;
8'D12:count_end=H1;

8'D14:count_end=M5;
8'D15:count_end=L1;
8'D16:count_end=M6;
8'D17:count_end=M6;

8'D18:count_end=M4;
8'D19:count_end=M3;
8'D20:count_end=M4;
8'D21:count_end=M1;

8'D22:count_end=M3;
8'D23:count_end=H1;
8'D24:count_end=H1;
8'D25:count_end=H1;

8'D26:count_end=M7;
8'D27:count_end=M4;
8'D28:count_end=M4;
8'D29:count_end=M7;

8'D30:count_end=M7;
8'D31:count_end=L1;
8'd32:count_end=M6; 
8'd33:count_end=M7;

8'd34:count_end=L1;
8'D35:count_end=M7;
8'D36:count_end=H1;
8'D37:count_end=H3;

8'D38:count_end=M7;
8'D39:count_end=L1;
8'D40:count_end=M3;
8'D42:count_end=M3;

8'D43:count_end=M6;
8'D44:count_end=M5;
8'D45:count_end=M6;
8'D46:count_end=H1;

8'D47:count_end=M5;
8'D48:count_end=M1;
8'D49:count_end=M1;
8'D50:count_end=M3;

8'D51:count_end=M4;
8'D52:count_end=H1;
8'D53:count_end=M7;
8'D54:count_end=M1;
8'D55:count_end=H1;

8'D56:count_end=H2;
8'D57:count_end=H2;
8'D58:count_end=H3;
8'D59:count_end=H1;

8'D60:count_end=H1;
8'D61:count_end=M7;
8'D62:count_end=M6;
8'D63:count_end=M6;

default: count_end = 16'h0;
endcase
end

五,总结

我本人对于FPGA完全不了解,之前也没有接触过verilog的语法编写,所以代码写的磕磕碰碰的,幸好在这个平台有许多同伴,一些我实在看不懂的,比如串口通信这一部分,通过借鉴他们的成果,才实现要求的功能,最后才完成了这个项目。希望以后可以熟练掌握这些知识,最终能够写出来自己的代码。

 

 

附件下载
xiangmu.jed
团队介绍
北京理工大学,信息与电子学院
团队成员
张乙凡
来自北理工的一个普通学生
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号