b型血和ab型血的孩子是什么血型| 脚肿吃什么消肿最快| 627是什么星座| 衣服38码相当于什么码| 什么是管制| 令人唏嘘是什么意思| 什么山不能爬脑筋急转弯| 梦见游泳是什么预兆| 手腕凸起的骨头叫什么| 去胎毒吃什么最好| 想飞上天和太阳肩并肩是什么歌| 1994是什么年| 口腔溃疡为什么是白色的| 府绸是什么面料| 脑梗吃什么水果好| 梦见自己家被盗有什么预兆| 切除子宫对身体有什么伤害| 肺部ct能查出什么病| 什么时候人流| 印第安人属于什么人种| 什么动物睡觉不闭眼| 精索静脉曲张吃什么药| 异丙嗪又叫什么名| 炉中火是什么意思| 胎膜早破是什么症状| 什么止痛药最快止痛| 医生属于什么编制| 不下面一个一念什么| 股票洗盘是什么意思| 屁股出血是什么原因| 肝做什么检查最准确| 银黑了用什么可以洗白| 熙熙攘攘是什么意思| 病毒性感冒什么症状| 武则天什么朝代| 摩卡是什么意思| 子宫是什么| 玄关挂什么装饰画好| 浊气是什么意思| 乳腺实性结节是什么意思| 石榴花是什么季节开的| 张牙舞爪是什么意思| 神疲乏力吃什么中成药| 洗衣机启动不了是什么原因| 身份证前六位代表什么| 做梦梦见狗咬我什么意思啊| 甘油三酯高吃什么降得快| 闪购是什么意思| 嘴巴经常长溃疡是什么原因| 抽筋是什么原因引起的| 经常肚子痛什么原因| 梦见好多衣服是什么意思| 国安是什么单位| 凉粉是用什么做的| 醒酒喝什么饮料| 五彩斑斓的意思是什么| 恩客是什么意思| 睡觉时胳膊和手发麻是什么原因| 澳门是什么时候回归的| 大连机场叫什么名字| 34属什么| 双子女和什么星座最配| 美篇是什么| 口唇疱疹用什么药膏| 一呼吸胸口疼是什么原因| 什么的小毛虫| 乙肝两对半45阳性是什么意思| 血压偏低有什么危害| 空气炸锅可以做什么| 钢铁侠叫什么名字| 舌苔黄腻吃什么中成药| 充电玩手机有什么危害| 辛属什么五行| 茉莉花茶适合什么季节喝| 高糖是什么| 身体虚弱打什么营养针| 向左向右向前看是什么歌| 月经期间喝什么汤好| 乘晕宁又叫什么| 什么叫凤凰男| 4.20什么星座| 旗开得胜是什么意思| 芽轴发育成什么| 腱鞘炎吃什么药最好| 散光是什么| 蕞是什么意思| 太阳穴凹陷是什么原因| 阑尾炎挂号挂什么科| 全身瘙痒是什么原因| 花重锦官城的重是什么意思| 新生儿屁多是什么原因| 什么叫前列腺钙化| 小媳妇是什么意思| 周围神经炎是什么症状| 癞蛤蟆长什么样| 肝藏血是什么意思| 2月14日是什么星座| 肛门潮湿用什么药最好| 红光对皮肤有什么作用| 耳鸣是什么原因导致的| 梦见海水是什么意思| 骨质增生是什么| 游泳比赛中wj是什么意思| 女人为什么不会怀孕| 什么是淋巴| 有机和无机是什么意思| 痰栓是什么意思| 红豆与赤小豆有什么区别| 丝瓜不能和什么食物一起吃| 瘿瘤是什么病| 雾化后为什么要漱口| 尿突然是红褐色的是什么问题| 山竹什么味道| 吃东西就打嗝是什么原因| 什么是低保| 女性甲状腺挂什么科| 骨骼清奇什么意思| 南瓜子不能和什么一起吃| 导盲犬一般是什么品种| 血小板偏高是什么意思| 皮试阳性是什么意思| 什么罗之恋| 加拿大现在什么季节| 婴儿喝什么奶粉| 可爱的动物是什么生肖| 梦见小白蛇是什么预兆| 吸允的读音是什么| 杨枝甘露是什么| 碳水化合物对人体有什么作用| 周吴郑王是什么意思| 什么是碳水化合物| 梦见买东西是什么意思| 完全性右束支阻滞是什么意思| 经期便秘是什么原因| 立春是什么生肖| 杀跌是什么意思| 血小板为什么会减少| 回头是岸是什么生肖| 宫颈癌什么症状| 塑料属于什么垃圾| 什么叫肛瘘| 木堂念什么| 度是什么意思| 胸有成竹是什么意思| mews评分是什么意思| 为什么明星不激光祛斑| 十三点是什么意思| 吃猪肺有什么好处和坏处| 精液是什么组成的| 女性吃辅酶q10有什么好处| 黑化是什么意思| 奶酪是什么东西| 萨洛蒙什么档次| 高密度脂蛋白低是什么原因| 蒙古族信仰什么教| 嗓子疼低烧吃什么药| 青黄不接是什么意思| 晕菜是什么意思| 港澳通行证办理需要什么证件| 达菲是什么药| 什么是阴虚什么是阳虚| 肾阴虚吃什么食物最好| avg是什么意思| 舌苔开裂是什么原因呢| 葡萄胎有什么症状反应| 上眼皮突然肿了是什么原因| 痰饮是什么意思| 真实写照的意思是什么| 什么什么的荷叶| 桃花是什么季节开的| zeesea是什么牌子| 摩羯座是什么性格| lsp什么意思| 丑拒是什么意思| 坐骨神经吃什么药| 皮肤长癣是什么原因引起的| 老年人腿肿是什么原因引起的| 手冲是什么意思| 尿糖一个加号是什么意思| 喝柠檬水对身体有什么好处| 肛门瘙痒是什么病| 外阴白斑擦什么药| 亿后面是什么单位| 天秤座男生和什么星座最配| 皮肤晒伤用什么药| 什么风云| 腰花是什么部位| 栀子花叶子发黄是什么原因| 皮肤一碰就破是什么病| 冷血动物是什么意思| 肝不好吃什么中成药| 送锦旗有什么讲究| 灵芝泡酒有什么功效| 西酞普兰为什么早晨吃| 梦见买猪肉是什么预兆| 有口无心是什么意思| 潍坊有什么好玩的| 的意思是什么| 意难平什么意思| 总是放屁什么原因| 左侧卵巢囊性包块是什么意思| 人参片泡水喝有什么功效和作用| 脾不好吃什么药| 泓五行属什么| 寒冷的反义词是什么| 唯小人与女子难养也什么意思| 为什么姨妈会推迟| 下午三点到四点是什么时辰| 宫寒是什么意思| 易胖体质是什么原因造成的| 1975年属兔五行属什么| 牛黄是什么东西| 女人裹脚是从什么时候开始的| 眼睛粘糊是什么原因| 为什么最近一直下雨| up是什么意思| 山开念什么| 138是什么意思啊| 胃溃疡a2期是什么意思| hpv亚临床感染是什么意思| a货翡翠是什么意思| 眩晕挂什么科| 屁股疼吃什么药| 狭鳕鱼是什么鱼| 男戴观音女戴佛是什么意思| 一点点奶茶什么最好喝| 咂嘴是什么意思| 牛筋草有什么功效| 倾诉是什么意思| 睾丸上长毛意味着什么| 吃什么能降血脂| 常吃猪油有什么好处和坏处| 桑葚有什么好处| 手上长水泡痒用什么药| 月季黑斑病用什么药| 什么银行卡最好用| 养牛仔裤是什么意思| 画龙点睛是什么生肖| 定日是什么意思| 醉清风是什么意思| 打乒乓球有什么好处| 心有余悸是什么意思| 清洁度iv是什么意思| 儿童吃手指是什么原因| 尿检隐血弱阳性是什么意思| 肠粉是什么| 连长是什么级别| 带蜜蜡有什么好处| 层峦叠翠的意思是什么| 丹田是什么器官| 牛奶和什么不能一起吃| 片仔癀是什么东西| 割包皮有什么用| 英雄难过美人关是什么意思| 奶泡是什么| 天蝎座是什么象| 仰卧起坐有什么好处| 梨状肌综合征挂什么科| 思想感情是什么意思| 中午吃什么减肥| 领衔是什么意思| 木字旁羽字是什么字| 1964年属什么的| 儿童不长个子去医院挂什么科| 百度
这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 ? 论坛首页 ? 活动中心 ? 板卡试用 ? 【分享开发笔记,赚取电动螺丝刀】Arduino下ESP8266读写W25Q128

