草庐IT

FPGA实现Flash读写操作

ValentineHP 2023-04-22 原文

一. 简介

本篇文章所使用的Flash型号为M25P16,是ST公司的一款(好像还有一款同名的,是别的公司的)。容量为16Mbit,SPI接口,时钟速率可达50Mhz。要想完成对Flash的读写擦除操作,只需要弄懂两点即可:SPI时序 和 Flash操作指令。其他的细节和一些概念可以学习的过程中了解补充。

二. SPI

SPI一共有四种模式,分别由两个变量CPOL和CPHA控制。此Flash芯片下面两种模式

  1. 第一种是都为0,时钟空闲时是低电平,数据在时钟的下降沿输出,在上升沿输入。这种模式需要注意的是,第一个bit的输出是没有下降沿的,得手动提前输出。
  2. 第二种是都为1,时钟空闲时是高电平,数据在时钟的下降沿输出,在上升沿输入。

一般来说,都采用第二种模式对Flash进行读写。

三. Flash指令

Flash的全部指令如下,不算多,而且其中有些指令不会用到。下面就对必须要用到的指令进行说明

(1). WREN 和 WRDI

这两条指令一个是写使能,另外一个是写失能,一般情况下,只用WREN就可以看,至于为什么,后面相关写指令会给出答案。

(2) RDID

用来读取Flash的设备ID号,通常用来测试SPI总线是否正确,写完SPI协议后,可以使用这条命令来进行测试。

(3) READ

发送指令和读取的首地址后,接下来就是读取数据,每读取一个数据,地址就会知道加一,当达到地址边界后,地址会自动跳转到0地址进行读取,读取数据的数量没有限制,可以无限读下去。读完最后一个字节后,只需要将S信号拉高即可结束本部读取操作。

(4) PP

对flash进行写入操作,以页为单位,每一页有256bytes,共8192页,具体如下。

然后时序图如下,

然后重点来了,意思就是,在执行PP命令的时候,需要先执行WREN命令,并且锁住,可能在PP命令结束后,WREN命令会失效,根据最后一行推测出来的,测试时确实如此。

(5) SE

擦除命令,很简单,给指令和地址后,就ok了,擦除完成后,再次读取的时候,应该是全FF。同样擦除命令和PP命令一样,需要先发送WREN命令才行。其他的就没了。

四. 其他注意事项

Tcsh : 表示两条指令间隔时间,

Tpp: 表示page program后,需要等待Tpp时间后,才能进行下一条指令的操作

Tse: 同Tpp一样。

五. Verilog实现

写流程: WREN -> SE -> WREN -> PP(PP只能将1写为0 ,所以在PP之前要先擦除)

读流程: READ

SPI模块

