一、SPI Flash与QSPI FLASH

1、首先说说FLASH,不管是QSPI Flash还是SPI Flash说的实际上是一种闪存芯片,比如最常见的W25Q128(下图),真正不同的是SPI协议与QSPI协议罢了。可以看到下图的芯片,2、3、5、7这四个引脚是可以复用的,根据不同的通信协议变换功能。

W25Q128 是华邦公司推出的大容量 SPI FLASH 产品,W25Q128 的容量为 128Mb,该系列还有 W25Q80/16/32/64 等。

W25Q128 将 16M 的容量分为 256 个块(Block),每个块大小为 64K 字节,每个块又分为16 个扇区(Sector),每个扇区 4K 个字节。W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作(SRAM:静态随机存取存储器(Static Random-Access Memory,SRAM)是随机存取存储器的一种。所谓的“静态”,是指这种存储器只要保持通电,里面储存的数据就可以恒常保持。)。

W25Q128 的擦写周期多达 10W 次,具有 20 年的数据保存期限,支持电压为2.7~ 3.6V,W25Q128 支持标准的 SPI,还支持双输出/四输出的 SPI,最大 SPI 时钟可以到 80Mhz(双输出时相当于 160Mhz,四输出时相当于 320M)。

  1. SPI与FLASH的通信方式:

SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

如下图所示,标椎的SPI接口一般使用四条信号线通信:

SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)

MISO: 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。

MOSI: 主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。

SCLK:串行时钟信号,由主设备产生。

CS/SS:从设备片选信号,由主设备控制。它的功能是用来作为“片选引脚”,也就是选择指定的从设备,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。

  1. QSPI与FLASH的通信方式:

所谓QSPI是Queued SPI的简写,是Motorola公司推出的SPI接口的扩展,比SPI应用更加广泛。在SPI协议的基础上,Motorola公司对其功能进行了增强,增加了队列传输机制,推出了队列串行外围接口协议(即QSPI协议)。QSPI 是一种专用的通信接口,连接单、双或四(条数据线)SPI Flash 存储介质。

该接口可以在以下三种模式下工作:

① 间接模式:使用 QSPI 寄存器执行全部操作

② 状态轮询模式:周期性读取外部 Flash 状态寄存器,而且标志位置 1 时会产生中断(如擦除或烧写完成,会产生中断)

③ 内存映射模式:外部 Flash 映射到微控制器地址空间,从而系统将其视作内部存储器

采用双闪存模式时,将同时访问两个 Quad-SPI Flash,吞吐量和容量均可提高二倍。

二、QSPI协议功能框图

QSPI 使用 6 个信号连接Flash,分别是四个数据线BK1_IO0~BK1_IO3,一个时钟输出CLK,一个片选输出(低电平有效)BK1_nCS,它们的作用介绍如下:

(1) BK1_nCS:片选输出(低电平有效),适用于 FLASH 1。如果 QSPI 始终在双闪存模式下工作,则其也可用于 FLASH 2从设备选择信号线。QSPI通讯以BK1_nCS线置低电平为开始信号,以BK1_nCS线被拉高作为结束信号。

(2) CLK:时钟输出,适用于两个存储器,用于通讯数据同步。它由通讯主机产生,决定了通讯的速率,不同的设备支持的最高时钟频率不一样,如STM32的QSPI时钟频率最大为fpclk/2,两个设备之间通讯时,通讯速率受限于低速设备。

(3) BK1_IO0:在双线 / 四线模式中为双向 IO,单线模式中为串行输出。

(4) BK1_IO1:在双线 / 四线模式中为双向 IO,单线模式中为串行输入。

(5) BK1_IO2:在四线模式中为双向 IO。

(6) BK1_IO3:在四线模式中为双向 IO。

二、QSPI初始化结构体详解

跟其它外设一样,STM32 HAL库提供了QSPI初始化结构体及初始化函数来配置SPI外设。初始化结构体及函数定义在库文件“stm32f7xx_hal_spi.h”及“stm32f7xx_hal _spi.c”中,编程时我们可以结合这两个文件内的注释使用或参考库帮助文档。了解初始化结构体后我们就能对SPI外设运用自如了,见代码清单 241。

a、 QSPI_InitTypeDef初始化结构体

1 typedef struct {2     uint32_t ClockPrescaler;     //预分频因子3     uint32_t FifoThreshold;      //FIFO中的阈值4     uint32_t SampleShifting;     //采样移位5     uint32_t FlashSize;          //Flash大小6     uint32_t ChipSelectHighTime; //片选高电平时间7     uint32_t ClockMode;          //时钟模式8     uint32_t FlashID;            //Flash ID9     uint32_t DualFlash;          //双闪存模式
10 } QSPI_InitTypeDef;

