2019-12-20 01:19:02 jdh99 阅读数 43
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

单片机flash通用读写库:TZFlash

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

说明

本文发布单片机flash通用读写库TZFlash,有两个优点:

  • TZFlash将flash的读写抽象成文件读写,更易于使用。
  • flash写入需要4字节对齐,TZFlash增加cache机制,可以将任意长度的写入flash。

源码

tzflash.h

// Copyright 2019-2019 The TZIOT Authors. All rights reserved.
// flash管理模块头文件

#ifndef TZFLASH_H
#define TZFLASH_H

#include "tzbasedef.h"

// TZFlashEraseFunc 函数类型:擦除flash
// addr:起始地址.size:擦除字节数
// 成功返回true,失败返回false
typedef bool (*TZFlashEraseFunc)(int addr, int size);

// TZFlashWriteFunc 函数类型:写入flash
// addr:起始地址.bytes:待写入的字节流.size:写入字节数
// 成功返回true,失败返回false
typedef bool (*TZFlashWriteFunc)(int addr, uint8_t* bytes, int size);

// TZFlashReadFunc 函数类型:读取flash
// addr:起始地址.bytes:读取的字节流存放的缓存.size:读取的字节数
// 成功返回true,失败返回false
typedef bool (*TZFlashReadFunc)(int addr, uint8_t* bytes, int size);

// TZFlashOpenMode 打开模式
typedef enum {
    TZFLASH_READ_ONLY = 0,
    TZFLASH_WRITE_ONLY
} TZFlashOpenMode;

// TZFlashLoad 模块载入
void TZFlashLoad(int pageSize, TZFlashEraseFunc eraseFunc, TZFlashWriteFunc writeFunc, TZFlashReadFunc readFunc);

// TZFlashOpen 打开flash文件.
// 注意:打开时会擦除flash.要保证打开的flash大小是页的整数倍,否则会打开失败
// 返回值为0表示打开失败
intptr_t TZFlashOpen(int addrStart, int size, TZFlashOpenMode mode);

// TZFlashWrite 向flash写入数据
// 成功返回写入的字节数,失败返回-1
int TZFlashWrite(intptr_t fd, uint8_t* bytes, int size);

// TZFlashRead 从flash中读取数据
// 成功返回读取的字节数,失败返回-1
int TZFlashRead(intptr_t fd, uint8_t* bytes, int size);

// TZFlashClose 关闭
void TZFlashClose(intptr_t fd);

#endif

tzflash.c

// Copyright 2019 The TZIOT Authors. All rights reserved.
// flash管理模块主文件

#include "tzflash.h"

#define CACHE_SIZE 64

#pragma pack(1)

// tFlashInterface flash管理接口
typedef struct {
    int pageSize;
    TZFlashEraseFunc erase;
    TZFlashWriteFunc write;
    TZFlashReadFunc read;
} tFlashInterface;

// tFlashFile flash文件类型
typedef struct {
    int addrStart;
    int addrStop;
    int offset;
    TZFlashOpenMode mode;
    uint8_t cache[CACHE_SIZE];
    int cacheLen;
} tFlashFile;

#pragma pack()

static tFlashInterface gInterface;

// TZFlashLoad 模块载入
void TZFlashLoad(int pageSize, TZFlashEraseFunc eraseFunc, TZFlashWriteFunc writeFunc, TZFlashReadFunc readFunc) {
    gInterface.pageSize = pageSize;
    gInterface.erase = eraseFunc;
    gInterface.write = writeFunc;
    gInterface.read = readFunc;
}

// TZFlashOpen 打开flash文件.
// 注意:只写模式打开时会擦除flash.要保证打开的flash大小是页的整数倍,否则会打开失败
// 返回值为0表示打开失败
intptr_t TZFlashOpen(int addrStart, int size, TZFlashOpenMode mode) {
    if (mode == TZFLASH_WRITE_ONLY) {
        if (size % gInterface.pageSize != 0) {
            return 0;
        }
        if (gInterface.erase(addrStart, size) == false) {
            return 0;
        }
    }

    tFlashFile* file = malloc(sizeof(tFlashFile));
    if (file == NULL) {
        return 0;
    }
    file->addrStart = addrStart;
    file->addrStop = addrStart + size - 1;
    file->mode = mode;
    file->offset = file->addrStart;
    file->cacheLen = 0;
    return (intptr_t)file;
}

