春节为什么要放鞭炮| 喜欢吃酸的人是什么体质| bone什么意思| 常务副省长是什么级别| 尿道炎吃什么药好| 办出国护照需要什么手续| 汉坦病毒是什么病| 生肖马和什么生肖最配| 便秘吃什么药最好| 呕吐后吃什么食物好| 农历五月的别称是什么| 齿痕舌吃什么中成药| ercp是什么| 为什么会得子宫肌瘤| 胃窦炎吃什么药效果最好| 小孩便秘是什么原因引起的| 阴虚火旺吃什么| 器质性心脏病是什么意思| 相生相克是什么意思| 脚踝疼是什么原因| 混合痔是什么意思| 诸葛亮儿子叫什么| 婴儿胎发什么时候剪最好| 腋下出汗多是什么原因| 夏天吹空调感冒吃什么药| 玉米吃多了有什么坏处| 黄字五行属什么| 没有料酒可以用什么代替| 透声差是什么意思| 腰肌劳损贴什么膏药| 长期熬夜吃什么可以补回来| 明前茶和明后茶有什么区别| 牛肉饺子馅配什么蔬菜| 外耳道湿疹用什么药| 中学校长是什么级别| 夏雨什么| 八月有什么节日| 诊断是什么意思| 卡介苗预防什么疾病| 宝刀未老的意思是什么| 蔻依属于什么档次| 淋巴结长什么样| 烂脚丫用什么药能治除根| 周围型肺ca是什么意思| 肾结石可以喝什么饮料| 失眠有什么办法解决| 错觉是什么意思| 屋尘螨是什么东西| 止痛片吃多了有什么副作用| 肿气肿用什么药比较好| 1月26是什么星座| 98年的虎是什么命| 霉菌性阴道炎用什么药| 胃疼吃什么药好| 家里养什么动物吃蟑螂| 血压低吃什么| 下水是什么意思| o血型的人有什么特点| 为什么舌头老是有灼烧感| 儿童说话晚去医院挂什么科| 湿疹用什么药效果好| 孙俪是什么星座| 胚芽发育成什么| 口腔发粘是什么原因| 什么人不能吃马齿苋| jk制服什么意思| 多吃黄瓜有什么好处和坏处| 627是什么意思| 驴板肠是什么部位| 结肠多发憩室是什么意思| 高等院校是什么意思| 吃姜有什么好处| 胆固醇偏高是什么意思| 民兵是干什么的| 威士忌是用什么酿造的| 蒙脱石散是什么药| 紫玫瑰花语是什么意思| 蔓字五行属什么| 湿气重吃什么中药好| rpr是什么意思| 夏天有什么蔬菜| 辣椒炒肉用什么肉| 一什么柜子| 男性囊肿是什么引起的| 卖什么小吃简单挣钱| 脉细滑是什么意思| 玉米淀粉可以做什么| 吃卡培他滨禁止吃什么| no.是什么意思| 易孕体质是什么意思| 代入感是什么意思| 总是饿是什么原因| 左下腹疼痛挂什么科| 冷战是什么意思| 青瓜和黄瓜有什么区别| 血管炎症状表现是什么| 朕是什么时候开始用的| 橙色五行属什么| 为什么心脏会突然刺痛| 士官是什么| 政治面貌是什么意思| 节气是什么意思| 精神分裂症吃什么药| gsp全称是什么| 凝血是什么意思| 结婚35周年是什么婚| 称心如意是什么意思| 生殖器是什么| 晕车药有什么副作用| 身上为什么老是痒| 风热感冒什么症状| 李连杰得了什么病| 女性肾虚是什么原因导致的| 属龙的今年要注意什么| 手指甲紫色是什么原因| 心境障碍是什么病| 长期干咳无痰是什么原因引起的| ca125是查什么的| 基佬什么意思| 北京大学校长是什么级别| 肌病是什么病| 什么牌子的辅酶q10好| 树洞什么意思| 双子后面是什么星座| 拉肚子喝什么| 大战三百回合是什么意思| 打嗝不停是什么病前兆| 竹笙是什么| 机智如你是什么意思| 月经提前吃什么药| 薛定谔的猫比喻什么| 掌眼什么意思| 飒的意思是什么| 排卵期会有什么症状| 朱元璋原名叫什么| 空明什么意思| 肺栓塞挂什么科| 吃樱桃有什么好处| 磺胺是什么药| 日本为什么要偷袭珍珠港| 十二月九号是什么星座| vj是什么意思| 三七粉主要治疗什么病| 血清铁是什么意思| 咖啡烘培度有什么区别| 2月2号是什么星座| 哥弟属于什么档次| 宝宝病毒感染吃什么药效果好| fila是什么牌子| 菜肴是什么意思| 劲酒加什么好喝| 别致是什么意思| 一什么一什么| 擤鼻涕带血是什么原因| 同型半胱氨酸高挂什么科| 维生素B1有什么副作用| 命门是什么意思| 菊花脑是什么菜| 身上发热是什么原因| 扶山是什么意思| 吃什么食物养胃| 肾虚去医院挂什么科| 毛巾发黄是什么原因| 喉咙发炎吃什么水果好| 舒坦是什么意思| 抗锯齿是什么意思| 水晶粉是什么原料做的| 孕妇子痫是什么病| 双子女和什么星座最配| 姨妈少是什么原因怎么办| 胎毒是什么意思| 俄罗斯什么东西值得买| 9月13日是什么星座| 金字旁有什么字| 胃痛按什么部位可以缓解疼痛| 来月经是黑色的是什么原因| 下午5点到7点是什么时辰| 7月初七是什么日子| 蝉喜欢吃什么| 34周为什么不建议保胎| 水瓶座是什么星象| 长期熬夜吃什么可以补回来| 尿点什么意思| 投诉与举报有什么区别| neg是什么意思| 万事如意是什么生肖| 曙光什么意思| 国家为什么重视合肥| 大闸蟹什么时候吃| 金牛座后面是什么星座| 音乐制作人是干什么的| 缘定三生是什么意思| editor是什么意思| 连长相当于地方什么官| 哪吒代表什么生肖| 斑秃吃什么药效果好| 丑小鸭告诉我们一个什么道理| 脚气挂什么科| 星座上升是什么意思| 血小板计数是什么意思| 贤惠是什么意思| 心心相印是什么生肖| 喝咖啡困倦是什么原因| 吃了就吐是什么原因| 晟读什么| 心塞是什么意思| 夏天可以干什么| 仙人掌煎鸡蛋治什么病| omega是什么意思| 排卵期同房要注意什么| 红斑狼疮是什么病图片| 牙周炎用什么药最见效| 梦到棺材什么意思| 10.30什么星座| 泽去掉三点水念什么| 百合为什么是苦的| 除了肠镜还有什么方法检查肠道| 考核是什么意思| 胎儿为什么会喜欢臀位| 狗可以吃什么水果| 脑供血不足用什么药好| 308什么意思| 字义是什么意思| nsaid是什么药| 哀鸿遍野是什么意思| 嗓子痛吃什么药| efw是胎儿的什么意思| 宝宝大便酸臭味是什么原因| 茉莉花是什么颜色| pray是什么意思| 什么食物蛋白质含量高| 飞蚊症用什么药物治疗最好| 不想要孩子用什么办法最好| 容易出汗什么原因| 刘五行属性是什么| 做梦结婚是什么征兆| 什么惊什么怪| 怀孕什么时候打掉最好| 甲状腺结节忌口什么| 男人小便刺痛吃什么药| 巨是什么结构| 脂肪瘤是什么引起的| 便秘缺什么维生素| 高笋和茭白有什么区别| 插入阴道是什么感觉| alds是什么病| 暑假让孩子学点什么好| 茯苓和土茯苓有什么区别| 孕酮低是什么原因| blacklabel是什么牌子| 8月底是什么星座| 为什么北极没有企鹅| 天下乌鸦一般黑是什么意思| 表姐的孩子叫我什么| 为什么有蟑螂| 什么什么鼎沸| 过去的日子叫什么日| 双肺散在纤维灶是什么意思| 粪便隐血试验弱阳性是什么意思| 喝脱脂牛奶有什么好处| 手足口病用什么药| 什么水果是热性的| 尿痛吃什么药效果最好| 今天有什么新闻| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 活动中心 ? 板卡试用 ? 【分享开发笔记,赚取电动螺丝刀】Arduino下ESP8266读写W25Q128

