STM32单片机介绍2
----------------------------------------------------------
表8.9 STK_CTRL, 0xE000E010 控制寄存器
首先看STK_CTRL控制寄存器:寄存器内有4个位具有意义
第0位:ENABLE,Systick 使能位 (0:关闭Systick功能;1:开启Systick功能)
第1位:TICKINT,Systick 中断使能位 (0:关闭Systick中断;1:开启Systick中断)
第2位:CLKSOURCE,Systick时钟源选择 (0:使用HCLK/8 作为Systick时钟;1:使用HCLK作为Systick时钟)
第16位:COUNTFLAG,Systick计数比较标志,如果在上次读取本寄存器后,SysTick 已经数到了0,则该位为1。如果读取该位。
校准寄存器一般很少用。
(以上寄存器操作可以参看以下程序加以理解:)
static u8 fac_us;//us延时倍乘数
static u32 fac_ms;//ms延时倍乘数
* Function Name :Delay_Init
* Description : SYSTICK的时钟固定为HCLK时钟的1/8
* Input : SYSCLK:系统主频时钟(SYSCLK Mhz)
* Return : None
void Delay_Init(u8 SYSCLK)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);// select HCLK/8 as systick clock source.
fac_us=SYSCLK/8; //9
fac_ms=(u32)fac_us*1000;
}
* Function Name:delay_ms
* Description : SysTick计数值最大为24位,最大值为16777215,如果fac_us=9000,那么nms的最大值为1864(1864ms)
* Input : nus,注意nms的范围 nms<=1864
void delay_ms(u16 nms)
{
SysTick->LOAD=(u32)nms*fac_ms;//时间加载(SysTick->LOAD为24bit)
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //Enable Systick Function and start counting
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); //等待计数到0
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
}
* Function Name :delay_us
* Description : SysTick计数值最大为24位,最大值为16777215,如果fac_us=72那么nus
的最大值为233016,如果fac_us=9那么nus的最大值为1864128(1864ms)
* Input : nus
* Return : None
void delay_us(u32 nus)
{
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk ; //Enable Systick Function and start counting
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); //等待计数到0
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
}
当我们需要精确延时时,就可以利用 SysTick timer实现,理论上它的最小计时单位为AHB的时钟周期,即1/72000000 秒,72分之一的微秒,足以满足大部分极端应用需求。本小节以实例讲解如何利用 SysTick进行精确延时。抢占优先级要设置最高。
中断分组M3内核的配置方法:
NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(NVIC_PRIORITY_GROUP_5,0,0)) //抢占优先级0,响应优先级0
NVIC_SetPriority(EXTI5_10_IRQn,NVIC_EncodePriority(NVIC_PRIORITY_GROUP_5,1,0))//抢占优先级1,响应优先级0
-------------------------------------------------------------------------------------------------------------------
十一、STM32_端口
1、端口的配置
图11.1.1
1)各种模式配置
浮空输入_Input_Floating
带上拉输入_Input Pull-up
带下拉输入_Input Pull-down
模拟输入_Analog
开漏输出_Out Ope-drain
推挽输出_Out Push-pull
复用功能的推挽输出_Alternate function open-drain
复用功能的开漏输出_Alternate function push-pull
-------------------------------------------
2)STM32 端口复用与重映射(如USART Remap)
(1)RCC_APB2Periph_AFIO时钟一般在什么时候下需要开启?
引脚复用,进行重映射时,需要开启AFIO时钟,包括输入管脚中断。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE );
//使能ADC1通道时钟,各个管脚时钟 就是使能USART1管脚复用
-------------
(2)以USART1的重映射为例
因为我要一个TFT_LCD屏的主控板,考虑到FSMC 我选用了STM32F103VCT6 型号的CPU,一不小心串口接到USART1上了。因为在调程序时才发现错了,没得办法,只能通过端口重映射来解决。
STM32上有很多I/O口,也有很多的内置外设像I2C、ADC、ISP、USART等,为了节省引出管脚,这些内置外设基本上是与I/O口共用管脚的,也就是I/O管脚的复用功能。但是STM32还有一特别之处就是:很多复用内置的外设的I/O引脚可以通过重映射功能,从不同的I/O管脚引出,即复用功能的引脚是可通过程序改变的。下面说说我的调试经历。
不知道是什么原因PCB制图时把串口接到USART1上了,当时也没在意,等我把USART测试程序写好烧进去硬件仿真时,串口给的是乱码,我当时就觉得奇怪。把程序检查了好几遍就是查不出问题来,以为是硬件有问题,但突然想到了
STM有复用功能,心想会不会是这里有鬼?于是找来datasheet 一看,真相大白。
(4)为了优化64脚或100 脚封装的外设数目,可以把一些复用功能重新映射到其他引脚上。设置复用重映射和调试I/O 配置寄存器(AFIO_MAPR) 实现引脚的重新映射。这时,复用功能不再映射到它们的原始分配上。需要用到外设的重映射功能时才需要使能AFIO的时钟。外部中断(EXTI)中与AFIO有关的寄存器是AFIO-EXTICR1、2、3,它们是用来选择EXTIx外部中断的输入脚之用。
举例:重映射USART2
USART2的TX/RX在PA.2/3,但是PA.2已经被Timer2的channel3使用。这时,如果还想使用USART2,但又不想影响Timer2的使用,这就需要把USART2的TX/RX重映射到PD.5/6。
映射库函数的调用过程:
使能被重新映射到的I/O端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
使能被重新映射的外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
使能AFIO功能的时钟(勿忘!)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
进行重映射
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
如在使用EXTI时,如果不启动RCC_APB2Periph_AFIO时钟,无法使用外部中断
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
-------------------------------------------
3)推挽输出和开漏输出的区别
推挽输出:
图11.1.2
GPIO引脚线路经过两个保护二极管后,向上流向“输入模式”结构,向下流向“输出模式”结构。先看输出模式部分,线路经过一个由P-MOS和N-MOS管组成的单元电路。这个结构使GPIO具有了“推挽输出”和“开漏输出”两种模式。
所谓的推挽输出模式,是根据这两个MOS管的工作方式来命名的。在该结构中输入高电平时,经过反向后,上方的P-MOS导通,下方的N-MOS关闭,对外输出高电平;而在该结构中输入低电平时,经过反向后,N-MOS管导通,P-MOS关闭,对外输出低电平。当引脚高低电平切换时,两个管子轮流导通,P管负责灌电流,N管负责拉电流,使其负载能力和开关速度都比普通的方式有很大的提高。推挽输出的低电平为0伏,高电平为3.3伏,图11.1.2是推挽输出模式时的等效电路。
开漏输出:
图11.1.3
而在开漏输出模式时,上方的P-MOS管完全不工作。若控制输出为0低电平,则P-MOS管关闭,N-MOS管导通,使输出接地,若控制输出为1 (它无法直接输出高电平)时,则P-MOS管和N-MOS管都关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。正常使用时必须外部接上拉电阻,参考图11.1.3中等效电路。它具有“线与”特性,也就是说,若有很多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平0伏。推挽输出模式一般应用在输出电平为0和3.3V且需要高速切换开关状态的场合。在STM32的应用中,除了必须用开漏模式的场合,都习惯使用推挽输出模式。
开漏输出一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输出5伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5V,并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5V的电平。
(1)端口 位设置/复位寄存器BSRR:(如果同时设置了BSy和BRy的对应位,BSy位起作用,低位优先)
0:对对应的ODRy位不产生影响(ODR=Output Data Register)
位15:0 BSy: 设置端口x的位y (y = 0…15) 这些位只能写入并只能以字(16位)的形式操作。
0:对对应的ODRy位不产生影响
1:设置对应的ODRy位为1
(2)端口 位复位寄存器BRR:
位31:16 保留。
位15:0 BRy: 清除端口x的位y (y = 0…15) 这些位只能写入并只能以字(16位)的形式操作。
0:对对应的ODRy位不产生影响
1:清除对应的ODRy位为0
-------------------------------------------
2)使用方法
(1)混合改变
需要置1的端口对应的位,在低16位里置1
需要置0的端口对应的位,在高16位里置1,不改变的,都置0. 然后写寄存器BSRR
(2)改变引脚为低
需要置0的端口对应的位,在低16位里置1,然后写寄存器BRR
(3)改变引脚为高
需要置1的端口对应的位,在低16位里置1 高16为全0 然后写寄存器BSRR
另外就是,STM32的库,GPIO_SetBits,GPIO_ResetBits,可以对多个引脚操作的,就是把需要操作的引脚用“|”(或运算)。
最方便的还是自己直接写寄存器(方法1)。
第一步:第一你要用的IO口 比如说要用A口的高8位定义 GPIOA_USE=0xF0
第二步:写BSRR寄存器。 GPIOA->BSRR=data&&GPIOA_USE
第三步:写BRR寄存器。 GPIOA->BRR=(~data)&&GPIOA_USE
假设data为8位要写入的数据:
GPIO_SetBits(GPIOD, data & 0xff00);
GPIO_ResetBits(GPIOD, (~data & 0xff00));
也可以直接操作这两个寄存器:
GPIOD->BSRR = data & 0xff00;
GPIOD->BRR = ~data & 0xff00;
规则:
规则一、置GPIOD->BSRR低16位的某位为'1',则对应的I/O端口置'1';而置GPIOD->BSRR低16位的某位为'0',则对应的I/O端口不变。
规则二、置GPIOD->BSRR高16位的某位为'1',则对应的I/O端口置'0';而置GPIOD->BSRR高16位的某位为'0',则对应的I/O端口不变。
规则三、置GPIOD->BRR低16位的某位为'1',则对应的I/O端口置'0';而置GPIOD->BRR低16位的某位为'0',则对应的I/O端口不变。
例如:
1)要设置D0、D5、D10、D11为高,而保持其它I/O口不变,只需一行语句:
GPIOD->BSRR = 0x0C21;// 使用规则一
2)要设置D1、D3、D14、D15为低,而保持其它I/O口不变,只需一行语句:
GPIOD->BRR = 0xC00A; // 使用规则三
3)要同时设置D0、D5、D10、D11为高,设置D1、D3、D14、D15为低,而保持其它I/O口不变,也只需一行语句:
高16位 低16位
31 24 16 8 0
1100 0000 0000 1010 0000 1100 0010 0001
GPIOD->BSRR = 0xC00A0C21;// 使用规则一和规则二
GPIOD->BSRR = (0x00 ff 00 00) | data;//根据data改变低8位端口的值,高8位端口不变(保持高8位不变,低8位为0)
-------------------------------------------------------------------------------------------------------------------
十二、STM32_大小端与MSB、LSB
1、STM32大小端
大端模式:低位字节存在高地址上,高位字节存在低地址上;
小端模式:高位字节存在高地址上,低位字节存在低地址上。
KEIL C51中,变量都是大端模式的;KEIL MDK中,变量是小端模式的,STM32属于小端模式。
以unsigned int value = 0x12345678
为例说明。
内存地址 | 0x00000001 | 0x00000002 | 0x00000003 | 0x00000004 |
---|---|---|---|---|
大端模式 | 0x12 | 0x34 | 0x56 | 0x78 |
小端模式 | 0x78 | 0x56 | 0x34 | 0x12 |
同样以unsigned int value = 0x12345678
为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]
来表示value
。
----------------------------------------------------------
2、大小端判断方法
1)通过程序
同样以0x12345678为例。
int temp=1; //定义一个int型变量temp并赋值1
char *p=(char *)&temp; //&temp取地址强制转换为指针,定义一个字符型指针指向temp变量的起始地址
if(*p==1)
printf("小端");
else
printf("大端");
参照上述两个图可知,若为小端则起始地址处被放入1,否则被放入0。
第3行读出字符型指针指向的地址处的字符,即变量temp的第一个字节处的值,并通过此值判断大端和小端。
-------------------------------------------
2)通过编译器编译结果
----------------------------------------------------------
3、MSB与LSB
1)简述
最低有效位(the Least Significant Bit:LSB)是指一个二进制数字中的第0位(即最低位),具有权值为2^0,可以用它来检测数的奇偶性。在大端模式中LSB最右边的位。
图12.2.3 无符号数149的二进制形式,蓝色为最高有效位
最低有效位代表二进制数中的最小的单位,可以用来指示数字很小的变化。LSB有时也指Least Significant Byte,指多字节序列中最小权重的字节。
最高有效位(the Most Significant Bit:MSB),是指一个n位二进制数字中的n-1位,具有最高的权值2^n-1。在大端模式中MSB指最左端的位。
图12.2.4 无符号数149的二进制形式,蓝色为最高有效位
对于有符号二进制数,负数采用反码或补码形式,此时MSB用来表示符号,MSB为1表示负数,0表示正数。MSB有时也指Most Significant Byte,指多字节序列中具有最大权重的字节。
所以0x12345678的最高有效字节就是0x12,最低有效字节就是0x78。
-------------------------------------------
2)高位先行MSB 、低位先行LSB
(1)串口传输是低位先行
UART在数据传输时,协议规定了数据传输必须是低位先行,看下面的时序图你就知道了。
-------------
(2)IIC传输是高位先行
IIC的数据和地址均以8位字节传输,MSB 在前。从图中可以清楚地看到:
-------------
(3)SPI上升沿发送、下降沿接收、高位先发送
-------------------------------------------------------------------------------------------------------------------
十三、STM32_I2C
I2C协议详见“算法、协议、信号处理/SPI与I2C总线协议”。
-------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------
十五、查找汇编指令
有关Cortex 内核的指令我们可以参考《CM3 权威指南 CnR2》第四章:指令集。剩下的 ARM 的汇编指令我们可以在 MDK->Help->Uvision Help 中搜索到,以 AREA 为例,检索如下:
-------------------------------------------------------------------------------------------------------------------
十六、KEIL MDK
1、数据类型
1)KELI MDK 数据类型定义
char 占用 1 个字节
short int 占用 2 字节//注意这里!
int 占用 4 字节
long 占用 4 字节 //注意这里!
long int 占用 4 字节 //注意这里!
float 占用 4 字节
double 占用 8 字节即有如下宏定义
typedef unsigned char uint8; // 无符号 8 位字符型变量
typedef signed char int8; // 有符号 8 位字符型变量
typedef unsigned short uint16; // 无符号 16 位短整型变量
typedef signed short int16; // 有符号 16 位短整型变量
typedef unsigned int uint32; // 无符号 32 位整型变量
typedef signed int int32; // 有符号 32 位整型变量
typedef float fp32; // 单精度浮点数(32 位长度)
typedef double fp64; // 双精度浮点数(64 位长度)
注:C 语言中的种类数据:整型:int、short、long,实型:float、double 。其中,unsigned 为无符号, signed 有符号。
-------------------------------------------
2)STM32数据类型宏定义
typedef unsigned char u8;0~255 一字节
typedef signed char s8;-128~127
typedef volatile unsigned char vu8;
typedef volatile signed char vs8;
typedef unsigned char const uc8;
typedef signed char const sc8;
typedef volatile unsigned char const vuc8;
typedef volatile signed char const vsc8;
typedef unsigned short u16; 0~65535 两字节
typedef signed short s16; -32768~32767 两字节
typedef volatile unsigned short vu16;
typedef volatile signed short vs16;
typedef unsigned short const uc16;
typedef signed short const sc16;
typedef signed short const sc16;
typedef volatile unsigned short const vuc16;
typedef volatile signed short const vsc16;
typedef unsigned long u32; 0~(2^32-1)四字节
typedef signed long s32; /
typedef signed long const sc32;
typedef volatile unsigned long const vuc32;
typedef volatile signed long const vsc32;
-------------------------------------------
3)数据类型混合运算
不同类型数据的混合运算在C 语言中,不同类型的数据间是可以混合运算的。在进行运算时,不同类型的数据要先转换成同一类型,然后进行运算。转换的规则如下:
注意:箭头的方向只表示数据类型级别的高低,由低向高转换,这个转换过程一步到位。
-------------------------------------------
4)数据类型转换规则
各类数据类型的转换,分为两种方式:隐式(编译软件自动完成),显式(程序强制转换)
(1)隐式转换规则
字符必须先转换为整数(C 语言规定字符类型数据和整型数据之间可以通用) short 型转换为 int 型(同属于整型)float 型数据在运算时一律转换为双精度(double)型,以提高运算精度(同属于实型) 赋值时,一律是右部值转换为左部类型
注:当整型数据和双精度数据进行运算时,C 先将整型数据转换成双精度型数据,再进行运算,结果为双精度类型数据
当字符型数据和实型数据进行运算时,C 先将字符型数据转换成实型数据,然后进行计算,结果为实型数据
----------------------
(2)显式转换规则:例:(int)(x+y);
注:强制类型转换时,得到一个所需要的中间变量,原来变量的类型未发生变化。
-------------------------------------------
5)volatile、const关键词说明
(1)volatile :这个关键字,很多人只知道用,不知道其含义,有介绍解释是不易被编译器优化的。在 STM32 资料中解释加了易挥发的变量。这些解释都是含糊不清的。为此笔者专门查了下这个修饰关键字含义。
通俗的解释: 随时会改变,并被多函数调用可以加 volatile 修饰。
简称易变变量或易挥发变量。 表示这个变量的真的很容易变。
进阶解释: 加了这个 volatile 意义就是在每次取这个变量值的时候,要求不是取它上次在某个时候取的临时缓存变量(比如说暂存在某个寄存器中),而是直接到内存中取。
个人经验:
告诉编译器,volatile 定义的变量必须 RAM 变量,不能是寄存器变量,尤其是中断中用全局变量。
----------------------
(2)const: 在定义变量时候,如果加上关键词 const,则变量的值在程序运行期间不能改变, 当然不能再赋值了。这种变量称为常变量(constant variable)或是只读变量(read-only-variable,这样觉得更恰当)。
----------------------------------------------------------
2、把变量定义到指定地址
1)定位到flash中
const u16 FlashVariable[128] __attribute__((at(0x08001000))) =
{0x1111,0x1111,0x1111,0x0111,0x0111,0x0111};//定位在flash中,其他flash补充为00
-------------------------------------------
2)定位到RAM中
u8 RAMVariable[64] __attribute__ ((at(0X20001000)))={0};
注意:
绝对定位不能用于函数的局域变量定义,局部变量是定义在栈区的,栈区由MDK自动分配、释放,不能定义为绝对地址,只能放在函数外定义。
-------------------------------------------------------------------------------------------------------------------
STM32单片机介绍2相关推荐
- 电源学习(1):stm32单片机buck电路可调电源设计介绍
最近,搞了一块stm32单片机的降压电路板,效果还不错分享分享给大家. 首先上图看效果! 下图 输入电压在20v不变,效果如图所示. 然后我又测了几组数据供大家参考一下,具体电路后续在写了 可见负载调 ...
- ARM® Cortex®-M内核单片机STM32家族介绍,覆盖STM32F、STM32H、STM32L全系列
STM32是ARM®Cortex®-M内核单片机.目前提供10大产品线(F0, F1, F2, F3, F4, F7, H7, L0, L1, L4),超过700个型号.STM32产品广泛应用于 ...
- STM32单片机IAP介绍
1.什么是IAP? 首先区分下两个概念:ISP和IAP: ISP:In System Programming (在系统中编程),通过芯片专用的串行编程接口对其内部的程序存储器进行擦写. IAP:In ...
- 5加载stm32 keil_快速入门STM32单片机-软件篇
关于这个STM32的编程开发环境Keil,网上有太多相关的资源了,而且大都讲解的非常详细.所以本篇文章无意于深入细节,只会提供我学习时候的一些体会,帮助你更好的掌握相关知识. 1.标准外设库(Stan ...
- STLINK怎么与STM32单片机连接
STLink是ST官方开发的单片机仿真工具,可以烧写程序.在线仿真,使用非常方便.STLink具有两种接口,分别为:1)SWD模式;2)SWIM单总线模式.SWD模式主要针对STM32系列的单片机,而 ...
- 单片机搭建环境烧录方法_万物互联-stm32单片机简介、烧录、编程及其项目环境搭建...
万物互联-stm32单片机简介.烧录.编程 前言:stm32单片机这里给出简单介绍,给不了解的朋友普及下硬件端的基本知识,叙述的较为简单,想深入研究的朋友可以去一些官方网站.论坛.博客汲取知识.最下端 ...
- 基于stm32单片机智能温控风扇控制系统Proteus仿真
资料编号:103 下面是相关功能视频演示: 103-基于stm32单片机智能温控风扇控制系统Proteus仿真(源码+仿真+全套资料) 功能介绍:采用stm32单片机.ds18b20温度传感器采集温 ...
- STM32单片机串口空闲中断+DMA接收不定长数据
在上一篇文章STM32单片机串口空闲中断接收不定长数据中介绍了利用串口空闲中断接收不定长数据,这种方式有一个问题就是串口每接收到一个字节就会进入一次中断,如果发送的数据比较频繁,那么串口中断就会不停打 ...
- STM32单片机语音声控智能台灯可调光冷暖光人检测锂电池供电太阳能和USB充电
实践制作DIY- GC0022-语音声控智能台灯 一.功能说明: 基于STM32单片机设计-语音声控智能台灯 功能介绍: 硬件:STM32F103C最小系统+语音识别模块+18650锂电池+太阳能充电 ...
- 单片机入门学习五 STM32单片机学习二 跑马灯程序衍生出的stm32编程基础
上篇文章 单片机入门学习四 STM32单片机学习一 跑马灯程序和创建工程 仅介绍了入门程序及其编译运行过程,下面开始对stm32的一些基础知识做一个记录. 1.stm32f103zet6(上篇问题3 ...
最新文章
- Mysql查询的一些操作(查表名,查字段名,查当月,查一周,查当天)
- 清华大学「天机」芯片登上Nature封面:类脑加传统计算融合实现通用人工智能...
- range方法在Python2和Python3中的不同
- 【VS C++ 2010】查看内存的方法详解
- 15-多容器复杂应用的部署
- linux一次执行多个命令,linux 一次执行多条命令
- linux有个进程有问题_第五十五章、linux下进程的基本知识
- dplyr | 数据处理函数的功能速查!dplyr包中的十类操作函数汇总(下篇)
- WinMerge只显示差异部分的设置方法
- 分享C#实现XML和实体序列化和反序列化的代码
- 阿里云申请商标注册步骤详细教程
- 江苏小高考计算机知识点,江苏文科小高考哪几门 考试内容是什么
- 统计检测(statistical tests)
- 遇到RAID5阵列硬盘出现问题的情况该如何解决?
- About Redistribute
- 2022-10-24 dell R740服务器 安装显卡 NVIDIA Tesla P40 24GB
- java 获取meta-inf路径_【Java】WEB-INF目录与META-INF目录的作用
- vulnstack_ATTCK1渗透
- pe怎么安装kali linux,U盘+kali+pe三合一教程!装机,存储,渗透,persistence存储问题解决!...
- 斐波那契生兔子问题(一月大兔子生a对,二月大兔子生b对,三月大兔子生c对。。。)