verilog bug记录——正点原子spi_drive存在的问题

verilog bug记录——正点原子spi_drive存在的问题

  • 问题概述
  • 代码修改—spi_drive.v
  • 遗留问题

问题概述

因为项目需求,需要利用spi对flash进行擦除和写入操作,所使用的开发板是正电原子的达芬奇开发板,我事先往Flash里面存了两个bit,分别对应LED0和LED1的点亮,但是我使用了正点原子的spi_dirve进行全擦除操作之后发现了很奇怪的现象:
1、没擦完,因为明显的看到LED1的灯亮了,说明擦除操作或许有效,但是可能只是破坏了第一个bit,第二个bit没有做修改;
2、时序不对,通过ila抓波形可以发现,全擦除之后的轮询寄存器,竟然只查了一次就自动跳出轮询的状态了,但是全擦除怎么说也不至于这么快吧。
我的flash_contol部分的指令操作顺序如下:

always @(*)begincase(cmd_cnt)0 : spi_cmd = WEL_CMD		;			//写使能1 : spi_cmd = R_STA_REG_CMD	;			//轮询2 : spi_cmd = WEL_CMD		;			//写使能3 : spi_cmd = R_STA_REG_CMD	;			//轮询4 : spi_cmd = BE_CMD		;			//全擦除5 : spi_cmd = R_STA_REG_CMD		;	    //轮询6 : spi_cmd = WEL_CMD	;			//轮询7 : spi_cmd = R_STA_REG_CMD		;			//读数据default:;endcase
end

我只执行了0~5步,另外原代码中指令运行是一上电就会自动运行,但是我改成了只有我按键按下的时候才会执行。
出问题的时序如下:
在这里插入图片描述
从图中黄线部分可以看到,CS信号在spi_clk信号立即拉高,但是我们看数据手册可以发现
在这里插入图片描述
在这里插入图片描述
在spi_clk停止输出的时候,CS信号至少要间隔4ns才拉高,虽然说实际上的时钟信号并不是理想的马上拉高,而是有一段过渡时间,但是这个过渡时间并不好把控,所以稳妥起见还是应该至少打一拍,因为时钟频率是100MHz,那么延迟未0.01us,即10ns,是满足时序要求的;

另外还有问题,看下图:
在这里插入图片描述
在这里插入图片描述
红圈标注的位置,从图中可以看出,我第一次发送写使能命令后进行轮询,会发现状态寄存器的第6位WEL并没有拉高,而是第二次发送写使能命令的时候才拉高。

根据数据手册上的要求,发送完写使能命令后,WEL位是应该拉高为高电平的
在这里插入图片描述
最后一个问题如下图所示:
在这里插入图片描述
该时序图是我我发送完全擦除指令随即发送轮询寄存器指令(读状态寄存器指令),会发现蓝线部分表示WEL位,红线部分表示WIP位,此时WIP位应该是高电平,轮询寄存器应该继续轮询才对,直到WIP为0表示擦除操作已完成,但是原代码中却是直接拉高,这就不合理。

代码修改—spi_drive.v