这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 HAL库中定义的宏:

(1) ClockPrescaler

本成员设置预分频因子,对应寄存器QUADSPI_CR [31:24]即PRESCALER[7:0],取值范围是0—255,可以实现1—256级别的分频。仅可在 BUSY = 0 时修改该字段。

(2) FifoThreshold

本成员设置FIFO 阈值级别,对应寄存器QUADSPI_CR [12:8]即FTHRES[4:0],定义在间接模式下 FIFO 中将导致 FIFO 阈值标志(FTF,QUADSPI_SR[2])置 1 的字节数阈值。

(3) SampleShifting

本成员设置采样,对应寄存器QUADSPI_CR [4],默认情况下,QUADSPI 在 Flash 驱动数据后过半个 CLK 周期开始采集数据。使用该位,可考虑外部信号延迟,推迟数据采集。可以取值0:不发生移位;1:移位半个周期。在 DDR 模式下 (DDRM = 1),固件必须确保 SSHIFT = 0。

(4) FlashSize

本成员设置FLASH大小,对应寄存器QUADSPI_CCR [20:16]的FSIZE[4:0]位。定义外部存储器的大小,简介模式Flash容量最高可达4GB(32位寻址),但是在内存映射模式下限制为256MB,如果是双闪存则可以达到512MB。

(5) ChipSelectHighTime

本成员设置片选高电平时间,对应寄存器QUADSPI_CR [10:8]的CSHT[2:0]位,定义片选 (nCS) 在发送至 Flash 的命令之间必须保持高电平的最少 CLK 周期数。可以取值1~8个周期。

(6) ClockMode

本成员设置时钟模式,对应寄存器QUADSPI_CR [0]位,指示CLK在命令之间的电平,可以选模式0,1: nCS 为高电平(片选释放)时,CLK 必须保持低电平;或者模式3 ,1:nCS 为高电平(片选释放)时,CLK 必须保持高电平。

(7) FlashID

本成员用于选择Flash1或者Flash2,单闪存模式下选择需要访问的flash。

(8) DualFlash

本成员用于激活双闪存模式,0:禁止双闪存模式;1:使能双闪存模式。双闪存模式可以使系统吞吐量和容量扩大一倍。

b、QSPI_CommandTypeDe通信配置命令结构体

1 typedef struct {2     uint32_t Instruction;        //指令3     uint32_t Address;            //地址4     uint32_t AlternateBytes;     //交替字节5     uint32_t AddressSize;        //地址长度6     uint32_t AlternateBytesSize; //交替字节长度7     uint32_t DummyCycles;        //空指令周期8     uint32_t InstructionMode;    //指令模式9     uint32_t AddressMode;        //地址模式
10     uint32_t AlternateByteMode;  //交替字节模式
11     uint32_t DataMode;           //数据模式
12     uint32_t NbData;             //数据长度
13     uint32_t DdrMode;            //双倍数据速率模式
14     uint32_t DdrHoldHalfCycle;   //DDR保持周期
15     uint32_t SIOOMode;           //仅发送指令一次模式
16 } QSPI_CommandTypeDef; 

这些结构体成员说明如下,其中括号内的文字是对应参数在STM32 HAL库中定义的宏:

(1) Instruction

本成员设置通信指令,指定要发送到外部 SPI 设备的指令。仅可在 BUSY = 0 时修改该字段。

(2) Address

本成员指定要发送到外部 Flash 的地址,BUSY = 0 或 FMODE = 11(内存映射模式)时,将忽略写入该字段。在双闪存模式下,由于地址始终为偶地址,ADDRESS[0] 自动保持为“0”。

(3) AlternateBytes

本成员指定要在地址后立即发送到外部 SPI 设备的可选数据,仅可在 BUSY = 0 时修改该字段。

(4) AddressSize

本成员定义地址长度,可以是8位,16位,24位或者32位。

(5) AlternateBytesSize

本成员定义交替字节长度,可以是8位,16位,24位或者32位。

(6) DummyCycles

本成员定义空指令阶段的持续时间,在 SDR 和 DDR 模式下,它指定 CLK 周期数 (0-31)。

(7) InstructionMode

本成员定义指令阶段的操作模式,00:无指令;01:单线传输指令;10:双线传输指令;11:四线传输指令。

(8) AddressMode

本成员定义地址阶段的操作模式,00:无地址;01:单线传输地址;10:双线传输地址;11:四线传输地址。

(9) AlternateByteMode