共2条 1/1 1 跳转至

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

专家
2025-08-03 09:44:28     打赏
百度 而马英九办公室前副秘书长罗智强认为,台湾地区领导人蔡英文在2010、2012、2016年选举公报中,也都未揭露其“宇昌公司董事长”经历,也涉犯“使公务员登载不实”的“伪造文书罪”,决定仿效办理,今早也赴台北地检署告发蔡英文,强调“以其人之道还治其人之身”。

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-03 11:05:40     打赏
2楼

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

这样是不是意义不大?!


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]
庄周梦蝶是什么意思 龟头敏感用什么药 1月3号是什么星座 1月1号什么星座 哮喘吃什么药最有效
什么是势能 阴茎溃疡用什么药 减肥早餐吃什么最好 怀孕前三个月忌吃什么 寡欲是什么意思
肝胆胰脾挂什么科 脚底板疼痛是什么原因 季昌明是什么级别 乳腺癌吃什么好 下巴长痘痘是什么原因
梦见病人好了什么预兆 喜欢趴着睡是什么原因 举足轻重是什么生肖 狐假虎威告诉我们什么道理 卵泡不破是什么原因造成的
低血压高吃什么药好hcv9jop0ns3r.cn 老日念什么hcv9jop7ns3r.cn 阴历六月十五是什么日子hcv9jop5ns3r.cn THENORTHFACE什么牌子cj623037.com 布洛芬缓释胶囊有什么副作用hcv8jop7ns7r.cn
韭菜有什么功效hcv9jop2ns9r.cn 泉中水是什么生肖hcv8jop5ns4r.cn 小动脉瘤是什么意思96micro.com 鼻炎和鼻窦炎有什么区别hcv8jop5ns1r.cn 什么叫十二指肠球炎hcv7jop6ns3r.cn
天天喝白酒对身体有什么危害hcv9jop4ns5r.cn 小孩过敏吃什么药clwhiglsz.com 思字属于五行属什么hcv7jop7ns2r.cn 翡翠都有什么颜色hcv9jop3ns3r.cn 托孤是什么意思hcv7jop9ns2r.cn
梦见大狼狗是什么意思hcv8jop7ns5r.cn THENORTHFACE什么牌子hcv9jop1ns9r.cn 蛔虫和蛲虫有什么区别adwl56.com 1962年属什么生肖hcv9jop6ns4r.cn 核素是什么hcv9jop7ns4r.cn
百度