//****************************************Copyright (c)***********************************//
//原子哥在线教学平台:www.yuanzige.com
//技术支持:www.openedv.com
//淘宝店铺:http://openedv.taobao.com
//关注微信公众平台微信号:"正点原子",免费获取ZYNQ & FPGA & STM32 & LINUX资料。
//版权所有,盗版必究。
//Copyright(C) 正点原子 2018-2028
//All rights reserved
//----------------------------------------------------------------------------------------
// File name:           spi_drive
// Last modified Date:  2020/12/01 10:39:20
// Last Version:        V1.0
// Descriptions:        FLASH读写实验
//                      
//----------------------------------------------------------------------------------------
// Created by:          正点原子
// Created date:        2020/12/01 10:39:20
// Version:             V1.0
// Descriptions:        The original version
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
module spi_drive(input             clk_100m      ,input             sys_rst_n     ,//user interfaceinput             spi_start     ,//spi开启使能。input [7:0 ]      spi_cmd       ,//FLAH操作指令input [23:0]      spi_addr      ,//FLASH地址input [7:0 ]      spi_data      ,//FLASH写入的数据input [3:0 ]      cmd_cnt       ,//指令计数器output            idel_flag_p   ,//空闲状态标志的上升沿 output reg        w_data_req    ,//FLASH写数据请求 output reg        error_flag     ,//读出的数据错误标志//spi interfaceoutput reg        spi_cs        ,//SPI从机的片选信号,低电平有效。output reg        spi_clk       ,//主从机之间的数据同步时钟。output reg        spi_mosi      ,//数据引脚,主机输出,从机输入。input             spi_miso       //数据引脚,主机输入,从机输出。);//define parameter
//状态机
parameter IDLE          = 4'd0;		//空闲状态
parameter WR_EN         = 4'd1;		//写使能状态
parameter S_ERA         = 4'd2;		//扇区擦除状态
parameter B_ERA         = 4'd3;		//全局擦除
parameter READ          = 4'd4;		//读状态
parameter WRITE         = 4'd5;		//写状态
parameter R_STA_REG     = 4'd6;		//读状态寄存器状态
//指令集
parameter WEL_CMD       = 8'h06;	//写使能指令
parameter SE_CMD        = 8'hd8;	//扇区擦除指令
parameter BE_CMD        = 8'hc7;	//全擦除指令
parameter READ_CMD      = 8'h03;	//读指令
parameter WRITE_CMD     = 8'h02;	//写指令
parameter R_STA_REG_CMD = 8'h05;	//读状态寄存器指令//wire define
wire      idel_flag;//reg define
reg		      		idel_flag_d0   ;		
reg		      		idel_flag_d1   ;	
reg		      		spi_clk_d0     ;
reg		[3:0] 		current_state  ;		
reg		[3:0] 		next_state     ;		
reg		[7:0 ]		data_reg	   ;		//数据寄存
reg		[7:0 ]		cmd_reg        ;		//指令寄存
reg		[23:0]		addr_reg       ;		//地址寄存器
reg		[31:0]		bit_cnt        ;		//bit计数器
reg		      		clk_cnt        ;		//时钟计数器
reg		      		delay_cnt      ;		//延迟计数器
reg		[15:0]		delay_state_cnt ;		//状态延迟计数器
reg		[7:0 ]		rd_data_reg    ;		//读数据寄存器	
reg		      		stdone         ;		//状态完成标志
reg		[7:0 ]		data_check     ;		//数据校验reg     [2047:0]    r_w_data       ;
reg                 r_w_data_req   ;
reg     [2047:0]    r_r_data       ;//FLASH读出的数据reg                 r_wip_flag          ;
reg     [7 :0  ]    r_rd_status_reg;
reg                 r_wel          ;
//*****************************************************
//**                    main code
//*****************************************************assign idel_flag = (current_state == IDLE) ? 1:0;		//空闲状态标志
assign idel_flag_p = idel_flag_d0 && (~idel_flag_d1);	//空闲状态标志的上升沿//idel_flga打拍取沿
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)beginidel_flag_d0 <= 1'b1;idel_flag_d1 <= 1'b1;endelse beginidel_flag_d0 <= idel_flag;idel_flag_d1 <= idel_flag_d0;end
end//写数据请求信号
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)w_data_req <= 1'b0;else if(current_state == WRITE && (bit_cnt+2)%8 == 0 && bit_cnt >= 30 && clk_cnt == 0)w_data_req <= 1'b1;elsew_data_req <= 1'b0;
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)r_w_data_req <= 'd0;elser_w_data_req <= w_data_req;
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)r_w_data <= 'd0;else if(r_w_data_req)r_w_data <= {r_w_data[2039:0],spi_data};
end//读出的数据移位寄存
always @(posedge clk_100m or negedge sys_rst_n )begin	if(!sys_rst_n)rd_data_reg <= 8'd0;else if(current_state == READ && bit_cnt >= 32 && bit_cnt <= 2080 && clk_cnt == 0)									rd_data_reg <= {rd_data_reg[6:0],spi_miso};elserd_data_reg <= rd_data_reg;
end// //检查读出的数据是否正确
// always @(posedge clk_100m or negedge sys_rst_n )begin
// 	if(!sys_rst_n)
// 		data_check <= 8'd0;
// 	else if(current_state == READ && bit_cnt%8 == 0 && bit_cnt >= 40 && clk_cnt == 1)
// 		data_check <= data_check + 1'd1;
// 	else
// 		data_check <= data_check;
// end//读出的数据
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)r_r_data <= 2048'd0;else if(current_state == READ && bit_cnt%8 == 0 && bit_cnt >38 && clk_cnt==1)r_r_data <= {r_r_data[2039:0],rd_data_reg};elser_r_data <= r_r_data;
end//读出的数据错误标志
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)error_flag<=1'd0;else if(current_state == READ && cmd_cnt == 6 && idel_flag_p)beginif(r_r_data!=r_w_data)error_flag <= 1'd1;elseerror_flag <= error_flag;endelseerror_flag <= error_flag;
end//数据寄存器	
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)data_reg <= 8'd0;else if((bit_cnt + 1'd1)%8 == 0 && bit_cnt > 30 && clk_cnt == 1)data_reg <= spi_data;else if(current_state == WRITE && clk_cnt == 1 && bit_cnt >= 32)data_reg <= {data_reg[6:0],data_reg[7]};elsedata_reg <= data_reg;
end//指令寄存器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)cmd_reg <= 8'd0;else if(spi_cs == 0 && delay_cnt == 0)cmd_reg <= spi_cmd;else if((clk_cnt == 1) && (current_state == WR_EN || current_state == S_ERA|| current_state == B_ERA || current_state == READ || current_state == WRITE || current_state == R_STA_REG) && (bit_cnt < 8))cmd_reg <= {cmd_reg[6:0],1'b1};elsecmd_reg <= cmd_reg;
end//地址寄存器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)addr_reg <= 8'd0;else if(spi_cs == 0 && delay_cnt == 0)addr_reg <= spi_addr;else if(clk_cnt==1 && (current_state == READ || current_state == WRITE) && bit_cnt >= 8 && bit_cnt < 32)addr_reg <= {addr_reg[22:0],addr_reg[23]};elseaddr_reg <= addr_reg;
end//时钟计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)clk_cnt <= 1'd0;else if(delay_cnt==1)clk_cnt <= clk_cnt+1'd1;else clk_cnt <= 1'd0;
end	//延迟标志
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)delay_cnt <= 1'd0;else if(spi_cs == 0)beginif(delay_cnt < 1)delay_cnt <= delay_cnt + 1'd1;elsedelay_cnt <= delay_cnt;endelsedelay_cnt <= 1'd0;
end//状态延迟计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)delay_state_cnt <= 1'd0;else if(spi_start)delay_state_cnt <= 1'd0;else if(spi_cs)beginif(delay_state_cnt < 20)delay_state_cnt <= delay_state_cnt + 1'd1;elsedelay_state_cnt <= delay_state_cnt;endelsedelay_state_cnt <= 1'd0;
end//bit计数器
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)bit_cnt <= 16'd0;else if(delay_cnt == 1)beginif(clk_cnt == 1'b1)bit_cnt <= bit_cnt+1'd1;elsebit_cnt <= bit_cnt;endelsebit_cnt <= 16'd0;
end// RDSR状态寄存器寄存
always @(posedge clk_100m or negedge sys_rst_n )begin	if(!sys_rst_n)r_rd_status_reg <= 8'd0;else if(current_state == R_STA_REG && bit_cnt >= 8 && clk_cnt == 1)r_rd_status_reg <= {r_rd_status_reg[6:0],spi_miso};elser_rd_status_reg <= r_rd_status_reg;
end//三段式状态机
always @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n)current_state <= IDLE;elsecurrent_state <= next_state;
endalways @(*)begincase(current_state)IDLE: beginif(spi_start && spi_cmd == WEL_CMD)next_state = WR_EN;else if(spi_start && spi_cmd == BE_CMD)next_state = B_ERA;else if(spi_start && spi_cmd == SE_CMD)next_state = S_ERA;else if(spi_start && spi_cmd == READ_CMD)next_state = READ;else if(spi_start && spi_cmd == WRITE_CMD)next_state = WRITE;else if(spi_start && spi_cmd == R_STA_REG_CMD)next_state = R_STA_REG;elsenext_state = IDLE;endWR_EN: beginif(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = WR_EN;endS_ERA: beginif(stdone)next_state = IDLE;elsenext_state = S_ERA;endB_ERA: begin		if(stdone)next_state = IDLE;elsenext_state = B_ERA;endREAD: begin 		if(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = READ;endWRITE: begin		if(stdone && bit_cnt >= 8)next_state = IDLE;elsenext_state = WRITE;endR_STA_REG: begin		if(stdone)next_state = IDLE;elsenext_state = R_STA_REG;enddefault: next_state = IDLE;			endcase				
endalways @(posedge clk_100m or negedge sys_rst_n )beginif(!sys_rst_n) beginspi_cs <= 1'b1;spi_clk <= 1'b0;spi_clk_d0 <= 1'b0;spi_mosi <= 1'b0;	stdone <= 1'b0;		endelse begincase(current_state)IDLE: beginstdone <= 1'b0;spi_cs <= 1'b1;spi_clk <= 1'b0;spi_mosi <= 1'b0;	r_wip_flag <= 1'b0;	spi_clk_d0 <= 'd0;endWR_EN: beginstdone <= 1'b0;if(delay_state_cnt == 10)  spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8) begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt == 8 && clk_cnt == 0)beginstdone <= 1'b1;spi_clk <= 1'b0;						spi_mosi <= 1'b0;						endelse if(bit_cnt == 8 && clk_cnt == 1)beginspi_cs <= 1'b1;						endendB_ERA: beginstdone <= 1'b0;if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8) begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt == 8 && clk_cnt == 0)beginstdone <= 1'b1;				    spi_clk <= 1'b0;spi_mosi <= 1'b0;	endelse if(bit_cnt == 8 && clk_cnt == 1)beginspi_cs <= 1'b1;						endendS_ERA: beginstdone <= 1'b0;				 if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8) begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt >= 8&& bit_cnt < 32 && spi_cs == 0)beginspi_cs <= 1'b0;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= addr_reg[23];endelse if(bit_cnt == 32 && clk_cnt == 0) beginspi_cs <= 1'b1;spi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;endendREAD: beginstdone <= 1'b0;if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8) begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt >= 8 && bit_cnt < 32 && spi_cs == 0)begin					    spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= addr_reg[23];endelse if(bit_cnt >= 32 && bit_cnt < 2080)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= 1'b0;						endelse if(bit_cnt == 2080 && clk_cnt == 0) begin						spi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;						endelse if(bit_cnt == 2080 && clk_cnt == 1) beginspi_cs<=1'b1;endendWRITE: beginstdone<=1'b0;if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8) begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt >= 8 && bit_cnt < 32 && spi_cs == 0)begin					   spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= addr_reg[23];endelse if(bit_cnt >= 32 && bit_cnt < 2080)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= data_reg[7];endelse if(bit_cnt == 2080 && clk_cnt == 0) beginspi_clk <= 1'b0;spi_mosi <= 1'b0;stdone <= 1'b1;endelse if(bit_cnt == 2080 && clk_cnt == 1) beginspi_cs <= 1'b1;endendR_STA_REG:begin				              stdone <= 1'b0;if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt == 8)begin					   				    spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= 1'b0;						end           else if(~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 0)beginr_wip_flag <= 1'b1;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;endelse if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)beginspi_clk <= 1'b0;spi_cs <= 1'b1;stdone <= 1'b1;endelse if(~spi_cs && delay_cnt == 1)beginspi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;end	   			         	 end default: beginstdone <= 1'b0;spi_cs <= 1'b1;spi_clk <= 1'b0;spi_clk_d0 <= 1'b0;spi_mosi <= 1'b0;				        endendcaseend
endila_spi u_ila_spi (.clk(clk_100m), // input wire clk.probe0(spi_start), // input wire [0:0]  probe0  .probe1(spi_cmd  ), // input wire [7:0]  probe1 .probe2(spi_addr ), // input wire [23:0]  probe2 .probe3(spi_data ), // input wire [7:0]  probe3 .probe4(cmd_cnt  ), // input wire [3:0]  probe4 .probe5(idel_flag_p), // input wire [0:0]  probe5 .probe6(w_data_req ), // input wire [0:0]  probe6 .probe7(error_flag ), // input wire [0:0]  probe7 .probe8(spi_cs  ), // input wire [0:0]  probe8 .probe9(spi_clk ), // input wire [0:0]  probe9 .probe10(spi_mosi), // input wire [0:0]  probe10 .probe11(spi_miso), // input wire [0:0]  probe11.probe12(idel_flag), // input wire [0:0]  probe12 .probe13(idel_flag_d0), // input wire [0:0]  probe13 .probe14(idel_flag_d1), // input wire [0:0]  probe14 .probe15(spi_clk_d0  ), // input wire [0:0]  probe15 .probe16(current_state  ), // input wire [3:0]  probe16 .probe17(next_state     ), // input wire [3:0]  probe17 .probe18(data_reg	   ), // input wire [7:0]  probe18 .probe19(cmd_reg        ), // input wire [7:0]  probe19 .probe20(addr_reg       ), // input wire [23:0]  probe20 .probe21(bit_cnt        ), // input wire [31:0]  probe21 .probe22(clk_cnt        ), // input wire [0:0]  probe22 .probe23(delay_cnt      ), // input wire [0:0]  probe23 .probe24(delay_state_cnt), // input wire [15:0]  probe24 .probe25(rd_data_reg    ), // input wire [7:0]  probe25 .probe26(stdone         ), // input wire [0:0]  probe26 .probe27(data_check     ), // input wire [7:0]  probe27 .probe28(r_w_data_req), // input wire [0:0]  probe28.probe29(r_wip_flag)
);endmodule

