STM32入门开发 介绍SPI总线、读写W25Q64
摘要
本文旨在为STM32微控制器的初学者提供一个关于SPI总线和W25Q64 Flash存储器的基础知识介绍,以及如何使用STM32硬件SPI来读写W25Q64。我们将从SPI总线的基本概念开始,逐步深入到W25Q64的特性、硬件连接、SPI配置、读写操作,并提供实际的代码示例。
1. SPI总线简介
SPI(Serial Peripheral Interface)是一种同步串行通信协议,用于微控制器和各种外围设备之间的通信。它是一种高速、全双工、主从模式的通信总线。
1.1 SPI通信特点
- 主设备:控制通信的时钟信号和数据交换的开始与结束。
- 从设备:响应主设备的通信请求。
- 数据传输:以主设备产生的时钟信号同步。
1.2 SPI通信信号线
MOSI
(Master Out Slave In):主设备数据输出,从设备数据输入。MISO
(Master In Slave Out):主设备数据输入,从设备数据输出。SCK
(Serial Clock):时钟信号,由主设备产生。CS
(Chip Select):片选信号,用于激活特定的从设备。
2. W25Q64 Flash存储器
W25Q64是一款8Mb(1M x 8位)的串行Flash存储器,适用于存储程序代码、数据等信息。
2.1 W25Q64特性
- 容量:8Mb
- 组织:1M字节,每页256字节
- 擦除时间:毫秒级别
- 读写周期:100万次
3. 硬件连接
将W25Q64连接到STM32开发板,确保以下引脚正确连接:
CS
连接到 STM32 GPIO(例如PA4)SCK
连接到 STM32 SPI SCK(例如PA5)MOSI
连接到 STM32 SPI MOSI(例如PA7)MISO
连接到 STM32 SPI MISO(例如PA6)VCC
连接到 3.3VGND
连接到 GND
4. SPI配置
在STM32中配置SPI,需要设置SPI的模式、数据大小、时钟极性、时钟相位等参数。
4.1 SPI初始化代码
void SPI_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &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_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
5. W25Q64操作
5.1 初始化W25Q64
void W25Q64_Init(void) {
SPI_CS_High(); // 确保CS是高电平开始
}
5.2 读取W25Q64 ID
uint16_t W25Q64_ReadID(void) {
uint16_t id = 0;
SPI_CS_Low();
SPI_SendByte(0x90); // 读取ID指令
id = SPI_ReceiveByte() << 8;
id |= SPI_ReceiveByte();
SPI_CS_High();
return id;
}
5.3 写入W25Q64
void W25Q64_WriteByte(uint32_t addr, uint8_t data) {
SPI_CS_Low();
SPI_SendByte(0x02); // 写入指令
SPI_SendByte((addr >> 16) & 0xFF);
SPI_SendByte((addr >> 8) & 0xFF);
SPI_SendByte(addr & 0xFF);
SPI_SendByte(data);
SPI_CS_High();
// 等待写入完成...
}
5.4 从W25Q64读取数据
uint8_t W25Q64_ReadByte(uint32_t addr) {
uint8_t data;
SPI_CS_Low();
SPI_SendByte(0x03); // 读取指令
SPI_SendByte((addr >> 16) & 0xFF);
SPI_SendByte((addr >> 8) & 0xFF);
SPI_SendByte(addr & 0xFF);
data = SPI_ReceiveByte();
SPI_CS_High();
return data;
}
6. 测试代码
以下是测试SPI通信和W25Q64读写操作的示例代码:
int main(void) {
// 系统初始化
SystemInit();
// 初始化SPI和W25Q64
SPI_Init();
W25Q64_Init();
// 读取W25Q64 ID
uint16_t id = W25Q64_ReadID();
printf("W25Q64 ID: 0x%X\r
", id);
// 测试写入和读取
uint8_t test_data = 0xAA;
uint8_t read_data;
W25Q64_WriteByte(0, test_data); // 写入测试数据
read_data = W25Q64_ReadByte(0); // 读取数据
if (test_data == read_data) {
printf("Read/Write test passed.\r
");
} else {
printf("Read/Write test failed.\r
");
}
while(1) {
// 这里可以添加其他测试或应用代码
}
}
7. 结论
本文为STM32的入门开发者提供了SPI总线和W25Q64 Flash存储器的基础知识,以及如何使用STM32的硬件SPI进行读写操作。通过实际的代码示例,读者可以快速理解并应用SPI通信。在实际开发中,开发者可能需要根据具体的硬件配置和需求进行适当的调整和优化。
✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
点击领取更多详细资料