// TZFlashWrite 向flash写入数据
// 成功返回写入的字节数,失败返回-1
int TZFlashWrite(intptr_t fd, uint8_t* bytes, int size) {
    tFlashFile* file = (tFlashFile*)fd;
    if (file->mode == TZFLASH_READ_ONLY) {
        return -1;
    }
    if (file->offset + file->cacheLen + size > file->addrStop) {
        return -1;
    }

    int delta = 0;
    int writeNum = 0;
    for (;;) {
        delta = CACHE_SIZE - file->cacheLen;
        // 比cache可写入空间小则直接写入
        if (size < delta) {
            memcpy(file->cache + file->cacheLen, bytes, (size_t)size);
            file->cacheLen += size;
            writeNum += size;
            break;
        }

        // 写满cache,再全部写入flash
        memcpy(file->cache + file->cacheLen, bytes, (size_t)delta);
        file->cacheLen += delta;
        gInterface.write(file->offset, file->cache, file->cacheLen);
        file->offset += file->cacheLen;
        file->cacheLen = 0;
        size -= delta;
        writeNum += delta;
    }
    return writeNum;
}

// TZFlashRead 从flash中读取数据
// 成功返回读取的字节数,失败返回-1
int TZFlashRead(intptr_t fd, uint8_t* bytes, int size) {
    tFlashFile* file = (tFlashFile*)fd;
    if (file->mode == TZFLASH_WRITE_ONLY) {
        return -1;
    }
    if (file->offset > file->addrStop) {
        return 0;
    }
    int delta = file->addrStop - file->offset + 1;
    int readSize = delta > size ? size : delta;
    gInterface.read(file->offset, bytes, readSize);
    file->offset += readSize;
    return readSize;
}

// TZFlashClose 关闭
void TZFlashClose(intptr_t fd) {
    tFlashFile* file = (tFlashFile*)fd;
    gInterface.write(file->offset, file->cache, file->cacheLen);
    free(file);
}

测试

#include "test_tzflash.h"
#include "tzflash.h"

#define PAGE_SIZE 1024
#define FLASH_SIZE 10240

static uint8_t gFlash[FLASH_SIZE] = {0};

static bool erase(int addr, int size);
static bool write(int addr, uint8_t* bytes, int size);
static bool read(int addr, uint8_t* bytes, int size);
static void testCase0(void);
static void testCase1(void);
static void testCase2(void);

void TestTZFlashRun(void) {
    printf("-------------------->test tz flash\n");
    TZFlashLoad(PAGE_SIZE, erase, write, read);
    testCase0();
    testCase1();
    testCase2();
    printf("-------------------->test end\n");
}

static bool erase(int addr, int size) {
    if (size % PAGE_SIZE != 0) {
        return false;
    }
    memset(gFlash + addr, 0, (size_t)size);
    return true;
}

static bool write(int addr, uint8_t* bytes, int size) {
    if (addr + size > FLASH_SIZE) {
        return false;
    }
    memcpy(gFlash + addr, bytes, (size_t)size);
    return true;
}

static bool read(int addr, uint8_t* bytes, int size) {
    if (size > FLASH_SIZE - addr) {
        return false;
    }
    memcpy(bytes, gFlash + addr, (size_t)size);
    return true;
}

static void testCase0(void) {
    printf("-------------------->testCase0\n");

    intptr_t fd = TZFlashOpen(0, PAGE_SIZE, TZFLASH_WRITE_ONLY);

    int writeNum = 0;
    writeNum = TZFlashWrite(fd, "i am jdh!", strlen("i am jdh"));
    printf("write:%s", "i am jdh!\n");
    writeNum += TZFlashWrite(fd, "123456789", strlen("123456789"));
    printf("write:%s", "123456789\n");
    writeNum += TZFlashWrite(fd, "abcde", strlen("abcde"));
    printf("write:%s", "abcde\n");

    TZFlashClose(fd);

    fd = TZFlashOpen(0, PAGE_SIZE, TZFLASH_READ_ONLY);
    char buf[100] = {0};
    int readNum = TZFlashRead(fd, buf, writeNum);

    TZFlashClose(fd);

    printf("write num:%d read num:%d read text:%s\n", writeNum, readNum, buf);
}