修改后的代码核心在于判断轮询寄存器那里,以及spi_clk_d0每次在idle状态的时候都要清零,清零这个步骤是在为了确保每次新的指令来时,时钟状态都能从0开始(由SPI的驱动模式决定);

R_STA_REG:begin				              stdone <= 1'b0;if(delay_state_cnt == 10)                spi_cs <= 1'b0;else if(delay_cnt == 1 && bit_cnt < 8)begin						spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= cmd_reg[7];endelse if(bit_cnt == 8)begin					   				    spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;spi_mosi <= 1'b0;						end           else if(~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 0)beginr_wip_flag <= 1'b1;spi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;endelse if(r_wip_flag && ~spi_miso && bit_cnt % 8==0 && bit_cnt > 8 && clk_cnt == 1)beginspi_clk <= 1'b0;spi_cs <= 1'b1;stdone <= 1'b1;endelse if(~spi_cs && delay_cnt == 1)beginspi_clk_d0 <= ~spi_clk_d0;spi_clk <= spi_clk_d0;end	   			         	 end 

主要修改的就是这里,思路是:
我会首先判断WIP位是否为0,如果为0,则把r_wip_flag标志位拉高,等到下一次轮询状态寄存器的时候就可以跳出当前轮询寄存器的状态。
修改后的时序如下:
在这里插入图片描述
可以看到擦除命令执行完之后,还需要等待一段时间后才会完成擦除,擦除后的时序为:
在这里插入图片描述

