2021寒假在家练项目4——杨璐琦
该项目基于小脚丫FPGA的综合技能训练板,制作一个能够计时、测温、定时报警、串口控制的系统。
标签
FPGA
杨璐琦
更新2021-03-01
1206

项目需求

      该项目基于小脚丫FPGA的综合技能训练板,制作一个能够计时、测温、定时报警、串口控制的系统,具体功能如下:

  1. 实现一个可定时时钟的功能,用小脚丫FPGA核心模块的4个按键设置当前的时间,OLED显示数字钟的当前时间,精确到分钟即可,到整点的时候比如8:00,蜂鸣器报警,播放音频信号,最长可持续30秒;
  2. 实现温度计的功能,小脚丫通过板上的温度传感器实时测量环境温度,并同时间一起显示在OLED的屏幕上;
  3. 定时时钟整点报警的同时,将温度信息通过UART传递到电脑上,电脑上能够显示当前板子上的温度信息(任何显示形式都可以),要与OLED显示的温度值一致;
  4. PC收到报警的温度信号以后,将一段音频文件(自己制作,持续10秒钟左右)通过UART发送给小脚丫FPGA,蜂鸣器播放收到的这段音频文件,OLED屏幕上显示的时间信息和温度信息都停住不再更新;
  5. 音频文件播放完毕,OLED开始更新时间信息和当前的温度信息

项目所用资源

   1. 核心板:基于Altera MAX10的STEP-MAX10小脚丫FPGA。

   2. 核心板板载资源:4路拨码开关; 4路按键开关。

   3. 扩展板所用资源:

       SSD1306驱动的128*32分辨率的OLED屏幕;

       DS18B20Z单总线温度传感器;

       无源蜂鸣器;

       micro-usb端口的UART数据传输模块。

项目实现

1.总体设计框图:

Fg6w8tvCskpv6BrhKXcBRh6LopGw

本项目的主要模块为:温度传感器模块(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	 

项目完成情况

   本项目完成了计时、测温、通信、报警等全部目标要求。具体展示见演示视频。

   板子:FlkvT4WwytBPW4EoauX73Mn7OEsI

   上位机UART通信接受到的信息:

FoUAoAXcKSk_J8yjPQSSIlFt3-mx

资源占用

FqmYxrgtrLYDDzDUleZIIxFHxh2j

项目总结及改进

    由于本人之前未接触过FPGA器件,所以项目一开始时面临着许多困难。从Verilog基本语法学起,再到了解oled的控制方式、uart通信等等,一路边学边练,在现有的例程上进行改进,一步步完成项目。

    本项目尚需改进,如按键控制需进一步稳定等。

附件下载
pro_1.sof
烧录文件
团队介绍
哈尔滨工业大学电信学院通信工程系
团队成员
杨璐琦
修炼中。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号