目标反射回波检测算法及其FPGA实现(准备篇): 用Verilog-HDL状态机控制硬件接口
基于FPGA的目标反射回波检测算法及其实现(准备篇)
:用Verilog-HDL状态机控制硬件接口
前段时间,开发了一个简单的目标反射回波信号识别算法,我会分几篇文章分享这个基于FPGA的回波识别算法的开发过程和原码,欢迎大家不吝赐教。“工欲善其事,必先利其器”,调试FPGA上的数字信号处理算法,最直接的办法是进行行为仿真(前仿)。但有时想通过testbench产生验证算法所需的特定激励信号,并不是一件容易的事情。往往导致通过行为仿真验证/调试FPGA数字信号处理算法的效率低下。
随着任意信号发生器(Arbitrary Wave Generator)的普及,通过matlab或numpy等算法开发工具产生的激励信号,可以轻松的通过任意波形发生器变成模拟信号,极大的方便了数字信号处理算法的开发。但想利用任意信号发生器产生的模拟激励信号,提升算法的开发和调试效率,必须先对这些模拟激励进行A/D转换,并通过D/A转换器显示算法中各个节点上产生的中间信号。——为了方便算法的开发,我尝试实现了一组基于PMOD接口的串行A/D、D/A。这些串行芯片的驱动电路则采用Verilog HDL实现的摩尔型状态机。以下原创内容欢迎网友转载,但请注明出处:https://www.cnblogs.com/helesheng
很多Xilinx公司的FPGA开发板提供一种称为PMOD的接口,如下图所示。
图1 PMOD接口
PMOD只有8个有效I/O,且采用了低成本的低速接插件,只能驱动低速的串行接口ADC、DAC。但对于FPGA数字信号处理算法的开发,最重要的是能验证算法行为的逻辑正确性。在没有高速且可靠的A/D、D/A板卡的情况下,采用PMOD接口和低速串口A/D和D/A转换器开发验证算法,不失为一种有效、快捷且廉价的方法。
A/D和D/A转换器方面,我选择了Microchip公司廉价的12bits MCP3202和MCP4822:MCP3202在3.3V下的转换速度为50KSPS,有两个模拟输入通道;MCP4822在3.3V下的建立时间为4.5uS,也有两个模拟输出通道。两个芯片的SPI接口的控制方法基本类似,下面先以较为复杂的MCP4822为例,介绍Verilog HDL状态机流程控制的实现方式。
一、 接口时序
控制MCP4822可以使用标准SPI接口的模式(1,1)和(0,0),对单个DAC通道进行控制时,官方手册上提供的时序如下图所示。
图2 MCP4822单个通道的控制时序
每次SPI传输的长度为16bits,包含D/A输出的数据信息、输出通道、模拟增益和关断信息。具体如下表所示。
由于MCP4822有A、B两个输出通道,为实现两个通道同时刷新数据的功能,MCP4822还有一个数据加载引脚LDAC(以下简称LD)。当通过SPI口完成D/A转换数据寄存器的刷新后,还需要在LD上给出一个低电平来将数值同时刷新到MCP4822的两个模拟输出通道。
根据上述时序要求,我规划了下图所示的双通道输出时序。
图3 双通道D/A输出时序及控制标志
上图描述了SPI接口的时钟SCK、片选CS和数据加载LD信号的时序,而数据引脚MOSI在并未在图中给出。整个输出时序包括了对两个通道的分别赋值及统一的加载等阶段,Verilog-HDL状态机要给出的状态除了两个通道的分别发送及数据加载状态之外还应包括这些状态之间的间隔状态。
图中的START信号是整个电路的触发信号,它的高电平启动电路按照事先设定的流程依次产生所需的信号。上层电路只要控制START信号产生的频率,就可以控制D/A转换的频率。而上图下半部分的PROC_CHA、PROC_INTV1、PROC_CHB、PROC_INTV1和PROC_LD等信号则是摩尔状态机中标志各个状态的wire型标志信号。
二、 状态及其迁移条件
根据上图所示的时序要求,我设计了如下图所示的状态转换图。
图4 双通道D/A转换器状态转换图
上图所示的状态机共分为:空闲状态(IDLE_STATE)、发送A通道数据状态(SEND_CHA_STATE)、两通道发送间隙状态(INTV1_STATE)、发送B通道数据状态(SEND_CHB_STATE)、数据发送完到加载数据之间的间隙状态(INTV2_STATE)、加载数据状态(LD_STATE)等共六个状态。每个状态都分别对应各自的标志位(即时序图中的PROC_CHA、PROC_INTV1、PROC_CHB、PROC_INTV1和PROC_LD等标志信号),各个状态按照各自的顺序逐次出现。而状态切换的标志则是对应的标志位被清零。
根据结构化程序/电路设计的思路,每个状态中要实现的具体功能不在状态机模块中实现,而是在各自对应的Verilog-HDL Module中实现;各模块则通过各自控制的“标志信号”和状态机模块交互。由于状态机模块不直接控制输出,只负责检测模块输出的状态信号,状态机显然属于“摩尔型”(Moore)。这种思路设计的摩尔型状态机虽然使电路结构更清晰易懂,但会带来状态切换时产生1个时钟周期的延迟的劣势。考虑到FPGA的工作频率可达100MHz以上,而设计的MCP4822的刷新速度只有50KHz左右,所以状态切换时产生1个时钟周期的延迟并不会对控制电路性能产生实质性影响。
三、 状态机程序的设计
根据上述设计思路,采用两段式摩尔型状态机设计的Verilog-HDL原码如下所示。
module mcp4822_state_machine
(clk,rst_n,state_flag,START,PROC_CHA,PROC_INTV1,PROC_CHB,PROC_INTV2,PROC_LD);
//这是用于控制MCP4822两个通道输出的状态机
input clk;
input rst_n;
input START; //起始信号,高电平表示开始一次转换
input PROC_CHA;
//通道A输出信号标志位,高电平表示正在输出通道A数据,低电平表示输出完成。
input PROC_INTV1;
//两通道数据输出之间的间隔标志位,高电平表示状态机正在两通道数据输出之间的间隔期。
input PROC_CHB;
//通道B输出信号标志位,高电平表示正在输出通道B数据,低电平表示输出完成。
input PROC_INTV2; //数据发送完成到加载数据之间的间隔标志位,高电平表示状态机正在数据发送和加载信号之间的间隔期。
input PROC_LD; //模拟数据加载阶段标志位,高电平表示状态机正处在数据加载阶段
output[:] state_flag;//状态机表示的状态
parameter IDLE_STATE = 'B000001; //空闲状态
parameter SEND_CHA_STATE = 'B000010; //发送通道A数据状态
parameter INTV1_STATE = 'B000100; //两个发送之间的间隔状态
parameter SEND_CHB_STATE = 'B001000; //发送通道B数据状态
parameter INTV2_STATE = 'B010000; //发送数据和加载模拟信号之间的等待状态
parameter LD_STATE = 'B100000; //加载模拟信号状态
reg[:] cur_state; //当前状态
reg[:] next_state; //下一个状态
assign state_flag[:] = cur_state[:];//用当前状态作为输出
//两段式moore状态机的第一段,时序逻辑控制
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
cur_state[:] <= IDLE_STATE;
else
cur_state[:] <= next_state[:];
end
//两段式moore状态机的第2段,控制下一个状态的组合逻辑
always @ (*)
begin
case(cur_state)
IDLE_STATE: begin
if(START) //收到开始信号,则进入发送状态
next_state <= SEND_CHA_STATE;
else
next_state <= IDLE_STATE;
end
SEND_CHA_STATE: begin
if(!PROC_CHA) //发送通道A标志为0,表示通道A数据发送完成,进入两通道之间的等待状态
next_state <= INTV1_STATE;
else
next_state <= SEND_CHA_STATE;
end
INTV1_STATE: begin
if(!PROC_INTV1) //两通道发送间隔标志为0,发送间隔完成,进入通道B数据发送状态
next_state <= SEND_CHB_STATE;
else
next_state <= INTV1_STATE;
end
SEND_CHB_STATE: begin
if(!PROC_CHB) //发送通道B标志为0,表示通道A数据发送完成,进入两通道之间的等待状态
next_state <= INTV2_STATE;
else
next_state <= SEND_CHB_STATE;
end
INTV2_STATE: begin
if(!PROC_INTV2) //数据发送完成等待加载间隔标志为0,等待间隔完成,模拟数据加载状态
next_state <= LD_STATE;
else
next_state <= INTV2_STATE;
end
LD_STATE: begin
if(!PROC_LD) //模拟数据加载标志0,数据加载标志完成,空闲状态
next_state <= IDLE_STATE;
else
next_state <= LD_STATE;
end
default: begin
next_state <= IDLE_STATE;
end
endcase
end
endmodule
上述代码注释详细,这里就不在一一解释了。
四、 SPI接口控制电路
SPI接口电路需要产生SCK、CS和MOSI,共3个接口信号;以及SPI忙的标志信号(例化为PROC_CHA和PROC_CHB)。三个接口信号分别用三个过程语句块实现,而标志信号则由CS取反产生。具体代码如下。
module mcp4822_spi(send_data16,en,clk,sck,mosi,cs,PROCING);
//这个模块用于产生控制MCP4822所需的SPI信号
input[:] send_data16;//用SPI口向外发送的数据
input clk;
input en; //使能信号,只在这个信号为高电平时发送SPI数据;这个信号是由状态机输入和本身所属的状态编号比较得到,相同时en为1
output sck;
output mosi;
output cs;
output PROCING; //处理标志,1表示本模块正在发送
reg[:] shift_reg;//移位寄存器,en为0时读取send_data16输入的数据,en为0时左移输出
wire clk_int;//移位寄存器的时钟,en为0时clk做时钟存储并行输入的数据,en为0时SCK为时钟,移位输出数据
assign clk_int = (en&(!sck)) | ((!en)&clk);//数据是在SCK的下降沿刷新的
reg sck;
reg[:] cnt_sck;//产生SPI时钟SCK的计数器
parameter CNT_SCK_NUM = 'D5; //5计数后产生一次反转,100M输入产生10M输出
reg cs;
reg[:] cnt_cs;//产生SPI片选信号CS的计数器
parameter CNT_CS_NUM = CNT_SCK_NUM**; //CS选中的时间长度为16个SCK周期 always @ (posedge clk or posedge cs)
begin
if(cs)
begin
sck <= ;
cnt_sck[:] <= 'd0;
end
else begin
if(cnt_sck[:] == CNT_SCK_NUM-)
begin
cnt_sck[:] <= ;
sck <= !sck;
end
else begin
cnt_sck[:] <= cnt_sck[:] + 'd1;
sck <= sck;
end
end
end assign PROCING = !cs;
always @ (negedge clk or negedge en)
begin
if(!en)
begin
cs <= 'b1;
cnt_cs[:] <= 'd0;
end
else begin
if(cnt_cs[:] < CNT_CS_NUM)
begin
cnt_cs[:] <= cnt_cs[:] + 'd1;
cs <= 'b0;
end
else begin
cnt_cs[:] <= CNT_CS_NUM;
cs <= 'b1;
end
end
end assign mosi = shift_reg[];
always @ (posedge clk_int)
begin
//由CS控制的数据选择电路,选择外部设置信号还是移位信号作为输入,
//即在移位寄存器的D触发器的输出端选择:当cs为1时设置初值,CS为0时移位。
shift_reg[] <= (cs & send_data16[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
shift_reg[] <= (cs & send_data16[]) | ((!cs) & shift_reg[]);
end
endmodule
其中产生移位输出的信号clk_int是由系统时钟clk和SPI输出时钟SCK结合产生的clk_int = (en&(!sck)) | ((!en)&clk);。在en(SPI模块使能信号)为高电平期间,clk_int是系统时钟clk,使模块不停地从并行的数据输入send_data16读取发送数据;en一旦变低SPI开始工作,则clk_int切换为SPI输出时钟SCK,以便于在SCK的驱动下逐位发送数据。
SPI模块的忙状态标志信号PROCING(后被例化为PROC_CHA和PROC_CHB)为CS取反得到,实现SPI模块和状态机模块之间的交互功能。但如果由状态机输出的CS信号取反产生,则有可能产生“先有鸡还是先有蛋”的矛盾:状态切换为SPI模块工作状态(SEND_CHA_STATE或SEND_CHB_STATE)后en将产生高电平,但作为被en使能的过程赋值语句所赋值的寄存器,CS只能在下一个时钟周期中才能产生响应。而摩尔型状态机将在下一个时钟周期结束时检测到被PROCING(也就是!CS)仍未变高,从而离开SPI输出状态SEND_CHA_STATE或SEND_CHB_STATE。仿真时序如下图所示。
图5 状态切换失败
从图中可以看到状态寄存器state_flag,被切换为SEND_CHA_STATE(编号为0x02)一个时钟周期后,由于PROCING(即cs取反)信号没有被置位,所以直接进入了下一个状态INTV1_STATE(编号为0x04)。我采取的解决办法,如上述代码所示:改为在时钟clk的下降沿切换CS的状态,即驱动CS的顺序执行块敏感信号变为:always @ (negedge clk or negedge en)。这样使CS和PROCING信号在en变高的半个clk周期后就被切换为工作状态,在下一个clk上升沿到来时PROCING已经被切换为了工作状态,从而保持住了SPI的工作状态。另外这样做还是的摩尔型状态机的状态切换的延迟时间降低为半个时钟周期。仿真时序如下图所示。
图6 状态切换正常的时序仿真图
五、 其他状态电路模块
除去两个SPI工作状态SEND_CHA_STATE和SEND_CHB_STATE之外,还有两通道发送间隙状态(INTV1_STATE)、数据发送完到加载数据之间的间隙状态(INTV2_STATE)和加载数据状态(LD_STATE)等三个状态只要根据MCP4822的数据手册产生适当时间的延迟即可。Verilog-HDL代码如下。
module INTV_2_CH(en,clk,PROCING);
//两个通道SPI数据加载之间的空闲时间
input en;
input clk;
output PROCING; //高电平表示正在进行延时处理
reg PROCING;
reg[:] cnt;
parameter CNT_NUM = 'D5; //延时时间
always @(negedge clk or negedge en)
begin
if(!en)
begin
cnt[:] <= 'd0;
PROCING <= 'b0;
end
else begin
if(cnt[:] < CNT_NUM)
begin
PROCING <= 'b1;
cnt[:] <= cnt[:] + 'd1;
end
else begin
PROCING <= 'b0;
cnt[:] <= cnt[:];
end
end
end
endmodule
module INTV_LD(en,clk,LD,PROCING);
input en;
input clk;
output PROCING; //高电平表示正在进行延时处理
reg PROCING;
output LD; //控制MCP4822的模拟加载信号
reg LD;
reg[:] cnt;
parameter CNT_NUM = 'D5; //模拟加载信号脉冲宽度
always @(negedge clk or negedge en)
begin
if(!en)
begin
cnt[:] <= 'd0;
PROCING <= 'b0;
LD <= 'b1;
end
else begin
if(cnt[:] < CNT_NUM)
begin
PROCING <= 'b1;
cnt[:] <= cnt[:] + 'd1;
LD <= 'b0;
end
else begin
PROCING <= 'b0;
cnt[:] <= cnt[:];
LD <= 'b1;
end
end
end
endmodule
这两段代码都注意了状态标志信号的产生时钟更应该是clk的下降沿这个问题,从而解决了状态切换失败的问题。
六、 顶层驱动模块
顶层驱动模块的作用有二:其一,准备D/A输出的数据;其三,例化所有模块。具体代码如下所示。
module MCP4822(clk100m,rst_n,start,dac_data_a,dac_data_b,cs,mosi,sck,ld);
//驱动MCP4822的顶层模块
input clk100m;
input rst_n;
input start;//高电平表示DA转换起始的信号
input [:] dac_data_a;//DA的A通道转换数据
input [:] dac_data_b;//DA的B通道转换数据
output cs;
output mosi;
output sck;
output ld;
wire [:] data_cha;//DA的A通道SPI输入的数据,含有通道控制的4个位的数据
wire [:] data_chb;//DA的B通道SPI输入的数据,含有通道控制的4个位的数据
wire clk;
assign data_cha[:]={'b0,1'b0,'b1,1'b1,dac_data_a[:]};//这是MCP4822输出数据的格式,通道A,无关位,增益为1,不关断
assign data_chb[:]={'b1,1'b0,'b1,1'b1,dac_data_b[:]};//通道B,无关位,增益为1,不关断 wire[:] state_flag;//状态机输出的状态线
parameter IDLE_STATE = 'B000001; //空闲状态
parameter SEND_CHA_STATE = 'B000010; //发送通道A数据状态
parameter INTV1_STATE = 'B000100; //两个发送之间的间隔状态
parameter SEND_CHB_STATE = 'B001000; //发送通道B数据状态
parameter INTV2_STATE = 'B010000; //发送数据和加载模拟信号之间的等待状态
parameter LD_STATE = 'B100000; //加载模拟信号状态
wire PROC_CHA; //通道A输出信号标志位,高电平表示正在输出通道A数据,低电平表示输出完成。
wire PROC_INTV1; //两通道数据输出之间的间隔标志位,高电平表示状态机正在两通道数据输出之间的间隔期。
wire PROC_CHB; //通道B输出信号标志位,高电平表示正在输出通道B数据,低电平表示输出完成。
wire PROC_INTV2; //数据发送完成到加载数据之间的间隔标志位,高电平表示状态机正在数据发送和加载信号之间的间隔期。
wire PROC_LD; //模拟数据加载阶段标志位,高电平表示状态机正处在数据加载阶段
wire cs_cha;
wire mosi_cha;
wire sck_cha;
wire cs_chb;
wire mosi_chb;
wire sck_chb;
assign cs = (state_flag[:]==SEND_CHA_STATE)? cs_cha : cs_chb;
assign mosi = (state_flag[:]==SEND_CHA_STATE)? mosi_cha : mosi_chb;
assign sck = (state_flag[:]==SEND_CHA_STATE)? sck_cha : sck_chb;
assign clk=clk100m; mcp4822_state_machine i_state_machine(//状态机例化模块
.clk(clk),
.rst_n(rst_n),
.state_flag(state_flag),
.START(start),
.PROC_CHA(PROC_CHA),
.PROC_INTV1(PROC_INTV1),
.PROC_CHB(PROC_CHB),
.PROC_INTV2(PROC_INTV2),
.PROC_LD(PROC_LD)
); mcp4822_spi i_mcp4822_spi_cha(//A通道SPI控制模块的例化
.send_data16(data_cha),
.en((state_flag[:]==SEND_CHA_STATE)),
.clk(clk),
.sck(sck_cha),
.mosi(mosi_cha),
.cs(cs_cha),
.PROCING(PROC_CHA)
); mcp4822_spi i_mcp4822_spi_chb(//B通道SPI控制模块的例化
.send_data16(data_chb),
.en((state_flag[:]==SEND_CHB_STATE)),
.clk(clk),
.sck(sck_chb),
.mosi(mosi_chb),
.cs(cs_chb),
.PROCING(PROC_CHB)
); INTV_2_CH i_intv_between_ch(//两个通道SPI通信之间的间隙模块例化
.en((state_flag[:]==INTV1_STATE)),
.clk(clk),
.PROCING(PROC_INTV1)
);
INTV_2_CH i_intv_behind_ch(//两个通道SPI通信完成后到模拟数据加载之间的间隙模块例化
.en((state_flag[:]==INTV2_STATE)),
.clk(clk),
.PROCING(PROC_INTV2)
); INTV_LD i_intv_ld(//模拟数据加载模块例化
.en((state_flag[:]==LD_STATE)),
.clk(clk),
.LD(ld),
.PROCING(PROC_LD)
); endmodule
其中,SPI通信所需的16bits数据,除了12bits的D/A数据外,还有四个bits的配置信息,可由MCP4822数据手册查询其具体含义。实现代码为:
assign data_cha[15:0]={1'b0,1'b0,1'b1,1'b1,dac_data_a[11:0]};//这是MCP4822输出数据的格式,通道A,无关位,增益为1,不关断
assign data_chb[15:0]={1'b1,1'b0,1'b1,1'b1,dac_data_b[11:0]};//通道B,无关位
在START信号触发下,上述MCP4822电路的整体仿真情况如下图所示,完全满足数据手册的要求。
图7 MCP4822驱动模块整体仿真时序图
七、 A/D转换器MCP3202的接口电路设计
MCP3202是SPI接口的双通道A/D转换器,用状态机控制其工作的方式与MCP4822相近,在这里就不在赘述了。
目标反射回波检测算法及其FPGA实现(准备篇): 用Verilog-HDL状态机控制硬件接口的更多相关文章
- 目标反射回波检测算法及其FPGA实现 之三:平方、积分电路及算法的顶层实现
目标反射回波检测算法及其FPGA实现之三: 平方.积分电路及算法的顶层实现 前段时间,接触了一个声呐目标反射回波检测的项目.声呐接收机要实现的核心功能是在含有大量噪声的反射回波中,识别出发射机发出的激 ...
- 目标反射回波检测算法及其FPGA实现 之二:互相关/卷积/FIR电路的实现
目标反射回波检测算法及其FPGA实现之二: 互相关/卷积/FIR电路的实现 前段时间,接触了一个声呐目标反射回波检测的项目.声呐接收机要实现的核心功能是在含有大量噪声的反射回波中,识别出发射机发出的激 ...
- 目标反射回波检测算法及其FPGA实现 之一:算法概述
目标反射回波检测算法及其FPGA实现之一:算法概述 前段时间,接触了一个声呐目标反射回波检测的项目.声呐接收机要实现的核心功能是在含有大量噪声的反射回波中,识别出发射机发出的激励信号的回波.我会分几篇 ...
- 浅谈Virtual Machine Manager(SCVMM 2012) cluster 过载状态检测算法
在我们使用scvmm2012的时候,经常会看到群集状态变成了这样 点开看属性后,我们发现是这样 . 发现了吗?Over-committed,如果翻译过来就是资源过载,或者说资源过量使用了,那么这个状态 ...
- 异常检测算法--Isolation Forest
南大周志华老师在2010年提出一个异常检测算法Isolation Forest,在工业界很实用,算法效果好,时间效率高,能有效处理高维数据和海量数据,这里对这个算法进行简要总结. iTree 提到森林 ...
- Harris角点检测算法优化
Harris角点检测算法优化 一.综述 用 Harris 算法进行检测,有三点不足:(1 )该算法不具有尺度不变性:(2 )该算法提取的角点是像素级的:(3 )该算法检测时间不是很令人满意. 基于以上 ...
- 机器学习:异常检测算法Seasonal Hybrid ESD及R语言实现
Twritters的异常检测算法(Anomaly Detection)做的比较好,Seasonal Hybrid ESD算法是先用STL把序列分解,考察残差项.假定这一项符合正态分布,然后就可以用Ge ...
- [转]前景检测算法--ViBe算法
原文:http://blog.csdn.net/zouxy09/article/details/9622285 转自:http://blog.csdn.net/app_12062011/article ...
- 基于Shading Model(对光照变化一定不变性)的运动目标检测算法
光照模型(Shading Model)在很多论文中得到了广泛的应用,如robust and illumination invariant change detection based on linea ...
随机推荐
- 将远程UI分支克隆到本地UI分支
git checkout -b UI git remote add origin <url> git fetch origin git branch --track UI origin/U ...
- numpy深入理解剖析
http://www.scipy-lectures.org/advanced/advanced_numpy/index.html
- Tomcat性能监控之Probe
目前采用java进行开发的系统居多,这些系统运行在java容器中,通过对容器的监控可以了解到java进程的运行状况,分析java程序问题.目前市面上流行的中间件有很多(Tomcat.jetty.jbo ...
- 更新tableView的某个cell
更新tableView的某个cell 异步加载完数据后更新某个cell,这应该是非常常见的使用方法了,我们经常会用reloadData. 效果: 源码: // // RootViewControlle ...
- Linux系统设置运行级别
设置运行级别 查看开机加载级别:7个级别 规范场景默认都是3 cat /etc/inittab --> 系统开机启动加载的文件,可以设置运行级别 # Default runlev ...
- 制作MacOS 系统启动盘
1,首先需要在一台有MacOS系统,在Apple stroe下载MacOS High Sierra安装程序: 2,准备一个至少8G容量的U盘: 3,打开 “应用程序 → 实用工具 → 磁盘工具”,将U ...
- javascript Spline代码
代码是通过网上一个winform代码中提取修改而来的.后转为javascript 版本. /* points = new Array(); points.push({x:1,y:2}); */ fun ...
- print in或者not in, 判断在不在里面
print("不疼" in "麻花疼") # 结果False print("不疼"in "真不疼") # ...
- CSS3 Transform变形理解与应用
CSS3 Transform变形理解与应用 Transform:对元素进行变形:Transition:对元素某个属性或多个属性的变化,进行控制(时间等),类似flash的补间动画.但只有两个关键贞.开 ...
- 【AT987】高橋君
题目 成爷爷一眼秒,\(tql!!!\) 多组询问,求 \[\sum_{i=0}^kC_{n}^i \] 发现\(k<=n\)啊,于是我们可以把一组询问抽象成一个区间\([k,n]\) 左指针的 ...