完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
对RAM(随机存储器)进行读和写操作。 使用tool工具生成IP核RAM,8位读地址8位写地址。 IP核仿真 `timescale 1ns/1ns `define clk_period 20 module dpram_tb; reg clock; reg [7:0]data; reg [7:0]rdaddress; reg [7:0]wraddress; reg wren; wire [7:0]q; integer n; //有符号数 寄存器类型 dpram dpram0( .clock(clock), .data(data), .rdaddress(rdaddress), //读地址 .wraddress(wraddress), //写地址 写地址变化后慢一个时钟写入 .wren(wren), //写请求信号,高电平有效 .q(q) //读出来的结果 rdaddress地址后两个时钟出结果 ); initial clock = 1; always #(`clk_period/2) clock = ~clock; initial begin data = 0; rdaddress = 20; wraddress = 0; wren = 0; #(`clk_period*20+1); for( n=0;n<=15; n=n+1) begin wren = 1; data = 255-n; wraddress = n; #`clk_period; end wren = 0; #(`clk_period*50); for( n=0;n<=15;n=n+1) begin rdaddress = n; #`clk_period; end #(`clk_period*10); $stop; end endmodule 当读地址为零时,两个周期后q信号输出数据。延迟两个周期。 简易系统 Key_shake模块 将按键异步信号消抖处理,产生Key_flag和Key_state信号,处理按键按下事件。 module Key_shake(Clk,Rst_n,Key_in,Key_flag,Key_data); input Clk; input Rst_n; input Key_in; output reg Key_flag; //当按键按下20ms消除抖动成功后产生一个脉冲flag信号,检测到产生flag信号后产生按键按下低电平。 output reg Key_data; reg [3:0]state; reg [19:0]count; //寄存器计数 reg count_start;//时能计时 reg count_full;//计满脉冲信号 reg reg0,reg1; reg key_in_now0,key_in_now1; wire rise,fall; localparam High_pulse = 4'b0001, //高电平稳定状态 Low_eliminate = 4'b0010, //键下降沿稳定状态 Low_pulse = 4'b0100, //低电平稳定状态 High_eliminate = 4'b1000; //键上升沿稳定状态 always @(posedge Clk or negedge Rst_n) //对输入按键信号做同步处理,消除异步信号亚稳态的影响。 if(!Rst_n) begin key_in_now0 <= 1'b0; key_in_now1 <=1'b0; end else begin key_in_now0 <= Key_in; key_in_now1 <= key_in_now0; end always @(posedge Clk or negedge Rst_n) //脉冲边沿检测 两个寄存器 if(!Rst_n) begin reg0 <= 1'b0; reg1 <=1'b0; end else begin reg0 <= key_in_now1; reg1 <= reg0; end assign fall = !reg0 & reg1; //检测到下降沿 assign rise = reg0 & !reg1; //检测到上升沿 always @(posedge Clk or negedge Rst_n) //20ms计数器 if(!Rst_n) count <= 20'b0; else if(count_start) count <= count + 20'b1; else count <= 20'b0; always @(posedge Clk or negedge Rst_n) //20ms计数器计数满标志脉冲信号 if(!Rst_n) count_full <= 1'b0; else if(count == 99_9999) count_full <= 1'b1; else count_full <= 1'b0; always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin Key_data <= 1'b1; state <= High_pulse; Key_flag <= 1'b0; count_start <= 1'b0; end else case(state) High_pulse : begin Key_flag <= 0; Key_data <= 1'b1; if(fall) begin state <= Low_eliminate; count_start <= 1'b1; //使能开始20ms计数 end else state <= High_pulse; end Low_eliminate : if(count_full) begin state <= Low_pulse; Key_flag <= 1'b1; Key_data <= 1'b0; count_start <= 1'b0; //关闭使能20ms计数 end else begin if(rise) begin state <= High_pulse; count_start <= 1'b0; //关闭使能20ms计数 end else state <= Low_eliminate; end Low_pulse: begin Key_flag <= 1'b0; if(rise) begin state <= High_eliminate; count_start <= 1'b1; //开始计时 end else state <= Low_pulse; end High_eliminate : if(count_full) begin Key_data <= 1'b1; Key_flag <= 1'b1; state <= High_pulse; end else begin if(fall) begin state <= Low_pulse; count_start <= 1'b0; end else state <= High_eliminate; end default : begin state <= High_pulse; //默认状态 count_start <= 1'b0; Key_data <= 1'b1; Key_flag <= 1'b0; end endcase endmodule uart_data_rx模块 接收外来信号并传输到dpram中。 module uart_data_rx( //串口接收模块 Clk, Rst_n, Rs232_rx, Bps_set, Data_out, Done_rx ); input Clk; input Rst_n; input Rs232_rx; input [2:0]Bps_set; output reg [7:0]Data_out; output reg Done_rx; reg [8:0]bps_max;//计数值 reg now_reg0,rs232_rx_now; //同步寄存器 消除亚稳态 reg data_reg0,data_reg1; //数据寄存器 判断高低电平 wire low; reg en_data; reg [8:0]bps_con; //bps_clk时钟计数器 reg bps_clk; reg [7:0]bps_count; reg [2:0]Data[7:0]; //共有8个Data数据每一个Data数据有3位 例如110 reg [2:0]start_bite; reg [2:0]stop_bite; //查找表选择计数值 always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_max <= 9'b0; else begin case(Bps_set) 0: bps_max <= 9'd324; 1: bps_max <= 9'd162; 2: bps_max <= 9'd80; 3: bps_max <= 9'd53; 4: bps_max <= 9'd26; default : bps_max <= 9'd324; endcase end //消除亚稳态 always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin now_reg0 <= 0; rs232_rx_now <= 0; end else begin now_reg0 <= Rs232_rx; rs232_rx_now <= now_reg0; end //判断低电平 always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin data_reg0 <= 0; data_reg1 <= 0; end else begin data_reg0 <= rs232_rx_now; data_reg1 <= data_reg0; end assign low = !data_reg0 & data_reg1; //使能开始计数 always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_con <= 9'b0; else if(en_data) begin if(bps_con == bps_max) bps_con <= 9'b0; else bps_con <= bps_con + 1'b1; end else bps_con <= 9'b0; //产生波特率时钟 always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_clk <= 0; else if(bps_con ==9'b1) bps_clk <= 1'b1; else bps_clk <= 1'b0; //计数波特率时钟 always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_count <= 8'b0; else if(Done_rx || ((bps_count == 8'd12) && (start_bite >2))) bps_count <= 8'b0; else if(bps_clk) bps_count <= bps_count + 1'b1; //产生Done_rx计数满信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) Done_rx <= 1'b0; else if(bps_count == 8'd159) Done_rx <= 1'b1; else Done_rx <= 1'b0; //将Data的值给Data_out输出查看 always @(posedge Clk or negedge Rst_n) if(!Rst_n) Data_out <= 8'b0; else if(bps_count == 8'd159) begin Data_out[0] <= Data[0][2]; //如果中间6位数值和加起来大于3(100.101.110)第3位数值将大于1,由此可以将第3位的值直接传给Data_out数据 Data_out[1] <= Data[1][2]; Data_out[2] <= Data[2][2]; Data_out[3] <= Data[3][2]; Data_out[4] <= Data[4][2]; Data_out[5] <= Data[5][2]; Data_out[6] <= Data[6][2]; Data_out[7] <= Data[7][2]; end //将Data的中间6位数据累加 always @(posedge Clk or negedge Rst_n) if(!Rst_n)begin start_bite <= 3'b0; Data[0] <= 3'b0; Data[1] <= 3'b0; Data[2] <= 3'b0; Data[3] <= 3'b0; Data[4] <= 3'b0; Data[5] <= 3'b0; Data[6] <= 3'b0; Data[7] <= 3'b0; stop_bite <= 3'b0; end else if(bps_clk) begin case(bps_count) 0:begin start_bite <= 3'b0; Data[0] <= 3'b0; Data[1] <= 3'b0; Data[2] <= 3'b0; Data[3] <= 3'b0; Data[4] <= 3'b0; Data[5] <= 3'b0; Data[6] <= 3'b0; Data[7] <= 3'b0; stop_bite <= 3'b0; end 6,7,8,9,10,11: start_bite <= start_bite + rs232_rx_now; 22,23,24,25,26,27: Data[0] <= Data[0] + rs232_rx_now; 38,39,40,41,42,43: Data[1] <= Data[1] + rs232_rx_now; 54,55,56,57,58,59: Data[2] <= Data[2] + rs232_rx_now; 70,71,72,73,74,75: Data[3] <= Data[3] + rs232_rx_now; 86,87,88,89,90,91: Data[4] <= Data[4] + rs232_rx_now; 102,103,104,105,106,107: Data[5] <= Data[5] + rs232_rx_now; 118,119,120,121,122,123: Data[6] <= Data[6] + rs232_rx_now; 134,135,136,137,138,139: Data[7] <= Data[7] + rs232_rx_now; 150,151,152,153,154,155: stop_bite <= stop_bite + rs232_rx_now; default : begin start_bite <= start_bite; Data[0] <= Data[0]; Data[1] <= Data[1]; Data[2] <= Data[2]; Data[3] <= Data[3]; Data[4] <= Data[4]; Data[5] <= Data[5]; Data[6] <= Data[6]; Data[7] <= Data[7]; stop_bite <= stop_bite; end endcase end //判断是否完成接收或无开始错误,产生使能信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) en_data <= 1'b0; else if(low) en_data <= 1'b1; else if(Done_rx ||((bps_count == 8'd12) && (start_bite >2))) en_data <= 1'b0; else en_data <= en_data; endmodule dpram模块 使用quartus2软件工具生成存储器IP核。 UART_TX模块 读取dpram中的值,con_en使能为高电平输出dapram中的值。 module UART_TX( Clk, Rst_n, Bps_set, Con_en, Data_in, Rs232_tx, Done_tx, Uart_state ); input Clk; input Rst_n; input [2:0]Bps_set; input Con_en; input [7:0]Data_in; output reg Rs232_tx; output reg Done_tx; output reg Uart_state; reg [15:0]count; //计数器定值 reg [15:0]high_count; //计数值 reg [7:0]Data_in_r; reg bps_clk; reg [3:0]bps_count; localparam start_bite = 1'b0; localparam stop_bite = 1'b1; //查找表输出计数值 always @(posedge Clk or negedge Rst_n) if(!Rst_n) count <= 16'd5207; else begin case(Bps_set) 0: count <= 16'd5207; 1: count <= 16'd2603; 2: count <= 16'd1301; 3: count <= 16'd865; 4: count <= 16'd433; default : count <= 16'd5207; endcase end //产生Uart_state使能信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) Uart_state <= 1'b0; else if(Con_en) Uart_state <= 1'b1; else if(bps_count == 4'd11) Uart_state <= 1'b0; else Uart_state <= Uart_state; //计数满产生bps_clk信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) high_count <= 0; else if(Uart_state) begin if(high_count == count) high_count <= 0; else high_count <= high_count + 1'b1; end else high_count <= 0; always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_clk <= 1'b0; else if(high_count == 16'b1) bps_clk <= 1'b1; else bps_clk <= 1'b0; //计数bps_clk的高电平到11计数满为0 产生Done_tx高点平信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) bps_count <= 4'b0; else if(bps_count == 4'd11) bps_count <= 4'b0; else if(bps_clk ) bps_count <= bps_count + 4'b1; else bps_count <= bps_count; always @(posedge Clk or negedge Rst_n) if(!Rst_n) Done_tx <= 1'b0; else if(bps_count == 4'd11) Done_tx <= 1; else Done_tx <= 0; always @(posedge Clk or negedge Rst_n ) if(!Rst_n) Data_in_r <= 0; else if(Con_en) Data_in_r <= Data_in ; else Data_in_r <= Data_in_r; //十选一多路选择器 always @(posedge Clk or negedge Rst_n) if(!Rst_n) Rs232_tx <= 1'b1; else begin case(bps_count) 0: Rs232_tx <= 1'b1; 1: Rs232_tx <= start_bite; 2: Rs232_tx <= Data_in_r[0]; 3: Rs232_tx <= Data_in_r[1]; 4: Rs232_tx <= Data_in_r[2]; 5: Rs232_tx <= Data_in_r[3]; 6: Rs232_tx <= Data_in_r[4]; 7: Rs232_tx <= Data_in_r[5]; 8: Rs232_tx <= Data_in_r[6]; 9: Rs232_tx <= Data_in_r[7]; 10: Rs232_tx <= stop_bite; default : Rs232_tx <= 1'b1; endcase end endmodule control模块 控制其他模块的输入输出。 module control( Key_state, Key_flag, Clk, Rst_n, Done_rx, Done_tx, Rdaddress, Wraddress, Wren, En_send ); input Key_flag; input Key_state; input Clk, Rst_n; input Done_rx,Done_tx; output reg [7:0]Rdaddress; output reg [7:0]Wraddress; output Wren; output reg En_send; reg put_button; reg delay_t0,delay_t1; assign Wren = Done_rx; always @(posedge Clk or negedge Rst_n) //写入地址 if(!Rst_n) Wraddress <= 8'd0; else if(Done_rx) Wraddress <= Wraddress + 1'b1; else Wraddress <= Wraddress ; always @(posedge Clk or negedge Rst_n) //乒乓操作 if(!Rst_n) put_button <= 1'b0; else if(Key_flag && !Key_state) put_button <= ~ put_button; always @(posedge Clk or negedge Rst_n) //读操作 if(!Rst_n) Rdaddress <= 8'b0; else if(put_button && Done_tx) Rdaddress <= Rdaddress + 1'b1; else Rdaddress <= Rdaddress; //将信号延迟两个周期 always @(posedge Clk or negedge Rst_n) if(!Rst_n) begin delay_t0 <= 1'b0; delay_t1 <= 1'b0; end else begin delay_t0 <= (put_button && Done_tx); delay_t1 <= delay_t0; end //控制产生发送使能信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) En_send <= 1'b0; else if(delay_t1) En_send <= 1'b1; else if(Key_flag && !Key_state) En_send <= 1'b1; else En_send <= 1'b0; endmodule //控制产生发送使能信号 always @(posedge Clk or negedge Rst_n) if(!Rst_n) En_send <= 1'b0; else if(delay_t1) En_send <= 1'b1; else if(Key_flag && !Key_state) En_send <= 1'b1; else En_send <= 1'b0; if(Key_flag && !Key_state)条件为第一次按下按键后的产生En_send使能信号发送地址为0的数据,if(delay_t1) 为按下按键后每当tx模块输出一次地址数据完成产生Done_tx信号自动输出下一个地址数据。 Uart_dapram顶层模块 module Uart_dapram( Clk, Rs232_rx, Rst_n, Key_in, Rs232_tx ); input Clk; input Rs232_rx; input Rst_n; input Key_in; output Rs232_tx; wire [7:0]Data_bite_rx,Data_bite_tx; wire Done_tx,Done_rx; wire Key_flag,Key_data; wire Con_en; wire [7:0]rdaddress,wraddress; wire wren; UART_TX UART_TX0( //串口发送模块 .Clk(Clk), .Rst_n(Rst_n), .Bps_set(3'b0), .Con_en(Con_en), .Data_in(Data_bite_tx), .Rs232_tx(Rs232_tx), .Done_tx(Done_tx), //一次发送完成标志信号 .Uart_state() //模块状态标志信号 ); uart_data_rx uart_data_rx0( //串口接收模块 .Clk(Clk), .Rst_n(Rst_n), .Rs232_rx(Rs232_rx), .Bps_set(3'b0), .Data_out(Data_bite_rx), .Done_rx(Done_rx) ); Key_shake Key_shake0( .Clk(Clk), .Rst_n(Rst_n), .Key_in(Key_in), .Key_flag(Key_flag), .Key_data(Key_data) ); dpram dpram0( .clock(Clk), .data(Data_bite_rx), .rdaddress(rdaddress), //读地址 .wraddress(wraddress), //写地址 .wren(wren), //写请求信号,高电平有效 .q(Data_bite_tx) ); control control0( .Clk(Clk), .Rst_n(Rst_n), .Done_rx(Done_rx), .Key_state(Key_data), .Key_flag(Key_flag), .Done_tx(Done_tx), .Rdaddress(rdaddress), .Wraddress(wraddress), .Wren(wren), .En_send(Con_en) ); endmodule Uart_dapram_tb顶层仿真模块 `timescale 1ns/1ns `define clk_period 20 module Uart_dapram_tb; reg Clk,Con_en; reg [7:0]Data_in; wire Rs232_rx; reg Rst_n; wire Key_in; reg press; wire Rs232_tx; wire [2:0]Bps_set; wire Done_tx; assign Bps_set = 3'd0; Uart_dapram Uart_dapram1( .Clk(Clk), .Rs232_rx(Rs232_rx), .Rst_n(Rst_n), .Key_in(Key_in), .Rs232_tx(Rs232_tx) ); //用tx模块产生数据激励信号 UART_TX UART_TX0( .Clk(Clk), .Rst_n(Rst_n), .Bps_set(Bps_set), .Con_en(Con_en), .Data_in(Data_in), .Rs232_tx(Rs232_rx), .Done_tx(Done_tx), .Uart_state() ); //产生按键信号 /按键模型 Key_model Key_model0( .Press(press), .Key(Key_in) ); initial Clk = 1; always#(`clk_period/2) Clk = ~Clk; initial begin Rst_n = 1'b0; Data_in = 8'b0; press = 1'b0; Con_en = 1'b0; #(`clk_period*20+1); Rst_n = 1'b1; #(`clk_period*20+1); Con_en = 1'b1; Data_in = 8'hae; #(`clk_period); Con_en = 1'b0; @(posedge Done_tx) #(`clk_period*3000); Con_en = 1'b1; Data_in = 8'h5b; #(`clk_period); Con_en = 1'b0; @(posedge Done_tx) #(`clk_period*3000); Con_en = 1'b1; Data_in = 8'hef; #(`clk_period); Con_en = 1'b0; @(posedge Done_tx) #(`clk_period*3000); Con_en = 1'b1; Data_in = 8'haa; #(`clk_period); Con_en = 1'b0; @(posedge Done_tx) #(`clk_period*3000); press = 1; #(`clk_period*5); press = 0; $stop; end endmodule Key_model模块为按键事件模型,模拟实际中产生的按键抖动信号。 当读地址rdaddress变化后,dpram寄存器输出Data_bite_tx信号。 |
|
|
|
只有小组成员才能发言,加入小组>>
3314 浏览 9 评论
2995 浏览 16 评论
3494 浏览 1 评论
9059 浏览 16 评论
4088 浏览 18 评论
1179浏览 3评论
605浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
599浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2335浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1896浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 16:35 , Processed in 1.250469 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号