卵泡长得慢是什么原因造成的| 鱼翅是什么东西| 心脏增大吃什么药| 9个月宝宝玩什么玩具| 元老是什么意思| 亚麻是什么植物| acei是什么| 1940年中国发生了什么| 急性阑尾炎可以吃什么| 牡丹什么意思| 御三家是什么意思| 7月30号什么星座| 对什么都不感兴趣| 山药炒什么好吃| 吃什么容易排便| 三七长什么样| 阴囊痒是什么原因| mol是什么意思| 阴囊潮湿是什么原因造成的| 博大精深什么意思| 韭菜苔炒什么好吃| offer什么意思| 标准员是干什么的| 什么是菜花病| edc是什么意思| 什么像什么似的什么造句| 电轴左偏是什么意思| 棉绸是什么面料| 脊柱侧弯有什么危害| 维生素c阴性什么意思| 血糖高的人应该吃什么食物最好| 626什么意思| 阴湿是什么病| 备孕需要做什么准备| 烫伤后擦什么药好得快| 护照免签是什么意思| 断片是什么意思| 葡萄柚是什么水果| 睡觉打嗝是什么原因| 吃什么养胃| 吃什么药怀孕最快| 风团是什么| 长裙配什么鞋| 水生木是什么意思| 人中长痘是什么原因| 木耳和什么菜搭配好吃| 皮蛋是什么蛋做的| 疼和痛有什么区别| 蜂蜜和柠檬一起喝有什么作用| 滢是什么意思| 做包子用什么面粉| 第一次查怀孕挂什么科| 4月15号是什么星座| 流金铄石是什么意思| 8月19号是什么星座| 人格魅力是什么意思| 不孕不育做什么检查| 脑供血不足是什么原因| 鸡胗是鸡的什么部位| 脚环肿是什么原因引起的| 不老莓是什么| 排卵期是什么时候开始算| 霖五行属性是什么| alp是什么意思| via什么意思| ena是什么检查项目| 阴道口出血是什么原因| 淋巴细胞比率偏高是什么原因| 什么事的英文| 锴字五行属什么| 甲流吃什么药效果最好| mcm中文叫什么牌子| l1是什么意思| 吃什么会影响验孕棒检验结果| 维生素b12是什么| 吃什么可以增强免疫力| 身份证上的数字是什么字体| 辰五行属什么| 二十七岁属什么生肖| 十月二十二什么星座| 梦见青蛇是什么预兆| 肢体麻木是什么原因| 什么矿泉水比较好| 文房四宝是什么| 耳根有痣代表什么| 介入科主要看什么病| 专科和本科有什么区别| 耳朵上长痣代表什么| 甲醛超标有什么反应| 骨密度低吃什么药最快| 4月5号是什么星座| 尿素氮肌酐比值偏高是什么原因| 门庭冷落是什么意思| 点完痣要注意什么| 暧昧什么意思| 6月16什么星座| 笃定什么意思| 什么叫磨玻璃结节| 睡眠不好吃什么中成药| sm是什么| 唾液粘稠是什么原因| 6.19什么星座| 颈椎病引起的头晕吃什么药| 肠系膜淋巴结炎吃什么药最有效| 股市量比什么意思| 哈伦裤配什么鞋子好看| 什么是独角兽企业| 6.21什么星座| 五月11号是什么星座| 什么都别说| 回煞是什么意思| 一凉就咳嗽是什么原因| 农历12月26日是什么星座| 点到为止是什么意思| 为什么无缘无故流鼻血| 咽鼓管炎吃什么药| 鲨鱼为什么怕海豚| 房性心动过速是什么意思| 富屋贫人是什么意思| hook是什么意思| 长脸适合什么短头发| 甲钴胺是治什么病的| 急性结膜炎用什么眼药水| 1977年属蛇是什么命| 老是打嗝是什么病的征兆| 什么是高筋面粉| 性病都有什么| lily是什么花| 蹲着有什么好处| 怀孕了用排卵试纸测会显示什么| ac什么意思| 3月20号是什么星座| 什么是阻生智齿| maybach是什么车| 蛇什么时候出来活动| 心脏支架不能吃什么| 小蛮腰什么意思| 手脚发麻是什么原因引起的| 胃镜预约挂什么科| 用字五行属什么| 鸦雀无声是什么意思| 妇科臭氧治疗的作用是什么| 感觉牙齿松动是什么原因| rose是什么意思| 鳞状上皮增生是什么意思| 神经炎是什么症状| 口是心非是什么动物| 我们在干什么| 什么是纯净物| he是什么气体| vin是什么| 5月26日什么星座| 表姐的孩子叫我什么| 女娲姓什么| 2021属什么生肖| 拔完智齿吃什么消炎药| 粗脖子病是什么原因引起的| 中国人在印度属于什么种姓| 牟作为姓氏时读什么| 女生的小鸡鸡长什么样| 强迫症什么意思| 月经一直不干净是什么原因引起的| LOP是什么胎位| 白细胞十十是什么意思| 赤茯苓又叫什么| 脚底有黑痣有什么说法| 阑尾炎可以吃什么东西| 白舌苔很厚是什么病症| 咳嗽胸口疼是什么原因| 梦见生男孩是什么征兆| 煞星是什么意思| pro是什么的缩写| 爱是什么感觉| 痛风什么引起的原因有哪些| 西游记主题曲叫什么| 砭石是什么东西| 凯旋归来是什么意思| 海尔洗衣机e3是什么故障| 喝什么提神| 12月7日是什么星座| 奔走相告的走是什么意思| 什么大米好吃| 总免疫球蛋白e是什么| 老放屁是什么病的征兆| 第一次见面送女生什么花| 什么的表演| 颈椎曲度变直有什么症状| 6月7日什么星座| 不让他看我的朋友圈是什么效果| 性激素检查是查什么| 镜花水月是什么意思| 苍耳是什么东西| 炸酥肉用什么肉最好吃| nt值代表什么| 博字五行属什么| 家五行属性是什么| 美国为什么那么强大| 候和侯有什么区别| 开诚布公是什么意思| 撕票是什么意思| 破月什么意思| 血糖高早饭吃什么最好| 困难的反义词是什么| 加拿大现在什么季节| 40周年是什么婚| 为什么会呕吐| 龟兔赛跑的故事告诉我们什么道理| 幽门螺杆菌感染有什么症状| 雨像什么| 缺锌有什么表现和症状| 泡泡纱是什么面料| 2岁属什么生肖| 房东是什么意思| 痰多吃什么好化痰| 晚上睡不着是什么原因引起的| 顾名思义的顾什么意思| 阴阳两虚用什么药| 牛肉和什么蔬菜搭配好| 有白痰是什么原因| 钙化点是什么意思| 起什么转什么成语| 甲流是什么病| 什么人容易得肺结核| 阿斯巴甜是什么| 阴茎疱疹用什么药| 唐僧最后成了什么佛| 退烧药吃多了有什么副作用| ohs是什么意思| 什么通便效果最快最好| 肾虚吃什么食物能补| 下午五点到七点是什么时辰| 人民币用什么材料做的| 什么食物胆固醇含量高| cfu是什么单位| 骨髓炎是什么病| 身上搓出来的泥是什么| 什么的天空飘着什么的白云| 甲流是什么| 吊销是什么意思| 萎缩性胃炎吃什么中成药| 梦到吃苹果是什么意思| 5p是什么意思| 肩周炎是什么引起的| 曜字五行属什么| 婴儿什么时候会走路| 什么是性冷淡| 什么马没有腿| 碱和小苏打有什么区别| 戌时是什么时候| 冰晶是什么| 非虫念什么| 对立面是什么意思| 谷什么意思| 生辉是什么意思| 说什么才好| 脊椎痛什么原因| 什么叫尿潴留| 束在什么情况下读su| 胃反酸是什么原因造成的| 七点到九点是什么时辰| 筋膜炎用什么药| 多巴胺高是什么原因| 户口迁移需要什么手续| 攀缘是什么意思| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 活动中心 ? 板卡试用 ? 【分享开发笔记,赚取电动螺丝刀】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 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
海豹油有什么功效 眼角发白是什么原因 为什么呢 屁股痒是什么原因 乙肝表面抗原大于250是什么意思
椰子水有什么功效 乜是什么意思 神是什么意思 牙齿出血是什么病表现出来的症状 什么是二次元
不吃早饭有什么危害 梦见自己得了绝症预示着什么 女人眼角有痣代表什么 楚楚欲动是什么意思 血液属于什么组织
港币长什么样 头出虚汗是什么原因引起的 坐月子吃什么菜 头汗多是什么原因引起的 肾囊肿是什么
尿蛋白是什么意思0735v.com 头孢不能和什么药一起吃hcv8jop9ns0r.cn 做脑ct对人体有什么危害cl108k.com 马头岩肉桂是什么茶hlguo.com 右肺疼是什么原因hcv8jop6ns6r.cn
自行车什么牌子好hcv9jop0ns1r.cn 大运流年是什么意思hcv8jop8ns1r.cn 二花是什么中药hcv8jop9ns7r.cn 赵本山什么时候去世的hcv9jop0ns3r.cn 生肖是什么意思hcv7jop4ns7r.cn
吃什么生发效果最好hcv7jop9ns7r.cn 韭菜吃多了有什么坏处hcv8jop4ns2r.cn 医保断了一个月有什么影响hcv7jop4ns6r.cn 睡觉吹气是什么原因hcv9jop2ns0r.cn 成都有什么区hcv9jop0ns1r.cn
闹觉是什么意思aiwuzhiyu.com 裙带菜不能和什么一起吃hcv9jop2ns9r.cn 1945年属什么hcv7jop9ns9r.cn h代表什么hcv8jop6ns2r.cn 悉心栽培什么意思hcv8jop2ns4r.cn
百度