`timescale 1ns/1ps



//MODE : CPOL=1 CPHA=1
//spi_clk = sys_clk / 2
module SPI_Master (
    //system interface
    input   wire            sys_clk,
    input   wire            sys_rstn,

    //user inferface
    //user read
    input   wire            read_req,
    output  wire[7:0]       read_data,
    output  wire            read_ack,

    //user write
    input   wire            write_req,
    input   wire[7:0]       write_data,
    output  wire            write_ack,


    //spi to external flash
    output  wire            spi_clk,
    output  wire            spi_mosi,
    input   wire            spi_miso
    //output  wire            spi_csn

);
    

localparam SPI_IDLE         = 4'b0001;
localparam SPI_DATA         = 4'b0010;
localparam SPI_END          = 4'b0100;
localparam SPI_END2         = 4'b1000;  

reg[3:0]    state , next_state;

reg         spi_clk_reg;
reg         spi_mosi_reg;
reg         spi_csn_reg;

reg         spi_clk_inverse_cnt;
reg[3:0]    spi_rev_send_bit_cnt;
reg[7:0]    write_data_reg;

reg[7:0]    read_data_reg;

assign      spi_clk           = spi_clk_reg;
assign      spi_mosi          = spi_mosi_reg;
assign      spi_csn           = spi_csn_reg;
assign      read_data         = read_data_reg;

assign      read_ack          = (state == SPI_END) ? 1'b1 : 1'b0;
assign      write_ack         = (state == SPI_END) ? 1'b1 : 1'b0;

always @(posedge sys_clk or negedge sys_rstn) begin
    if (sys_rstn == 1'b0)
        state <= SPI_IDLE;
    else
        state <= next_state;
end


always@(*)begin
    case (state)
        SPI_IDLE: 
            if( write_req == 1'b1  || read_req == 1'b1)
                next_state <= SPI_DATA;
            else
                next_state <= SPI_IDLE;
        SPI_DATA:
            if( spi_rev_send_bit_cnt == 'd7 && spi_clk_inverse_cnt == 1'b1)
                next_state <= SPI_END;
            else
                next_state <= SPI_DATA;
        SPI_END:
            next_state <= SPI_END2;
        SPI_END2:
            next_state <= SPI_IDLE;
        default: next_state <= SPI_IDLE; 
    endcase
end


always @(posedge sys_clk or negedge sys_rstn) begin
    if( sys_rstn == 1'b0)
        spi_clk_inverse_cnt <= 1'b0;
    else if( state == SPI_DATA)
        spi_clk_inverse_cnt <= spi_clk_inverse_cnt + 1'b1;
    else
        spi_clk_inverse_cnt <= 1'b0;       
end

//spi csn out
// always @(posedge sys_clk or negedge sys_rstn) begin
//     if( sys_rstn == 1'b0 )
//         spi_csn_reg <= 1'b1;
//     else if( state == SPI_IDLE && (write_req == 1'b1  || read_req == 1'b1))
//         spi_csn_reg <= 1'b0;
//     else if( state == SPI_DATA)
//         spi_csn_reg <= 1'b0;
//     else
//         spi_csn_reg <= 1'b1;
// end

//spi write/read data bit cnt
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        spi_rev_send_bit_cnt <= 4'd0;
    else if( spi_clk_inverse_cnt == 1'b1)
        spi_rev_send_bit_cnt <= spi_rev_send_bit_cnt + 1'b1;
    else if( state == SPI_DATA)
        spi_rev_send_bit_cnt <= spi_rev_send_bit_cnt;
    else
        spi_rev_send_bit_cnt <= 4'd0;
end

//mosi data shift
always @(posedge sys_clk or negedge sys_rstn) begin
    if( sys_rstn == 1'b0)
        write_data_reg <= 8'd0;
    else if( state == SPI_IDLE && (write_req == 1'b1  || read_req == 1'b1))
        write_data_reg <= write_data;
    else if( state == SPI_DATA && spi_clk_inverse_cnt == 1'b1)
        write_data_reg <= {write_data_reg[6:0],write_data_reg[7]};
    else
        write_data_reg <= write_data_reg;
end

//spi_clk_gen
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        spi_clk_reg <= 1'b1;
    else if(state == SPI_DATA)
        spi_clk_reg <= ~spi_clk_reg;
    else   
        spi_clk_reg <= 1'b1;
end

//mosi data out
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        spi_mosi_reg <= 1'b1;
    else if(state == SPI_DATA  && write_req == 1'b1)
        spi_mosi_reg <= write_data_reg[7];
    else    
        spi_mosi_reg <= 1'b1;
end


//miso data in
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        read_data_reg <= 1'b0;
    else if(state == SPI_DATA && spi_clk_inverse_cnt == 1'b1)
        read_data_reg <= {read_data_reg[6:0] , spi_miso};
    else
        read_data_reg <= read_data_reg;
end


endmodule

Flash模块





//flash  write/read control   : M25P16
module flash_contorl (
    //system interface
    input   wire            sys_clk,
    input   wire            sys_rstn,


    //user interface
    //read identification
    input   wire            read_id_req,
    output  wire[23:0]      flash_id,
    output  wire            read_id_end,

    //read data
    input   wire            read_req,
    input   wire[23:0]      read_addr,
    input   wire[9:0]       read_size,
    output  wire[7:0]       read_data,    
    output  wire            read_ack,
    output  wire            read_end,

    //write enalbe
    input   wire            write_enable_req,
    output  wire            write_enable_end,

    //write disalbe
    //write data
    input   wire            write_req, 
    input   wire[23:0]      write_page,     //write num page
    input   wire[8:0]       write_size,     //max equal 256

    input   wire[7:0]       write_data,
    output  wire            write_ack,
    output  wire            write_end,
    
    //erase sector
    input   wire            erase_sector_req,
    input   wire[23:0]      erase_sector_addr,
    output  wire            erase_sector_end,

    //erase bulk
    input   wire            erase_bulk_req,
    output  wire            erase_bulk_end,

    //spi to external flash
    output  wire            spi_clk,
    output  wire            spi_mosi,
    input   wire            spi_miso,
    output  wire            spi_csn
);



//control flash instruction    
`define Write_Enable                    8'h06
`define Write_Disable                   8'h04
`define Read_Identification             8'h9F
`define Read_Status_Reg                 8'h05
`define Write_Status_Reg                8'h01
`define Read_Data_Bytes                 8'h03
`define Read_Data_At_Higher_Speed       8'h0B
`define Page_Program                    8'h02
`define Sector_Erase                    8'hD8
`define Bulk_Erase                      8'hC7               


`define Read_Identification_Bytes       4'd4
`define Sector_Erase_Bytes              4'd4
`define Bulk_Erase_Bytes                4'd1

