基于FPGA的AD5753(DAC数模转换器)的控制 II(SPI驱动)

基于FPGA的AD5753(DAC数模转换器)的控制 II(已上板验证)

语言 :Verilg HDL

EDA工具:Vivado

  • 关键词: AD5753 驱动,Verilog HDL,SPI驱动,DAC数模转换器,上板已验证成功

一、引言

本次分享DAC(AD5753) SPI驱动控制器的FPGA实现,可以借鉴到大部分DAC或者ADC的SPI驱动控制,是上篇基于FPGA的AD5753(DAC数模转换器)的控制 I(SPI驱动)文章的续篇。主要包括DAC(AD5753) FPGA的工程实现,仿真以及上板调试,实现了对DAC芯片的寄存器读写控制。

二、基于FPGA的AD5753控制驱动实现
1. 顶层模块

顶层模块代码如下所示,主要包括

(1)AD5753驱动模块:AD5753_driver模块负责与AD5753 DAC通信,发送数据和触发信号。

(2)数据控制模块:AD5753_DATA_Ctrl模块生成要发送给DAC的数据,并控制数据发送。

(3)逻辑分析仪(ILA):ila实例用于监视和记录信号,以便于调试。

(4)虚拟输入输出(VIO):vio_0实例用于虚拟探针,可以观察或驱动信号。

clk_wiz_0实例用于生成50MHz的时钟信号clk_50m,并且locked信号表示时钟锁定状态。dac_reset_n输出端口被设置为locked,用于DAC的复位。