共2条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】Arduino下ESP8266读写W25Q128

专家
2025-08-04 09:44:28     打赏
百度 而地方教育部门也该用依规办事,去给正当的权利伸张行为撑腰。

W25Q128是一款大容量SPI FLASH 产品,容量为128Mb。擦写周期多达 10W 次,具有 20 年的数据保存期限,支持电压为 2.7~3.6V,支持高达104MHz的串行时钟通讯。

图片1.png

我买的是W25Q128模块,HOLD引脚和WP引脚都接入了3.3V。

图片2.png


原理图:

图片3.png

ESP8266模块的引脚图:

图片4.png

使用D5\D6\D7\D8四个引脚连接模块

图片5.png

为了验证去读取的操作是否正常,预先使用其它编程器改写了部分单元的内容(从地址0xFFFFF0开始的额6个单元的数据:00、01、02、03、04、05、06、07、08、09、10、11、12、13、14、15)。

W25Q128的资料在其它帖子中简单做了说明(W25Q128的简单说明资料)。

程序代码如下:

/**
本例使用软件模拟方式读写操作W25Q128
*/
#include <SPI.h>
#define NORFLASH_CS_PIN         15        // D8
#define NORFLASH_CLK_PIN        14        // D5
#define NORFLASH_MOSI_PIN       13        // D7       
#define NORFLASH_MISO_PIN       12        // D6
#define NORFLASH_HOLD_PIN       -1        // hold引脚接3.3V
#define NORFLASH_WP_PIN         -1        // wp引脚接3.3V
// 操作W25Q128的指令
#define ManufactDeviceID_CMD    0x90   // 制造商设备ID
#define READ_JEDEC_ID_CMD       0x9F   // JEDEC ID:标识制造商和设备类型的重要代码
#define WRITE_STATUS            0x01   // 写状态寄存器
#define READ_STATU_REGISTER_1   0x05   // 读状态寄存器1
#define READ_STATU_REGISTER_2   0x35   // 读状态寄存器2
#define READ_DATA_CMD           0x03   // 读数据
#define WRITE_ENABLE_CMD        0x06   // 写使能
#define WRITE_DISABLE_CMD       0x04   // 写失能
#define SECTOR_ERASE_CMD        0x20   // 扇区擦除
#define CHIP_ERASE_CMD          0xC7   // 全片擦除
#define PAGE_PROGRAM_CMD        0x02   // 页编程
#define ONE_PAGE_SIZE           256    // 页数据字节数量 
#define SPI_FREQUENCY           40 * 1000000    // SPI通讯速度,SCK频率
/* 初始化SPI */
void norflash_spi_init() {
    // gpio init
    pinMode(NORFLASH_HOLD_PIN, OUTPUT);
    pinMode(NORFLASH_WP_PIN, OUTPUT);  
    digitalWrite(NORFLASH_HOLD_PIN, HIGH);
    digitalWrite(NORFLASH_WP_PIN, HIGH);
    pinMode(NORFLASH_CS_PIN, OUTPUT);  
    digitalWrite(NORFLASH_CS_PIN, HIGH);
    // 软件模拟方式
    pinMode(NORFLASH_CLK_PIN, OUTPUT);  
    pinMode(NORFLASH_MOSI_PIN, OUTPUT);
    pinMode(NORFLASH_MISO_PIN, INPUT);
    digitalWrite(NORFLASH_CLK_PIN, LOW);
    delay(1);
    uint8_t data = 0;
    write_enable();                         // 开放写
    data = read_status();                   // 读状态,确认是否可写
    Serial.printf("norflash write enable status:");
    Serial.println(data, BIN);
    // 读取设备ID
    uint16_t device_id = 0;
    device_id = read_norflash_id();
    Serial.printf("norflash device id: 0x%04X", device_id);
}
/* 写字节数据 */
void write_byte(uint8_t data) {
    for(uint8_t i = 0; i < 8; i++) {    
        uint8_t status;
        status = data & (0x80 >> i);
        digitalWrite(NORFLASH_MOSI_PIN, status);
        digitalWrite(NORFLASH_CLK_PIN, LOW);
        digitalWrite(NORFLASH_CLK_PIN, HIGH);  
    }
}
/* 读一字节 */
uint8_t read_byte(uint8_t tx_data) {  
    // 软件模拟方式
    uint8_t i = 0, data = 0;
    for(i = 0; i < 8; i++) {        
        digitalWrite(NORFLASH_CLK_PIN, HIGH);
        digitalWrite(NORFLASH_CLK_PIN, LOW);
        if(digitalRead(NORFLASH_MISO_PIN)) {
            data |= 0x80 >> i;
        }
    }
    return data;
}
/* 允许写 */
void write_enable() {
    digitalWrite(NORFLASH_CS_PIN, LOW);
    write_byte(WRITE_ENABLE_CMD);
    digitalWrite(NORFLASH_CS_PIN, HIGH);
}
/* 禁止写*/
void write_disable() {
    digitalWrite(NORFLASH_CS_PIN, LOW);
    write_byte(WRITE_DISABLE_CMD);
    digitalWrite(NORFLASH_CS_PIN, HIGH);
}
/* 读状态 */
uint8_t read_status() {
    uint8_t status = 0;
    digitalWrite(NORFLASH_CS_PIN, LOW);
    write_byte(READ_STATU_REGISTER_1);      
    status = read_byte(0);                      
    digitalWrite(NORFLASH_CS_PIN, HIGH);  
    return status;
}
/* 检查是否忙 */
void check_busy(char *str) {
    while(read_status() & 0x01) {
    #ifdef NORFLASH_DEBUG_ENABLE
        Serial.printf("status = 0, flash is busy of %s\n", str);  
    #endif 
    }
}
/* 写入少于一个块(256字节)的数据 */
void write_one_block_data(uint32_t addr, uint8_t * pbuf, uint16_t len) {
    uint16_t i;
    check_busy("write_one_block_data");
    write_enable();                              
    digitalWrite(NORFLASH_CS_PIN, LOW);          
    write_byte(PAGE_PROGRAM_CMD);                
    write_byte((uint8_t)(addr >> 16));            
    write_byte((uint8_t)(addr >> 8));  
    write_byte((uint8_t)addr);      
    for(i = 0; i < len; i++) {
        write_byte(*pbuf++);  
    }
    digitalWrite(NORFLASH_CS_PIN, HIGH);                              
    check_busy("write_one_block_data");
} 
/* 写入少于一个扇区(4096字节)长度的数据  */
void write_one_sector_data(uint32_t addr, uint8_t * pbuf, uint16_t len) { 
    uint16_t free_space, head, page, remain;  
    free_space = ONE_PAGE_SIZE - addr % ONE_PAGE_SIZE;  
    if(len <= free_space)  {
        head = len;
        page = 0;                      
        remain = 0;
    }
    if(len > free_space) {
        head = free_space;
        page = (len - free_space) / ONE_PAGE_SIZE;    
        remain = (len - free_space) % ONE_PAGE_SIZE;
    }
   
    if(head != 0) {
        Serial.print("head:");
        Serial.println(head);
        write_one_block_data(addr, pbuf, head);
        pbuf = pbuf + head;
        addr = addr + head;
    }
    if(page != 0) {
        Serial.print("page:");
        Serial.println(page);
        for(uint16_t i = 0; i < page; i++) {
            write_one_block_data(addr, pbuf, ONE_PAGE_SIZE);
            pbuf = pbuf + ONE_PAGE_SIZE;
            addr = addr + ONE_PAGE_SIZE;
        }
    }
    if(remain != 0) {
        Serial.print("remain:");
        Serial.println(remain);
        write_one_block_data(addr, pbuf, remain);
    }  
}
/* Write arbitrary length data */
void write_arbitrary_data(uint32_t addr, uint8_t* pbuf, uint32_t len)  { 
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;    
    uint16_t i;    
    uint8_t *write_buf = pbuf;  
    uint8_t save_buffer[4096];  // 保存扇区原始数据并添加新数据  
    secpos = addr / 4096;       // 扇区编号
    secoff = addr % 4096;       // 扇区地址偏移量
    secremain = 4096 - secoff;  // 扇区剩余空间   
   
    if(len <= secremain) {
        secremain = len;        // 扇区剩余空间小于4096
    }
    while(1) {  
        read_data(secpos * 4096, save_buffer, 4096); // read sector data
        for(i = 0; i < secremain; i++) {
            // 检查数据,如果所有数据都是0xFF,则不需要擦除扇区
            if(save_buffer[secoff + i] != 0XFF) {
                // 不需要擦除扇区
                break;    
            }
        }
        if(i < secremain) {
            // 擦除扇区并写入数据
            sector_erase(secpos);
            for(i = 0; i < secremain; i++)  {
                save_buffer[i + secoff] = write_buf[i];  // add new data 
            }
            write_one_sector_data(secpos * 4096, save_buffer, 4096); // write sector
        } else {
            // 不需要擦除扇区
            write_one_sector_data(addr, write_buf, secremain);  
        }
        if(len == secremain) {
            // 完成写入
            break;
        } else {
            // 继续写入
            secpos ++;  // 扇区编号 + 1
            secoff = 0; // 扇区地址偏移量 = 0   
            write_buf += secremain;  // 写缓冲偏移
            addr += secremain;       // 地址     
            len -= secremain;        // 数据长度
            if(len > 4096) {
                // 剩余数据超过一个扇区(4096字节)
                secremain = 4096;    
            } else {
                // 剩余数据少于一个扇区(4096字节)
                secremain = len;            
            }
        }    
    }    
}
/* 读取任意长度的数据 */
void read_data(uint32_t addr24, uint8_t *pbuf, uint32_t len) {
    check_busy("read_data");
    digitalWrite(NORFLASH_CS_PIN, LOW);
    write_byte(READ_DATA_CMD);
    write_byte((uint8_t)(addr24 >> 16));  
    write_byte((uint8_t)(addr24 >> 8));  
    write_byte((uint8_t)addr24);  
    for(uint32_t i = 0; i < len; i++) {
        *pbuf = read_byte(0xFF);
        pbuf ++;
    }
    digitalWrite(NORFLASH_CS_PIN, HIGH);
}
/* 擦除扇区 */
void sector_erase(uint32_t addr24)  {
    addr24 *= 4096;  
    check_busy("sector_erase");
    write_enable();                           // WP=0,允许写操作          
   
    digitalWrite(NORFLASH_CS_PIN, LOW);       // CS = 0,允许操作
    write_byte(SECTOR_ERASE_CMD);             // 发送清除扇区指令:   
    write_byte((uint8_t)(addr24 >> 16));      // 发送地址
    write_byte((uint8_t)(addr24 >> 8));  
    write_byte((uint8_t)addr24);  
     
    digitalWrite(NORFLASH_CS_PIN, HIGH);      // CS = 1,禁止操作
    check_busy("sector_erase");
} 
/* Read norflash id */
uint16_t read_norflash_id() {
    uint8_t data = 0;
    uint16_t device_id = 0;
    digitalWrite(NORFLASH_CS_PIN, LOW);
    write_byte(ManufactDeviceID_CMD);             // 发送读取ID的指令
    write_byte(0x00);
    write_byte(0x00);
    write_byte(0x00);
    data = read_byte(0);
    device_id |= data;  // low byte
    data = read_byte(0);
    device_id |= (data << 8);  // high byte
    digitalWrite(NORFLASH_CS_PIN, HIGH);
   
    return device_id;
}
void setup() {
    uint16_t id=0;
    Serial.begin(115200);
    norflash_spi_init();
    int g = 0;
    uint8_t str[1280];
    memset(str, 0, sizeof(str));
    unsigned int  j = 0;      
    for(int k=0; k < 5; k++) {
        for(int i = 0; i < 256; i++) {
            str[j] = i;
            j++;
        }
    }
    Serial.println("");
    Serial.println("-----write data-------");
    sector_erase(0x00);
    write_one_sector_data(0x00, str, 512);
    memset(str, 0, sizeof(str));
    id = read_norflash_id();
    Serial.printf("IC ID = %04X \n", id);
    read_data(0x00, str, 512);
    Serial.println("data:");
    for(int k = 0; k < 512; k++) {
        if(g == 16) {
            Serial.println("|");
            if(k % 256 == 0) {
                Serial.println("---------------");
            }
            g = 1;
        } else  {
            g++;
        }
        Serial.printf("%02X ", str[k]);
    }
   
    //为了验证读操作,预先用其它编程器改写了 0x00FFFFF0 所在单元的数据,计16字节
    read_data(0x00fffff0, str, 16);  // 读取地址=0x00FFFFF0所在单元的16个字节
    Serial.println("\n 0xFFFFF0:");
    g=0;
    for(int k = 0; k < 16; k++) {
        if(g == 16) {
            Serial.println("|");
            if(k % 256 == 0) {
                Serial.println("---------------");
            }
            g = 1;
        } else  {
            g++;
        }
        Serial.printf("%02X ", str[k]);
    }
}
void loop() {
}

