项目需求
本项目为基于Altera MAX10 FPGA的一个完成定时、测温、报警、控制的小项目,具体功能如下:
-
实现一个可定时时钟的功能,用小脚丫FPGA核心模块的4个按键设置当前的时间,OLED显示数字钟的当前时间,精确到分钟即可,到整点的时候比如8:00,蜂鸣器报警,播放音频信号,最长可持续30秒;
-
实现温度计的功能,小脚丫通过板上的温度传感器实时测量环境温度,并同时间一起显示在OLED的屏幕上;
-
定时时钟整点报警的同时,将温度信息通过UART传递到电脑上,电脑上能够显示当前板子上的温度信息(任何显示形式都可以),要与OLED显示的温度值一致;
-
PC收到报警的温度信号以后,将一段音频文件(自己制作,持续10秒钟左右)通过UART发送给小脚丫FPGA,蜂鸣器播放收到的这段音频文件,OLED屏幕上显示的时间信息和温度信息都停住不再更新;
-
音频文件播放完毕,OLED开始更新时间信息和当前的温度信息
项目所用资源:
1.核心板:基于LatticeXO2-4000HC的STEP-MXO2小脚丫
2.核心板板载资源:
4路拨码开关(使用1个);
4路按键开关(使用4个);
3.扩展板所用资源:
SSD1306驱动的128*32分辨率的OLED屏幕;
DS18B20Z单总线温度传感器;
无源蜂鸣器;
micro-usb端口的UART数据传输模块;
项目实现:
1.整体设计
整个项目的代码实现可以分为如下五个模块:温度传感器模块、时间模块、UART数据传输模块、OLED显示屏模块、蜂鸣器模块。总体来看,项目代码需要输入(INPUT)如下:时钟CLK、温度总线DS_wire、UART数据接收线RxD、时间调节按键、重置信号(因为按键外设不够用,只能将一个拨码开关当作重置信号来源)。
需要输出(OUTPUT)如下:UART数据传输线TxD、OLED五路控制信号、蜂鸣器输出。
2.OLED显示屏
OLED显示屏模块完成温度数据和时间数据的显示,并在温度报警信号来临时暂停OLED显示屏的刷新。本项目使用的OLED显示屏代码主要来自于电子森林的案例分享,通过稍加修改使得其能够接收温度数据以及时间数据并将其显示在显示屏上,并能够接收温度报警信号实现显示屏停止刷新的功能。
3.DS18B20Z温度传感器
温度传感器模块通过温度总线DS_wire与温度传感器外设进行数据交互,得到外界温度数据,并将其分发到UART数据传输模块和OLED显示屏模块。本项目使用的DS18B20Z温度传感器代码主要来自于电子森林的案例分享,通过修改使得其输出数据从纯2进制表达变化为温度数据百位、十位、个位、小数位的BCD码表达,而后再将该BCD码数据接入OLED显示屏,或是通过UART传输给上位机,从而实现不同模块接口对接。
4.Uart通信
UART数据传输模块负责与上位机进行通信。不仅要把来自温度传感器的温度数据传输给上位机,还要接收来自上位机的报警信号以及报警音乐数据,并将它们送至蜂鸣器。本项目使用的UART通信代码主要来自于电子森林的案例分享,通过深入分析钻研该案例的代码,了解如何使用该模块的输入输出接口,完成了与上位机的通信。
5.蜂鸣器模块
蜂鸣器模块接收来自OLED显示屏的整点信号来达到整点报时功能,并要接收来自UART的报警音乐数据,转发来自UART的温度报警信号给OLED显示屏。本项目使用的蜂鸣器代码小部分来自于电子森林的案例分享。电子森林的案例给出了想要蜂鸣器发出对应声音所需的数据表。而我自己通过编写一个状态机,实现了音乐数据装载、随时钟逐步读取音乐数据并发送到蜂鸣器等功能。
6.时间模块
时间模块用于产生时间数据发送到OLED显示屏,并可以被四个按键来修改当前时间。该模块全部由自己完成。模块输出时钟十位、时钟个位、分钟十位、分钟个位的BCD码到OLED显示屏,也可以通过长按按钮来修改时间。为了防止“一次短时间按下按键触发多次时间修改”情况的出现,我还编写了一个可重复触发的单稳态负脉冲触发器,达到了按钮每被按下超过0.5秒,则产生一次时间修改的功能。
RTL图;
资源报告:
关键代码:
1.闹钟:
module alarm
#(
parameter simPresent = 0
)
(
input clk,
input rst_n,
output reg pulse,
output reg [5:0] second,
output [5:0] hour_o,
output [5:0] minute_o,
input time_enter,
input time_aug,
input time_minus,
input time_set
);
reg [5:0] hour;
reg [5:0] minute;
reg [23:0] cnt;
reg [5:0] minute_set;
reg [5:0] hour_set;
reg [3:0] state;
reg [3:0] state_next;
localparam ST_IDLE = 0;
localparam ST_SETHOURS = 1;
localparam ST_SETMINUTES = 2;
localparam prescale = simPresent ? 12 : 12000000;
//localparam prescale = simPresent ? 12 : 200000;
always @(posedge clk, negedge rst_n) begin
if(!rst_n) cnt <= 0;
else if(cnt==(prescale-1)) cnt<=0;
else cnt <= cnt+1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) pulse <= 0;
else pulse <= (cnt==(prescale-1));
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) second <= 0;
else if(state!=ST_IDLE) second <= 0;
else if((second==59)&pulse) second <= 0;
else if(pulse) second <= second + 1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) minute_set <= 0;
else if((state==ST_IDLE)&time_enter) minute_set <= minute;
else if((state==ST_SETMINUTES)&time_aug&(minute_set==59)) minute_set <= 0;
else if((state==ST_SETMINUTES)&time_aug) minute_set <= minute_set + 1;
else if((state==ST_SETMINUTES)&time_minus&(minute_set==0)) minute_set <= 59;
else if((state==ST_SETMINUTES)&time_minus) minute_set <= minute_set - 1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) minute <= 0;
else if((state!=ST_IDLE)&time_set) minute <= minute_set;
else if((minute==59)&(second==59)&pulse) minute <= 0;
else if((second==59)&pulse) minute <= minute + 1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) hour_set <= 0;
else if((state==ST_IDLE)&time_enter) hour_set <= hour;
else if((state==ST_SETHOURS)&time_aug&(hour_set==23)) hour_set <= 0;
else if((state==ST_SETHOURS)&time_aug) hour_set <= hour_set + 1;
else if((state==ST_SETHOURS)&time_minus&(hour_set==0)) hour_set <= 23;
else if((state==ST_SETHOURS)&time_minus) hour_set <= hour_set - 1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) hour <= 0;
else if((state!=ST_IDLE)&time_set) hour <= hour_set;
else if((hour==23)&(second==59)&(minute==59)&pulse) hour <= 0;
else if((second==59)&(minute==59)&pulse) hour <= hour + 1;
end
always @(posedge clk, negedge rst_n) begin
if(!rst_n) state <= ST_IDLE;
else state <= state_next;
end
always @(*) begin
case(state)
ST_IDLE: begin if(time_enter) state_next = ST_SETHOURS; else state_next = state; end
ST_SETHOURS: begin if(time_enter) state_next = ST_SETMINUTES; else if(time_set) state_next = ST_IDLE; else state_next = state; end
ST_SETMINUTES: begin if(time_enter) state_next = ST_IDLE; else if(time_set) state_next = ST_IDLE; else state_next = state; end
default: state_next = ST_IDLE;
endcase
end
assign hour_o = (state==ST_IDLE) ? hour : hour_set;
assign minute_o = (state==ST_IDLE) ? minute : minute_set;
endmodule
2.oled:
module OLED12832
(
input clk, //12MHz
input rst_n,
input [15:0] oled1,
input [15:0] oled2,
input [15:0] oled3,
output reg oled_csn,
output reg oled_rst,
output reg oled_dcn,
output reg oled_clk,
output reg 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;
reg [7:0] cmd [24:0];
reg [39:0] mem [122: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;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) 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 >= 5'd8) cnt_main <= 5'd5;
else cnt_main <= cnt_main + 1'b1;
case(cnt_main) //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 <= "Time ";state <= SCAN; end
5'd2: begin y_p <= 8'hb1; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " ";state <= SCAN; end
5'd3: begin y_p <= 8'hb2; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= "Temperature ";state <= SCAN; end
5'd4: begin y_p <= 8'hb3; x_ph <= 8'h10; x_pl <= 8'h00; num <= 5'd16; char <= " ";state <= SCAN; end
5'd5: begin y_p <= 8'hb0; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <= " "; state <= SCAN; end
5'd6: begin y_p <= 8'hb1; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 5; char <= {oled2,":",oled3}; state <= SCAN; end
5'd7: begin y_p <= 8'hb2; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 1; char <= " "; state <= SCAN; end
5'd8: begin y_p <= 8'hb3; x_ph <= 8'h15; x_pl <= 8'h00; num <= 5'd 2; char <= oled1; 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
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
5'd4: begin
if(cnt>=INIT_DEPTH) begin
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
default: state <= IDLE;
endcase
end
SCAN:begin
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'd 5: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end
5'd 6: begin oled_dcn <= DATA; char_reg <= 8'h00; state <= WRITE; state_back <= SCAN; end
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
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
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
endmodule
3.蜂鸣器:
module PWM #
(
parameter WIDTH = 32 //ensure that 2**WIDTH > cycle
)
(
input clk,
input rst_n,
input en,
input [WIDTH-1:0] cycle, //cycle > duty
input [WIDTH-1:0] duty, //duty < cycle
output reg pwm_out
);
reg [WIDTH-1:0] cnt;
//counter for cycle
always @(posedge clk or negedge rst_n)
if(!rst_n) cnt <= 1'b1;
else if(cnt >= cycle) cnt <= 1'b1;
else if(en) cnt <= cnt + 1'b1;
//pulse with duty
always @(posedge clk or negedge rst_n)
if(!rst_n) pwm_out <= 1'b1;
else if(!en) pwm_out <= 0;
else if(cnt < duty) pwm_out <= 1'b1;
else pwm_out <= 1'b0;
endmodule
驱动蜂鸣器相关代码:
module tone
(
input clk,
input rst_n,
input en,
output reg [15:0] cycle
);
// localparam DO = 10215;
// localparam RE = 12148;
// localparam MI = 15306;
// localparam FA = 17180;
// localparam SO = 20432;
// localparam LA = 24296;
// localparam TI = 30612;
localparam DO = 19389;
localparam RE = 17256;
localparam MI = 15358;
localparam FA = 13669;
localparam SO = 12895;
localparam LA = 11477;
localparam TI = 10215;
reg [25:0] cnt;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 1'b0;
else if(!en) cnt <= 0;
else cnt <= cnt + 1'b1;
end
//always@(cnt[25:22]) begin
// case(cnt[25:22])
// 4'd0: cycle = 16'd45872; //L1,
// 4'd1: cycle = 16'd40858; //L2,
// 4'd2: cycle = 16'd36408; //L3,
// 4'd3: cycle = 16'd34364; //L4,
// 4'd4: cycle = 16'd30612; //L5,
// 4'd5: cycle = 16'd27273; //L6,
// 4'd6: cycle = 16'd24296; //L7,
// 4'd7: cycle = 16'd22931; //M1,
// 4'd8: cycle = 16'd20432; //M2,
// 4'd9: cycle = 16'd18201; //M3,
// 4'd10: cycle = 16'd17180; //M4,
// 4'd11: cycle = 16'd15306; //M5,
// 4'd12: cycle = 16'd13636; //M6,
// 4'd13: cycle = 16'd12148; //M7,
// 4'd14: cycle = 16'd11478; //H1,
// 4'd15: cycle = 16'd10215; //H2,
// default: cycle = 16'd0; //cycle为0,PWM占空比为0,低电平
// endcase
//end
always@(cnt[25:22]) begin
case(cnt[25:22])
4'd0: cycle = DO; //L1,
4'd1: cycle = DO; //L2,
4'd2: cycle = SO; //L3,
4'd3: cycle = SO; //L4,
4'd4: cycle = LA; //L5,
4'd5: cycle = LA; //L6,
4'd6: cycle = SO; //L7,
4'd7: cycle = 0; //M1,
4'd8: cycle = FA; //M2,
4'd9: cycle = FA; //M3,
4'd10: cycle = MI; //M4,
4'd11: cycle = MI; //M5,
4'd12: cycle = RE; //M6,
4'd13: cycle = RE; //M7,
4'd14: cycle = DO; //H1,
4'd15: cycle = 0; //H2,
default: cycle = 16'd0; //cycle为0,PWM占空比为0,低电平
endcase
end
endmodule
4.温度传感器:
module DS18B20Z
(
input clk, // system clock
input rst_n, // system reset, active low
inout one_wire, // ds18b20z one-wire-bus
output reg [15:0] data_out // ds18b20z 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;
//generate clk_1mhz clock
reg clk_1mhz;
reg [2:0] cnt_1mhz;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) 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
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 [5:0] cnt_write;
reg [5:0] cnt_read;
reg [15:0] temperature;
reg [7:0] temperature_buffer;
reg [2:0] state = IDLE;
reg [2:0] state_back = IDLE;
always@(posedge clk_1mhz or negedge rst_n) begin
if(!rst_n) 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;
one_wire_buffer <= 1'bz;
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;
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_write >= 6'd50) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
//lock data_wr
6'd0: begin data_wr_buffer <= data_wr; end
//write bit 0
6'd1: begin one_wire_buffer <= 1'b0; end
6'd2: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd3: begin one_wire_buffer <= data_wr_buffer[0]; end
6'd4: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd5: begin one_wire_buffer <= 1'bz; end
6'd6: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 1
6'd7: begin one_wire_buffer <= 1'b0; end
6'd8: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd9: begin one_wire_buffer <= data_wr_buffer[1]; end
6'd10: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd11: begin one_wire_buffer <= 1'bz; end
6'd12: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 2
6'd13: begin one_wire_buffer <= 1'b0; end
6'd14: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd15: begin one_wire_buffer <= data_wr_buffer[2]; end
6'd16: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd17: begin one_wire_buffer <= 1'bz; end
6'd18: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 3
6'd19: begin one_wire_buffer <= 1'b0; end
6'd20: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd21: begin one_wire_buffer <= data_wr_buffer[3]; end
6'd22: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd23: begin one_wire_buffer <= 1'bz; end
6'd24: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 4
6'd25: begin one_wire_buffer <= 1'b0; end
6'd26: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd27: begin one_wire_buffer <= data_wr_buffer[4]; end
6'd28: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd29: begin one_wire_buffer <= 1'bz; end
6'd30: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 5
6'd31: begin one_wire_buffer <= 1'b0; end
6'd32: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd33: begin one_wire_buffer <= data_wr_buffer[5]; end
6'd34: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd35: begin one_wire_buffer <= 1'bz; end
6'd36: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 6
6'd37: begin one_wire_buffer <= 1'b0; end
6'd38: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd39: begin one_wire_buffer <= data_wr_buffer[6]; end
6'd40: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd41: begin one_wire_buffer <= 1'bz; end
6'd42: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//write bit 7
6'd43: begin one_wire_buffer <= 1'b0; end
6'd44: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
6'd45: begin one_wire_buffer <= data_wr_buffer[7]; end
6'd46: begin num_delay <= 20'd80;state <= DELAY;state_back <= WRITE; end
6'd47: begin one_wire_buffer <= 1'bz; end
6'd48: begin num_delay <= 20'd2;state <= DELAY;state_back <= WRITE; end
//back to main
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 one_wire_buffer <= 1'b0; end
6'd1: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd2: begin one_wire_buffer <= 1'bz; end
6'd3: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd4: begin temperature_buffer[0] <= one_wire; end
6'd5: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 1
6'd6: begin one_wire_buffer <= 1'b0; end
6'd7: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd8: begin one_wire_buffer <= 1'bz; end
6'd9: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd10: begin temperature_buffer[1] <= one_wire; end
6'd11: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 2
6'd12: begin one_wire_buffer <= 1'b0; end
6'd13: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd14: begin one_wire_buffer <= 1'bz; end
6'd15: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd16: begin temperature_buffer[2] <= one_wire; end
6'd17: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 3
6'd18: begin one_wire_buffer <= 1'b0; end
6'd19: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd20: begin one_wire_buffer <= 1'bz; end
6'd21: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd22: begin temperature_buffer[3] <= one_wire; end
6'd23: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 4
6'd24: begin one_wire_buffer <= 1'b0; end
6'd25: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd26: begin one_wire_buffer <= 1'bz; end
6'd27: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd28: begin temperature_buffer[4] <= one_wire; end
6'd29: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 5
6'd30: begin one_wire_buffer <= 1'b0; end
6'd31: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd32: begin one_wire_buffer <= 1'bz; end
6'd33: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd34: begin temperature_buffer[5] <= one_wire; end
6'd35: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 6
6'd36: begin one_wire_buffer <= 1'b0; end
6'd37: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd38: begin one_wire_buffer <= 1'bz; end
6'd39: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd40: begin temperature_buffer[6] <= one_wire; end
6'd41: begin num_delay <= 20'd55;state <= DELAY;state_back <= READ; end
//read bit 7
6'd42: begin one_wire_buffer <= 1'b0; end
6'd43: begin num_delay <= 20'd2;state <= DELAY;state_back <= READ; end
6'd44: begin one_wire_buffer <= 1'bz; end
6'd45: begin num_delay <= 20'd10;state <= DELAY;state_back <= READ; end
6'd46: begin temperature_buffer[7] <= one_wire; 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
assign one_wire = one_wire_buffer;
endmodule
5.串口通信:
module Baud #
(
parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率
)
(
input clk, //系统时钟
input rst_n, //系统复位,低有效
input bps_en, //接收或发送时钟使能
output reg bps_clk //接收或发送时钟输出
);
reg [12:0] cnt;
//计数器计数满足波特率时钟要求
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 1'b0;
else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数
cnt <= 1'b0; //当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期
else
cnt <= cnt + 1'b1;
end
//产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
bps_clk <= 1'b0;
else if(cnt == (BPS_PARA>>1)) //右移一位等于除以2,终值BPS_PARA为数据更替点,中值数据稳定,做采样点
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
end
endmodule
module Baud #
(
parameter BPS_PARA = 1250 //12MHz时钟时参数1250对应9600的波特率
)
(
input clk, //系统时钟
input rst_n, //系统复位,低有效
input bps_en, //接收或发送时钟使能
output reg bps_clk //接收或发送时钟输出
);
reg [12:0] cnt;
//计数器计数满足波特率时钟要求
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 1'b0;
else if((cnt >= BPS_PARA-1)||(!bps_en)) //当时钟信号不使能(bps_en为低电平)时,计数器清零并停止计数
cnt <= 1'b0; //当时钟信号使能时,计数器对系统时钟计数,周期为BPS_PARA个系统时钟周期
else
cnt <= cnt + 1'b1;
end
//产生相应波特率的时钟节拍,接收模块将以此节拍进行UART数据接收
always @ (posedge clk or negedge rst_n) begin
if(!rst_n)
bps_clk <= 1'b0;
else if(cnt == (BPS_PARA>>1)) //右移一位等于除以2,终值BPS_PARA为数据更替点,中值数据稳定,做采样点
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
end
endmodule
遇到的困难:
1.零基础,只能根据案例一点点改动
2.会出现很多意想不到的状况,网上的解决办法不一定有效
3.内存资源占用过大
收获:
1.为日后数字电路学习打下基础
2.多了解些FPGA
3.充实了寒假