项目需求
该项目基于小脚丫FPGA的综合技能训练板,制作一个能够计时、测温、定时报警、串口控制的系统,具体功能如下:
- 实现一个可定时时钟的功能,用小脚丫FPGA核心模块的4个按键设置当前的时间,OLED显示数字钟的当前时间,精确到分钟即可,到整点的时候比如8:00,蜂鸣器报警,播放音频信号,最长可持续30秒;
- 实现温度计的功能,小脚丫通过板上的温度传感器实时测量环境温度,并同时间一起显示在OLED的屏幕上;
- 定时时钟整点报警的同时,将温度信息通过UART传递到电脑上,电脑上能够显示当前板子上的温度信息(任何显示形式都可以),要与OLED显示的温度值一致;
- PC收到报警的温度信号以后,将一段音频文件(自己制作,持续10秒钟左右)通过UART发送给小脚丫FPGA,蜂鸣器播放收到的这段音频文件,OLED屏幕上显示的时间信息和温度信息都停住不再更新;
- 音频文件播放完毕,OLED开始更新时间信息和当前的温度信息
项目所用资源
1. 核心板:基于Altera MAX10的STEP-MAX10小脚丫FPGA。
2. 核心板板载资源:4路拨码开关; 4路按键开关。
3. 扩展板所用资源:
SSD1306驱动的128*32分辨率的OLED屏幕;
DS18B20Z单总线温度传感器;
无源蜂鸣器;
micro-usb端口的UART数据传输模块。
项目实现
1.总体设计框图:
本项目的主要模块为:温度传感器模块(DS18B20)、OLED模块、UART串口通信模块、蜂鸣器模块、时钟模块。
顶层文件如下:
module top(
input clk,
input rst,
input mindown,
input minup,
input hourdown,
inout tone_en,
input onoff_uart_t,
inout one_wire,
input uart_rxd,
output oled_csn,
output oled_rst,
output oled_dcn, //OLCD数据指令控制
output oled_clk, //OLCD时钟信号
output oled_dat, //OLCD数据信号
output uart_out,
output beep
);
wire[3:0] temp_h;
wire[3:0] temp_t;
wire[3:0] temp_u;
wire[3:0] temp_d;
wire[3:0] six;
wire[3:0] five;
wire[3:0] four;
wire[3:0] three;
wire[3:0] two;
wire[3:0] one;
wire[15:0] data_out;
wire[7:0] uart_data;
wire clk1h;
wire fresh_flag;
OLED12832 OLED12832_v1(
.clk(clk),
.rst_n(rst),
.temp_d(temp_d),
.temp_h(temp_h),
.temp_t(temp_t),
.temp_u(temp_u),
.six(six),
.five(five),
.four(four),
.three(three),
.two(two),
.one(one),
.oled_clk(oled_clk),
.oled_csn(oled_csn),
.oled_dat(oled_dat),
.oled_dcn(oled_dcn),
.oled_rst(oled_rst)
);
DS18B20Z DS18B20Z_v1(
.clk_in(clk),
.rst_n_in(rst),
.one_wire(one_wire),
.data_out(data_out)
);
TempDatCvrt TempDatCvrt_v1(
.datin(data_out),
.clk(clk),
.rst(rst),
.fresh_flag(fresh_flag),
.dat_d(temp_d),
.dat_h(temp_h),
.dat_t(temp_t),
.dat_u(temp_u)
);
FreqDiv FreqDiv_v1(
.clk(clk),
.rst(rst),
.clkout(clk1h)
);
clock clock_v1(
.clk1h(clk1h),
.rst(rst),
.mindown(mindown),
.minup(minup),
.hourdown(hourdown),
.fresh_flag(fresh_flag),
.six(six),
.five(five),
.four(four),
.three(three),
.two(two),
.one(one)
);
uart_tx uart_tx_v1(
.clk_in(clk),
.onoff_uart_t(onoff_uart_t),
.temp_d(temp_d),
.temp_t(temp_t),
.temp_u(temp_u),
.six(six),
.five(five),
.four(four),
.three(three),
.two(two),
.one(one),
.uart_out(uart_out)
);
song song_v1(
.clk(clk),
.clk1h(clk1h),
.rst(rst),
.tone_en(tone_en),
.uart_done(uart_done),
.uart_data(uart_data),
.two(two),
.three(three),
.four(four),
.fresh_flag(fresh_flag),
.beep(beep)
);
uart_recv uart_recv_v1(
.sys_clk(clk),
.sys_rst_n(rst),
.uart_rxd(uart_rxd),
.uart_done(uart_done),
.uart_data(uart_data)
);
endmodule
2. 温度传感器模块
温度传感器模块通过温度总线与温度传感器外设进行数据交互,得到外界温度数据,并将其分发到UART数据传输模块和OLED显示屏模块。本项目使用的DS18B20Z温度传感器代码主要来自于电子森林的案例分享并加以修改。
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; //1MHz时钟
input rst;
inout bus; //DS18B20Z传感器单总线,双向管脚
output[15:0] data_out;//DS18B20Z有效温度数据输出
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
3. OLED模块
OLED显示屏模块完成温度数据和时间数据的显示,并在温度报警信号来临时暂停OLED显示屏的刷新。本项目使用的OLED显示屏代码主要来自于电子森林的案例分享,通过稍加修改使得其能够接收温度数据以及时间数据并将其显示在显示屏上,并能够接收温度报警信号实现显示屏停止刷新的功能
module OLED(clk,rst,hour_0,hour_1,min_0,min_1,tem_0,tem_1,tem_sign,oled_csn,oled_rst,oled_dcn,oled_clk,oled_dat);
input clk,rst,tem_sign;
input[7:0] hour_1,hour_0,min_1,min_0,tem_1,tem_0;
output oled_csn,oled_rst,oled_dcn,oled_clk,oled_dat;
reg oled_csn,oled_rst,oled_dcn,oled_clk,oled_dat;
localparam INIT_DEPTH = 16'd25;
localparam IDLE = 6'h1, MAIN = 6'h2, INIT = 6'h4, SCAN = 6'h8, WRITE = 6'h10, DELAY = 6'h20;
localparam HIGH = 1'b1, LOW = 1'b0;
localparam DATA = 1'b1, CMD = 1'b0;
localparam time_long = 5;//time:
localparam temp_long = 12;//temperature:
reg[7:0] cmd[24:0];
reg[39:0] mem[123:0];
reg[7:0] y_p,x_ph,x_pl;
reg[(8*21-1):0] char;
reg[7:0] num,char_reg;
reg[4:0] cnt_main,cnt_init,cnt_scan,cnt_write;
reg[15:0] num_delay,cnt_delay,cnt;
reg[5:0] state,state_back;
reg[39:0] time_head;
reg[95:0] temp_head;
wire[7:0] sign;
assign sign = tem_sign?" ":"+";
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
cnt_main <= 1'b0;
cnt_init <= 1'b0;
cnt_scan <= 1'b0;
cnt_write <= 1'b0;
y_p <= 1'b0;
x_ph <= 1'b0;
x_pl <= 1'b0;
num <= 1'b0;
char <= 1'b0;
char_reg <= 1'b0;
num_delay <= 16'd5;
cnt_delay <= 1'b0;
cnt <= 1'b0;
oled_csn <= HIGH;
oled_rst <= HIGH;
oled_dcn <= CMD;
oled_clk <= HIGH;
oled_dat <= LOW;
state <= IDLE;
state_back <= IDLE;
end
else
begin
case(state)
IDLE:
begin
cnt_main <= 1'b0;
cnt_init <= 1'b0;
cnt_scan <= 1'b0;
cnt_write <= 1'b0;
y_p <= 1'b0;
x_ph <= 1'b0;
x_pl <= 1'b0;
num <= 1'b0;
char <= 1'b0;
char_reg <= 1'b0;
num_delay <= 16'd5;
cnt_delay <= 1'b0;
cnt <= 1'b0;
oled_csn <= HIGH;
oled_rst <= HIGH;
oled_dcn <= CMD;
oled_clk <= HIGH;
oled_dat <= LOW;
state <= MAIN;
state_back <= MAIN;
end
MAIN:
begin
if(cnt_main >= 4)
cnt_main <= 1;
else
cnt_main <= cnt_main+1;
case(cnt_main)
5'd0:begin state <= INIT; end
5'd1:
begin
y_p <= 8'hb0;
x_ph <= 8'h10;
x_pl <= 8'h00;
num <= 5'd16;
char <= {" "};
state <= SCAN;
end
5'd2:
begin
y_p <= 8'hb1;
x_ph <= 8'h10;
x_pl <= 8'h00;
num <= 5'd16;
char <= {time_head,hour_1,hour_0,":",min_1,min_0," "};
state <= SCAN;
end
5'd3:
begin
y_p <= 8'hb2;
x_ph <= 8'h10;
x_pl <= 8'h00;
num <= 5'd16;
char <= {" "};
state <= SCAN;
end
5'd4:
begin
y_p <= 8'hb3;
x_ph <= 8'h10;
x_pl <= 8'h00;
num <= 5'd16;
char <= {temp_head,sign,tem_1,tem_0,8'h7b,"C"," "};
state <= SCAN;
end
default: state <= IDLE;
endcase
end
INIT:
begin //初始化状态
case(cnt_init)
5'd0: begin oled_rst <= LOW; cnt_init <= cnt_init + 1'b1; end //复位有效
5'd1: begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end //延时大于3us
5'd2: begin oled_rst <= HIGH; cnt_init <= cnt_init + 1'b1; end //复位恢复
5'd3: begin num_delay <= 16'd25000; state <= DELAY; state_back <= INIT; cnt_init <= cnt_init + 1'b1; end //延时大于220us
5'd4: begin
if(cnt>=INIT_DEPTH)
begin //当25条指令及数据发出后,配置完成
cnt <= 1'b0;
cnt_init <= cnt_init + 1'b1;
end
else
begin
cnt <= cnt + 1'b1;
num_delay <= 16'd5;
oled_dcn <= CMD;
char_reg <= cmd[cnt];
state <= WRITE;
state_back <= INIT;
end
end
5'd5: begin cnt_init <= 1'b0; state <= MAIN; end //初始化完成,返回MAIN状态
default: state <= IDLE;
endcase
end
SCAN:
begin //刷屏状态,从RAM中读取数据刷屏
if(cnt_scan == 5'd11)
begin
if(num)
cnt_scan <= 5'd3;
else
cnt_scan <= cnt_scan + 1'b1;
end
else if(cnt_scan == 5'd12)
cnt_scan <= 1'b0;
else
cnt_scan <= cnt_scan + 1'b1;
case(cnt_scan)
5'd 0: begin oled_dcn <= CMD; char_reg <= y_p; state <= WRITE; state_back <= SCAN; end //定位列页地址
5'd 1: begin oled_dcn <= CMD; char_reg <= x_pl; state <= WRITE; state_back <= SCAN; end //定位行地址低位
5'd 2: begin oled_dcn <= CMD; char_reg <= x_ph; state <= WRITE; state_back <= SCAN; end //定位行地址高位
5'd 3: begin num <= num - 1'b1;end
5'd 4: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end //将5*8点阵编程8*8
5'd 5: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end //将5*8点阵编程8*8
5'd 6: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end //将5*8点阵编程8*8
5'd 7: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][39:32]; state <= WRITE; state_back <= SCAN; end
5'd 8: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][31:24]; state <= WRITE; state_back <= SCAN; end
5'd 9: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][23:16]; state <= WRITE; state_back <= SCAN; end
5'd10: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][15: 8]; state <= WRITE; state_back <= SCAN; end
5'd11: begin oled_dcn <= DATA; char_reg <= mem[char[(num*8)+:8]][ 7: 0]; state <= WRITE; state_back <= SCAN; end
5'd12: begin state <= MAIN; end
default: state <= IDLE;
endcase
end
WRITE:
begin //WRITE状态,将数据按照SPI时序发送给屏幕
if(cnt_write >= 5'd17)
cnt_write <= 1'b0;
else
cnt_write <= cnt_write + 1'b1;
case(cnt_write)
5'd 0: begin oled_csn <= LOW; end //9位数据最高位为命令数据控制位
5'd 1: begin oled_clk <= LOW; oled_dat <= char_reg[7]; end //先发高位数据
5'd 2: begin oled_clk <= HIGH; end
5'd 3: begin oled_clk <= LOW; oled_dat <= char_reg[6]; end
5'd 4: begin oled_clk <= HIGH; end
5'd 5: begin oled_clk <= LOW; oled_dat <= char_reg[5]; end
5'd 6: begin oled_clk <= HIGH; end
5'd 7: begin oled_clk <= LOW; oled_dat <= char_reg[4]; end
5'd 8: begin oled_clk <= HIGH; end
5'd 9: begin oled_clk <= LOW; oled_dat <= char_reg[3]; end
5'd10: begin oled_clk <= HIGH; end
5'd11: begin oled_clk <= LOW; oled_dat <= char_reg[2]; end
5'd12: begin oled_clk <= HIGH; end
5'd13: begin oled_clk <= LOW; oled_dat <= char_reg[1]; end
5'd14: begin oled_clk <= HIGH; end
5'd15: begin oled_clk <= LOW; oled_dat <= char_reg[0]; end //后发低位数据
5'd16: begin oled_clk <= HIGH; end
5'd17: begin oled_csn <= HIGH; state <= DELAY; end //
default: state <= IDLE;
endcase
end
DELAY:
begin //延时状态
if(cnt_delay >= num_delay)
begin
cnt_delay <= 16'd0;
state <= state_back;
end
else
cnt_delay <= cnt_delay + 1'b1;
end
default:state <= IDLE;
endcase
end
end
initial
begin
time_head = "TIME:";
temp_head = "TEMP:";
cnt_main = 1'b0;
cnt_init = 1'b0;
cnt_scan = 1'b0;
cnt_write = 1'b0;
y_p = 1'b0;
x_ph = 1'b0;
x_pl = 1'b0;
num = 1'b0;
char = 1'b0;
char_reg = 1'b0;
num_delay = 16'd5;
cnt_delay = 1'b0;
cnt = 1'b0;
oled_csn <= HIGH;
oled_rst <= HIGH;
oled_dcn <= CMD;
oled_clk <= HIGH;
oled_dat <= LOW;
state <= IDLE;
state_back <= IDLE;
cmd[ 0] = {8'hae};
cmd[ 1] = {8'h00};
cmd[ 2] = {8'h10};
cmd[ 3] = {8'h00};
cmd[ 4] = {8'hb0};
cmd[ 5] = {8'h81};
cmd[ 6] = {8'hff};
cmd[ 7] = {8'ha1};
cmd[ 8] = {8'ha6};
cmd[ 9] = {8'ha8};
cmd[10] = {8'h1f};
cmd[11] = {8'hc8};
cmd[12] = {8'hd3};
cmd[13] = {8'h00};
cmd[14] = {8'hd5};
cmd[15] = {8'h80};
cmd[16] = {8'hd9};
cmd[17] = {8'h1f};
cmd[18] = {8'hda};
cmd[19] = {8'h00};
cmd[20] = {8'hdb};
cmd[21] = {8'h40};
cmd[22] = {8'h8d};
cmd[23] = {8'h14};
cmd[24] = {8'haf};
mem[ 0] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E}; // 48 0
mem[ 1] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00}; // 49 1
mem[ 2] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46}; // 50 2
mem[ 3] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31}; // 51 3
mem[ 4] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10}; // 52 4
mem[ 5] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39}; // 53 5
mem[ 6] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30}; // 54 6
mem[ 7] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03}; // 55 7
mem[ 8] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36}; // 56 8
mem[ 9] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E}; // 57 9
mem[ 10] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C}; // 65 A
mem[ 11] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36}; // 66 B
mem[ 12] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22}; // 67 C
mem[ 13] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C}; // 68 D
mem[ 14] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41}; // 69 E
mem[ 15] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01}; // 70 F
mem[ 32] = {8'h00, 8'h00, 8'h00, 8'h00, 8'h00}; // 32 sp
mem[ 33] = {8'h00, 8'h00, 8'h2f, 8'h00, 8'h00}; // 33 !
mem[ 34] = {8'h00, 8'h07, 8'h00, 8'h07, 8'h00}; // 34
mem[ 35] = {8'h14, 8'h7f, 8'h14, 8'h7f, 8'h14}; // 35 #
mem[ 36] = {8'h24, 8'h2a, 8'h7f, 8'h2a, 8'h12}; // 36 $
mem[ 37] = {8'h62, 8'h64, 8'h08, 8'h13, 8'h23}; // 37 %
mem[ 38] = {8'h36, 8'h49, 8'h55, 8'h22, 8'h50}; // 38 &
mem[ 39] = {8'h00, 8'h05, 8'h03, 8'h00, 8'h00}; // 39 '
mem[ 40] = {8'h00, 8'h1c, 8'h22, 8'h41, 8'h00}; // 40 (
mem[ 41] = {8'h00, 8'h41, 8'h22, 8'h1c, 8'h00}; // 41 )
mem[ 42] = {8'h14, 8'h08, 8'h3E, 8'h08, 8'h14}; // 42 *
mem[ 43] = {8'h08, 8'h08, 8'h3E, 8'h08, 8'h08}; // 43 +
mem[ 44] = {8'h00, 8'h00, 8'hA0, 8'h60, 8'h00}; // 44 ,
mem[ 45] = {8'h08, 8'h08, 8'h08, 8'h08, 8'h08}; // 45 -
mem[ 46] = {8'h00, 8'h60, 8'h60, 8'h00, 8'h00}; // 46 .
mem[ 47] = {8'h20, 8'h10, 8'h08, 8'h04, 8'h02}; // 47 /
mem[ 48] = {8'h3E, 8'h51, 8'h49, 8'h45, 8'h3E}; // 48 0
mem[ 49] = {8'h00, 8'h42, 8'h7F, 8'h40, 8'h00}; // 49 1
mem[ 50] = {8'h42, 8'h61, 8'h51, 8'h49, 8'h46}; // 50 2
mem[ 51] = {8'h21, 8'h41, 8'h45, 8'h4B, 8'h31}; // 51 3
mem[ 52] = {8'h18, 8'h14, 8'h12, 8'h7F, 8'h10}; // 52 4
mem[ 53] = {8'h27, 8'h45, 8'h45, 8'h45, 8'h39}; // 53 5
mem[ 54] = {8'h3C, 8'h4A, 8'h49, 8'h49, 8'h30}; // 54 6
mem[ 55] = {8'h01, 8'h71, 8'h09, 8'h05, 8'h03}; // 55 7
mem[ 56] = {8'h36, 8'h49, 8'h49, 8'h49, 8'h36}; // 56 8
mem[ 57] = {8'h06, 8'h49, 8'h49, 8'h29, 8'h1E}; // 57 9
mem[ 58] = {8'h00, 8'h36, 8'h36, 8'h00, 8'h00}; // 58 :
mem[ 59] = {8'h00, 8'h56, 8'h36, 8'h00, 8'h00}; // 59 ;
mem[ 60] = {8'h08, 8'h14, 8'h22, 8'h41, 8'h00}; // 60 <
mem[ 61] = {8'h14, 8'h14, 8'h14, 8'h14, 8'h14}; // 61 =
mem[ 62] = {8'h00, 8'h41, 8'h22, 8'h14, 8'h08}; // 62 >
mem[ 63] = {8'h02, 8'h01, 8'h51, 8'h09, 8'h06}; // 63 ?
mem[ 64] = {8'h32, 8'h49, 8'h59, 8'h51, 8'h3E}; // 64 @
mem[ 65] = {8'h7C, 8'h12, 8'h11, 8'h12, 8'h7C}; // 65 A
mem[ 66] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h36}; // 66 B
mem[ 67] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h22}; // 67 C
mem[ 68] = {8'h7F, 8'h41, 8'h41, 8'h22, 8'h1C}; // 68 D
mem[ 69] = {8'h7F, 8'h49, 8'h49, 8'h49, 8'h41}; // 69 E
mem[ 70] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h01}; // 70 F
mem[ 71] = {8'h3E, 8'h41, 8'h49, 8'h49, 8'h7A}; // 71 G
mem[ 72] = {8'h7F, 8'h08, 8'h08, 8'h08, 8'h7F}; // 72 H
mem[ 73] = {8'h00, 8'h41, 8'h7F, 8'h41, 8'h00}; // 73 I
mem[ 74] = {8'h20, 8'h40, 8'h41, 8'h3F, 8'h01}; // 74 J
mem[ 75] = {8'h7F, 8'h08, 8'h14, 8'h22, 8'h41}; // 75 K
mem[ 76] = {8'h7F, 8'h40, 8'h40, 8'h40, 8'h40}; // 76 L
mem[ 77] = {8'h7F, 8'h02, 8'h0C, 8'h02, 8'h7F}; // 77 M
mem[ 78] = {8'h7F, 8'h04, 8'h08, 8'h10, 8'h7F}; // 78 N
mem[ 79] = {8'h3E, 8'h41, 8'h41, 8'h41, 8'h3E}; // 79 O
mem[ 80] = {8'h7F, 8'h09, 8'h09, 8'h09, 8'h06}; // 80 P
mem[ 81] = {8'h3E, 8'h41, 8'h51, 8'h21, 8'h5E}; // 81 Q
mem[ 82] = {8'h7F, 8'h09, 8'h19, 8'h29, 8'h46}; // 82 R
mem[ 83] = {8'h46, 8'h49, 8'h49, 8'h49, 8'h31}; // 83 S
mem[ 84] = {8'h01, 8'h01, 8'h7F, 8'h01, 8'h01}; // 84 T
mem[ 85] = {8'h3F, 8'h40, 8'h40, 8'h40, 8'h3F}; // 85 U
mem[ 86] = {8'h1F, 8'h20, 8'h40, 8'h20, 8'h1F}; // 86 V
mem[ 87] = {8'h3F, 8'h40, 8'h38, 8'h40, 8'h3F}; // 87 W
mem[ 88] = {8'h63, 8'h14, 8'h08, 8'h14, 8'h63}; // 88 X
mem[ 89] = {8'h07, 8'h08, 8'h70, 8'h08, 8'h07}; // 89 Y
mem[ 90] = {8'h61, 8'h51, 8'h49, 8'h45, 8'h43}; // 90 Z
mem[ 91] = {8'h00, 8'h7F, 8'h41, 8'h41, 8'h00}; // 91 [
mem[ 92] = {8'h55, 8'h2A, 8'h55, 8'h2A, 8'h55}; // 92 .
mem[ 93] = {8'h00, 8'h41, 8'h41, 8'h7F, 8'h00}; // 93 ]
mem[ 94] = {8'h04, 8'h02, 8'h01, 8'h02, 8'h04}; // 94 ^
mem[ 95] = {8'h40, 8'h40, 8'h40, 8'h40, 8'h40}; // 95 _
mem[ 96] = {8'h00, 8'h01, 8'h02, 8'h04, 8'h00}; // 96 '
mem[ 97] = {8'h20, 8'h54, 8'h54, 8'h54, 8'h78}; // 97 a
mem[ 98] = {8'h7F, 8'h48, 8'h44, 8'h44, 8'h38}; // 98 b
mem[ 99] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h20}; // 99 c
mem[100] = {8'h38, 8'h44, 8'h44, 8'h48, 8'h7F}; // 100 d
mem[101] = {8'h38, 8'h54, 8'h54, 8'h54, 8'h18}; // 101 e
mem[102] = {8'h08, 8'h7E, 8'h09, 8'h01, 8'h02}; // 102 f
mem[103] = {8'h18, 8'hA4, 8'hA4, 8'hA4, 8'h7C}; // 103 g
mem[104] = {8'h7F, 8'h08, 8'h04, 8'h04, 8'h78}; // 104 h
mem[105] = {8'h00, 8'h44, 8'h7D, 8'h40, 8'h00}; // 105 i
mem[106] = {8'h40, 8'h80, 8'h84, 8'h7D, 8'h00}; // 106 j
mem[107] = {8'h7F, 8'h10, 8'h28, 8'h44, 8'h00}; // 107 k
mem[108] = {8'h00, 8'h41, 8'h7F, 8'h40, 8'h00}; // 108 l
mem[109] = {8'h7C, 8'h04, 8'h18, 8'h04, 8'h78}; // 109 m
mem[110] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h78}; // 110 n
mem[111] = {8'h38, 8'h44, 8'h44, 8'h44, 8'h38}; // 111 o
mem[112] = {8'hFC, 8'h24, 8'h24, 8'h24, 8'h18}; // 112 p
mem[113] = {8'h18, 8'h24, 8'h24, 8'h18, 8'hFC}; // 113 q
mem[114] = {8'h7C, 8'h08, 8'h04, 8'h04, 8'h08}; // 114 r
mem[115] = {8'h48, 8'h54, 8'h54, 8'h54, 8'h20}; // 115 s
mem[116] = {8'h04, 8'h3F, 8'h44, 8'h40, 8'h20}; // 116 t
mem[117] = {8'h3C, 8'h40, 8'h40, 8'h20, 8'h7C}; // 117 u
mem[118] = {8'h1C, 8'h20, 8'h40, 8'h20, 8'h1C}; // 118 v
mem[119] = {8'h3C, 8'h40, 8'h30, 8'h40, 8'h3C}; // 119 w
mem[120] = {8'h44, 8'h28, 8'h10, 8'h28, 8'h44}; // 120 x
mem[121] = {8'h1C, 8'hA0, 8'hA0, 8'hA0, 8'h7C}; // 121 y
mem[122] = {8'h44, 8'h64, 8'h54, 8'h4C, 8'h44}; // 122 z
mem[123] = {8'h00, 8'h00, 8'h00, 8'h03, 8'h03}; // 123
end
endmodule
4.蜂鸣器模块
蜂鸣器模块接收来自OLED显示屏的整点信号来达到整点报时功能,并要接收来自UART的报警音乐数据,转发来自UART的温度报警信号给OLED显示屏。
module buzzer(tri_time,tri_uart,data_uart,clk,clk_buzzer,stop,out);
input tri_time,tri_uart,clk,clk_buzzer;
input[231:0] data_uart;
output stop,out;
localparam size = 29;
localparam IDLE = 2'b00;
localparam LOAD_1 = 2'b01;
localparam LOAD_2 = 2'b10;
localparam MAIN = 2'b11;
reg stop,out;
reg[3:0] tone;
reg[5:0] num;
reg[15:0] time_end;
reg[17:0] time_cnt;
reg[size*8-1:0] music;
reg[1:0] state;
reg flag_1,flag_2;
reg[2:0] judge;
reg[23:0] num_delay;
initial
begin
stop = 1;
music = 0;
flag_1 = 0;
flag_2 = 0;
num = size-1;
time_cnt = 0;
state = 2'b00;
end
always @(posedge clk_buzzer)
begin
case(state)
IDLE:
begin
music = 0;
case(judge)
2'b01:state = LOAD_1;
2'b10:state = LOAD_2;
default:state = IDLE;
endcase
end
LOAD_1://整点报警
begin
music = 120'h0606070708080a0a0d0d00;//16进制 1234567
num = 12;//14个音符+末尾两个0
state = MAIN;
end
LOAD_2://uart接收到音乐数据后报警
begin
music = data_uart;
num = 28;//28个音符+末尾两个0
state = MAIN;
stop = 0;
end
MAIN:
begin
if(num == 0)
begin
num <= 0;
state <= IDLE;
stop <= 1;
end
else
begin
tone <= music[num*8+:8];
num <= num - 1;
end
end
default:state = IDLE;
endcase
end
always @(posedge clk)
begin
case(tone)
5'd1: time_end = 16'd22935; //L1,01
5'd2: time_end = 16'd20428; //L2,02
5'd3: time_end = 16'd18203; //L3,03
5'd4: time_end = 16'd17181; //L4,04
5'd5: time_end = 16'd15305; //L5,05
5'd6: time_end = 16'd13635; //L6,06
5'd7: time_end = 16'd12147; //L7,07
5'd8: time_end = 16'd11464; //M1,08
5'd9: time_end = 16'd10215; //M2,09
5'd10: time_end = 16'd9100; //M3,0a
5'd11: time_end = 16'd8589; //M4,0b
5'd12: time_end = 16'd7652; //M5,0c
5'd13: time_end = 16'd6817; //M6,0d
5'd14: time_end = 16'd6073; //M7,0e
5'd15: time_end = 16'd5740; //H1,0f
5'd16: time_end = 16'd5107; //H2,11
5'd17: time_end = 16'd4549; //H3,12
5'd18: time_end = 16'd4294; //H4,13
5'd19: time_end = 16'd3825; //H5,14
5'd20: time_end = 16'd3408; //H6,15
5'd21: time_end = 16'd3036; //H7,16
default: time_end = 16'd0;
endcase
if(time_end == 0||num == 0)
out <= 0;
else if(time_cnt >= time_end) //蜂鸣器发声
begin
out <= ~out;
time_cnt <= 0;
end
else
time_cnt <= time_cnt + 1;
end
always @(posedge clk)
begin
if(num_delay != 0)
begin
num_delay = num_delay - 1;
end
else
begin
judge[0] = tri_time;
judge[1] = tri_uart;
if(judge != 0)
num_delay = 7000000;
else
num_delay = 0;
end
end
endmodule
5. UART通信模块
UART数据传输模块负责与上位机进行通信。不仅要把来自温度传感器的温度数据传输给上位机,还要接收来自上位机的报警信号以及报警音乐数据,并将它们送至蜂鸣器。
module uart_tx(tem_0,tem_1,clk,en,uart_out);
localparam IDLE = 2'b0;
localparam SEND = 2'b1;
input[7:0] tem_0,tem_1;
input clk,en;
output uart_out;
reg uart_out,flag_1,flag_2,state;
reg[101:0] uart_data;
reg[7:0] tab[9:0];
reg[6:0] i;
initial
begin
tab[0] = 8'h30;
tab[1] = 8'h31;
tab[2] = 8'h32;
tab[3] = 8'h33;
tab[4] = 8'h34;
tab[5] = 8'h35;
tab[6] = 8'h36;
tab[7] = 8'h37;
tab[8] = 8'h38;
tab[9] = 8'h39;
uart_data = 1;
flag_1 = 0;
flag_2 = 0;
i = 0;
state = IDLE;
end
always @(posedge en)
begin
uart_data = {1'd1,8'h43,1'd0,1'd1,8'he3,1'd0,1'd1,8'ha1,1'd0,1'd1,tab[tem_0],1'd0,1'd1,tab[tem_1],1'd0,
1'd1,8'h3a,1'd0,1'd1,8'h70,1'd0,1'd1,8'h6d,1'd0,1'd1,8'h65,1'd0,1'd1,8'h54,1'd0,1'd1,1'd1};
//1'd1,8'h20,1'd0,1'd1,8'h43,1'd0,1'd1,8'ha1,1'd0,
flag_1 = ~flag_1;
end
always @(posedge clk)
begin
case(state)
IDLE:
if(flag_2 != flag_1)
begin
flag_2 = flag_1;
state = SEND;
end
SEND:
if(i < 102)
begin
uart_out = uart_data[i];
i = i+1;
end
else
begin
i = 0;
state = IDLE;
end
endcase
end
endmodule
module uart_rx(uart_in,clk,receive,tri_uart);
localparam IDLE = 2'b00;
localparam CHEC = 2'b01;
localparam RECE = 2'b11;
localparam TIMES = 1250;
input uart_in,clk;
output tri_uart;
output[231:0] receive;
reg[231:0] receive;
reg[1:0] state;
reg[10:0] times,times_zero;
reg[3:0] num;
reg[5:0] B;
reg tri_uart;
initial
begin
times = 0;
times_zero = 0;
state = 0;
num = 0;
B = 0;
receive = 0;
end
always @(posedge clk)
begin
if(tri_uart == 1)
tri_uart = 0;
case(state)
IDLE:
begin
if(uart_in == 0)
state = CHEC;
end
CHEC:
begin
if(uart_in == 0)
times_zero = times_zero+1;
times = times+1;
if(times >= TIMES)
begin
if(times_zero >= (TIMES>>1))
begin
state = RECE;
times = 0;
times_zero = 0;
end
else
begin
state = IDLE ;
times = 0;
times_zero = 0;
end
end
end
RECE:
begin
times = times+1;
if(uart_in == 0)
begin
times_zero = times_zero+1;
end
if(times >= TIMES)
begin
if(times_zero >= (TIMES>>1))
begin
receive[B*8+num] = 0;
end
else
begin
receive[B*8+num] = 1;
end
num = num+1;
times = 0;
times_zero = 0;
end
if(num > 7)
begin
state = IDLE;
num = 0;
times = 0;
times_zero = 0;
if(B > 27)
begin
B = 0;
tri_uart = 1;
end
else
B = B+1;
end
end
endcase
end
endmodule
6.时钟模块
时间模块用于产生时间数据发送到OLED显示屏,并可以被四个按键来修改当前时间。
module clock(hour_a,hour_d,min_a,min_d,clk_1ms,clk_500ms,hour_out,min_out,t_i_u);
input hour_a,hour_d,min_a,min_d,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_set;
reg[15:0] second;
initial
begin
hour_mem = 0;
hour_set = 0;
hour_out = 0;
min_mem = 0;
min_set = 0;
min_out = 0;
second = 0;
t_i_u = 0;
end
always @(posedge clk_500ms)//检测按键状态
begin
if(hour_a == 0&&hour_d == 0&&min_a == 0&&min_d == 0)
begin
hour_set = 0;
min_set = 0;
end
else if(hour_a == 0)
begin
hour_set = hour_out;
min_set = min_out;
hour_set = hour_set+1;
end
else if(hour_d == 0)
begin
hour_set = hour_out;
min_set = min_out;
hour_set = hour_set-1;
end
else if(min_a == 0)
begin
hour_set = hour_out;
min_set = min_out;
min_set = min_set+1;
end
else if(min_d == 0)
begin
hour_set = hour_out;
min_set = min_out;
min_set = min_set-1;
end
if(hour_set == 24)
hour_set = 0;
if(hour_set > 24)
hour_set = 23;
if(min_set == 60)
min_set = 0;
if(min_set > 60)
min_set = 59;
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 < 60000)
second = second+1;
else
begin
min_out = min_out+1;
second = 0;
if(min_out == 60)
begin
hour_out = hour_out+1;
min_out = 0;
t_i_u = 1;
if(hour_out == 24)
begin
hour_out = 0;
end
end
end
end
end
endmodule
module clk_1MHz(clk,clk_1MHz);
input clk;
output clk_1MHz;
reg clk_1MHz;
reg[2:0] num;
always @(posedge clk)
begin
if(num < 6)
num = num+1;
else
begin
clk_1MHz = ~clk_1MHz;
num = 0;
end
end
endmodule
module clk_buzzer(clk_in,clk_out);
input clk_in;
output clk_out;//0.2s时钟
reg clk_out;
reg [22:0] times_out;
initial
begin
times_out = 0;
clk_out = 0;
end
always @(posedge clk_in)
begin
if(times_out < 1200000)
begin
times_out = times_out+1;
end
else
begin
clk_out = ~clk_out;
times_out = 0;
end
end
endmodule
module clk_second(clk_in,clk_1ms,clk_500ms);
input clk_in;
output clk_1ms;
output clk_500ms;
reg clk_1ms,clk_500ms;
reg [22:0] times_1ms,times_500ms;
initial
begin
times_1ms = 0;
times_500ms = 0;
clk_1ms = 0;
clk_500ms = 0;
end
always @(posedge clk_in)
begin
if(times_1ms < 6000)
begin
times_1ms = times_1ms+1;
end
else
begin
clk_1ms = ~clk_1ms;
times_1ms = 0;
end
if(times_500ms < 1200000)
begin
times_500ms = times_500ms+1;
end
else
begin
clk_500ms = ~clk_500ms;
times_500ms = 0;
end
end
endmodule
项目完成情况
本项目完成了计时、测温、通信、报警等全部目标要求。具体展示见演示视频。
板子:
上位机UART通信接受到的信息:
资源占用
项目总结及改进
由于本人之前未接触过FPGA器件,所以项目一开始时面临着许多困难。从Verilog基本语法学起,再到了解oled的控制方式、uart通信等等,一路边学边练,在现有的例程上进行改进,一步步完成项目。
本项目尚需改进,如按键控制需进一步稳定等。