static void testCase1(void) {
    printf("-------------------->testCase1\n");

    intptr_t fd = TZFlashOpen(1024, PAGE_SIZE * 4, TZFLASH_WRITE_ONLY);

    uint8_t buf[255] = {0};
    for (int i = 0; i < 234; i++) {
        buf[i] = i;
    }

    int writeNum = 0;
    for (int i = 0; i < 10; i++) {
        writeNum += TZFlashWrite(fd, buf, 234);
    }
    printf("write num:%d\n", writeNum);

    TZFlashClose(fd);

    fd = TZFlashOpen(1024, PAGE_SIZE, TZFLASH_READ_ONLY);

    uint8_t buf1[255] = {0};
    int readNum = 0;
    for (int i = 0; i < 5; i++) {
        readNum = TZFlashRead(fd, buf1, 10);
        printf("read num:%d\n", readNum);
        for (int i = 0; i < 10; i++) {
            printf("%d ", buf1[i]);
        }
        printf("\n");
    }

    TZFlashClose(fd);
}

static void testCase2(void) {
    printf("-------------------->testCase2\n");

    intptr_t fd = TZFlashOpen(2048, PAGE_SIZE * 4, TZFLASH_WRITE_ONLY);

    uint8_t buf[1] = {0};
    int writeNum = 0;
    for (int i = 0; i < 1024; i++) {
        buf[0] = i;
        writeNum += TZFlashWrite(fd, buf, 1);
        if (i < 5 || i > 1020) {
            printf("write:%d:%d\n", i, buf[0]);
        }
    }
    printf("write num:%d\n", writeNum);

    TZFlashClose(fd);

    fd = TZFlashOpen(2048, PAGE_SIZE, TZFLASH_READ_ONLY);

    int readNum = 0;
    for (int i = 0; i < 1024; i++) {
        readNum += TZFlashRead(fd, buf, 1);
        if (i < 5 || i > 1020) {
            printf("read:%d:%d\n", i, buf[0]);
        }
    }
    printf("read num:%d\n", readNum);

    TZFlashClose(fd);
}

测试输出:

-------------------->test tz flash
-------------------->testCase0
write:i am jdh!
write:123456789
write:abcde
write num:22 read num:22 read text:i am jdh123456789abcde
-------------------->testCase1
write num:2340
read num:10
0 1 2 3 4 5 6 7 8 9
read num:10
10 11 12 13 14 15 16 17 18 19
read num:10
20 21 22 23 24 25 26 27 28 29
read num:10
30 31 32 33 34 35 36 37 38 39
read num:10
40 41 42 43 44 45 46 47 48 49
-------------------->testCase2
write:0:0
write:1:1
write:2:2
write:3:3
write:4:4
write:1021:253
write:1022:254
write:1023:255
write num:1024
read:0:0
read:1:1
read:2:2
read:3:3
read:4:4
read:1021:253
read:1022:254
read:1023:255
read num:1024
-------------------->test end
2015-08-21 14:15:15 qq_16597387 阅读数 3369
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

该方法用来查看烧写进单片机的文件有多大

1,右键点击IAR的Message窗口,选择option选项

2,下拉菜单选“ALL”,并点击确定

3,回到IAR的菜单栏,点“rebuild”

4,rebuil完了以后可以在Message窗口查看需要烧写到单片机的文件是多大了(如红框所示)



最后可以去看看HEX文件有多大,在IAR工程文件夹下的\Debug\Exe里面,如图所示



最后可知,HEX文件有11k,而烧写进单片机flash的code+data=(3193+272+300)/1024=3.68k

(本人新手,请勿喷,如有错误,欢迎指正!)

2019-06-26 15:13:20 YingRE_1 阅读数 55
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