localparam  Page_Size                   =   9'd256;
localparam  Write_Enable_Wait           =   'd10;
localparam  Read_Data_Bytes_Wait        =   'd10;               //wait      60ns
localparam  Sector_Erase_Wait           =   32'd35_000_000;     //wait      640ms
localparam  Page_Program_Wait           =   32'd350_000;        //wait       640us
localparam  Bulk_Erase_Wait             =   32'd650_000_000;    //wait      13s


localparam  Flash_Idle                  =   13'b0_0000_0000_0001;
localparam  Flash_Write_Enable          =   13'b0_0000_0000_0010;
localparam  Flash_Write_Disable         =   13'b0_0000_0000_0100;
localparam  Flash_Read_Identification   =   13'b0_0000_0000_1000;
localparam  Flash_Read_Status_Reg       =   13'b0_0000_0001_0000;
localparam  Flash_Write_Status_Reg      =   13'b0_0000_0010_0000;
localparam  Flash_Read_Data_Bytes       =   13'b0_0000_0100_0000;
localparam  Flash_Read_Data_At_hSpeed   =   13'b0_0000_1000_0000;
localparam  Flash_Page_Program          =   13'b0_0001_0000_0000;
localparam  Flash_Sector_Erase          =   13'b0_0010_0000_0000;
localparam  Flash_Bulk_Erase            =   13'b0_0100_0000_0000;
localparam  Flash_Wait                  =   13'b0_1000_0000_0000;
localparam  Flash_End                   =   13'b1_0000_0000_0000;



reg[12:0]   state , next_state;

reg[12:0]   state_ts;

//spi read
reg         spi_read_req;
wire[7:0]   spi_read_data;
wire        spi_read_ack;

//spi write
reg         spi_write_req;
reg[7:0]    spi_write_data;
wire        spi_write_ack;

reg         spi_csn_reg;

reg[9:0]    spi_wr_byte_cnt;


reg[23:0]   flash_id_reg;

reg[32:0]   pp_erase_wait_cnt;

assign      spi_csn             =   spi_csn_reg;   //to spi flash csn

