上篇文章 单片机入门学习四 STM32单片机学习一 跑马灯程序和创建工程 仅介绍了入门程序及其编译运行过程,下面开始对stm32的一些基础知识做一个记录。

1、stm32f103zet6(上篇问题3 stm32f103是什么)

上篇的跑马灯程序采用的开发板使用的mcu是stm32f103zet6,根据stm32系列产品命名规则,我们知道这款mcu为基于ARM®的32位微控制器、是增强型的、拥有144个引脚、512K字节的闪存存储器、采用LQFP封装、工作温度范围在-40℃~85℃。这款芯片包含的资源有 64KB SRAM(Static Random Access Memory静态随机存取存储器)、512KB FLASH、2个基本定时器、4个通用定时器、2个高级定时器、2个DMA(Direct Memory Access直接内存存取)控制器(公12个通道)、3个SPI(Serial Peripheral Interface串行外设接口)、2个IIC(Inter-Integrated Circuit集成电路总线)、5个串口、1个USB、1个CAN(控制器局域网络Controller Area Network)、3个12位ADC(Analog-to-Digital Converter模/数转换)、1个12位DAC(Digital-to-Analog Converter数/模转换)、1个SDIO(Secure Digital Input and Output安全数字输入输出卡)接口、1个FSMC(Flexible Static Memory Controller可变静态存储控制器)接口以及112个GPIO(General Purpose Input Output 通用输入/输出)口。
下图是其系统结构图

虽然上面已经将stm32f103zet6芯片系统构成已经介绍,但是下面的介绍是针对上图给的一个更直观的概况。
stm32主要由四个驱动单元和四个被动单元构成。

  • 四个驱动单元

    • Cortex™-M3内核Dcode总线(D-bus)
    • 系统总线(S-bus)
    • 通用DMA1
    • 通用DMA2
  • 四个被动单元
    • 内部SRAM
    • 内部闪存存储器
    • FSMC
    • AHB到APB的桥(AHB2APBx) ,它连接所有的APB设备

ICode总线:该总线将Cortex™-M3内核的指令总线与闪存接口相连接。指令预取在此总线上完成。
DCode总线:该总线将Cortex™-M3内核的DCode总线与闪存存储器的数据接口相连接(常量加载和调试访问)
系统总线:此总线连接Cortex™-M3内核的系统总线(外设总线)到总线矩阵,总线矩阵协调着内核和DMA间的访问
DMA总线:此总线将DMA的AHB主控接口与总线矩阵相联,总线矩阵协调着CPU的DCode和DMA到 SRAM、闪存和外设的访问。
总线矩阵:协调内核系统总线和DMA主控总线之间的访问仲裁,仲裁利用轮换算法。在互联型产品中,总线矩阵包含5个驱动部件(CPU的DCode、系统总线、以太网DMA、DMA1总线和DMA2总线)和3个从部件(闪存存储器接口(FLITF)、SRAM和AHB2APB桥)。在其它产品中总线矩阵包含4个驱动部件(CPU的DCode、系统总线、DMA1总线和DMA2总线)和4个被动部件(闪存存储器接口(FLITF)、SRAM、FSMC和AHB2APB桥)。AHB外设通过总线矩阵与系统总线相连,允许DMA访问。
AHB/APB桥(APB) :两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于36MHz,APB2操作于全速(最高72MHz)。 在每一次复位以后,所有除SRAM和FLITF以外的外设都被关闭,在使用一个外设之前,必须设置寄存器RCC_AHBENR来打开该外设的时钟。 注意: 当对APB寄存器进行8位或者16位访问时,该访问会被自动转换成32位的访问:桥会自动将8位或者32位的数据扩展以配合32位的向量。

注: ROM、RAM、DRAM、SRAM和FLASH的区别
1、ROM和RAM指的都是半导体存储器,ROM在系统停止供电的时候仍然可以保持数据,而RAM通常都是在掉电之后就丢失数据,典型的RAM就是计算机的内存。
2、RAM有两大类:
1)静态RAM(SRAM),SRAM速度非常快,是目前读写最快的存储设备了,但是它也非常昂贵,所以只在要求很苛刻的地方使用,譬如CPU的一级缓冲,二级缓冲。
2)动态RAM(DRAM),DRAM保留数据的时间很短,速度也比SRAM慢,不过它还是比任何的ROM都要快,但从价格上来说DRAM相比SRAM要便宜很多,计算机内存就是DRAM的。
3、FLASH,又称闪存,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还不会断电丢失数据同时可以快速读取数据(NVRAM的优势),U盘和MP3里用的就是这种存储器。在过去的20年里,嵌入式系统一直使用ROM(EPROM)作为它们的存储设备,然而近年来Flash全面代替了ROM(EPROM)在嵌入式系统中的地位,它用作存储Bootloader以及操作系统或者程序代码,或者直接当硬盘使用(U盘)。