本成员定义交替字节阶段的操作模式00:无交替字节;01:单线传输交替字节;10:双线传输交替字节;11:四线传输交替字节。

(10) DataMode

本成员定义数据阶段的操作模式,00:无数据;01:单线传输数据;10:双线传输数据;11:四线传输数据。该字段还定义空指令阶段的操作模式。

(11) NbData

本成员设置数据长度,在间接模式和状态轮询模式下待检索的数据数量(值 + 1)。对状态轮询模式应使用不大于 3 的值(表示 4 字节)。

(12) DdrMode

本成员为地址、交替字节和数据阶段设置 DDR 模式,0:禁止 DDR 模式;1:使能 DDR 模式。

(13) DdrHoldHalfCycle

本成员设置DDR 模式下数据输出延迟 1/4 个 QUADSPI 输出时钟周期,0:使用模拟延迟来延迟数据输出;1:数据输出延迟 1/4 个 QUADSPI 输出时钟周期。仅在 DDR 模式下激活。

(14) SIOOMode

本成员设置仅发送指令一次模式,。IMODE = 00 时,该位不起作用。0:在每个事务中发送指令;1:仅为第一条命令发送指令。

三、QSPI—读写串行FLASH实验

(1) 初始化通讯使用的目标引脚及端口时钟;

      GPIO_InitTypeDef GPIO_InitStruct;/* 使能 QSPI 及 GPIO 时钟 */QSPI_FLASH_CLK_ENABLE();QSPI_FLASH_CLK_GPIO_ENABLE();QSPI_FLASH_BK1_IO0_CLK_ENABLE();QSPI_FLASH_BK1_IO1_CLK_ENABLE();QSPI_FLASH_BK1_IO2_CLK_ENABLE();QSPI_FLASH_BK1_IO3_CLK_ENABLE();QSPI_FLASH_CS_GPIO_CLK_ENABLE();

(2) 配置SPI外设的模式、地址、速率等参数并使能SPI外设;

     /* QSPI_FLASH 模式配置 */QSPIHandle.Instance = QUADSPI;QSPIHandle.Init.ClockPrescaler = 2;QSPIHandle.Init.FifoThreshold = 4;QSPIHandle.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;QSPIHandle.Init.FlashSize = 23;QSPIHandle.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_8_CYCLE;QSPIHandle.Init.ClockMode = QSPI_CLOCK_MODE_0;HAL_QSPI_Init(&QSPIHandle);

(3)初始化QSPI接口;

uint8_t BSP_QSPI_Init(void){QSPI_CommandTypeDef s_command;uint8_t value = W25Q128FV_FSR_QE;/* QSPI存储器复位 */if (QSPI_ResetMemory() != QSPI_OK) {return QSPI_NOT_SUPPORTED;}/* 使能写操作 */if (QSPI_WriteEnable() != QSPI_OK) {return QSPI_ERROR;}/* 设置四路使能的状态寄存器,使能四通道IO2和IO3引脚 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = WRITE_STATUS_REG2_CMD;s_command.AddressMode       = QSPI_ADDRESS_NONE;s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;s_command.DataMode          = QSPI_DATA_1_LINE;s_command.DummyCycles       = 0;s_command.NbData            = 1;s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;/* 配置命令 */if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){return QSPI_ERROR;}/* 传输数据 */if (HAL_QSPI_Transmit(&QSPIHandle, &value, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){return QSPI_ERROR;}/* 自动轮询模式等待存储器就绪 */if (QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) {return QSPI_ERROR;}return QSPI_OK;}

