一、功能描述
1、实现一个可定时时钟的功能,用小脚丫FPGA核心模块的4个按键设置当前的时间,OLED显示数字钟的当前时间,精确到分钟即可,到整点的时候比如8:00,蜂鸣器报警,播放音频信号,最长可持续30秒;
2、实现温度计的功能,小脚丫通过板上的温度传感器实时测量环境温度,并同时间一起显示在OLED的屏幕上;
3、定时时钟整点报警的同时,将温度信息通过UART传递到电脑上,电脑上能够显示当前板子上的温度信息(任何显示形式都可以),要与OLED显示的温度值一致;
4、PC收到报警的温度信号以后,将一段音频文件(自己制作,持续10秒钟左右)通过UART发送给小脚丫FPGA,蜂鸣器播放收到的这段音频文件,OLED屏幕上显示的时间信息和温度信息都停住不再更新;
5、音频文件播放完毕,OLED开始更新时间信息和当前的温度信息
二、模块划分
1、时钟分频模块
2、波特率时钟产生模块:波特率->9600bps
3、蜂鸣器奏乐模块: 接收来自上位机的乐谱,并确定计时终点。
4、二进制转BCD码模块
5、按键防抖模块
6、温度信息采集及显示模块
7、 Uart收发模块
8、顶层模块:例化各模块,并进行信号连接
9、上位机:显示PC端接收到的温度信息
三、资源占用情况
四、具体代码
1、时钟
module clk_uart_tx(clk_input,clk_output);//9600Baud
input clk_input;
output clk_output;
reg clk_output;
reg[9:0] t;
initial
t = 0;
always @(posedge clk_input)
begin
if(t < 625)
t = t+1;
else
begin
clk_output = ~clk_output;
t = 0;
end
end
endmodule
2、定时时钟
定时时钟相关代码:
module clock(hour_a, min_1,min_2, clk_1ms,clk_500ms,hour_out,min_out,t_i_u);
input hour_a, min_a, clk_1ms,clk_500ms;
output[6:0] hour_out,min_out;
output t_i_u;
reg t_i_u;
reg[6:0] hour_out,min_out;
reg[6:0] hour_mem,min_mem,hour_set,min_set1,min_set2;
reg[15:0] second;
initial
begin
hour_mem = 0;
hour_set = 0;
hour_out = 0;
min_mem = 0;
min_set1 = 0;
min_set2 = 0;
min_out1 = 0;
min_out2=0
second = 0;
t_i_u = 0;
end
always @(posedge clk_500ms)
begin
if(hour_a == 0&& == 0&&min_a == 0&& == 0)
begin
hour_set = 0;
min_set = 0;
end
else if(hour_a == 0)
begin
hour_set = hour_out;
min_set1 = min_out1;
min_set2 = min_out2;
hour_set = hour_set+1;
end
else if(min_1 == 0)
begin
hour_set = hour_out;
min_set1 = min_out1;
min_set1 = min_set1+1;
end
else if(min_2 == 0)
begin
hour_set = hour_out;
min_set2 = min_out2;
min_set2 = min_set2+1;
end
if(hour_set == 24)
hour_set = 0;
if(min_set 1== 6)
min_set = 0;
if(min_set2 ==9)
min_set2 = 0;
end
always @(posedge clk_1ms)
begin
if(t_i_u == 1)
t_i_u = 0;
if(hour_set != hour_mem || min_set != min_mem)
begin
hour_mem = hour_set;
min_mem = min_set;
hour_out = hour_set;
min_out = min_set;
end
else
begin
if(second < 600000)
second = second+1;
else
begin
min_out2 = min_out2+1;
second = 0;
if(min_out2 == 9)
begin
min_out1=min_out1 +1;
if(min_out1 = 6)
begin
hour_out = hour_out+1;
min_out1 = 0;
min_out2 = 0;
end
min_out2 = 0;
t_i_u = 1;
if(hour_out == 24)
begin
hour_out = 0;
end
end
end
end
end
endmodule
3、温度计
温度传感器为DS18B20Z芯片。该芯片为单总线通信,对时序要求较严格。项目中通过驱动温度传感器对温度信息进行读取。并对读取到的数据对温度进行转换。该模块使用的时钟频率为1MHz。该模块主要部分代码为网上教学的已有代码。
module temperature(clk,rst,bus,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;
input clk;
input rst;
inout bus;
output[15:0] data_out;
reg[15:0] data_out;
reg bus_output;
reg io_link;
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,num_delay;
reg[5:0] cnt_write,cnt_read;
reg[15:0] temperature;
reg[7:0] temperature_buffer;
reg[2:0] state,state_back;
initial
begin
state = IDLE;
state_back = IDLE;
end
assign
bus = io_link?bus_output:1'bz;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
state <= IDLE;
state_back <= IDLE;
cnt_main <= 4'd0;
cnt_init <= 3'd0;
cnt_write <= 6'd0;
cnt_read <= 6'd0;
cnt_delay <= 20'd0;
io_link <= 1'b0;
temperature <= 16'h0;
end
else
begin
case(state)
IDLE:
begin
state <= MAIN;
state_back <= MAIN;
cnt_main <= 4'd0;
cnt_init <= 3'd0;
cnt_write <= 6'd0;
cnt_read <= 6'd0;
cnt_delay <= 20'd0;
io_link <= 1'b0;
end
MAIN:
begin
if(cnt_main >= 11)
cnt_main <= 0;
else
cnt_main <= cnt_main+1;
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 <= 0;
else
cnt_init <= cnt_init+1;
case(cnt_init)
3'd0:
begin
io_link <= 1;
bus_output <= 0;
end
3'd1:
begin
num_delay <= 20'd500;
state <= DELAY;
state_back <= INIT;
end
3'd2:
begin
io_link = 0;
end
3'd3:
begin
num_delay <= 20'd100;
state <= DELAY;
state_back <= INIT;
end
3'd4:
begin
if(bus)
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_write >= 6'd50)
cnt_write <= 1'b0;
else
cnt_write <= cnt_write + 1'b1;
case(cnt_write)
6'd0:
begin
data_wr_buffer <= data_wr;
end
//bit0
6'd1:
begin
io_link <= 1;
bus_output <= 0;
end
6'd2:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd3:
begin
bus_output <= data_wr_buffer[0];
end
6'd4:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd5:
begin
io_link <= 0;
end
6'd6:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit1
6'd7:
begin
io_link <= 1;
bus_output <= 0;
end
6'd8:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd9:
begin
bus_output <= data_wr_buffer[1];
end
6'd10:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd11:
begin
io_link <= 0;
end
6'd12:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit2
6'd13:
begin
io_link <= 1;
bus_output <= 0;
end
6'd14:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd15:
begin
bus_output <= data_wr_buffer[2];
end
6'd16:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd17:
begin
io_link <= 0;
end
6'd18:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit3
6'd19:
begin
io_link <= 1;
bus_output <= 0;
end
6'd20:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd21:
begin
bus_output <= data_wr_buffer[3];
end
6'd22:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd23:
begin
io_link <= 0;
end
6'd24:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit4
6'd25:
begin
io_link <= 1;
bus_output <= 0;
end
6'd26:
begin num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd27:
begin
bus_output <= data_wr_buffer[4];
end
6'd28:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd29:
begin
io_link <= 0;
end
6'd30:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit5
6'd31:
begin
io_link <= 1;
bus_output <= 0;
end
6'd32:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd33:
begin
bus_output <= data_wr_buffer[5];
end
6'd34:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd35:
begin
io_link <= 0;
end
6'd36:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit6
6'd37:
begin
io_link <= 1;
bus_output <= 0;
end
6'd38:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd39:
begin
bus_output <= data_wr_buffer[6];
end
6'd40:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd41:
begin
io_link <= 0;
end
6'd42:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//bit7
6'd43:
begin
io_link <= 1;
bus_output <= 0;
end
6'd44:
begin num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
6'd45:
begin
bus_output <= data_wr_buffer[7];
end
6'd46:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd47:
begin
io_link <= 0;
end
6'd48:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= WRITE;
end
//
6'd49:
begin
num_delay <= 20'd80;
state <= DELAY;
state_back <= WRITE;
end
6'd50:
begin state <= MAIN;
end
default:
state = IDLE;
endcase
end
READ:
begin
if(cnt_read >= 6'd48)
cnt_read <= 1'b0;
else
cnt_read <= cnt_read + 1'b1;
case(cnt_read)
//read bit 0
6'd0:
begin
io_link <= 1;
bus_output <= 0;
end
6'd1:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd2:
begin
io_link <= 0;
end
6'd3:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd4:
begin
temperature_buffer[0] <= bus;
end
6'd5:
begin num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 1
6'd6:
begin
io_link <= 1;
bus_output <= 0;
end
6'd7:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd8:
begin
io_link <= 0;
end
6'd9:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd10:
begin
temperature_buffer[1] <= bus;
end
6'd11:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 2
6'd12:
begin
io_link <= 1;
bus_output <= 0;
end
6'd13:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd14:
begin
io_link <= 0;
end
6'd15:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd16:
begin
temperature_buffer[2] <= bus;
end
6'd17:
begin num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 3
6'd18:
begin
io_link <= 1;
bus_output <= 0;
end
6'd19:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd20:
begin
io_link <= 0;
end
6'd21:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd22:
begin
temperature_buffer[3] <= bus;
end
6'd23:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 4
6'd24:
begin
io_link <= 1;
bus_output <= 0;
end
6'd25:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd26:
begin
io_link <= 0;
end
6'd27:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd28:
begin
temperature_buffer[4] <= bus;
end
6'd29:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 5
6'd30:
begin
io_link <= 1;
bus_output <= 0;
end
6'd31:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd32:
begin
io_link <= 0;
end
6'd33:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd34:
begin
temperature_buffer[5] <= bus;
end
6'd35:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 6
6'd36:
begin
io_link <= 1;
bus_output <= 0;
end
6'd37:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd38:
begin
io_link <= 0;
end
6'd39:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd40:
begin
temperature_buffer[6] <= bus;
end
6'd41:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//read bit 7
6'd42:
begin
io_link <= 1;
bus_output <= 0;
end
6'd43:
begin
num_delay <= 20'd2;
state <= DELAY;
state_back <= READ;
end
6'd44:
begin
io_link <= 1;
end
6'd45:
begin
num_delay <= 20'd10;
state <= DELAY;
state_back <= READ;
end
6'd46:
begin
temperature_buffer[7] <= bus;
end
6'd47:
begin
num_delay <= 20'd55;
state <= DELAY;
state_back <= READ;
end
//back to main
6'd48:
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
endmodule
4.控制蜂鸣器播放音乐需要按音乐的拍子去控制蜂鸣器响的频率与时间,利用上位机去控制这个时间。
module Beeper
(
input clk_in, //系统时钟
input rst_n_in, //系统复位,低有效
input tone_en, //蜂鸣器使能信号
input [4:0] tone, //蜂鸣器音节控制
output reg piano_out //蜂鸣器控制输出
);
/*
reg [15:0] time_end;
always@(tone) begin
case(tone)
5'd1: time_end = 16'd22935; //L1,
5'd2: time_end = 16'd20428; //L2,
5'd3: time_end = 16'd18203; //L3,
5'd4: time_end = 16'd17181; //L4,
5'd5: time_end = 16'd15305; //L5,
5'd6: time_end = 16'd13635; //L6,
5'd7: time_end = 16'd12147; //L7,
5'd8: time_end = 16'd11464; //M1,
5'd9: time_end = 16'd10215; //M2,
5'd10: time_end = 16'd9100; //M3,
5'd11: time_end = 16'd8589; //M4,
5'd12: time_end = 16'd7652; //M5,
5'd13: time_end = 16'd6817; //M6,
5'd14: time_end = 16'd6073; //M7,
5'd15: time_end = 16'd5740; //H1,
5'd16: time_end = 16'd5107; //H2,
5'd17: time_end = 16'd4549; //H3,
5'd18: time_end = 16'd4294; //H4,
5'd19: time_end = 16'd3825; //H5,
5'd20: time_end = 16'd3408; //H6,
5'd21: time_end = 16'd3036; //H7,
default:time_end = 16'd65535;
endcase
end
reg [17:0] time_cnt;
//当蜂鸣器使能时,计数器按照计数终值(分频系数)计数
always@(posedge clk_in or negedge rst_n_in) begin
if(!rst_n_in) begin
time_cnt <= 1'b0;
end else if(!tone_en) begin
time_cnt <= 1'b0;
end else if(time_cnt>=time_end) begin
time_cnt <= 1'b0;
end else begin
time_cnt <= time_cnt + 1'b1;
end
end
//根据计数器的周期,翻转蜂鸣器控制信号
always@(posedge clk_in or negedge rst_n_in) begin
if(!rst_n_in) begin
piano_out <= 1'b0;
end else if(time_cnt==time_end) begin
piano_out <= ~piano_out; //蜂鸣器控制输出翻转,两次翻转为1Hz
end else begin
piano_out <= piano_out;
end
end
endmodule
6、使用了几个特殊的数值作为开始结束的判断
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
beep_state <= 1'b0;
else
case(beep_data)
8'd01: cycle = 16'd45872;
8'd02: cycle = 16'd40858;
8'd03: cycle = 16'd36408;
8'd04: cycle = 16'd34364;
8'd05: cycle = 16'd30612;
8'd06: cycle = 16'd27273;
8'd07: cycle = 16'd24296;
8'd11: cycle = 16'd22931;
8'd12: cycle = 16'd20432;
8'd13: cycle = 16'd18201;
8'd14: cycle = 16'd17180;
8'd15: cycle = 16'd15306;
8'd16: cycle = 16'd13636;
8'd17: cycle = 16'd12148;
8'd21: cycle = 16'd11478;
8'd22: cycle = 16'd10215;
8'd100: beep_state <= 1'b0;
8'd200: beep_state <= 1'b1;
default: begin
cycle = 16'd0; //cycle为0,PWM占空比为0,低电平
beep_state <= beep_state;
end
endcase
end
五、总结
由于我在毕业设计中选择了有关FPGA的项目,所以看到这个寒假一起锻炼的项目就报名参加了,主要是为了学习对verilog语句的理解和使用,在项目的实现过程中遇到了很多的困难,对diamond的使用是其中最大的困难之一。在任务完成过程中,参考了很多已经完成的项目菜勉强完成这次实验,希望以后可以有些进步。