测试时串口输出的信息:

图片6.png



院士
2025-08-04 11:05:40     打赏
2楼

王哥,您这是使用GPIO来模拟的SPI的时序来读取与写入Flash吗?

这样是不是意义不大?!


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
消症是什么意思 重庆为什么这么热 子宫内膜16mm说明什么 农历11月14日是什么星座 什么地看
梦见狗咬自己是什么意思 心率快吃什么中成药 九寨沟在什么地方 为什么要做包皮手术 前列腺炎中医叫什么病
1990属马的是什么命 米字五行属什么 艾滋病是什么病毒 形态什么 肺部纤维化是什么意思
尿隐血阳性是什么病 什么是血液病 孵化基地是什么意思 怀孕了不能吃什么 病态是什么意思
山昆读什么hcv8jop4ns4r.cn 韩愈字什么hcv9jop0ns5r.cn 清热去湿热颗粒有什么功效hcv7jop7ns4r.cn 状物是什么意思hcv8jop3ns2r.cn 子宫长什么样子图片hcv9jop2ns8r.cn
梦到和婆婆吵架是什么意思hcv7jop6ns4r.cn 甲状腺属于什么系统hcv9jop6ns0r.cn 什么时候有流星hcv7jop9ns5r.cn 猪大肠炒什么好吃hcv7jop9ns0r.cn 旭日东升是什么生肖hcv8jop9ns0r.cn
祭坛是什么意思hcv9jop0ns6r.cn 保妇康栓治疗什么妇科病hcv8jop4ns5r.cn 爱爱是什么感觉hcv8jop7ns4r.cn 低血压吃什么食物hcv9jop3ns3r.cn 什么不平hcv9jop5ns9r.cn
女生不来大姨妈是什么原因hcv9jop4ns5r.cn 心脏疼吃什么药效果好hcv7jop4ns5r.cn 吃樱桃有什么好处hcv8jop5ns9r.cn 烤麸是用什么做的hcv8jop2ns7r.cn 男人遗精是什么原因造成的hcv9jop4ns1r.cn
百度