(4) 编写基本SPI按字节收发的函数;

 /**接收函数* @brief  从QSPI存储器中读取大量数据.* @param  pData: 指向要读取的数据的指针* @param  ReadAddr: 读取起始地址* @param  Size: 要读取的数据大小* @retval QSPI存储器状态*/uint8_t BSP_QSPI_Read(uint8_t* pData, uint32_t ReadAddr, uint32_t Size){QSPI_CommandTypeDef s_command;/* 初始化读命令 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = READ_CMD;s_command.AddressMode       = QSPI_ADDRESS_1_LINE;s_command.AddressSize       = QSPI_ADDRESS_24_BITS;s_command.Address           = ReadAddr;s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;s_command.DataMode          = QSPI_DATA_1_LINE;s_command.DummyCycles       = 0;s_command.NbData            = Size;s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;/* 配置命令 */
if (HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK){return QSPI_ERROR;}/* 接收数据 */if(HAL_QSPI_Receive(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE)!= HAL_OK) {return QSPI_ERROR;}return QSPI_OK;}发送函数/*** @brief  将大量数据写入QSPI存储器* @param  pData: 指向要写入数据的指针* @param  WriteAddr: 写起始地址* @param  Size: 要写入的数据大小* @retval QSPI存储器状态*/uint8_t BSP_QSPI_Write(uint8_t* pData, uint32_t WriteAddr, uint32_t Size){QSPI_CommandTypeDef s_command;uint32_t end_addr, current_size, current_addr;/* 计算写入地址和页面末尾之间的大小 */current_addr = 0;while (current_addr <= WriteAddr) {current_addr += W25Q128FV_PAGE_SIZE;}current_size = current_addr - WriteAddr;/* 检查数据的大小是否小于页面中的剩余位置 */if (current_size > Size) {current_size = Size;}/* 初始化地址变量 */current_addr = WriteAddr;end_addr = WriteAddr + Size;/* 初始化程序命令 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = QUAD_INPUT_PAGE_PROG_CMD;s_command.AddressMode       = QSPI_ADDRESS_1_LINE;s_command.AddressSize       = QSPI_ADDRESS_24_BITS;s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;s_command.DataMode          = QSPI_DATA_4_LINES;s_command.DummyCycles       = 0;s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;/* 逐页执行写入 */do {s_command.Address = current_addr;s_command.NbData  = current_size;/* 启用写操作 */if (QSPI_WriteEnable() != QSPI_OK) {return QSPI_ERROR;}/* 配置命令 */if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 传输数据 */if(HAL_QSPI_Transmit(&QSPIHandle, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 配置自动轮询模式等待程序结束 */if(QSPI_AutoPollingMemReady(HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != QSPI_OK) {return QSPI_ERROR;}/* 更新下一页编程的地址和大小变量 */current_addr += current_size;pData += current_size;current_size = ((current_addr + W25Q128FV_PAGE_SIZE) > end_addr) ? (end_addr-current_addr) : W25Q128FV_PAGE_SIZE;} while (current_addr < end_addr);return QSPI_OK;}

(5) 编写对FLASH擦除及读写操作的的函数;

由于FLASH存储器的特性决定了它只能把原来为“1”的数据位改写成“0”,而原来为“0”的数据位不能直接改写为“1”。所以这里涉及到数据“擦除”的概念,在写入前,必须要对目标存储矩阵进行擦除操作,把矩阵中的数据位擦除为“1”,在数据写入的时候,如果要存储数据“1”,那就不修改存储矩阵 ,在要存储数据“0”时,才更改该位。

通常,对存储矩阵擦除的基本操作单位都是多个字节进行,如本例子中的FLASH芯片支持“扇区擦除”、“块擦除”以及“整片擦除”,

扇区擦除指令的第一个字节为指令编码,紧接着发送的3个字节用于表示要擦除的存储矩阵地址。要注意的是在扇区擦除指令前,还需要先发送“写使能”指令,发送扇区擦除指令后,通过读取寄存器状态等待扇区擦除操作完毕。

/*** @brief  擦除QSPI存储器的指定块* @param  BlockAddress: 需要擦除的块地址* @retval QSPI存储器状态*/
uint8_t BSP_QSPI_Erase_Block(uint32_t BlockAddress)
{QSPI_CommandTypeDef s_command;/* 初始化擦除命令 */s_command.InstructionMode   = QSPI_INSTRUCTION_1_LINE;s_command.Instruction       = SECTOR_ERASE_CMD;s_command.AddressMode       = QSPI_ADDRESS_1_LINE;s_command.AddressSize       = QSPI_ADDRESS_24_BITS;s_command.Address           = BlockAddress;s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;s_command.DataMode          = QSPI_DATA_NONE;s_command.DummyCycles       = 0;s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;/* 启用写操作 */if (QSPI_WriteEnable() != QSPI_OK) {return QSPI_ERROR;}/* 发送命令 */
if(HAL_QSPI_Command(&QSPIHandle, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) {return QSPI_ERROR;}/* 配置自动轮询模式等待擦除结束 */if (QSPI_AutoPollingMemReady(W25Q128FV_SUBSECTOR_ERASE_MAX_TIME) != QSPI_OK) {return QSPI_ERROR;}return QSPI_OK;
}

STM32的QSPI通信(学习笔记)相关推荐

  1. STM32 CAN总线通信学习笔记(一)

    STM32 CAN总线通信学习笔记(一) 一.CAN总线简介 CAN 是控制器局域网络(Controller Area Network, CAN)的简称.CAN采用数据块编码的方式,数据块根据帧的类型 ...

  2. 基于STM32的CAN总线通信学习笔记

    转自:https://blog.csdn.net/ludaoyi88/article/details/53350077 基于STM32的CAN总线通信学习笔记 本文主要简单介绍CAN总线的相关概念,以 ...

  3. STM32 LCD中英文字符显示学习笔记

    本实验基于STM32 LCD英文字符显示学习笔记. 开发板:野火指南者(STM32F103VE) STM32库版本:STM32F10x_StdPeriph_Lib_V3.5.0 IDE:KEIL5(代 ...

  4. CAN总线通信学习笔记

    CAN总线通信学习笔记 完整笔记链接:https://mubu.com/doc/67Rn6yaozhS CAN总线笔记目录 定义 底层原理 CAN信号传输 发送 接收 CAN总线结构.特点.分类 CA ...

  5. 【STM32】OV2640摄像头学习笔记 转

    [STM32]OV2640摄像头学习笔记 2019年03月03日 13:01:35 淹死的大白鲨 阅读数 4736更多 分类专栏: [STM32] 版权声明:本文为博主原创文章,遵循 CC 4.0 B ...

  6. openmv与stm32之间的通信学习(数字识别)

    前提:软件安装与学习视频讲解 在我们使用openmv中的神经网络时,在新的版本里是没有nn的库给你调用的,需要在老版本里才有,百度云链接:https://pan.baidu.com/s/1bgLiLM ...

  7. stm32正常运行流程图_stm32学习笔记之问题总结

    1. SYSCLK时钟源有三个来源:HSI RC.HSE OSC.PLL; 2. MCO[2:0]可以提供4源不同的时钟同步信号; 3. GPIO口貌似有两个反向串联的二极管用作钳位二极管; 4. 总 ...

  8. STM32 HAL库开发学习笔记: USART1串口通讯(中断方式) IDE-STM32CubeIDE

    STM32串口通讯有三种方式,分别为阻塞(轮询).中断.DMA.这里将用中断的方式开发. 笔者也是刚入门STM32 HAL库开发,该笔记致希望于能帮到初学者,文中配置步骤.代码.实验现象均是笔者实践可 ...

  9. i2c hid 触摸板不能用_I2C 总线协议初探 - STM32 I2C 接口外设学习笔记

    I2C(Inter-Integrated Circuit)总线是由 PHILIPS(飞利浦) 公司开发的两线式串行总线,用于连接微控制器及其外围设备.是微电子通信控制领域广泛采用的一种总线标准.它是同 ...

最新文章

  1. 三国演义人物出场统计代码含义_实例2之《三国演义》人物出场统计
  2. 在此处打开命令窗口_这样操作方便多了!简单DOS命令实用技巧详解
  3. wpf中groupbox有什么用_环境中的硫化氢用什么检测好
  4. 一个不错的游戏 - flash webgame
  5. 【SP26073】DIVCNT1 - Counting Divisors 题解
  6. go kegg_工具篇丨GO和KEGG富集不到通路?快试试这个超赞的功能分析工具吧
  7. 创业公司用 Serverless,到底香不香?
  8. mysql基础和高级整理_mysql基础整理01
  9. PLSQL连接oracel数据库_用户无法登陆_oci.dll_配置问题
  10. php curl 发送post请求带参数
  11. [CQOI2017]小Q的棋盘
  12. java in 绑定变量_ng-model绑定的变量在controller中为undefined
  13. xcode模拟器不显示键盘解决方案
  14. [windows]mstsc远程报:这可能是由于CredSSP 加密Oracle修正的解决方法
  15. 编译器错误信息:CS0016:未能写入输出文件 c:\WINDOWS\Microsoft.NET\Framework\...的解决办法...
  16. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面...
  17. Voip中的音频Codec技术
  18. 如何从阿里巴巴矢量图标库引入图标
  19. 笔记本电脑突然搜索不到无线网信号怎么办?
  20. 三国时代微博(佩服博主琢磨先生太有才了!)

热门文章

  1. 打不开regedit.exe、gpedit.msc和taskmgr.exe的解决方法
  2. 蓝牙耳机芯片,苹果弹窗电量显示为0的解决方法
  3. 杂谈---LZ的编程之路以及十点建议
  4. 3. 使用DSPack打开摄像头
  5. HttpClient的使用案例-图片下载
  6. 手机怎么查看已经记住的WiFi密码?手机查看wifi密码三种方法介绍(图文)
  7. 非洛达芯片检测聚合教程NOT AIROHA CHIP
  8. sound、noise、voice的区别
  9. 飛飛(四十一)建立一个Point类,包含数据成员x,y.......
  10. 一门改考三门!西安电子科技大学网络与信息安全学院