1.led控制:控制底板的两个led灯,在1s内两个灯交叉闪烁,各0.5s
module led_twinkle(
input clk,//50MHZ,等同于1ns,故有26位来计数,20ns
input rst_n,//复位信号
output [1:0] led
);
reg [25:0] cnt;//计数器
assign led=cnt<26'd2500_0000 ? 2'b10:2'b01;
always@ ( posedge clk or negedge st_n) begin
if(!rst_n)
cnt <= 26'd0;
else if(cnt<26'd5000_0000)
cnt <= cnt+1'b1;
else
cnt <= 26'd0;
end
endmodule
2.led控制,通过按键1和2来控制灯的闪烁实际情况。
module key_led( input clk,
input rst_n,
input [1:0] key,
output reg [1:0] led
);
reg [24:0] cnt;//25位的cnt
reg led_control;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt<=25'd0;
else if(cnt<25'd2500_0000)
cnt<=cnt+1'b1;
else
cnt<=25'd0;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
led_control<=1'b0;
else if(cnt==25'd2500_0000)
led_control<=~led_control;
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
led<=2'b11;
else case(key)
2'b10: if(led_control==1'b0)//如果按键0按下,交替闪烁
led<=2'b10;
else
led<=2'b01;
2'b01: if(led_control==1'b0)//如果按键1按下,同时闪烁
led<=2'b11;
else
led<=2'b00;
2'b11:
led<=2'b11;//如果两个按键都没有按下来,则保持两个灯一起亮起来
default: ;
endcase
end
endmodule
3.蜂窝器控制,按下按键后不响,再次按下后响,并且要考虑消抖情况。
top_beep_control.v
module top_beep_debounce(
input clk,
input rst_n,
input key,
output beep//这里不再需要进行reg
);
wire key_flag;
wire key_value;
deep_debaunce u1(
.clk (clk) ,
.rst_n (rst_n) ,
.key (key) ,
.key_value (key_value) ,
.key_flag (key_flag)
);
beep_control u2(
.clk (clk),
.rst_n (rst_n),
.key_value (key_value),
.key_flag (key_flag),
.beep (beep)
);
endmodule
deep_debaunce.v
module deep_debaunce(
input clk,
input rst_n,
input key,
output reg key_value,
output reg key_flag
);
reg [19:0] cnt;
reg key_reg;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt<=20'd0;
key_reg<=1'b1;
end
else begin
key_reg<=key;
if(key!=key_reg) begin
cnt<=20'd1000_000;
end
else begin
if(cnt>20'd0)
cnt<=cnt-1'b1;
else
cnt<=20'd0;
end
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
begin
key_value<=1'b1;
key_flag<=1'b0;
end
else begin
if(cnt==20'd1) begin
key_flag <= 1'b1;
key_value <= key;
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
beep_control.v
module beep_control(
input clk,
input rst_n,
input key_value,
input key_flag,
output reg beep
);
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
beep<=1'b1;
else if (key_flag && (key_value==0))
beep<=1'b0;
end
endmodule
4.呼吸灯:实现类似呼吸灯的效果,控制闪烁的速度
//呼吸灯
module breath_led(
input clk,
input rst_n,
output led
);
reg [15:0] period_cnt; //表示当前的计时
reg [15:0] duty_cycle; //表示调控的多少范围内的具体数值大小
reg inc_dec_flag; //0表示增加,1表示减小
assign led = (period_cnt>=duty_cycle)?1'b1:1'b0;//如果大于duty_cycle.则led被放置为0.这个时候灯被点亮的
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
period_cnt<=16'd0;
else if(period_cnt==16'd50000)
period_cnt<=16'd0;
else
period_cnt<=period_cnt+1'b1;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
inc_dec_flag<=1'b0;
duty_cycle<=16'd0;
end
else
begin
if(period_cnt==16'd50000)
begin
if(inc_dec_flag==1'b0)
begin
if(duty_cycle==16'd50000)
inc_dec_flag<=1'b1;
else
duty_cycle<=duty_cycle+16'd50;
end
else begin
if(duty_cycle==16'd0)
inc_dec_flag<=1'b0;
else
duty_cycle<=duty_cycle-16'd50;
end
end
end
end
endmodule
5.clock的ip调用
调用ip核 clock_twi
//IP核调用实验 clk_wiz 分频实验
module clock_twi(
input sys_clk_50M,
input sys_rst_n,
output clk_out1_100m,
output clk_out2_100m_180,
output clk_out3_50m ,
output clk_out4_25m
);
wire locked;
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1_100m (clk_out1_100m),
.clk_out2_100m_180 (clk_out2_100m_180),
.clk_out3_50m (clk_out3_50m),
.clk_out4_25m (clk_out4_25m),
// Status and control signals
.reset (~sys_rst_n),//在clk_wiz_0里面默认是以高电位作为复位的,这里我们用~来转化为取得低电位
.locked (locked),
// Clock in ports
.clk_in1 (sys_clk_50M)
);
endmodule
编写testbench
//编写testbench文件
`timescale 1ns / 1ps
module tb_clock_twi();
reg sys_clk_50M;
reg sys_rst_n;
wire clk_out1_100m;
wire clk_out2_100m_180;
wire clk_out3_50m ;
wire clk_out4_25m ;
clock_twi u
(
.sys_clk_50M (sys_clk_50M),
.sys_rst_n (sys_rst_n) ,
.clk_out1_100m (clk_out1_100m ),
.clk_out2_100m_180 (clk_out2_100m_180),
.clk_out3_50m (clk_out3_50m),
.clk_out4_25m (clk_out4_25m )
);
always #10 sys_clk_50M = ~sys_clk_50M;
initial begin
sys_clk_50M=1'b0;
sys_rst_n=1'b0;//低电位复位
#200
sys_rst_n=1'b1;
end
endmodule
结果生成了四个不同的时钟
6.RAM的ip核调用,RAM能够调用内存,这个实验暂时还没有上板。
1.ip_ram.v(top)
module ip_ram(
input sys_clk
//input sys_rst_n
);
wire sys_rst_n; //zcu106的rst_n在哪里呢
wire ram_en;
wire rw;
wire [4:0] ram_addr;
wire [7:0] ram_wr_data;
wire [7:0] douta;
ram_rw u1(
.rst_n (sys_rst_n),
.clk (sys_clk),
.ram_en (ram_en), //使能信号
.rw (rw), //读状态还是写状态
.ram_addr (ram_addr),
.ram_wr_data (ram_wr_data)
);
blk_mem_gen_0 u2 (
.clka(sys_clk), // input wire clka
.ena(ram_en), // input wire ena
.wea(rw), // input wire [0 : 0] wea
.addra(ram_addr), // input wire [4 : 0] addra
.dina(ram_wr_data), // input wire [7 : 0] dina
.douta(douta) // output wire [7 : 0] douta
);
ila_0 u3 (
.clk(sys_clk), // input wire clk
.probe0(ram_en), // input wire [0:0] probe0
.probe1(rw), // input wire [0:0] probe1
.probe2(ram_addr), // input wire [4:0] probe2
.probe3(ram_wr_data), // input wire [7:0] probe3
.probe4(douta) // input wire [7:0] probe4
);
endmodule
2.ram_rw.v 设置读写数据的过程。
//ram的ip核调用
module ram_rw(
input rst_n,
input clk,
output reg ram_en, //使能信号
output reg rw, //读状态还是写状态
output reg [4:0] ram_addr,
output reg [7:0] ram_wr_data
);
reg [5:0] cnt; //定义计数器
always @(posedge clk or negedge rst_n) begin //使能信号
if(!rst_n)
ram_en<=1'b0;
else
ram_en<=1'b1;
end
always @(posedge clk or negedge rst_n) begin //0到31写,32到63读
if(!rst_n)
cnt<=6'd0;
else if(cnt==6'd63)
cnt<=6'd0;
else
cnt<=cnt+6'd1;
end
always @(posedge clk or negedge rst_n) begin //低31位写入数据
if(!rst_n)
ram_wr_data<=8'd0;
else if (cnt<=6'd31&&ram_en)
ram_wr_data<=ram_wr_data+8'd1;
else
ram_wr_data<=8'd0;
end
always @(posedge clk or negedge rst_n) begin //0到31只写,rw为1,只写模式
if(!rst_n)
rw<=1'b1;
else if (cnt<=6'd31)
rw<=1'b1;
else
rw<=1'b0;
end
always @(posedge clk or negedge rst_n) begin //取cnt的低五位就是对应的地址大小
if(!rst_n)
ram_addr<=5'd0;
else
ram_addr<=cnt[4:0]; //低5位数据对应的就是地址大小
end
endmodule
7.FIFO的ip核实验
fifo_ip.v
module fifo_ip(
input sys_clk,
input sys_rst_n
);
wire almost_empty;
wire almost_full;
wire fifo_wr_en;
wire [7:0] fifo_wr_data;
wire fifo_rd_en;
wire dout;
wire full;
wire empty;
wire [7:0] rd_data_count;
wire [7:0] wr_data_count;
fifo_wr fifo_wr_u(
. rst_n (sys_rst_n),
. clk (sys_clk),
. almost_empty (almost_empty),
. almost_full (almost_full),
. fifo_wr_en (fifo_wr_en ),
. fifo_wr_data (fifo_wr_data)
);
fifo_rd fifo_rd_u(
. rst_n (sys_rst_n),
. clk (sys_clk),
. almost_empty (almost_empty),
. almost_full (almost_full),
. fifo_rd_en (fifo_rd_en)
);
fifo_generator_0 fifo_generator_0_u (
.wr_clk(sys_clk), // input wire wr_clk
.rd_clk(sys_clk), // input wire rd_clk
.din(fifo_wr_data), // input wire [7 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(dout), // output wire [7 : 0] dout
.full(full), // output wire full
.almost_full(almost_full), // output wire almost_full
.empty(empty), // output wire empty
.almost_empty(almost_empty), // output wire almost_empty
.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [7 : 0] wr_data_count
);
ila_0 ila_0_u(
.clk(sys_clk), // input wire clk
.probe0(empty), // input wire [0:0] probe0
.probe1(full), // input wire [0:0] probe1
.probe2(almost_full), // input wire [0:0] probe2
.probe3(almost_empty), // input wire [0:0] probe3
.probe4(fifo_wr_data), // input wire [7:0] probe4
.probe5(dout), // input wire [7:0] probe5
.probe6(rd_data_count), // input wire [7:0] probe6
.probe7(wr_data_count), // input wire [7:0] probe7
.probe8(rd_data_count), // input wire [0:0] probe8
.probe9(wr_data_count) // input wire [0:0] probe9
);
endmodule
fifo_wr.v 写模块
//fifo写模块,这里还使用了状态机的功能
module fifo_wr(
input rst_n ,
input clk ,
input almost_empty ,
input almost_full ,
output reg fifo_wr_en ,
output reg [7:0] fifo_wr_data
);
reg almost_empty_d0;
reg almost_empty_syn;
wire syn;
reg [1:0] state;
reg [3:0] dly_cnt;
assign syn=~almost_empty_syn & almost_empty_d0;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
almost_empty_d0<=1'b0;
almost_empty_syn<=1'b0;
end
else begin
almost_empty_d0<=almost_empty;
almost_empty_syn<=almost_empty_d0;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
fifo_wr_en<=1'b0;
fifo_wr_data<=8'd0;
state<=2'd0;
dly_cnt<=4'b0; //延迟的时拍
end
else begin
case(state)
2'd0:begin
if(syn) begin
state<=2'd1;
end
else
state<=state;
end
2'd1:begin
if(dly_cnt==4'd10)begin
dly_cnt<=4'b0;
state<=2'd2;
fifo_wr_en<=1'b1;
end
else
dly_cnt<=dly_cnt+1'b1;
end
2'd2:begin
if(almost_full)begin
fifo_wr_en<=1'b0;
fifo_wr_data<=8'd0;
state<=2'b0;
end
else begin
fifo_wr_en<=1'b1;
fifo_wr_data<=fifo_wr_data+1'd1;
end
end
default: state<=2'b0;
endcase
end
end
endmodule
fifo_rd.v 读模块
//fifo读模块,这里还使用了状态机的功能
module fifo_rd(
input rst_n ,
input clk ,
input almost_empty ,
input almost_full ,
output reg fifo_rd_en
);
reg almost_full_d0;
reg almost_full_syn;
wire syn;
reg [1:0] state;
reg [3:0] dly_cnt;
assign syn=~almost_full_syn & almost_full_d0;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
almost_full_d0<=1'b0;
almost_full_syn<=1'b0;
end
else begin
almost_full_d0<=almost_full;
almost_full_syn<=almost_full_d0;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
fifo_rd_en<=1'b0;
state<=2'd0;
dly_cnt<=4'b0; //延迟的时拍
end
else begin
case(state)
2'd0:begin
if(syn) begin
state<=2'd1;
end
else
state<=state;
end
2'd1:begin
if(dly_cnt==4'd10)begin
dly_cnt<=4'b0;
state<=2'd2;
end
else
dly_cnt<=dly_cnt+1'b1;
end
2'd2:begin
if(almost_empty)begin
fifo_rd_en<=1'b0;
state<=2'b0;
end
else begin
fifo_rd_en<=1'b1;
//只要有写使能,会自动读取文件
end
end
default: state<=2'b0;
endcase
end
end
endmodule
8.uart串口接收实验
top_uart.v
module top_uart(
input sys_clk,
input sys_rst_n,
input uart_rxd,
output uart_txd
);
wire [7:0] uart_data;
wire uart_done;
uart_recv uart_recv_u(
.uart_rxd (uart_rxd),
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_data (uart_data),
.uart_done (uart_done)
);
uart_send uart_send_u(
.uart_en (uart_done),
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_din (uart_data),
.uart_txd (uart_txd)
);
endmodule
uart_rece.v
module uart_recv(
input uart_rxd,
input sys_clk,
input sys_rst_n,
output reg [7:0] uart_data,
output reg uart_done
);
parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;
reg uart_rxd_d0;
reg uart_rxd_d1;
reg rx_flag;
reg [3:0] rx_cnt;
reg [15:0] clk_cnt;
reg [8:0] rx_data;
wire start_flag;
assign start_flag=~uart_rxd_d0 & uart_rxd_d1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_rxd_d0<=1'b0;
uart_rxd_d1<=1'b0;
end
else begin
uart_rxd_d0<=uart_rxd;
uart_rxd_d1<=uart_rxd_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_flag<=1'b0;
else if(start_flag)
rx_flag<=1'b1;
else if((rx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2-1'b1)) //最后一个周期,必须要提前结束半个周期结束,为下一个周期收听信号留下准备作用
rx_flag<=1'b0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_cnt<=16'd0;
else if(rx_flag) begin
if(clk_cnt<BPS_CNT-1'b1)
clk_cnt<=clk_cnt+1'b1;
else
clk_cnt<=16'd0;
end
else
clk_cnt<=16'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_cnt<=4'd0;
else if(rx_flag) begin
if(clk_cnt==BPS_CNT-1'b1)
rx_cnt<=rx_cnt+1'b1;
else
rx_cnt<=rx_cnt;
end
else
rx_cnt<=4'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_data<=8'd0;
else if(rx_flag && (clk_cnt==BPS_CNT/2) ) begin //在中间一半的地方来进行存储数据
case(rx_cnt)
4'd1: rx_data[0]<=uart_rxd_d1; //不同使用异步信号,使用同步之后的同步信号uart_rxd_d1而不是uart_rxd
4'd2: rx_data[1]<=uart_rxd_d1;
4'd3: rx_data[2]<=uart_rxd_d1;
4'd4: rx_data[3]<=uart_rxd_d1;
4'd5: rx_data[4]<=uart_rxd_d1;
4'd6: rx_data[5]<=uart_rxd_d1;
4'd7: rx_data[6]<=uart_rxd_d1;
4'd8: rx_data[7]<=uart_rxd_d1;
endcase
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_done<=1'b0;
uart_data<=8'd0;
end
else if(rx_cnt==4'd9) begin
uart_done<=1'b1;
uart_data<=rx_data;
end
else begin
uart_done<=1'b0;
uart_data<=8'd0;
end
end
endmodule
uart_send.v
module uart_send(
input uart_en,
input sys_clk,
input sys_rst_n,
input [7:0] uart_din,
output reg uart_txd
);
parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;
reg uart_en_d0;
reg uart_en_d1;
reg tx_flag;
reg [3:0] tx_cnt;
reg [15:0] clk_cnt;
reg [8:0] tx_data;
wire en_flag;
assign en_flag=(~uart_en_d1) & uart_en_d0;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_en_d0<=1'b0;
uart_en_d1<=1'b0;
end
else begin
uart_en_d0<=uart_en;
uart_en_d1<=uart_en_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_data<=8'd0;
else if(en_flag ) begin
tx_data<=uart_din;
end
else
tx_data<=tx_data;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_flag<=1'b0;
else if(en_flag)
tx_flag<=1'b1;
else if((tx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2-1'b1)) //最后一个周期,必须要提前结束半个周期结束,为下一个周期收听信号留下准备作用
tx_flag<=1'b0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_cnt<=16'd0;
else if(en_flag) begin
if(clk_cnt<BPS_CNT-1'b1)
clk_cnt<=clk_cnt+1'b1;
else
clk_cnt<=16'd0;
end
else
clk_cnt<=16'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_cnt<=4'd0;
else if(en_flag) begin
if(clk_cnt==BPS_CNT-1)
tx_cnt<=tx_cnt+1'b1;
else
tx_cnt<=tx_cnt;
end
else
tx_cnt<=4'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
uart_txd<=1'b1;
else if(en_flag && (clk_cnt==16'd0) ) begin //在中间一半的地方来进行存储数据
case(tx_cnt)
4'd0: uart_txd<=1'b0;
4'd1: uart_txd<=tx_data[0]; //不同使用异步信号,使用同步之后的同步信号uart_rxd_d1而不是uart_rxd
4'd2: uart_txd<=tx_data[1];
4'd3: uart_txd<=tx_data[2];
4'd4: uart_txd<=tx_data[3];
4'd5: uart_txd<=tx_data[4];
4'd6: uart_txd<=tx_data[5];
4'd7: uart_txd<=tx_data[6];
4'd8: uart_txd<=tx_data[7];
endcase
end
end
// always @(posedge sys_clk or negedge sys_rst_n) begin
// if(!sys_rst_n) begin
// uart_done<=1'b0;
// uart_data<=8'd0;
// end
// else if(rx_cnt==4'd9) begin
// uart_done<=1'b1;
// uart_data<=rx_data;
// end
// else begin
// uart_done<=1'b0;
// uart_data<=8'd0;
// end
// end
endmodule
9.uart串口接收实验,加入一个loop来防止连续传送带来的数据丢失问题
top_uart_loop.v
module top_uart(
input sys_clk,
input sys_rst_n,
input uart_rxd,
output uart_txd
);
// wire [7:0] uart_data;
// wire uart_done;
wire [7:0] uart_recv_data;
wire [7:0] uart_send_data;
wire uart_send_en;
wire uart_tx_busy;
wire uart_recv_done;
uart_recv uart_recv_u(
.uart_rxd (uart_rxd),
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_data (uart_recv_data),
.uart_done (uart_recv_done)
);
uart_send uart_send_u(
.uart_en (uart_send_en),
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.uart_din (uart_send_data),
.uart_txd (uart_txd),
.uart_tx_busy (uart_tx_busy)
);
//串口的环回模块
uart_loop uart_loop_u(
.sys_clk (sys_clk),
.sys_rst_n(sys_rst_n),
.recv_done(uart_recv_done),
.recv_data(uart_recv_date),
.tx_busy(uart_tx_busy),
.send_en(uart_send_en),
.send_data(uart_send_data)
);
endmodule
top_uart_recv.v
module uart_recv(
input uart_rxd,
input sys_clk,
input sys_rst_n,
output reg [7:0] uart_data,
output reg uart_done
);
parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;
reg uart_rxd_d0;
reg uart_rxd_d1;
reg rx_flag;
reg [3:0] rx_cnt;
reg [15:0] clk_cnt;
reg [8:0] rx_data;
wire start_flag;
assign start_flag=~uart_rxd_d0 & uart_rxd_d1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_rxd_d0<=1'b0;
uart_rxd_d1<=1'b0;
end
else begin
uart_rxd_d0<=uart_rxd;
uart_rxd_d1<=uart_rxd_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_flag<=1'b0;
else if(start_flag)
rx_flag<=1'b1;
else if((rx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2-1'b1)) //最后一个周期,必须要提前结束半个周期结束,为下一个周期收听信号留下准备作用
rx_flag<=1'b0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_cnt<=16'd0;
else if(rx_flag) begin
if(clk_cnt<BPS_CNT-1'b1)
clk_cnt<=clk_cnt+1'b1;
else
clk_cnt<=16'd0;
end
else
clk_cnt<=16'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_cnt<=4'd0;
else if(rx_flag) begin
if(clk_cnt==BPS_CNT-1'b1)
rx_cnt<=rx_cnt+1'b1;
else
rx_cnt<=rx_cnt;
end
else
rx_cnt<=4'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
rx_data<=8'd0;
else if(rx_flag && (clk_cnt==BPS_CNT/2) ) begin //在中间一半的地方来进行存储数据
case(rx_cnt)
4'd1: rx_data[0]<=uart_rxd_d1; //不同使用异步信号,使用同步之后的同步信号uart_rxd_d1而不是uart_rxd
4'd2: rx_data[1]<=uart_rxd_d1;
4'd3: rx_data[2]<=uart_rxd_d1;
4'd4: rx_data[3]<=uart_rxd_d1;
4'd5: rx_data[4]<=uart_rxd_d1;
4'd6: rx_data[5]<=uart_rxd_d1;
4'd7: rx_data[6]<=uart_rxd_d1;
4'd8: rx_data[7]<=uart_rxd_d1;
endcase
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_done<=1'b0;
uart_data<=8'd0;
end
else if(rx_cnt==4'd9) begin
uart_done<=1'b1;
uart_data<=rx_data;
end
else begin
uart_done<=1'b0;
uart_data<=8'd0;
end
end
endmodule
top_uart_send.v
module uart_send(
input uart_en,
input sys_clk,
input sys_rst_n,
input [7:0] uart_din,
output reg uart_txd,
output uart_tx_busy
);
parameter CLK_FREQ = 50_000_000;
parameter UART_BPS = 115200;
parameter BPS_CNT = CLK_FREQ/UART_BPS;
reg uart_en_d0;
reg uart_en_d1;
reg tx_flag;
reg [3:0] tx_cnt;
reg [15:0] clk_cnt;
reg [8:0] tx_data;
wire en_flag;
assign en_flag=(~uart_en_d1) & uart_en_d0;
assign uart_tx_busy = tx_flag;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
uart_en_d0<=1'b0;
uart_en_d1<=1'b0;
end
else begin
uart_en_d0<=uart_en;
uart_en_d1<=uart_en_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_data<=8'd0;
else if(en_flag ) begin
tx_data<=uart_din;
end
else
tx_data<=tx_data;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_flag<=1'b0;
else if(en_flag)
tx_flag<=1'b1;
else if((tx_cnt==4'd9)&&(clk_cnt==BPS_CNT/2-1'b1)) //最后一个周期,必须要提前结束半个周期结束,为下一个周期收听信号留下准备作用
//但是效果不是很好。可以考虑增加半个周期,改为4/5周期,也可以考虑增加一个uart_loop缓冲的模块
tx_flag<=1'b0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
clk_cnt<=16'd0;
else if(en_flag) begin
if(clk_cnt<BPS_CNT-1'b1)
clk_cnt<=clk_cnt+1'b1;
else
clk_cnt<=16'd0;
end
else
clk_cnt<=16'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
tx_cnt<=4'd0;
else if(en_flag) begin
if(clk_cnt==BPS_CNT-1)
tx_cnt<=tx_cnt+1'b1;
else
tx_cnt<=tx_cnt;
end
else
tx_cnt<=4'd0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
uart_txd<=1'b1;
else if(en_flag && (clk_cnt==16'd0) ) begin //在中间一半的地方来进行存储数据
case(tx_cnt)
4'd0: uart_txd<=1'b0;
4'd1: uart_txd<=tx_data[0]; //不同使用异步信号,使用同步之后的同步信号uart_rxd_d1而不是uart_rxd
4'd2: uart_txd<=tx_data[1];
4'd3: uart_txd<=tx_data[2];
4'd4: uart_txd<=tx_data[3];
4'd5: uart_txd<=tx_data[4];
4'd6: uart_txd<=tx_data[5];
4'd7: uart_txd<=tx_data[6];
4'd8: uart_txd<=tx_data[7];
endcase
end
end
// always @(posedge sys_clk or negedge sys_rst_n) begin
// if(!sys_rst_n) begin
// uart_done<=1'b0;
// uart_data<=8'd0;
// end
// else if(rx_cnt==4'd9) begin
// uart_done<=1'b1;
// uart_data<=rx_data;
// end
// else begin
// uart_done<=1'b0;
// uart_data<=8'd0;
// end
// end
endmodule
uart_loop.v
module uart_loop(
input sys_clk ,
input sys_rst_n,
input recv_done,
input [7:0] recv_data,
input tx_busy,
output reg send_en,
output reg [7:0] send_data
);
reg recv_done_d0;
reg recv_done_d1;
reg tx_ready;
wire recv_done_flag;
//边缘检测信号
assign recv_done_flag= (~recv_done_d1)&recv_done_d0;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
recv_done_d0<=1'b0;
recv_done_d1<=1'b0;
end
else begin
recv_done_d0<=recv_done;
recv_done_d1<=recv_done_d0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
tx_ready<=1'b0;
send_en<=1'b0;
send_data<=8'd0;
end
else begin
if(recv_done_flag)begin
tx_ready<=1'b1;
send_en<=1'b0;
send_data<=recv_data;
end
else if (tx_ready && (~tx_busy)) begin //检测串口的发送模块,拉高来发送使能信号的大小
tx_ready<=1'b0;
send_en<=1'b1;
end
end
end
endmodule
10.LCD点亮RGB色条
lcd_rgb_clolorbar.v(top)
module lcd_rgb_clolorbar(
input sys_clk,
input sys_rst_n,
//RGB LCD
output lcd_de,
output lcd_hs,
output lcd_vs,
output lcd_bl,
output lcd_clk,
inout [23:0] lcd_rgb //既要输入也需要输出的端口,我们把他改成inout的端口类型
);
wire [23:0] lcd_rgb_i;
wire [15:0] lcd_id;
wire lcd_pclk;
wire [10:0] pixel_xpos; //显示周期大小设置
wire [10:0] pixel_ypos;
wire [10:0] h_disp; //分辨率
wire [10:0] v_disp;
wire [23:0] pixel_data; //颜色
wire [23:0] lcd_rgb_o ;
assign lcd_rgb_i = lcd_rgb;
assign lcd_rgb = lcd_de ? lcd_rgb_o: {24{1'bz}}; //24位全部是最高位的大小,即为白色的结果????
rd_id rd_id_u(
.clk (sys_clk),
.rst_n (sys_rst_n),
.lcd_rgb (lcd_rgb_i),
.lcd_id (lcd_id)
);
CLOCK_DIV CLOCK_DIV_u(
.clk(sys_clk),
.rst_n(sys_rst_n),
.lcd_id(lcd_id),
.lcd_plck(lcd_plck)
);
lcd_display lcd_display_u(
.lcd_pclk (lcd_pclk) ,
.rst_n (sys_rst_n) ,
.pixel_xpos (pixel_xpos) , //显示周期大小设置
.pixel_ypos (pixel_ypos) ,
.h_disp (h_disp) , //分辨率
.v_disp (v_disp) ,
.pixel_data (pixel_data) //颜色
);
lcd_driver lcd_driver_u(
.lcd_pclk(lcd_pclk),
.rst_n(sys_rst_n),
.lcd_id(lcd_id),
.pixel_data(pixel_data),
.pixel_xpos(pixel_xpos), //显示周期大小设置
.pixel_ypos(pixel_ypos),
.h_disp(h_disp), //分辨率
.v_disp(v_disp),
//RGB LCD
.lcd_de(lcd_de),
.lcd_hs(lcd_hs),
.lcd_vs(lcd_vs),
.lcd_bl(lcd_bl),
.lcd_clk(lcd_clk),
.lcd_rgb(lcd_rgb_o)
);
endmodule
rd_id.v
//LCD读取id的那个模块
module rd_id(
input clk,
input rst_n,
input [23:0] lcd_rgb,
output reg [15:0] lcd_id
);
reg rd_flag; //获取id的标志
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rd_flag<=1'b0;
lcd_id<=16'd0;
end
else begin
if(rd_flag==1'b0) begin
rd_flag<=1'b1;
case({lcd_rgb[7],lcd_rgb[15],lcd_rgb[23]}) //M2:B7,M1:G7,M0:R7
3'b000: lcd_id<=16'h4342; //4.3寸
3'b001: lcd_id<=16'h7084; //4.3寸
3'b010: lcd_id<=16'h7016; //4.3寸
3'b100: lcd_id<=16'h4384; //4.3寸
3'b101: lcd_id<=16'h1018; //4.3寸
default: lcd_id<=16'd0;
endcase
end
end
end
endmodule
CLOCK_DIV.v
//对时钟进行一个分频的操作
module CLOCK_DIV(
input clk,
input rst_n,
input [15:0] lcd_id,
output reg lcd_pclk
);
reg clk_25m;
reg clk_12_5m;
reg div_4_cnt;
//2分频
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_25m <= 1'b0;
end
else
clk_25m <= ~clk_25m;
end
//4分频
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
clk_12_5m <= 1'b0;
div_4_cnt <= 1'b0;
end
else begin
div_4_cnt <= div_4_cnt + 1'b1;
if(div_4_cnt == 1'b1)
clk_12_5m<=~clk_12_5m;
end
end
always @(*) begin
case(lcd_id)
16'h4342: lcd_pclk <= clk_12_5m;
16'h7084: lcd_pclk <= clk_25m;
16'h7016: lcd_pclk <= clk;
16'h4384: lcd_pclk <= clk_25m;
16'h1018: lcd_pclk <= clk;
default: lcd_pclk <= 1'b0;
endcase
end
endmodule
lcd_display.v
//显示模块
module lcd_display(
input lcd_pclk,
input rst_n,
input [10:0] pixel_xpos, //显示周期大小设置
input [10:0] pixel_ypos,
input [10:0] h_disp, //分辨率
input [10:0] v_disp,
output reg [23:0] pixel_data //颜色
);
parameter WHITE = 24'hffffff;
parameter BLACK = 24'h000000;
parameter RED = 24'hff0000;
parameter GREEN = 24'h00ff00;
parameter BLUE = 24'h0000ff;
always @(posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
pixel_data <= BLACK ;
else begin
if((pixel_xpos >= 11'd0) && (pixel_xpos < h_disp/5*1)) //第一个彩条 白色
pixel_data <= WHITE ;
else if((pixel_xpos >= h_disp/5*1) && (pixel_xpos < h_disp/5*2)) //第二个彩条 黑色
pixel_data <= BLACK ;
else if((pixel_xpos >= h_disp/5*2) && (pixel_xpos < h_disp/5*3)) //第三个彩条 红色
pixel_data <= RED ;
else if((pixel_xpos >= h_disp/5*3) && (pixel_xpos < h_disp/5*4)) //第四个彩条 绿色
pixel_data <= GREEN ;
else //第五个彩条 蓝色
pixel_data <= BLUE ;
end
end
endmodule
lcd_driver.v
//驱动操作
module lcd_driver(
input lcd_pclk,
input rst_n,
input [15:0] lcd_id,
input [23:0] pixel_data,
output [10:0] pixel_xpos, //显示周期大小设置
output [10:0] pixel_ypos,
output reg [10:0] h_disp, //分辨率
output reg [10:0] v_disp,
//RGB LCD
output lcd_de,
output lcd_hs,
output lcd_vs,
output lcd_bl,
output lcd_clk,
output [23:0] lcd_rgb
);
//4.3' 480x472
parameter H_SYNC_4342 = 11'd41; //行同步
parameter H_BACK_4342 = 11'd2; //行显示后延
parameter H_DISP_4342 = 11'd480; //行显示区域
parameter H_FRONT_4342 = 11'd2; //行显示前沿
parameter H_TOTAL_4342 = 11'd525; //行总计
parameter V_SYNC_4342 = 11'd10; //列同步
parameter V_BACK_4342 = 11'd2; //列显示后延
parameter V_DISP_4342 = 11'd272; //列显示区域
parameter V_FRONT_4342 = 11'd2; //列显示前沿
parameter V_TOTAL_4342 = 11'd286; //列总计
// 7' 800*480
parameter H_SYNC_7084 = 11'd128;
parameter H_BACK_7084 = 11'd88;
parameter H_DISP_7084 = 11'd800;
parameter H_FRONT_7084 = 11'd40;
parameter H_TOTAL_7084 = 11'd1056;
parameter V_SYNC_7084 = 11'd2;
parameter V_BACK_7084 = 11'd33;
parameter V_DISP_7084 = 11'd480;
parameter V_FRONT_7084 = 11'd10;
parameter V_TOTAL_7084 = 11'd525;
// 7' 1024*600
parameter H_SYNC_7016 = 11'd20;
parameter H_BACK_7016 = 11'd140;
parameter H_DISP_7016 = 11'd1024;
parameter H_FRONT_7016 = 11'd160;
parameter H_TOTAL_7016 = 11'd1344;
parameter V_SYNC_7016 = 11'd3;
parameter V_BACK_7016 = 11'd20;
parameter V_DISP_7016 = 11'd600;
parameter V_FRONT_7016 = 11'd12;
parameter V_TOTAL_7016 = 11'd635;
// 10.1' 1280*800
parameter H_SYNC_1018 = 11'd10;
parameter H_BACK_1018 = 11'd80;
parameter H_DISP_1018 = 11'd1280;
parameter H_FRONT_1018 = 11'd70;
parameter H_TOTAL_1018 = 11'd1440;
parameter V_SYNC_1018 = 11'd3;
parameter V_BACK_1018 = 11'd10;
parameter V_DISP_1018 = 11'd800;
parameter V_FRONT_1018 = 11'd10;
parameter V_TOTAL_1018 = 11'd823;
// 4.3' 800*480
parameter H_SYNC_4384 = 11'd128;
parameter H_BACK_4384 = 11'd88;
parameter H_DISP_4384 = 11'd800;
parameter H_FRONT_4384 = 11'd40;
parameter H_TOTAL_4384 = 11'd1056;
parameter V_SYNC_4384 = 11'd2;
parameter V_BACK_4384 = 11'd33;
parameter V_DISP_4384 = 11'd480;
parameter V_FRONT_4384 = 11'd10;
parameter V_TOTAL_4384 = 11'd525;
reg [10:0] h_sync;
reg [10:0] h_back;
reg [10:0] h_total;
reg [10:0] v_sync;
reg [10:0] v_back;
reg [10:0] v_total;
reg [15:0] h_cnt;
reg [15:0] v_cnt;
wire lcd_en;
wire data_req;
assign lcd_hs =1'b1;
assign lcd_vs =1'b1;
assign lcd_bl =1'b1;
assign lcd_clk =lcd_pclk;
assign lcd_de = lcd_en;
assign lcd_en= ( h_cnt >= h_sync + h_back ) && ( h_cnt < h_sync + h_back + h_disp)
&&( v_cnt >= v_sync +v_back ) && ( v_cnt < v_sync + v_back + v_disp)
? 1'b1 : 1'b0 ;
assign lcd_rgb = lcd_en ? pixel_data : 24'd0 ;
assign data_req= ( h_cnt >= h_sync + h_back -1'b1) && ( h_cnt < h_sync + h_back + h_disp -1'b1)
&&( v_cnt >= v_sync +v_back ) && ( v_cnt < v_sync + v_back + v_disp)
? 1'b1 : 1'b0 ;
// 提前一个时钟周期发送确定位置(坐标)的信号大小
assign pixel_xpos = data_req ? ( h_cnt - ( h_sync + h_back -1'b1 )) : 11'd0; //垂直方向的有效坐标
assign pixel_ypos = data_req ? ( v_cnt - ( v_sync + v_back -1'b1 )) : 11'd0; //水平方向的有效坐标
always @(*) begin
case(lcd_id)
16'h4342: begin
h_sync = H_SYNC_4342;
h_back = H_BACK_4342;
h_total = H_TOTAL_4342;
v_sync = V_SYNC_4342;
v_back = V_BACK_4342;
v_total = V_TOTAL_4342;
end
16'h7084 : begin
h_sync = H_SYNC_7084;
h_back = H_BACK_7084;
h_disp = H_DISP_7084;
h_total = H_TOTAL_7084;
v_sync = V_SYNC_7084;
v_back = V_BACK_7084;
v_disp = V_DISP_7084;
v_total = V_TOTAL_7084;
end
16'h7016 : begin
h_sync = H_SYNC_7016;
h_back = H_BACK_7016;
h_disp = H_DISP_7016;
h_total = H_TOTAL_7016;
v_sync = V_SYNC_7016;
v_back = V_BACK_7016;
v_disp = V_DISP_7016;
v_total = V_TOTAL_7016;
end
16'h4384 : begin
h_sync = H_SYNC_4384;
h_back = H_BACK_4384;
h_disp = H_DISP_4384;
h_total = H_TOTAL_4384;
v_sync = V_SYNC_4384;
v_back = V_BACK_4384;
v_disp = V_DISP_4384;
v_total = V_TOTAL_4384;
end
16'h1018 : begin
h_sync = H_SYNC_1018;
h_back = H_BACK_1018;
h_disp = H_DISP_1018;
h_total = H_TOTAL_1018;
v_sync = V_SYNC_1018;
v_back = V_BACK_1018;
v_disp = V_DISP_1018;
v_total = V_TOTAL_1018;
end
default : begin
h_sync = H_SYNC_4342;
h_back = H_BACK_4342;
h_disp = H_DISP_4342;
h_total = H_TOTAL_4342;
v_sync = V_SYNC_4342;
v_back = V_BACK_4342;
v_disp = V_DISP_4342;
v_total = V_TOTAL_4342;
end
endcase
end
//h_cnt 行的计数器
always @(posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
h_cnt <=16'd0;
else begin
if(h_cnt == h_total-1'b1)
h_cnt <=16'd0;
else
h_cnt <= h_cnt + 1'b1;
end
end
//V_cnt 列的计数器
always @(posedge lcd_pclk or negedge rst_n) begin
if(!rst_n)
v_cnt <=16'd0;
else begin
if(h_cnt == h_total-1'b1) begin
if(v_cnt == v_total-1'b1)
v_cnt <= 16'd0;
else
v_cnt <= v_cnt+1'b1;
end
end
end
endmodule