在这里插入图片描述
即回到初始状态。

遗留问题

其实从上面波形中可以看到,仍然是第二次发送写指令的时候,WEL位才会拉高,目前猜测是flash本身的问题,之后的思路可以改成直到WEL位拉高后才执行之后的擦除或者写命令,否则就会一直发送写使能指令,直到WEL拉高。
目前可以暂时改成发送两次写使能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3249448.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

数据挖掘与分析部分实验与实训项目报告

一、机器学习算法的应用 1. 朴素贝叶斯分类器 相关代码 import pandas as pd from sklearn.model_selection import train_test_split from sklearn.naive_bayes import GaussianNB, MultinomialNB from sklearn.metrics import accuracy_score # 将数据加载到DataFrame中&a…

【已解决】Django连接MySQL启动报错Did you install mysqlclient?

在终端执行python manage.py makemigrations报错问题汇总 错误1&#xff1a;已安装mysqlclient&#xff0c;提示Did you install mysqlclient? 当你看到这样的错误信息&#xff0c;表明Django尝试加载MySQLdb模块但未找到&#xff0c;因为MySQLdb已被mysqlclient替代。 【解…

【删除排序链表中的重复元素 II】python刷题记录

因为可能删除头结点&#xff0c;所以我们采用dummy哑结点&#xff08;跟上一篇类似&#xff09; dummy初始化 dummyListNode(0,head) # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # …

黑客自学手册(网络安全)

前言 一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防…

网络安全----防御----防火墙双机热备

实验要求&#xff1a; 1&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW4&#xff0c;生产区和办公区的流量走FW1 2&#xff0c;办公区上网用户限制流量不超过100M&#xff0…

如何将PDF转换成可以直接编辑的CAD图纸?

PDF图纸是为了让用户更好的阅览CAD文件&#xff0c;但是&#xff0c;当我们想要对其进行编辑的时候&#xff0c;PDF图纸就是一个麻烦了。那么PDF转换成CAD后可以编辑吗&#xff1f;如何将PDF转换成可以直接编辑的CAD图纸呢&#xff1f;本篇给你答案。 1、启动迅捷CAD编辑器&…

不同业务场景下通过mars3d实现绕点旋转效果

1.鼠标单击地图某一处就对该点进行绕点旋转效果 相关代码&#xff1a; 1.相关绕点旋转的初始化代码&#xff1a; const rotatePoint new mars3d.thing.RotatePoint({direction: false, // 方向 true逆时针&#xff0c;false顺时针time: 50 // 给定飞行一周所需时间(单位 秒)&…

python如何输入矩阵

使用numpy创建矩阵有2种方法&#xff0c;一种是使用numpy库的matrix直接创建&#xff0c;另一种则是使用array来创建。 首先导入numpy&#xff1a; &#xff08;1&#xff09;import numpy &#xff08;2&#xff09;from numpy import * &#xff08;3&#xff09;import …

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件&#xff0c;这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法&#xff0c;但是如果真正在项目中使用起来&#xff0c;基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与M…