assign      flash_id            =   flash_id_reg;
assign      read_id_end         =   ((spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0;


assign      read_data           =   spi_read_data;
assign      read_ack            =   ((state == Flash_Read_Data_Bytes) && (spi_wr_byte_cnt > 'd3) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0;   //读出数据有效
assign      read_end            =   ((state == Flash_Read_Data_Bytes) &&(spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1) ? 1'b1 : 1'b0;

assign      write_enable_end    =   ((state == Flash_Write_Enable) &&(spi_wr_byte_cnt == 'd0) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0;


assign      write_ack           =   ((state == Flash_Page_Program) && (spi_wr_byte_cnt > 'd3) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0;    //请求下一个数据
assign      write_end           =   ((state == Flash_Page_Program) && (spi_wr_byte_cnt == write_size + 'd1 + 'd3 - 1'b1) && spi_write_ack == 1'b1) ? 1'b1 : 1'b0;

assign      erase_sector_end    =   ((state == Flash_Sector_Erase) && (spi_wr_byte_cnt == `Sector_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1 ) ? 1'b1 : 1'b0; 
assign      erase_bulk_end      =   ((state == Flash_Bulk_Erase) && (spi_wr_byte_cnt == `Bulk_Erase_Bytes - 1'b1)   && spi_write_ack == 1'b1 ) ? 1'b1 : 1'b0; 

always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        state <= Flash_Idle;
    else
        state <= next_state;
end


always@(*)begin
    case (state)
        Flash_Idle: 
            if( read_id_req == 1'b1)
                next_state <= Flash_Read_Identification;
            else if( write_enable_req == 1'b1)
                next_state <= Flash_Write_Enable;
            else if( write_req == 1'b1 )
                next_state <= Flash_Page_Program;
            else if( read_req == 1'b1 )
                next_state <= Flash_Read_Data_Bytes;
            else if( erase_sector_req == 1'b1)
                next_state <= Flash_Sector_Erase;
            else if( erase_bulk_req == 1'b1 )
                next_state <= Flash_Bulk_Erase;
            else
                next_state <= Flash_Idle; 

        Flash_Read_Identification:
            if( (spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1)
                next_state <= Flash_End;
            else
                next_state <= Flash_Read_Identification;
        Flash_Write_Enable:
            if( spi_write_ack == 1'b1)
                next_state <= Flash_Wait;
            else
                next_state <= Flash_Write_Enable;
        Flash_Page_Program:
            if( (spi_wr_byte_cnt == write_size + 'd1 + 'd3 - 1'b1) && spi_write_ack == 1'b1)  //写入指令 + 地址 + 数据
                next_state <= Flash_Wait;
            else
                next_state <= Flash_Page_Program;
        Flash_Read_Data_Bytes:
            if( (spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1)  //写入指令 + 地址 + 数据   
                next_state <= Flash_Wait;
            else
                next_state <= Flash_Read_Data_Bytes;
        Flash_Sector_Erase:
            if( (spi_wr_byte_cnt == `Sector_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1)
                next_state <= Flash_Wait;
            else
                next_state <= Flash_Sector_Erase;
        Flash_Bulk_Erase:
            if( (spi_wr_byte_cnt == `Bulk_Erase_Bytes - 1'b1) && spi_write_ack == 1'b1)
                next_state <= Flash_Wait;
            else
                next_state <= Flash_Bulk_Erase;
        Flash_Wait:
            if( state_ts == Flash_Page_Program && pp_erase_wait_cnt == Page_Program_Wait)
                next_state <= Flash_End;
            else if(state_ts == Flash_Sector_Erase && pp_erase_wait_cnt == Sector_Erase_Wait)
                next_state <= Flash_End;
            else if(state_ts == Flash_Bulk_Erase && pp_erase_wait_cnt == Bulk_Erase_Wait)
                next_state <= Flash_End;
            else if(state_ts == Flash_Read_Data_Bytes && pp_erase_wait_cnt == Read_Data_Bytes_Wait)
                next_state <= Flash_End;
            else if(state_ts == Flash_Write_Enable && pp_erase_wait_cnt == Write_Enable_Wait)
                next_state <= Flash_End;

            else
                next_state <= Flash_Wait;
        Flash_End:
            next_state <= Flash_Idle;
        default:    next_state <= Flash_Idle;
    endcase
end

always@(posedge sys_clk or negedge sys_rstn ) begin
    if( sys_rstn == 1'b0)
        state_ts <= Flash_Idle;
    else if( state == Flash_Idle )
        if( write_req == 1'b1 )
            state_ts <= Flash_Page_Program;
        else if( erase_sector_req == 1'b1)
            state_ts <= Flash_Sector_Erase;
        else if( erase_bulk_req == 1'b1 )
            state_ts <= Flash_Bulk_Erase;
        else if( read_req == 1'b1)
            state_ts <= Flash_Read_Data_Bytes;
        else if( write_enable_req == 1'b1)
            state_ts <= Flash_Write_Enable;
        else
            state_ts <= Flash_Idle; 
    else
        state_ts <= state_ts;
end


always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        pp_erase_wait_cnt <= 'd0;
    else if(state == Flash_Wait)
        pp_erase_wait_cnt <= pp_erase_wait_cnt + 1'b1;
    else    
        pp_erase_wait_cnt <= 'd0;

end

// spi csn
always@(posedge sys_clk or negedge sys_rstn )begin
    if( sys_rstn == 1'b0)
        spi_csn_reg <= 1'b1;
    else if( state == Flash_Idle || state == Flash_End || state == Flash_Wait)
        spi_csn_reg <= 1'b1;
    else
        spi_csn_reg <= 1'b0;
end
//spi read/write byte cnt
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0 )
        spi_wr_byte_cnt <= 'd0;
    else if( state != next_state)   
        spi_wr_byte_cnt <= 'd0;
    else if( spi_read_ack == 1'b1 || spi_write_ack == 1'b1)
        spi_wr_byte_cnt <= spi_wr_byte_cnt + 1'b1;
    else    
        spi_wr_byte_cnt <= spi_wr_byte_cnt;
end


//spi read
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0 )
        spi_read_req <= 1'b0;
    
    else if( state == Flash_Read_Identification && spi_wr_byte_cnt > 'd0)  
        if((spi_wr_byte_cnt == `Read_Identification_Bytes - 1'b1) && spi_read_ack == 1'b1)
            spi_read_req <= 1'b0;
        else
            spi_read_req <= 1'b1;
    else if(state == Flash_Read_Data_Bytes && spi_wr_byte_cnt > 'd3)
        if((spi_wr_byte_cnt == read_size + 'd1 + 'd3 - 1'b1) && spi_read_ack == 1'b1)
            spi_read_req <= 1'b0;
        else
            spi_read_req <= 1'b1;
    else
        spi_read_req <= 1'b0;
end


//read flash identification
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0)
        flash_id_reg <= 'd0;
    else if( state == Flash_Read_Identification && spi_wr_byte_cnt > 'd0)
        if( spi_read_ack == 1'b1)
            flash_id_reg <= {flash_id_reg[15:0],spi_read_data};
        else
            flash_id_reg <= flash_id_reg;
    else
        flash_id_reg <= flash_id_reg;
end


//spi write req
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0 )
        spi_write_req <= 1'b0;
    else if( state == Flash_Write_Enable)
        spi_write_req <= 1'b1;
    else if( state == Flash_Read_Identification && spi_wr_byte_cnt == 'd0)
        spi_write_req <= 1'b1;
    else if( state == Flash_Page_Program)
        spi_write_req <= 1'b1;
    else if( state == Flash_Read_Data_Bytes && spi_wr_byte_cnt < 'd4)
        spi_write_req <= 1'b1;
    else if( state == Flash_Sector_Erase && spi_wr_byte_cnt < 'd4 )
        spi_write_req <= 1'b1;
    else if( state == Flash_Bulk_Erase )    
        spi_write_req <= 1'b1;
    else
        spi_write_req <= 1'b0;
end

//spi write data
always@(posedge sys_clk or negedge sys_rstn)begin
    if( sys_rstn == 1'b0 )
        spi_write_data <= 8'd0;
    else if( state == Flash_Write_Enable )
        spi_write_data <= `Write_Enable;
    else if( state == Flash_Read_Identification && spi_wr_byte_cnt == 'd0)
        spi_write_data <= `Read_Identification;    
    else if( state == Flash_Page_Program)
        case(spi_wr_byte_cnt)
        'd0:     spi_write_data <= `Page_Program;
        'd1:     spi_write_data <= write_page[23:16];
        'd2:     spi_write_data <= write_page[15:8];
        'd3:     spi_write_data <= write_page[7:0];    
        default: spi_write_data <= write_data;
        endcase
    else if(state == Flash_Read_Data_Bytes)
        if( spi_wr_byte_cnt == 'd0)
            spi_write_data <= `Read_Data_Bytes;
        else if( spi_wr_byte_cnt == 'd1)
            spi_write_data <= read_addr[23:16];
        else if( spi_wr_byte_cnt == 'd2)
            spi_write_data <= read_addr[15:8];
        else
            spi_write_data <= read_addr[7:0];
    else if( state == Flash_Sector_Erase)
        if( spi_wr_byte_cnt == 'd0)
            spi_write_data <= `Sector_Erase;
        else if( spi_wr_byte_cnt == 'd1)
            spi_write_data <= erase_sector_addr[23:16];
        else if( spi_wr_byte_cnt == 'd2)
            spi_write_data <= erase_sector_addr[15:8];
        else
            spi_write_data <= erase_sector_addr[7:0];
    else if( state == Flash_Bulk_Erase)
        spi_write_data <= `Bulk_Erase;
    else
        spi_write_data <= 8'd0;
end




SPI_Master SPI_Master_hp(
    //system interface
    /*input   wire            sys_clk */    .sys_clk    (sys_clk),
    /*input   wire            sys_rstn*/    .sys_rstn   (sys_rstn),

    //user inferface
    //user read
    /*input   wire            read_req */   .read_req   (spi_read_req),
    /*output  wire[7:0]       read_data*/   .read_data  (spi_read_data),
    /* output  wire            read_ack*/   .read_ack   (spi_read_ack),

    //user write
    /*input   wire            write_req */  .write_req  (spi_write_req),
    /*input   wire[7:0]       write_data*/  .write_data (spi_write_data),
    /*output  wire            write_ack */  .write_ack  (spi_write_ack),


    //spi to external flash
    /*output  wire            spi_clk */   .spi_clk     (spi_clk), 
    /*output  wire            spi_mosi*/   .spi_mosi    (spi_mosi),
    /*input   wire            spi_miso*/   .spi_miso    (spi_miso)
    /*output  wire            spi_csn */   //.spi_csn     ()

);

endmodule

下面给出测试读取ID的值

完整工程 可以 关注 回复 FPGA读写Flash 获取

有关FPGA实现Flash读写操作的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  5. ruby-on-rails - 在 Flash 警报 Rails 3 中显示错误消息 - 2

    如果我在模型中设置验证消息validates:name,:presence=>{:message=>'Thenamecantbeblank.'}我如何让该消息显示在闪光警报中,这是我迄今为止尝试过的方法defcreate@message=Message.new(params[:message])if@message.valid?ContactMailer.send_mail(@message).deliverredirect_to(root_path,:notice=>"Thanksforyourmessage,Iwillbeintouchsoon")elseflash[:error]

  6. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  7. ruby - Arrays Sets 和 SortedSets 在 Ruby 中是如何实现的 - 2

    通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复

  8. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  9. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  10. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

随机推荐