单片机学习小组
直播中

laisvl

9年用户 1144经验值
私信 关注

如何对RAM进行读和写的操作?

如何对RAM进行读和写的操作?

回帖(1)

陈英

2022-1-18 11:01:02

对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信号。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分