单片机开发过程中会经历不断地擦写和写入程序的过程,如果做到一些小细节可以延长Flash工艺单片机的Flash擦写使用时间。单片机开发Enroo以Flash 工艺EN单片机为例进行讲解。EN单片机具有1000 K Flash擦除次数,一个Flash Page是512字节,也就是在执行擦除指令时,一次至少擦除512字节的数据。EN Flash 工艺单片机提供了Flash自编程的读、写和擦除函数以及对Flash操作的参考例程。Flash支持单字节读和写,但是每次在更新数据之前必须要先擦除原来的数据,不能在原数据基础上直接写新数据内容。假设每次需要更新的数据长度是16个字节,最简单的方法就是在每次更新数据之前执行擦除指令,然后写入新数据。但是更新数据频率比较高的应用场合,这种方法显然是不行的。此时需要采取“空间换时间”的方法了,擦写的次数和存储数据长度的大小成反比。“空间换时间”就是指利用相对多的Flash空间来换取相对多的擦写时间(次数)。在第一次执行擦除指令后,可以依次将数据写入Flash的这一页,当写满一页后再进行擦除操作。这样的话,一页512字节空间,每次写入16字节长度的数据,一页就可以写32个数据块,写满后再全部擦除,而不用每次写数据前都擦除,该页的擦除次数就可以提高32倍,也就是100K*32=320万次了。

既然思路清晰了,那么单片机软件实现起来就相对比较简单。
单片机编程烧录

首先需要选取数据块中的某一字节作为地址INDEX,更新数据时第一个写入Flash。Flash的编程原理都是只能将1写为0,而不能将0写为1。所以在Flash编程之前,必须将对应的页擦除,而擦除的过程就是把所有位都写为1的过程,页内的所有字节变为0xFF。

写入数据实现过程:

每次写入数据时,从低地址到高地址依次(以16位步进)判断INDEX的内容,为了防止实际数据中包含0xFF内容,从而出现误判的情况,建议判断INDEX和INDEX+1两个地址的内容。如果都为0xFF,表示该地址空间未被写过数据,写入需要更新的数据;如果至少有一个不为0xFF,表示该地址空间已被写过数据,继续查询,直到查到内容都为0xFF为止;如果所有的INDEX(32个)和INDEX+1都至少有一个不为0xFF,表示该页已经写满,执行擦除指令后从首地址写入数据。

读取数据实现过程:

每次读取数据时,从高地址到低地址依次(以16为步进)判断INDEX的内容,这样是为了查询到最新的数据。同样为了防止实际数据中包含0xFF内容,从而出现误判的情况,建议判断INDEX和INDEX+1两个地址的内容。如果至少有一个不为0xFF,表示该地址已写过数据,读取数据;如果所有的INDEX(32个)和INDEX+1都为0xFF,表示该页还未写入数据。
以上是单片机开发Enroo的分享。

2008-06-07 16:03:00 sbtdkj1017 阅读数 5321
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

在单片机编程中往往需要长期保存某些数据,尤其是一些配置参数,这样掉电后这些数据仍然还在。于是就开始了FLASH读写的编程,经过了一天多的努力,终于把FLASH的读写调通了。主要有三点:

一、读FLASH

要用MOVC指令才能读FLASH,这个比较简单。

二、写FLASH

严格按照下面的流程即可完成写操作

1. 禁止中断。

2. 置位FLWEFLSCL.0),以允许由用户软件写/擦除FLASH

3. 置位PSEEPSCTL.1),以允许FLASH 扇区擦除。

4. 置位PSWEPSCTL.0),以允许FLASH 写。

5. 用MOVX 指令向待擦除扇区内的任何一个地址写入一个数据字节。

6. 清除PSEE 以禁止FLASH 扇区擦除。

7. 用MOVX 指令向刚擦除的扇区中所希望的地址写入数据字节。重复该步直到所有字

节都已写入(目标扇区内)。

8. 清除PSWE 以禁止FLASH 写,使MOVX 操作指向XRAM 数据空间。

9. 重新允许中断。

三、指针

C语言里可没有MOVCMOVX,为了实现这两个指令,需要定义指针。根据Keil C的语法可知,将变量(指针)声明为code型和xdata型时相应的赋值操作即对应于MOVCMOVX。当然,如果用汇编语言就没这个问题了。

下面给出一个最简单的例子(在C8051F020Keil uV2下调试通过,程序的功能是每次复位后P1口的输出状态为上次的取反)

#include<c8051f020.h>

unsigned char test; //保存输出状态

//FLASH中保存输出状态

/*For reading*/

unsigned char code test_c _at_ 0xCF20;

/*For writing*/

unsigned char xdata test_x _at_ 0xCF20;

void ReadState()

{     //FLASH中读取信号输出状态与PWM

       test=test_c;

}

