STM32之SPI的使用
2016-12-13 23:05
281 查看
通常SPI通过4个引脚与外部器件相连:
● MISO:主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。● MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
● SCK:串口时钟,作为主设备的输出,从设备的输入
●NSS:从设备选择。这是一个可选的引脚,用来选择主/从设备。它的功能是用来作为“片选引脚”,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突。从设备的NSS引脚可以由主设备的一个标准I/O引脚来驱动。一旦被使能(SSOE位),NSS引脚也可以作为输出引脚,并在SPI处于主模式时拉低;此时,所有的SPI设备,如果它们的NSS引脚连接到主设备的NSS引脚,则会检测到低电平,如果它们被设置为NSS硬件模式,就会自动进入从设备状态。当配置为主设备、NSS配置为输入引脚(MSTR=1,SSOE=0)时,如果NSS被拉低,则这个SPI设备进入主模式失败状态:即MSTR位被自动清除,此设备进入从模式。
注意:
在改变CPOL/CPHA位之前,必须清除SPE位将SPI禁止。主和从必须配置成相同的时序模式。
3.SCK的空闲状态必须和SPI_CR1寄存器指定的极性一致(CPOL为’1’时,空闲时应上拉SCK为高电平;CPOL为’0’时,空闲时应下拉SCK为低电平)。
数据帧格式(8位或16位)由SPI_CR1寄存器的DFF位选择,并且决定发送/接收的数据长度。
编程实现:
#define SPI1_SCK_PORT GPIOA #define SPI1_SCK_PIN GPIO_Pin_5 #define SPI1_MISO_PORT GPIOA #define SPI1_MISO_PIN GPIO_Pin_6 //MISO 主设备输入从设备输出 #define SPI1_MOSI_PORT GPIOA #define SPI1_MOSI_PIN GPIO_Pin_7 //MOSI 主设备输出 从设备输入 #define SPI1_APB2_GPIO RCC_APB2Periph_GPIOA //SPI1所在管脚时钟 #define SPI2_SCK_PORT GPIOB #define SPI2_SCK_PIN GPIO_Pin_13 #define SPI2_MISO_PORT GPIOB #define SPI2_MISO_PIN GPIO_Pin_14 #define SPI2_MOSI_PORT GPIOB #define SPI2_MOSI_PIN GPIO_Pin_15 #define SPI2_APB1_GPIO RCC_APB2Periph_GPIOB //SPI2所在管脚时钟 class SPI { private: SPI_TypeDef *spiX; SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; public: SPI(); ~SPI(); SPI(SPI_TypeDef *spi); uint8_t SPISendByte(uint8_t sendByte); }; // 函数:SPI // 功能:初始化SPI外设 // 返回: // 参数: SPIX // SPI::SPI(SPI_TypeDef *spi) { spiX = spi; if (spi==SPI1) { SPI_Cmd(SPI1, DISABLE); //禁用SPI外设 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //使能SPI外设APB2 RCC_APB2PeriphClockCmd(SPI1_APB2_GPIO | RCC_APB2Periph_AFIO, ENABLE); //使能复用时钟AFIO SPI1所在管脚时钟 GPIO_InitStructure.GPIO_Pin = SPI1_MOSI_PIN; // MOSI(主设备输出 从设备输入) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度 GPIO_Init(SPI1_MOSI_PORT, &GPIO_InitStructure); //初始化GPIO GPIO_InitStructure.GPIO_Pin = SPI1_SCK_PIN; //配置SCK 输出 GPIO_Init(SPI1_SCK_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //MISO浮空输入 GPIO_InitStructure.GPIO_Pin = SPI1_MISO_PIN; // GPIO_Init(SPI1_MISO_PORT, &GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工模式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI数据大小8BIT SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI串行时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI数据捕获第一个上升沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部产生NSS信号 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //8分频 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从高位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC校验生成多项式 SPI_Init(SPI1, &SPI_InitStructure); //初始化SPI寄存器 SPI_Cmd(SPI1, ENABLE); //使能SPI外设 } else if (spi==SPI2) { SPI_Cmd(SPI2, DISABLE); //禁用SPI外设 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); //使能SPI外设APB2 RCC_APB1PeriphClockCmd(SPI2_APB1_GPIO | RCC_APB2Periph_AFIO, ENABLE); //使能复用时钟AFIO SPI2所在管脚时钟 GPIO_InitStructure.GPIO_Pin = SPI2_MOSI_PIN; // MOSI(主设备输出 从设备输入) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出速度 GPIO_Init(SPI2_MOSI_PORT, &GPIO_InitStructure); //初始化GPIO GPIO_InitStructure.GPIO_Pin = SPI2_SCK_PIN; //配置SCK 输出 GPIO_Init(SPI2_SCK_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //MISO浮空输入 GPIO_InitStructure.GPIO_Pin = SPI2_MISO_PIN; // GPIO_Init(SPI2_MISO_PORT, &GPIO_InitStructure); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工模式 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI数据大小8BIT SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //SPI串行时钟悬空低 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //SPI数据捕获第一个上升沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部产生NSS信号 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //8分频 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从高位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC校验生成多项式 SPI_Init(SPI2, &SPI_InitStructure); //初始化SPI寄存器 SPI_Cmd(SPI2, ENABLE); //使能SPI外设 } } // // 函数: SPISendByte // 功能: 发送一个字节数据 // 返回: uint8_t 返回的数据 // 参数: sendByte:发送的数据 // uint8_t SPI::SPIReadWriteByte(uint8_t sendByte) { uint8_t i; while (SPI_I2S_GetFlagStatus(spiX, SPI_I2S_FLAG_TXE) == RESET) //发射缓冲区非空时等待 { i++; if (i >= 200)return 0; } //超时返回 SPI_I2S_SendData(spiX,sendByte); //SPI发送数据 i = 0; while (SPI_I2S_GetFlagStatus(spiX, SPI_I2S_FLAG_RXNE) == RESET) //接收缓冲器空等待 { i++; if (i >= 200)return 0; } //超时返回 return SPI_I2S_ReceiveData(spiX); //返回收到的数据 } // // 函数:SPIReadRegister // 功能:读寄存器值 // 返回:registerValue:寄存器值 // 参数:regitsterAdress:寄存器地址 // uint8_t SPI::SPIReadRegister(uint8_t regitsterAdress) { uint8_t registerValue; SPIReadWriteByte(regitsterAdress); //写寄存器地址 registerValue = SPIReadWriteByte(READ_ADDRESS); //读寄存器值 return registerValue; //返回寄存器值 } // // 函数:SPIWriteRegister // 功能:写寄存器值 // 返回: registerStatus:寄存器状态 // 参数: registerAdress:寄存器地址 registerValue:值 // uint8_t SPI::SPIWriteRegister(uint8_t registerAdress, uint8_t registerValue) { uint8_t registerStatus; registerStatus = SPIReadWriteByte(registerAdress); //读寄存器值 SPIReadWriteByte(registerValue); //写寄存器值 return registerStatus; //返回寄存器状态 } // // 函数: SPIReadBufferRegister // 功能:读寄存器指定长度数据 // 返回: 寄存器状态 // 参数: registerAddress:寄存器地址 buffer:数据 length:长度 // uint8_t SPI::SPIReadBufferRegister(uint8_t registerAddress,uint8_t *buffer, uint8_t length) { uint8_t registerStatus; uint8_t i; registerStatus = SPIReadWriteByte(registerAddress); //读取寄存器状态 for (i = 0; i < length;i++) { buffer[i] = SPIReadWriteByte(READ_ADDRESS); //读数据 } return registerStatus; } // // 函数: SPIWriteBufferRegister // 功能:写寄存器指定长度数据 // 返回: 寄存器状态值 // 参数: registerAddress:寄存器地址 buffer:数据 length:长度 // uint8_t SPI::SPIWriteBufferRegister(uint8_t registerAddress, uint8_t *buffer, uint8_t length) { uint8_t registerStatus; uint8_t i; registerStatus = SPIReadWriteByte(registerAddress); //读取寄存器状态 for (i = 0; i < length; i++) { SPIReadWriteByte(*buffer); //写数据 buffer++; } return registerStatus; }
相关文章推荐
- STM32 IO口双向问题
- 使用CMake来构建STM32工程
- Keil STM32工程环境搭建
- stm32之RTC
- STM32串口操作相关事项
- 【eBox生态圈】连载一:简化STM32的编程之eBox生态圈
- STM32 SPI工作在主模式时用DMA方式接收数据
- STM32 配置定时器让引脚输出PWM波形
- stm32笔记:Systick系统滴答定时器
- stm32笔记:GPIO的简介
- stm32笔记:GPIO的的配置和操作(1)推挽输出方式
- stm32笔记:GPIO的的配置和操作(2)引脚输入之查询按键
- [嵌入式裸机课程]Cortex-M3开发实训班
- 开源硬件:最好编程的STM32开发板
- 第一篇==STM32吧
- 关于常用STM32F103芯片型号代码
- stm32的1602操作显示
- STM32 UART DMA实现未知数据长度接收(转自amoBBs)
- STM32F429 LTDC学习笔记1
- Keil 工程出现 error: #757: variable "uint32_t" is not a type name的一次纠错历程(最后没解决)