bash 复制代码
module test_ADC5753(

    input           sys_clk,
    input           fault_n,
    output           sdi, // to ac5753
    output          sclk,
    input           sdo,  // from ad5753
    output          dac_reset_n,
    output          sync_n,   
    output          ldac_n,
    output          led

    );
 
 wire [32:0]   send_data;
 wire          send_trig;
 wire [32:0]   spi_rx_dat;
 wire          spi_rx_int;
 wire          send_done ;
 //wire          spi_clk_i2;
 wire          spi_clk_i;
 wire          locked;
 wire          clk_50m;
 wire          dat_gen_en;
 wire [15:0]   data;
 
   clk_wiz_0 clk_wiz_inst
   (
    .clk_out2(clk_50m),     
    .clk_out1( ),     
    .locked  (locked  ),      
    .clk_in1 (sys_clk    )     //50M
    
    );  
   assign  dac_reset_n = locked;
    
  assign  led = 1'b0; 
   reg[4:0] cnt;   
 

 reg  clk_1M;
   always@(posedge clk_50m or negedge locked) 
   begin
        if(!locked) begin
           cnt = 5'b0;
           clk_1M = 1'b0;
        end
        else begin
            if(cnt == 5'd24 ) begin
                clk_1M = !clk_1M;
                cnt = 5'd0;
            end
            else begin
                cnt = cnt +5'b1;
            end
         end

   end
   




      
 AD5753_driver AD5753_driver (
    .clk(clk_50m), 
    .dac_reset_n(locked), 
    .fault_n(fault_n), 
    .send_data(send_data), 
    .send_trig(send_trig), 
    .send_done(send_done), 
    .spi_clk_i(clk_1M),
    .spi_rx_dat(spi_rx_dat), 
    .spi_rx_int(spi_rx_int), 
    .ldac_n(ldac_n), 
    .spi_clk(sclk), 
    .sync_n(sync_n), 
    .spi_mosi(sdi), 
    .spi_miso(sdo)
    );   

AD5753_DATA_Ctrl AD5753_DATA_Ctrl (
    .clk(clk_50m), 
    .spi_clk_i(clk_1M), 
    .locked(locked), 
    .data(data),
    .send_done(send_done), 
    .send_trig(send_trig), 
    .send_data(send_data), 
    .dat_gen_en(1'b1), 
    .spi_rx_int(spi_rx_int), 
    .spi_rx_dat(spi_rx_dat)
    );


ila ila_inst (
	.clk(clk_50m), // input wire clk


	.probe0(send_data), // input wire [23:0]  probe0  
	.probe1(send_trig), // input wire [0:0]  probe1 
	.probe2(spi_rx_dat), // input wire [23:0]  probe2 
	.probe3(spi_rx_int), // input wire [0:0]  probe3 
	.probe4(send_done), // input wire [0:0]  probe4 
	.probe5(locked), // input wire [0:0]  probe5 
	.probe6(dac_reset_n), // input wire [0:0]  probe6 
	.probe7(fault_n), // input wire [0:0]  probe7 
	.probe8(sdi), // input wire [0:0]  probe8 
	.probe9(sclk), // input wire [0:0]  probe9 
	.probe10(sync_n), // input wire [0:0]  probe10 
	.probe11(ldac_n), // input wire [0:0]  probe11 
	.probe12(sdo) // input wire [0:0]  probe12
);
 
vio_0 vio_0 (
  .clk(clk_50m),                // input wire clk
  .probe_in0( ),    // input wire [0 : 0] probe_in0
  .probe_out0(),  // output wire [0 : 0] probe_out0
  .probe_out1(data)  // output wire [0 : 0] probe_out0 
);
    
endmodule
2. 数据控制模块(AD5753_DATA_Ctrl模块)

AD5753_DATA_Ctrl 模块,设计用于控制与AD5753数字到模拟转换器(DAC)的数据传输。通过定义一系列的输入输出端口、内部状态、计数器和标志位来实现对数据发送过程的精确控制。

模块内部实现了一个状态机,通过不同的状态(如 DATA_IDLE、DATA_FAULT、DATA_Key 等)来管理数据传输流程。状态机根据当前状态和输入信号(例如 dat_gen_en、send_done)来决定下一个状态,并通过 spi_clk_i 来同步数据的发送。

模块还包括了CRC校验逻辑,通过 gen_crc8 子模块生成数据的CRC校验码,确保数据传输的可靠性。在不同的状态下,模块会设置相应的发送触发信号 send_trig 和发送数据 send_data,以及实现特定操作的500us延时,从而完成对AD5753 DAC的命令设置和数据更新。

bash 复制代码
module AD5753_DATA_Ctrl(
    input            clk,        //50M
    input            spi_clk_i,
    input            locked,
    input            send_done,
    output   reg        send_trig,
    output [31:0]    send_data,
    input            dat_gen_en,
    input           spi_rx_int,
    input [15:0]    data,
    input  [31:0]   spi_rx_dat
    );
 
 // device adress   
    localparam[2:0] DEVICE_ADRESS=3'b011;   
 // register
    localparam[4:0] NOP=5'h00;
    localparam[4:0] Key=5'h00;   
    
    
    
 //   STATE
    localparam[4:0] DATA_IDLE  =    5'd0;
    localparam[4:0] DATA_FAULT  =   5'd1;     
    localparam[4:0] DATA_Key   =    5'd2;  
    localparam[4:0] DATA_Key_wait = 5'd3;       
    localparam[4:0] DATA_CLEAR =    5'd4; 
    localparam[4:0] DATA_REQ =      5'd5;     
    localparam[4:0] DATA_DC_SET =   5'd6;       
    localparam[4:0] DATA_DC_SET_WAIT =  5'd7; 
    localparam[4:0] DATA_DC_MOD =       5'd8;       
    localparam[4:0] DATA_DC_MOD_WAIT =  5'd9;     
    localparam[4:0] DATA_DAC_SET =      5'd10;                  
    localparam[4:0] DATA_DAC_SET_WAIT = 5'd11; 
    localparam[4:0] DATA_DAC_MOD =      5'd12;   
    localparam[4:0] DATA_DAC_MOD_WAIT = 5'd13;    
    localparam[4:0] DATA_LDAC =         5'd14;      
    localparam[4:0] DATA_OUTPUT =       5'd15;
    localparam[4:0] DATA_REQ_DAC =      5'd16;   
    localparam[4:0] DATA_REQ_DAC_WAIT = 5'd17;       
    localparam[4:0] DAC_read =          5'd18;
    localparam[4:0] DAC_nop =           5'd19;               
 
 
 
    reg [13:0]       cnt_500us;
    reg              FLAG;
    
    reg [4:0]        state;
    reg [4:0]        next_state;
    reg             send_trig_tem;
    reg [23:0]      send_data_tem;
    reg             spi_clk_dly;
    wire            spi_clk_pos;
    wire            spi_clk_neg;   
    reg             send_done_dly;
    wire            send_done_pos;
    reg             FLAG2;
    
     wire[7:0]      nextCRC8_D24;
     wire           crc_out_en;
    reg [15:0]       data_reg;
    reg [15:0]       data_reg2;  
   
    
      always @ ( posedge spi_clk_i ) begin
         if( ~locked ) begin
            data_reg <= 16'b0;
            data_reg2 <= 16'b0;
          end
         else begin
            data_reg <= data;
            data_reg2 <= data_reg; 
            
            end
      
      end  
    
    
    
    always @ ( posedge spi_clk_i ) begin
      if( ~locked )
        state <= DATA_IDLE;
      else 
        state <= next_state; 
     end

    always @ (*) begin
      if( ~locked )	
         next_state = DATA_IDLE;
       else 
          case ( state )
            DATA_IDLE:       
                  if( dat_gen_en )
                    next_state = DATA_FAULT;
                  else 
                    next_state = DATA_IDLE; 
           DATA_FAULT:          
                  if( send_done )  
                     next_state = DATA_Key;
                  else 
                    next_state = DATA_FAULT;                            
            DATA_Key:
                  if( send_done )  
                     next_state = DATA_Key_wait;
                  else 
                     next_state = DATA_Key;                          
           DATA_Key_wait:
                  if( FLAG ) 
                     next_state = DATA_CLEAR;
                  else 
                     next_state = DATA_Key_wait;  
                     
           DATA_CLEAR:
                  if( send_done ) 
                     next_state = DATA_REQ;
                  else 
                     next_state = DATA_CLEAR; 
            DATA_REQ:
                  if( send_done ) 
                     next_state = DATA_DC_SET;
                  else 
                     next_state = DATA_REQ;                     
            DATA_DC_SET:
                  if( send_done ) 
                     next_state = DATA_DC_SET_WAIT;
                  else 
                     next_state = DATA_DC_SET;                       
            DATA_DC_SET_WAIT:
                  if( FLAG ) 
                     next_state = DATA_DC_MOD;
                  else 
                     next_state = DATA_DC_SET_WAIT; 
            DATA_DC_MOD:
                  if( send_done ) 
                     next_state = DATA_DC_MOD_WAIT;
                  else 
                     next_state = DATA_DC_MOD;                     
            DATA_DC_MOD_WAIT:
                  if( FLAG ) 
                     next_state = DATA_DAC_SET;
                  else 
                     next_state = DATA_DC_MOD_WAIT;                    
            DATA_DAC_SET:
                  if( send_done ) 
                     next_state = DATA_DAC_SET_WAIT;
                  else 
                     next_state = DATA_DAC_SET;                       
            DATA_DAC_SET_WAIT:
                  if( FLAG ) 
                     next_state = DATA_LDAC ;
                  else 
                     next_state = DATA_DAC_SET_WAIT;     
//             DATA_DAC_MOD:
//                  if( send_done ) 
//                     next_state = DATA_DAC_MOD_WAIT ;
//                  else 
//                     next_state = DATA_DAC_MOD;                     
//             DATA_DAC_MOD_WAIT:
//                  if( FLAG ) 
//                     next_state = DATA_LDAC ;
//                  else 
//                     next_state = DATA_DAC_MOD_WAIT;                      
             DATA_LDAC:
                  if( send_done ) 
                     next_state =  DATA_OUTPUT ;
                  else 
                     next_state = DATA_LDAC;   
             DATA_OUTPUT:
                  if( send_done ) 
                     next_state =  DATA_REQ_DAC ;
                  else 
                     next_state = DATA_OUTPUT;                      
             DATA_REQ_DAC:
                  if( send_done) 
                     next_state =  DATA_REQ_DAC_WAIT ;
                  else 
                     next_state = DATA_REQ_DAC;  
              DATA_REQ_DAC_WAIT:       
                  if( FLAG ) 
                     next_state =  DATA_LDAC ;
                  else 
                     next_state = DATA_REQ_DAC_WAIT;                                                                                                     
             DAC_read:
                if( send_done ) 
                     next_state = DAC_nop;
                  else 
                     next_state = DAC_read;                     
             DAC_nop:
                if( send_done ) 
                     next_state = DATA_REQ_DAC;
                  else 
                     next_state = DAC_nop;                       
                     
                                    
          default :
                    next_state = DATA_IDLE; 
          endcase
    end


 always @ ( posedge clk ) begin
    if(~locked) begin
        spi_clk_dly <= 1'b0;
        send_done_dly <= 1'b0;
     end
     else begin
        spi_clk_dly <=spi_clk_i;
        send_done_dly <= send_done;      
     end
 end

assign spi_clk_neg = spi_clk_dly && ~spi_clk_i;
assign spi_clk_pos = (~spi_clk_dly )&& spi_clk_i;
assign send_done_pos =( ~send_done_dly) && send_done;
reg[7:0] nextCRC8_D24_tem;
//assign send_trig =crc_out_en;
assign send_data ={send_data_tem,nextCRC8_D24_tem};

always@( posedge clk) begin
 if( ~locked ) begin
    send_trig <= 1'b0;
    nextCRC8_D24_tem <=8'b0;
 end
    if(crc_out_en) begin
    send_trig <= 1'b1;
    nextCRC8_D24_tem <= nextCRC8_D24;
    
    end
    else if(send_done)
     send_trig <= 1'b0;   
    else
    send_trig <=send_trig;

end



 always @ ( posedge clk ) begin
  if( ~locked ) begin
    send_trig_tem <= 1'b0;
    send_data_tem <= 24'b0;
  end
  else begin
    if( state == DATA_IDLE && ~send_done ) begin
        send_trig_tem <= 1'b0;
        send_data_tem <= 24'b0; 
     end
     else if( state == DATA_FAULT && ~send_done  ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h10,16'h005c};    //   
    end       
     else if( state == DATA_Key  && ~send_done) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h08,16'hFCBA};         
    end
    else if( state == DATA_CLEAR && ~send_done  ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h14,16'h2000};    //     
    end
     else if( state == DATA_REQ && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h09,16'h0644};        
    end
      else if( state == DATA_DC_SET && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h0C,16'h010E};        
    end   
      else if( state == DATA_DC_MOD && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h0B,16'h0020};        
    end    
       else if( state == DATA_DAC_SET && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01a8};        
    end   
      else if( state == DATA_DAC_MOD && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h01,16'h0000};        
    end    
    
       else if( state == DATA_LDAC && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h07,16'h1DAC};        
    end   
      else if( state == DATA_OUTPUT && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h06,16'h01E8};       //D6 = 1
    end    
      else if( state == DATA_REQ_DAC && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h01,data_reg2};        
    end            
    
      else if( state == DAC_read && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,5'h13,16'h02};     //读output寄存器  
    end
         else if( state == DAC_nop && ~send_done ) begin
        send_trig_tem <= 1'b1;
        send_data_tem <= {DEVICE_ADRESS,NOP,16'h00};        
    end   
     else   begin
      send_trig_tem <= 1'b0;   

    end
    end

 end
 
    // 延时500us
    always@( posedge spi_clk_i or negedge locked)
    begin
      if( ~locked)  begin
            cnt_500us <= 14'b0;
            FLAG <= 1'b0;
        end
       else begin
         if(state == DATA_Key_wait ) begin
             if(cnt_500us == 14'd1010 ) begin
                cnt_500us <= 1'b1;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end  
         else if(state == DATA_DC_SET_WAIT ) begin
             if(cnt_500us == 14'd1010 ) begin
                cnt_500us <= 1'b0;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end        
           else if(state == DATA_DC_MOD_WAIT ) begin
             if(cnt_500us == 14'd1010 ) begin
                cnt_500us <= 1'b0;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end           
            else if(state == DATA_REQ_DAC_WAIT ) begin
             if(cnt_500us == 14'd16 ) begin
                cnt_500us <= 1'b0;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end   
  
           else if(state == DATA_DAC_SET_WAIT ) begin
             if(cnt_500us == 14'd1010 ) begin
                cnt_500us <= 1'b0;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end          
          else if(state == DATA_DAC_MOD_WAIT ) begin
             if(cnt_500us == 14'd16 ) begin
                cnt_500us <= 1'b0;
                FLAG  <= 1'b1;
             end
             else begin
                cnt_500us <= cnt_500us +14'b1;
                FLAG <= 1'b0;
             end
         end         
         
         
         
         
         else begin
                   FLAG  <= 1'b0; 
                              
         end
                             
       end  

    end
    

    
gen_crc8 gen_crc8 (
    .clk(clk), 
    .rst_n(locked), 
    .crc_in_en(send_trig_tem), 
    .Data(send_data_tem), 
    .nextCRC8_D24(nextCRC8_D24), 
    .crc_out_en(crc_out_en)
    );
    
    
    
endmodule
3、gen_crc8校验模块

gen_crc8 的模块用于生成8位循环冗余校验(CRC)码,模块包含时钟输入 clk,复位信号 rst_n,CRC输入使能 crc_in_en,待处理数据 Data(24位宽),以及CRC校验码输出 nextCRC8_D24 和输出使能 crc_out_en。

模块使用一个寄存器 crc_in_en_d0 来检测 crc_in_en 的边沿,即从0到1的跳变,这通常表示一个新数据块的到来。

在检测到 crc_in_en 的上升沿后,模块根据输入数据 Data 和当前的CRC寄存器值 nextCRC8_D24 来计算新的CRC校验码。CRC的计算使用了一系列异或(XOR)操作,这些操作定义了CRC的多项式。

bash 复制代码
`timescale 1ns / 1ps
 


module gen_crc8(

input clk,
input rst_n,

input crc_in_en,
input [23:0] Data,
output reg [7:0] nextCRC8_D24,
output reg crc_out_en

);

reg crc_in_en_d0=0;

always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        crc_in_en_d0 <= 1'b0;
    else
        crc_in_en_d0 <= crc_in_en;
end      
    
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        nextCRC8_D24 <= 'd0;
    else if(!crc_in_en_d0 && crc_in_en)begin    
        nextCRC8_D24[0] <= Data[23] ^ Data[21] ^ Data[19] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[8] ^ Data[7] ^ Data[6] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5] ^ nextCRC8_D24[7];
        nextCRC8_D24[1] <= Data[23] ^ Data[22] ^ Data[21] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[16] ^ Data[15] ^ Data[14] ^ Data[13] ^ Data[12] ^ Data[9] ^ Data[6] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[5] ^ nextCRC8_D24[6] ^ nextCRC8_D24[7];
        nextCRC8_D24[2] <= Data[22] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[6] ^ Data[2] ^ Data[1] ^ Data[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[6];
        nextCRC8_D24[3] <= Data[23] ^ Data[18] ^ Data[16] ^ Data[14] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[7] ^ Data[3] ^ Data[2] ^ Data[1] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[7];
        nextCRC8_D24[4] <= Data[19] ^ Data[17] ^ Data[15] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[8] ^ Data[4] ^ Data[3] ^ Data[2] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3];
        nextCRC8_D24[5] <= Data[20] ^ Data[18] ^ Data[16] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[9] ^ Data[5] ^ Data[4] ^ Data[3] ^ nextCRC8_D24[0] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4];
        nextCRC8_D24[6] <= Data[21] ^ Data[19] ^ Data[17] ^ Data[16] ^ Data[14] ^ Data[12] ^ Data[10] ^ Data[6] ^ Data[5] ^ Data[4] ^ nextCRC8_D24[0] ^ nextCRC8_D24[1] ^ nextCRC8_D24[3] ^ nextCRC8_D24[5];
        nextCRC8_D24[7] <= Data[22] ^ Data[20] ^ Data[18] ^ Data[17] ^ Data[15] ^ Data[13] ^ Data[11] ^ Data[7] ^ Data[6] ^ Data[5] ^ nextCRC8_D24[1] ^ nextCRC8_D24[2] ^ nextCRC8_D24[4] ^ nextCRC8_D24[6];
    end
end

always @(posedge clk)begin
    crc_out_en <= !crc_in_en_d0 && crc_in_en;
end  

endmodule

这个模块是数据传输中确保数据完整性的一个重要组件,通过CRC校验可以检测数据在传输过程中是否出现错误。如果CRC校验失败,系统可以采取相应的措施来纠正或重新发送数据。

三、结尾

本文主要描述如何使用FPGA驱动DAC芯片AD5753,已经在开发板上验证成功。使得配置完成之后,可以正常的控制dac的输出。

相关推荐
HIZYUAN4 分钟前
AGM FPGA如何配置上拉或者下拉电阻
fpga开发
∑狸猫不是猫7 分钟前
(13)CT137A- 简易音乐盒设计
fpga开发
ThreeYear_s6 小时前
基于FPGA 的4位密码锁 矩阵键盘 数码管显示 报警仿真
fpga开发·矩阵·计算机外设
星河梦瑾8 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
长潇若雪10 小时前
《类和对象:基础原理全解析(上篇)》
开发语言·c++·经验分享·类和对象
志-AOX12 小时前
C语言入门指南:从零开始的编程之路
经验分享
WANGWUSAN6612 小时前
Python高频写法总结!
java·linux·开发语言·数据库·经验分享·python·编程
Anin蓝天(北京太速科技-陈)12 小时前
252-8路SATAII 6U VPX高速存储模块
fpga开发
赵谨言14 小时前
基于python+django的外卖点餐系统
经验分享·python·毕业设计
如何学会学习?14 小时前
2. FPGA基础了解--全局网络
fpga开发