void StoreState()

{     //此函数不可频繁调用,对FLASH有损(寿命一般为100000)

       //FLASH中写入输出状态

       EA=0;     //为了避免对FLASH的误写,需禁止中断

       FLSCL = 0x81;      //允许由用户软件写/擦除FLASH

       PSCTL = 0x03;      //允许FLASH扇区擦除及FLASH

       test_x=0; //擦除扇区

       PSCTL &= 0xFD;  //清除PSEE 以禁止FLASH 扇区擦除

       test_x=~test;   //输出状态按位取反后写入FLASH

       PSCTL = 0;    //禁止FLASH

//     FLSCL = 0x80;      //disable FLASH writes

       EA=1;     //重新允许中断

}

void main(void)

{     WDTCN=0xde;

       WDTCN=0xad;

       //Add initialization code here

       P1MDOUT=0xff;

       ReadState();

       P1=test;

       StoreState();

       while(1);

}

2019-07-15 17:25:01 weixin_42967006 阅读数 319
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3995 人正在学习 去看看 朱有鹏

最近工作上需要对英飞凌XC886这款单片机的Flash进行读写,以下为简要的几点总结:

一、Flash存储器结构:
XC886共有32KFlash,地址映射如下图所示:

Flash地址映射
共三块P-Flash用来存储程序,两块D-Flash既可用来存储程序也可以存储数据,每块D-Flash映射到两个不同的地址,如Bank1映射到6000-6FFF和B000-BFFF,通常存储程序的时候采用低地址,存储数据的时候采用高地址。此处需注意每个Flash bank虽然映射到了两个地址,但实际在物理上是同一块Flash,不要把两组地址当做两块Flash来操作,否则会相互影响数据。

二、Flash bank的分区如下图所示:
Flash bank的分区
D-Flash分区较为灵活。因为Flash每次擦除要擦除整个扇区(Sector),所以扇区划分越细越有利于我们操作。Flash写之前都需要先擦除,擦除后的状态为全0,写的时候可以从0写为1,不能从1写为0。

三、写Flash:
写Flash的时候每次要写一个字线地址(WL),对于P-Flash来说是64个字节,D-Flash来说是32个字节,下图为手册中给出的字线地址划分:
P-Flash字线地址
D-Flash字线地址
芯片手册中对于Flash的写给出了如下说明:

对于 P- Flash bank,由于 Flash 单元只能承受一个门干扰,因此已编程的字线在重新编程前必须先擦除。因为不可能单独擦除一条字线,这即意味着包৿该字线的整个扇区必须全部被擦除。
对于 D- Flash bank,由于 Flash 单元能承受两个门干扰,同一条字线在擦除前可编程两次。 这即意味着如果需要编程的数据字节的个数小于 32 字节(最小编程宽度), 用户可选择先编程这些数据字节(x; x 可以是 1-31 之间的任意整数),之后再编程其余字节(32-x)。 不过,由于 D-Flash 的最小编程宽度始终为 32 个字节,因此在每个编程周期中᳾被编程的字节必须写入全 0。

没有能够很透彻地理解它的这段话,但实际试验结果是对于D-Flash来说,一个WL在擦除前可被编程多次,即只要原来为0x00的字节都可以被写入非0值,对于原来已有数据的字节,已经被写入1的数据位不能再被写入0,但如果有某一位没有被写入过1,通常情况下可以被写入1,例如0x80(10000000)可以被写为0x81(10000001),但这并不代表Flash可以按位操作,例如实测0x03(00000011)想写为0x07(00000111)时就会写入失败,原因没有深入研究。

四、Flash模拟EEPROM
因为Flash使用寿命有限,只针对Flash的一个区域进行操作会造成其快速老化,使用效率过低,所以可以通过算法来模拟EEPROM,循环使用Flash的多个Sector,延长寿命,同时也避免存储数据时相互冲突和影响。英飞凌官方提供了三种Flash模拟EEPROM的算法,例程代码和说明见
https://download.csdn.net/download/weixin_42967006/11356942
其中操作Flash的函数是用汇编写的,如下图所示,给出了在C语言中调用的接口。 Flash读写函数
官方给出的三个算法都略为复杂,我只需存储一个标志位,所以在实际应用的时候自己简单做了个简单的小算法,能够实现标志位的存储,并且循环使用了bank1的每一个sector,把代码贴出来供大家参考。

