单片机与 8 脚 Flash 的通信通常基于 SPI(Serial Peripheral Interface)协议,下面为你详细介绍通信过程及实现方法。
单片机与 8 脚 Flash 的典型硬件连接方式如下:
单片机引脚 | Flash 引脚 |
---|---|
SCK(时钟输出) | CLK(时钟输入) |
MOSI(主出从入) | DI(数据输入) |
MISO(主入从出) | DO(数据输出) |
片选输出 | CS#(低电平有效) |
通用输出 | HOLD#(低电平有效) |
VCC | VCC(接电源) |
GND | VSS(接地) |
SPI 通信的关键要点如下:
与 Flash 通信的基本流程为:
Flash 芯片支持多种指令,下面列举一些常用指令及其功能:
指令代码(十六进制) | 指令名称 | 功能描述 |
---|---|---|
03H | 读数据 | 从指定地址连续读取数据。 |
0BH | 快速读 | 比普通读数据指令速度更快,在地址后需发送一个空字节。 |
06H | 写使能 | 使能芯片的写操作,在执行写数据或擦除操作前必须先执行此指令。 |
04H | 写禁止 | 禁止芯片的写操作。 |
05H | 读状态寄存器 | 读取状态寄存器内容,可获取芯片是否忙碌、写保护状态等信息。 |
0AH | 写状态寄存器 | 向状态寄存器写入数据,可设置写保护、块锁定等功能。 |
20H | 扇区擦除 | 擦除指定地址所在的扇区(通常为 4KB),擦除后扇区数据全部变为 FFH。 |
D8H | 块擦除 | 擦除指定地址所在的块(通常为 64KB),擦除后块内数据全部变为 FFH。 |
C7H | 芯片擦除 | 擦除整个 Flash 芯片的数据,所有存储单元数据变为 FFH。 |
02H | 页编程 | 向指定地址写入数据,每次最多可写入 256 字节(一页)。 |
下面以 Arduino 为例,展示 SPI 通信的代码实现:
#define CS_PIN 10 // 片选引脚#define HOLD_PIN 9 // HOLD引脚void setup() { // 初始化SPI接口 SPI.begin(); // 设置引脚模式 pinMode(CS_PIN, OUTPUT); pinMode(HOLD_PIN, OUTPUT); // 初始状态:CS和HOLD为高电平 digitalWrite(CS_PIN, HIGH); digitalWrite(HOLD_PIN, HIGH); Serial.begin(115200); Serial.println("Flash初始化完成");}// 读取Flash状态寄存器byte readStatusRegister() { digitalWrite(CS_PIN, LOW); // 选中Flash SPI.transfer(0x05); // 发送读状态寄存器指令 byte status = SPI.transfer(0x00); // 读取状态寄存器值 digitalWrite(CS_PIN, HIGH); // 取消选中Flash return status;}// 等待Flash空闲void waitForFlashReady() { while ((readStatusRegister() & 0x01) == 0x01); // 等待忙碌位(BUSY)清零}// 使能写操作void writeEnable() { digitalWrite(CS_PIN, LOW); // 选中Flash SPI.transfer(0x06); // 发送写使能指令 digitalWrite(CS_PIN, HIGH); // 取消选中Flash}// 读取Flash数据void readData(uint32_t address, byte* buffer, uint16_t length) { waitForFlashReady(); digitalWrite(CS_PIN, LOW); // 选中Flash SPI.transfer(0x03); // 发送读数据指令 SPI.transfer((address >> 16) & 0xFF); // 发送地址高字节 SPI.transfer((address >> 8) & 0xFF); // 发送地址中字节 SPI.transfer(address & 0xFF); // 发送地址低字节 // 读取数据 for (uint16_t i = 0; i < length; i++) { buffer[i] = SPI.transfer(0x00); } digitalWrite(CS_PIN, HIGH); // 取消选中Flash}// 页编程(写入数据)void pageProgram(uint32_t address, byte* data, uint16_t length) { if (length > 256) length = 256; // 一页最多256字节 waitForFlashReady(); writeEnable(); // 使能写操作 digitalWrite(CS_PIN, LOW); // 选中Flash SPI.transfer(0x02); // 发送页编程指令 SPI.transfer((address >> 16) & 0xFF); // 发送地址高字节 SPI.transfer((address >> 8) & 0xFF); // 发送地址中字节 SPI.transfer(address & 0xFF); // 发送地址低字节 // 写入数据 for (uint16_t i = 0; i < length; i++) { SPI.transfer(data[i]); } digitalWrite(CS_PIN, HIGH); // 取消选中Flash waitForFlashReady(); // 等待写入完成}// 扇区擦除void sectorErase(uint32_t address) { waitForFlashReady(); writeEnable(); // 使能写操作 digitalWrite(CS_PIN, LOW); // 选中Flash SPI.transfer(0x20); // 发送扇区擦除指令 SPI.transfer((address >> 16) & 0xFF); // 发送地址高字节 SPI.transfer((address >> 8) & 0xFF); // 发送地址中字节 SPI.transfer(address & 0xFF); // 发送地址低字节 digitalWrite(CS_PIN, HIGH); // 取消选中Flash waitForFlashReady(); // 等待擦除完成(耗时较长)}void loop() { // 示例:读取Flash ID byte id[3]; digitalWrite(CS_PIN, LOW); SPI.transfer(0x9F); // 发送读取设备ID指令 id[0] = SPI.transfer(0x00); // 制造商ID id[1] = SPI.transfer(0x00); // 设备ID1 id[2] = SPI.transfer(0x00); // 设备ID2 digitalWrite(CS_PIN, HIGH); Serial.print("Flash ID: 0x"); for (int i = 0; i < 3; i++) { if (id[i] < 0x10) Serial.print("0"); Serial.print(id[i], HEX); } Serial.println(); // 示例:写入数据 byte writeData[] = "Hello, Flash!"; pageProgram(0x0000, writeData, sizeof(writeData)); // 示例:读取数据 byte readBuffer[32]; readData(0x0000, readBuffer, sizeof(writeData)); Serial.print("读取的数据: "); Serial.println((char*)readBuffer); delay(5000); // 每5秒执行一次}
上一篇:8脚flash引脚定义