WinOS下获取dll中的方法列表

开发的Windows应用程序的安装环境从Win11 23H2切换到24H2时&#xff0c;出现获取电源模式不正确的问题&#xff0c;通过debug代码发现获取电源模式的方法是走的方法编号。由于Win11 24H2中增加了对外提供的方法&#xff0c;而增加的方法放在方法列表中间&#xff0c;导致其后面…

SpringMVC的底层工作原理?

1.用户发送请求至前端控制器DispatcherServlet. 2.DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器 3.HandlerMapping找到具体的处理器(可以根据 xml 配置、注解进行查找&#xff09;&#xff0c;生成处理器及处理器拦截器(如果有则生成)一并返回给DispatcherSe…

了解财税RPA的背景和意义

作为数字化转型的助推器&#xff0c;RPA近年来正掀起传统财务转型与变革的浪潮&#xff0c;企业想要在数字时代中持续发展繁荣&#xff0c;必须以财务转型为起点&#xff0c;以科技为手段&#xff0c;积极迎接智慧财务的未来。本文金智维将分析财税RPA在财务和税务领域的应用&a…

php 小白新手从入门到精通教程(第3版)

前言 PHP&#xff08;PHP: Hypertext Preprocessor&#xff09;即“超文本预处理器”&#xff0c;是在服务器端执行的脚本语言&#xff0c;尤其适用于Web开发并可嵌入HTML中。PHP语法学习了C语言&#xff0c;吸纳Java和Perl多个语言的特色发展出自己的特色语法&#xff0c;并根…

Pytorch基础应用

1.数据加载 1.1 读取文本文件 方法一&#xff1a;使用 open() 函数和 read() 方法 # 打开文件并读取全部内容 file_path example.txt # 替换为你的文件路径 with open(file_path, r) as file:content file.read()print(content)方法二&#xff1a;逐行读取文件内容 # 逐…

GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建

原文链接&#xff1a;GPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608565&idx3&snd4e9d447efd82e8dd8192f7573886dab&chksmfa826912cdf5e00414e01626b52bab83a96199a6bf69cbbef7f7fe…

Web开发:ASP.NET CORE的后端小结(基础)

1.后端重定向到指定路由 public IActionResult Index(){return RedirectToAction("Index", "Main");//重定向>Main/Index} 【备注】如果在MainController的Index方法中return View();本质是 return View("Index")&#xff0c;返回和方法同名的…

LabVIEW和Alicat Scientific质量流量计实现精确流量控制

在现代工业自动化和科研实验中&#xff0c;精确的气体流量控制至关重要。这里将介绍一个使用LabVIEW与Alicat Scientific公司的质量流量计实现流量控制的项目。项目采用Alicat Scientific的质量流量计&#xff08;型号&#xff1a;M-200SCCM-D&#xff09;&#xff0c;通过LabV…

memcached 高性能内存对象缓存

memcached 高性能内存对象缓存 memcache是一款开源的高性能分布式内存对象缓存系统&#xff0c;常用于做大型动态web服务器的中间件缓存。 mamcached做web服务的中间缓存示意图 当web服务器接收到请求需要处理动态页面元素时&#xff0c;通常要去数据库调用数据&#xff0c;但…

RK3568平台(环境篇)windon与ubuntu之间文件互传

一.windon与ubuntu共享文件夹 打开设置&#xff1a; 点击选项&#xff0c;共享文件夹 共享文件夹&#xff0c;就是在电脑的固定盘符下面&#xff0c;找一个文件夹为Windows和Linux都能看得见的共用的看得见的文件夹&#xff0c;点击添加文件夹。 点击确定后在ubuntu添加共享文…

【JavaEE】volatile + final + wait-notify + join + park-unpark 相关原理

本文基于jdk8 本文所讲的一些原理都是在多线程中经常使用的内容。 参考&#xff1a;黑马程序员深入学习Java并发编程&#xff0c;JUC并发编程全套教程_哔哩哔哩_bilibili 目录 volatile原理 Java内存模型(JMM) 可见性&有序性 双重检查锁应用 final原理 设置final变量…