char selectedLanguage=0; //
unsigned char code * piWLAddress;
unsigned char code * piWLAddressToCover=-1;
char idata ucSectorNumberToRead=0;
char idata ucSectorNumberToErase=-1;
unsigned char data storedLanguage[32]=0;
char code * code iSectorAddress[10]={0xB000,0xB400,0xB800,0xBA00,0xBC00,0xBD00,0xBE00,0xBE80,0xBF00,0xBF80};

//查找有效的Sector
SearchSector:
	piWLAddress=iSectorAddress[ucSectorNumberToRead];
SearchWL:
	if(*piWLAddress==0x81)//用过,失效
		{
			if(piWLAddress==0xBFE0 )//到达最后一个WL
			{
				selectedLanguage=0; 
				ucSectorNumberToErase=0;		//	ucSectorNumber无效sector,待擦除写入有效值 	
				piWLAddress=iSectorAddress[ucSectorNumberToErase];
				goto SearchEnd;
			}
			else
				{
				piWLAddress+=0x20;
				if(ucSectorNumberToRead<9 && piWLAddress==iSectorAddress[ucSectorNumberToRead+1])//判断是否到达下一个sector
					{
					ucSectorNumberToRead++;
					goto SearchSector;
					}
				else goto SearchWL;
				}
		}
		else if(*piWLAddress==0x80)//有效
		{
			selectedLanguage=*(piWLAddress+1);
			if(selectedLanguage<0||selectedLanguage>2) selectedLanguage=0;
			if(piWLAddress==0xBFE0)//已经是最后一个WL
				{
				ucSectorNumberToErase=0;
				piWLAddressToCover=piWLAddress;
				piWLAddress=iSectorAddress[ucSectorNumberToErase];
				}
			else
				{
				piWLAddressToCover=piWLAddress;
				piWLAddress+=0x20;
				if(piWLAddress==iSectorAddress[ucSectorNumberToRead+1])//是否到达下一个sector
					{
					ucSectorNumberToErase=ucSectorNumberToRead+1;//擦除下一个sector
					}
				}
		}
		else//无有效sector
		{
			//	ucSectorNumber无效sector,待擦除写入有效值 					
				selectedLanguage=0; 
				ucSectorNumberToErase=ucSectorNumberToRead;		//	ucSectorNumber无效sector,待擦除写入有效值 	
				piWLAddress=iSectorAddress[ucSectorNumberToErase];
		}
SearchEnd:
……
//写入有效数据
//其中NMISR为单片机NMI状态寄存器,当Flash动作执行完毕后第3位会置1
	if(piWLAddressToCover!=-1)//将已用WL置为已用
	{
		storedLanguage[0]=0x81;
		FLASH_PROG(piWLAddressToCover,(char data*)storedLanguage);
		while(0==(NMISR & 0x04));
		NMISR &= ~(ubyte)0x04;
	}
	
	//erase sector
	if(ucSectorNumberToErase!=-1)
		{
//								lEraseSector=0x00000001<<ucSectorNumberToErase;
//								FLASH_ERASE((char)(lEraseSector>>16),(char)(lEraseSector>>24),//D-Flash bank 0 sector 0-9
//														(char)lEraseSector,(char)(lEraseSector>>8),//D-Flash bank 1 sector 0-9
//														0,0,0);//P-Flash
		FLASH_ERASE(0,0,//D-Flash bank 0 sector 0-9
								(char)(0x0001<<ucSectorNumberToErase),(char)(0x00000001<<(ucSectorNumberToErase-8)),//D-Flash bank 1 sector 0-9
								0,0,0);//P-Flash

		while(0==(NMISR & 0x04));
		NMISR &= ~(ubyte)0x04;
		}
	
	storedLanguage[0]=0x80;
	storedLanguage[1]=selectedLanguage;
	FLASH_PROG(piWLAddress,(char data*)storedLanguage);//存有效数据
	while(0==(NMISR & 0x04));
	NMISR &= ~(ubyte)0x04;

以上。其实大部分内容是参考的芯片手册,这里只是将我觉得有用的地方做了记录和提炼,方便日后查询,也欢迎大家交流指正。

没有更多推荐了,返回首页