AHB (Advanced High-performance Bus高级高性能总线) 主要是针对高效率、高频宽及快速系统模块所设计的总线,它可以连接如微处理器、芯片上或芯片外的内存模块和DMA等高效率模块。
APB (Advanced Peripheral Bus高级外围总线) 主要用在低速且低功率的外围,可针对外围设备作功率消耗及复杂接口的最佳化。APB在AHB和低带宽的外围设备之间提供了通信的桥梁,所以APB是AHB的二级拓展总线。

2、GPIO

1)概念

GPIO英文为General Purpose Input Output,称为通用输入/输出
stm32f103zet6包含112个GPIO(stm32f103zet6有144个引脚,其中有11个VSS、11个VDD、还有10个其他用途的引脚分别是VBAT、OSC_IN、OSC_OUT、NRST、Vref+、Vref-、VDDA、VSSA、BOOT0、NC),112个GPIO分别是PA[0..15]~PG[0..15],stm32f103zet6引脚图如下:

2)如何使用

stm32单片机是操作寄存器来控制IO口的,首先我们应该知道GPIO的寄存器地址为多少,下表中记录了STM32F10ZET6中内置外设的起始地址。

从图中我们可以看到GPIO起始地址是0x40010800,在系统库函数stm32f10x.h中为我们定义了宏定义,方便我们操作寄存器控制外设,stm32f10x.h中的GPIOx定义如下

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)#define GPIOA_BASE            (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE            (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE            (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE            (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE            (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE            (APB2PERIPH_BASE + 0x2000)#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD               ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE               ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF               ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG               ((GPIO_TypeDef *) GPIOG_BASE)typedef struct
{__IO uint32_t CRL;__IO uint32_t CRH;__IO uint32_t IDR;__IO uint32_t ODR;__IO uint32_t BSRR;__IO uint32_t BRR;__IO uint32_t LCKR;
} GPIO_TypeDef;typedef enum
{ GPIO_Mode_AIN = 0x0,GPIO_Mode_IN_FLOATING = 0x04,GPIO_Mode_IPD = 0x28,GPIO_Mode_IPU = 0x48,GPIO_Mode_Out_OD = 0x14,GPIO_Mode_Out_PP = 0x10,GPIO_Mode_AF_OD = 0x1C,GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;typedef enum
{ GPIO_Speed_10MHz = 1,GPIO_Speed_2MHz, GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;typedef struct
{uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.This parameter can be any value of @ref GPIO_pins_define */GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.This parameter can be a value of @ref GPIOSpeed_TypeDef */GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

上述代码定义了8个GPIO的访问地址GPIOA~GPIOG,同时定义了每个GPIO 16个引脚的选择码,同时还可以看到定义了几个GPIO相关的结构体,分别是GPIO_TypeDef、GPIO_InitTypeDef、GPIOMode_TypeDef、GPIOSpeed_TypeDef,下面会对每个结构体做一下更细的介绍。

① GPIO寄存器介绍(GPIO_TypeDef)
typedef struct
{__IO uint32_t CRL;__IO uint32_t CRH;__IO uint32_t IDR;__IO uint32_t ODR;__IO uint32_t BSRR;__IO uint32_t BRR;__IO uint32_t LCKR;
} GPIO_TypeDef;

从库给出的结构体结合芯片手册,我们知道GPIO端口有:

  • 2个32位 配置寄存器 CRL、CRH
    CRL控制每个IO口低8位引脚的模式(例如控制GPIOA的0~7引脚),CRH控制每个IO口高8位引脚的模式(例如控制GPIOA8~15引脚),下图是对CRL/CRH的截图说明

    CRL:结构体偏移地址0x00、(默认)复位值0x44444444,即默认为浮空输入模式
    CRH:结构体偏移地址0x04、(默认)复位值0x44444444,即默认为浮空输入模式
    注:IO口的模式与硬件电路有关,在此不细说了(本人目前对这些模式具体应用场景也没有很清晰的感念,即在此不详述了)

  • 2个32位 数据寄存器 IDR、ODR
    IDR:端口输入寄存器,只用了低16位。该寄存器为只读寄存器,并且只能以16位的形式读出。该寄存器描述如下图:

    ODR:端口输出数据寄存器,只用了低16位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前IO口的输出状态。而向该寄存器写数据,则可以控制某个IO口的输出电平。

  • 1个32位 置位/复位寄存器 BSRR
    可以用来设置GPIO端口的输出位是1还是0.

    该寄存器往相应的位写0是无影响的,所以我们要设置某些位,不用管其他位的值。例如设置GPIOA的GPIO_Pin_1引脚值为1,即往低16位写1即可。

    GIPOA->BSRR=1<<1;

    设置GPIOA的GPIO_Pin_1引脚值为0,即往寄存器高16位写1即可,而不是往第十六为写0。

    GIPOA->BSRR=1<<(16+1);
  • 1个16位 复位寄存器 BRR
    该寄存器是端口位清除寄存器,其作用跟BSRR的高16位雷同。
  • 1个32位 锁定寄存器 LCKR
    当执行正确的写序列设置了位16(LCKK)时,该寄存器用来锁定端口位的配置。位[15:0]用于锁定GPIO端口的配置。在规定的写入操作期间,不能改变LCKP[15:0]。当对相应的端口位执行了LOCK序列后,在下次系统复位之前将不能再更改端口位的配置。 每个锁定位锁定控制寄存器(CRL, CRH)中相应的4个位。
②库函数编程(GPIO_InitTypeDef、GPIOMode_TypeDef、GPIOSpeed_TypeDef)

上面①中给我们详细介绍了GPIO寄存器的相应的功能,在了解之后我们即可直接操作寄存器写自己的IO控制程序了,如跑马灯的程序我们就可按如下代码编写:

RCC->APB2ENR|=1<<3;    //使能PORTB时钟
RCC->APB2ENR|=1<<6;    //使能PORTE时钟GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5;      //PB.5 输出高GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000;//PE.5推挽输出
GPIOE->ODR|=1<<5;      //PE.5输出高
while(1)
{GPIOB->BRR=GPIO_Pin_5;//LED0亮GPIOE->BSRR=GPIO_Pin_5;//LED1灭delay_ms(300);GPIOB->BSRR=GPIO_Pin_5;//LED0灭GPIOE->BRR=GPIO_Pin_5;//LED1亮delay_ms(300);}

stm32有上百个寄存器,每次编程都需要翻手册在编程可想象这种场景应该很恐怖,故官方为我们提供了相应的库函数,这些函数将寄存器的操作封装,即可靠又方便使用。
GPIO官方为我们提供了如下几个库函数

/** @defgroup GPIO_Exported_Functions**/
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
void GPIO_AFIODeInit(void);
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_EventOutputCmd(FunctionalState NewState);
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);

GPIO相应的库函数很多,可以查看手册或示例了解使用方法,跑马灯程序使用到的函数有:

//用来设置GPIO端口的模式
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
//用来给GPIO端口设置1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//用来给GPIO端口设置0
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

跑马灯库函数程序

GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);   //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);                   //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5);                      //PB.5 输出高GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);                   //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5);                          //PE.5 输出高while(1)
{GPIO_ResetBits(GPIOB,GPIO_Pin_5);  //LED0对应引脚GPIOB.5拉低,亮  等同LED0=0;GPIO_SetBits(GPIOE,GPIO_Pin_5);   //LED1对应引脚GPIOE.5拉高,灭 等同LED1=1;delay_ms(300);             //延时300msGPIO_SetBits(GPIOB,GPIO_Pin_5);    //LED0对应引脚GPIOB.5拉高,灭  等同LED0=1;GPIO_ResetBits(GPIOE,GPIO_Pin_5); //LED1对应引脚GPIOE.5拉低,亮 等同LED1=0;delay_ms(300);                     //延时300ms
}

3、板子原理图确定GPIO端口

看了跑马灯的代码估计很多人会发出疑问:怎么知道操作的是GPIOB的GPIO_Pin_5去控制一个灯,操作GPIOE的GPIO_Pin_5去控制另外一个灯。
针对这个疑问,解决方法是 我们必须看所使用的板子的原理图了,我使用的板子关于LED灯的原理图如下:

控制LED灯的stm32芯片部分原理图

从上面两个图可以看出,我所使用的板子已将LED与stm32f103芯片连接好了。LED0接PB5,所以我们使用的是GPIOB、GPIO_Pin_5这两个宏定义,代表PB5。
LED1接PE5,所以我们使用的是GPIOE、GPIO_Pin_5这两个宏定义,代表PE5。

4、时钟

从跑马灯程序中我们看到以下代码:

/** **使用寄存器初始化时钟**
RCC->APB2ENR|=1<<3;    //使能PORTB时钟
RCC->APB2ENR|=1<<6;    //使能PORTE时钟
**/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);   //使能PB,PE端口时钟

之所以在程序开头要开启时钟,是因为任何MCU的任何外设都需要有时钟 ,STM32为了让用户更好地掌握功耗,对每个外设的时钟都设置了开关,所以我们在使用外设(GPIO)前需要开启时钟(51单片机不用配置IO时钟,只是因为默认使用同一个时钟)
下图是RCC_APB2ENR外设时钟使能寄存器图

单片机入门学习五 STM32单片机学习二 跑马灯程序衍生出的stm32编程基础相关推荐

  1. STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结

    摘自:STM32F103五分钟入门系列(一)跑马灯(库函数+寄存器)+加编程模板+GPIO总结 作者:自信且爱笑' 发布时间: 2021-04-28 21:17:40 网址:https://blog. ...

  2. 《51单片机应用开发从入门到精通》——2.2 跑马灯实例

    本节书摘来自异步社区<51单片机应用开发从入门到精通>一书中的第2章,第2.2节,作者 张华杰,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.2 跑马灯实例 ...

  3. stc51单片机入门 c语言,STC51单片机入门 (C语言)

    51单片机发展主要历程:AT89C51系列--STC89C52系列--STC90系列--STC11系列--STC12系列--STC15F系列--STC15W系列(最新主流),由于STC12系列功能已经 ...

  4. 【2021最全】51单片机入门+驱动下载安装+keil下载配置+烧入程序教程

    注:我不是标题党 文章目录 入门 1. 装驱动 2. 新建项目 3.项目配置 4. 新建c程序 5. 第一个程序 6. 烧入程序 6.1 设置选择芯片型号 6.2 选择烧入的程序(就是hex文件) 6 ...

  5. 单片机跑马灯程序c语言,MCS-51单片机控制跑马灯的三种方法

    描述 在MCS一51单片机的控制系统中,它的四个并行8位输入输出端口P0一P3是我们经常使用的.在并行端口的编程学习中,"跑马灯"是单片机并行端口输出控制的典型实例.所谓跑马灯,是 ...

  6. 【前端学习日记】利用Vue实现跑马灯的效果

    一.效果 按下roll按钮,文字进行滚动: 按下stop按钮,文字停止滚动: 二.重要代码 1.通过以下方式引入Vue <!-- 开发环境版本,包含了有帮助的命令行警告 --> <s ...

  7. Vue学习笔记(一):跑马灯的实现

    首先根据vue的基础框架搭建出需要呈现的文件(将需要进行跑马灯操作的程序进行文字呈现) 程序分析: 1. 给 [触发] 按钮,绑定一个点击事件   v-on 2. 在按钮的事件处理函数中,写相关的业务 ...

  8. STM32(1)跑马灯

    建立LED初始化头文件 建立头文件有点像C++中,头文件中可以添加宏定义以及函数原型,然后在.c文件中写入函数定义 "sys.h" "sys.h"这个头文件中# ...

  9. pytorch学习五、深度学习计算

    来自于 https://tangshusen.me/Dive-into-DL-PyTorch/#/ 官方文档 https://pytorch.org/docs/stable/tensors.html ...

最新文章

  1. Openstack贡献者须知 2 — 社区工作运作 代码贡献流程
  2. uva 11992 - Fast Matrix Operations
  3. linux安装python3.7的步骤_Linux 安装python3.7.3
  4. 苹果发布 macOS 12——Monterey
  5. 从Eclipse切换到IDEA后需要做的事情
  6. 随想录(快速使用lua)
  7. SAP License:烟草行业ERP选型
  8. Tensorrt7: AttributeError: ‘NoneType‘ object has no attribute ‘create_execution_context‘
  9. android apk 防止反编译技术加壳技术(转)
  10. Matlab45度边缘连接,为什么Matlab的delaunayn()的delaunay边缘与非相邻的Voronoi区域连接点?...
  11. 互联网开发人员压力到底有多大?
  12. html5 游戏 算法,JS/HTML5游戏常用算法之路径搜索算法 A*寻路算法完整实例
  13. 无IDE时,使用支持HTML5的浏览器作编辑器的方法
  14. gauscoor软件怎么用_高斯坐标经纬度转换器
  15. 韩顺平java学习day1
  16. iOS新闻类App内容页技术探索
  17. BAT实现文件下载功能
  18. 阿里云——云迁移中心
  19. #define的用法
  20. 项目管理界最经典教材——PMBOK指南,如果现在备考PMP看哪一版?

热门文章

  1. 多事之秋----为什么受伤又是华为
  2. [FMG]ADT-eclipse升级为可以添加javaWeb
  3. Presto常用语句整理
  4. ubuntu下载神器---xdm
  5. matplotlib之pyplot模块之坐标轴配置(axis():设置坐标轴外观、设置坐标轴范围)
  6. 【windows】windows创建软件raid0
  7. PHP将word文件转为图片预览
  8. 麻省理工学院计算机博士奖学金,NWU这位高颜值学霸小姐姐,获麻省理工博士全额奖学金录取!...
  9. 大话赛宁云 | 培训服务打造实战型网络安全人才
  10. MIPI 系列之 D-PHY