不同的存储器有不同的类型,这是由制造工艺所决定的制造材料和工艺决定的。
flash存储器具有读写快速
STM8S单片机使用一系列先进的存储管理机制来管理片内的多个存储器。要明确STM8S单片机的存储器组织结构,需要理解一下几个基本概念:
- 块(BLOCK):块是指可由一个简单编程操作“编程”或“擦除”的一组字节。块的操作非常快,是“编程”和“擦除”操作的基本单元。
- 页(PAGE):页有一组“块”组成。STM8S单片机内有启动代码、程序代码和数据EEPROM,这些区域都有特定的结构所保护。通过对特定的选项字节进行操作,这些区域的大小能够一页为单位进行调整。
- 在线编程(ICP):在线编程用于更新整个存储器的内容,编程器通过SWIM接口把编译生成的程序代码下载到微控制器中。
- 在应用编程(IAP):在应用编程可以使用STM8支持的任意通讯接口(I/O、I2C、SPI、UART)来下载要编入存储器的中的数据。IAP允许应用程序在运行中对FLASH程序存储器的内容进行更新。
这种操作是芯片以及应用在实际的使用环境中了,可以脱离SWIM接口以及脱离编程器。
5.读写同时(RWW):RWW允许单片机在执行程序和读程序的存储器时对DATA和EEPROM区域进行写操作,由于读和写同时进行,可以提高代码的执行速度。
存储器的基本结构:
STMS的存储器的基本单位是“字”,每个字有4个字节即32位构成。所有存储器都是以“字”为单位基础组织起来的。按照片内存储容量不同,STM8S单片机分为小容量产品8K,中容量产品(16K-32K)和大容量产品(64K-128K)三类。
1字 = 4字节 = 32位
存储器的组织结构:
STM8S单片机片内有2K字节数据EEPROM,每页512字节,共有4页。数据EEPROM中包括一页的选项字节(512字节);128K字节FLASH程序存储器,每页512字节,共256页,其中中断向量占用了最初的128字节,之后可定义大小(以页为单位)的启动代码区域(UBC)。
1、数据EEPROM(DATA)
数据EEPROM(DATA)区域可用于存储程序中所需要的数据。在默认情况下EEPROM区域是写保护的,只有使用特定的MASS密钥才能对DATA区域的写保护解锁。
2、选项字节(Option byte)
选项字节用于配置硬件特性和存储器的保护状态。选项字节位于数据EEPROM中特定的存储阵列中,占用一个页的存储空间。选项字节可以在ICP/SWIM模式或ICP下被修改。
修改选项字节的方式是通过编程器来操的。
3、主程序区
主程序区是指在FLASH程序存储器中用于存储应用代码的区域。STM8S208RB单片机的主程序区大小为128K字节。
4、启动代码区域(UBC)
用户启动区域位于主程序区的起始部分,这一区域包含有128字节的复位和中断向量表。
UBC区域可用于存储IAP及通讯程序,通常状态下该区域是写保护的,以防止用户代码及数据在IAP编程中对其擦除或者修改。
UBC区域写保护状态不能通过使用MASS密钥来解锁。UBC区域的大小是可编程的,在ICP模式下(使用SWIM接口)可以通过修改选项字节来配置。
存储器保护
存储器的保护分成“写保护”和“读保护”两种。
当选字节中ROP字节被编成“0xAA”时,存储器的读保护功能使能。此时使用SWIM接口读取或修改FLASH程序存储器、UBC、和DATA区域都是被禁止的。应当说STM8单片机所提供的都保护安全级别是很高的,这对程序安全和知识产权保护十分的重要。
可以在ICP模式中通过对选项字节的ROP字节重新编程来解除程序存储器、UBC和DATA区域保护。一旦读保护被解除,程序存储器、UBC和DATA区域以及选项字节都被自动擦除,器件恢复到初始状态并可以重新编程。
存取安全系统
存储器存取安全系统(MASS)是在系统复位以后,主程序区(FLASH)和DATA(EEPROM)区都被自动保护起来,以防止无意的写操作。在试图修改前必须要对其进行解锁,而解锁的机制是有存储器存取安全系统(MASS)来管理的。
解除主程序存储器区域的写保护的过程:
1)向FLASH_PUKR寄存器写入一个8位密钥。在系统复位以后,当着寄存器首次写入时,数据总线上的值没有被直接所存到这个寄存器中,而是和第一个硬件密钥(0xAE)进行比较。如果密钥是错误的,FLASH_PUKR寄存器在下一次复位之前将一直被锁存,此时间段内向寄存器中进行任何操作都会被忽略。
2)如果第一个硬件密钥正确,当这个寄存器FLASH_PUKR被第二次写入硬件密钥时,数据总线上的值同样也不会直接所存到这个寄存器中,而是再次和第二个硬件密钥(0x56)相比较。如果密钥输入错误,FLASH_PUKR寄存器会再次进入锁定状态。
3)如果第二个密钥正确,主程序的写保护被解除,FLASH_PUKR寄存器中的PUL位置位。因此同样可以通过判断FLASH_PUKR寄存器中的PUL位是否被置位来判断主程序写保护功能有没有被解除。PUL需要在软件中清零操作,因此应用程序可以在任意的时刻通过清空PUL位来重新禁止对FLASH程序区域的写操作。
1、对主程序存储器的写操作
在器件复位后,可以通过向FLASH_PUKR寄存器连续写入两个MASS密钥来解除主程序存储器的写保护。这两个写入FLASH_PUKR的值会和以下两个硬件密钥值相比较:
第一个硬件密钥: 0b 1010 1110(0xAE)
第二个硬件密钥:0b 0101 0110(0x56)
2、对DATA区域的写操作
在器件复位后,可以通过向FLASH_DUKR寄存器连续写入两个MASS密钥来解除DATA区域的写保护操作。这两个写入FLASH_DUKR的值会和一下两个硬件密钥相比较。
第一个硬件密钥: 0b 1010 1110(0xAE)
第二个硬件密钥:0b 0101 0110(0x56)
解除主程序存储器区域的写保护的过程:
1)向FLASH_DUKR寄存器写入一个8位密钥。在系统复位以后,当着寄存器首次写入时,数据总线上的值没有被直接所存到这个寄存器中,而是和第一个硬件密钥(0xAE)进行比较。如果密钥是错误的,FLASH_DUKR寄存器在下一次复位之前将一直被锁存,此时间段内向寄存器中进行任何操作都会被忽略。
2)如果第一个硬件密钥正确,当这个寄存器FLASH_DUKR被第二次写入硬件密钥时,数据总线上的值同样也不会直接所存到这个寄存器中,而是再次和第二个硬件密钥(0x56)相比较。如果密钥输入错误,FLASH_DUKR寄存器会再次进入锁定状态。
3)如果第二个密钥正确,主程序的写保护被解除,FLASH_DUKR寄存器中的DUL位置位。因此同样可以通过判断FLASH_DUKR寄存器中的DUL位是否被置位来判断主程序写保护功能有没有被解除。DUL需要在软件中清零操作,因此应用程序可以在任意的时刻通过清空PUL位来重新禁止对FLASH程序区域的写操作。
存储器的编程
STM8S单片机的DATA(EEPROM)和FLASH存储器与内存统一编址,应用程序可以直接访问该内存储存器的地址以以及读写该存储单元的数据,这无疑给编程带来了极大的方便。STM8S单片机支持字节编程、字编程和块编程三种方式。
DATA(EEPROM)和FLASH存储器地址分配:
DATA(EEPROM) 起始地址00 4000h 到 00487Fh结束 FLASH起始地址 00 8000h 到 02 7FFFh结束
1、字节编程
STM8S字节编程是所有 存储器 编程的基础。主程序存储器FLASH和数据存储器DATA(EEPROM)区域都可以以字节为单位逐一读写,应用程序可以直接向目标地址写入数据。
于对主程序存储器,当字节编程操作执行时,应用程序会停止运行。
在对DATA区域编程时,有RWW功能的器件,在IAP模式下应用程序不会停止运行,而对于无RWW功能器件,当字节编程操作执行时,应用程序停止运行。
另外,在擦除一个字节时,只要向对应的字节地址写入“0x00”即可。
应用程序可以通过读取FLASH状态寄存器FLASH_IAPSR寄存器来检验编程或擦除操作是否已经被正确的执行,当一次成功的编程操作之后,FLASH_IAPSR寄存器的EOP为会自动被置1。另外,当软件试图对一个已经写保护的页进行操作时,FLASH_IAPSR寄存器的WP_PG_DIS位会被置1,言外之意就是在对FLASH存储器进行写操作之前,可以先判断FLASH_IAPSR寄存器中的WP_PG_DIS位的状态,如果这个的位的状态是1说明FLASH寄存器的写操作是被禁止的。在这种情况下写操作是不会被执行的。如果FLASH_CR1中的IE位已经被使能,上述标志位均会产生中断。
2,字编程
字写入操作允许一次对整个4字节的字进行编程,从而将编程的时间缩短。主程序存储器FLASH和数据的存储器DATA EEPROM都可以进行字操作。在使用字操作编程之前需要将FLASH_CR2和FLASH_NCR2寄存器中的WPRG/NWPRG位置位和清零以使能字编程模式。之后将被编程字的4个字节从首地址依次写入,编程周期会自动开始。同字节操作一样,FLASH_IAPSR寄存器中的EOP与WR_PG_DIS控制位和FLASH中断相配合,可用于检查字编程操作是否被正确执行。
PALSH_CR2 和 FLASH_WCR2是互补寄存器,它们两个的操作是相反的。
3、块编程
主程序存储器FLASH和数据存储器DATA EEPROM区域都可以执行块操作。块编程和字节编程和字编程都要快,在块编程操作中,整个块的编程和擦除在以一个编程周期就可以完成。
在对主程序存储器FLASH执行块编程时,所有的代码必须全部在RAM中执行,既是需要将数据通过变量读取出来操作。在对DATA EEPROM数据存储器区域进行块编程时,有RWW功能的器件,块操作可在主程序存储器中执行,然而数据的装载阶段必须在RAM中执行,无RWW功能的器件,用于块编程的代码必须全部在RAM中执行。
同样,块编程需要通过FLASH_CR2和FLASH_NCR2寄存器的相应控制位才可进行。
块编程又可以细分为以下三种不同的操作:
标准块编程:整个块在变成前被自动删除
快速块编程:在编程前没有预先的块擦除操作。
块擦除:对所有块内字节写0.
存储器的控制寄存器
1、FLASH_CR1 FLASH控制寄存器1
2、FLASH_CR2 FLASH控制寄存器2
3、FLASH_NCR2 FLASH互补控制寄存器
4、FLASH_PUKR FLASH程序存储器解保护寄存器
5、FLASH_DUKR DATA EEPROM 数据存储器解保护寄存器
6、FLASH_IAPSR FLASH状态寄存器
与其他集成EEPROM的单片机不同,在STM8单片机中,EEPROM的地址空间与内存是统一编址的,地址从004000H开始。
选项字节的功能:
STM8S系列单片机使用选项字节来配置芯片的硬件特性和存储器的保护状态,这些字节保存在EEPROM存储器中一个专用的快内,可以在ICP模式下,通过SWIM方式来访问和修改,也可以通过应用程序在IAP模式下修改。
试列:
//EEPROM读写
#include <STM8S208R.h>
const unsigned char table0[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; // 共阴码表无点
const unsigned char table1[]= {0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; // 共阴码表有点
unsigned char NUM; //定义显示变量
unsigned int *P; //定义指针变量
void Delay_Ms(unsigned int ms);//毫秒级延时函数
void Delay_Us(unsigned char t);//微秒级延时函数
void Seg_Init(void);//数码管初始化
void Display(unsigned int num);//数码管显示函数
main()
{
CLK_SWCR = 0x02; //使能时钟切换
CLK_SWR = 0xB4; //时钟源为HSE 0xB4 HSI 0xE1 LSI 0xD2
Seg_Init(); //数码管驱动初始化
P = (unsigned int *)0x4000; //指针P指向EEPROM第一个单元
FLASH_DUKR = 0xAE; // 写入第1个硬件密钥对数据EEPROM进行解锁
FLASH_DUKR = 0x56; // 写入第2个硬件密钥对数据EEPROM进行解锁
while((FLASH_IAPSR & 0x08) == 0); //等待DATA EEPROM数据解锁成功
while(1)
{
NUM = *P; //从EEPROM的*P位置(0x4000)读取数据并赋值给NUM
Display(NUM); //显示NUM的值
NUM++; //NUM的值自加
*P = NUM; //将自加后的NUM值写入EEPROM的*P位置(0x4000)
while((FLASH_IAPSR & 0x04) == 0); //等待写入成功
}
}
void Seg_Init(void)
{
PB_DDR = 0xFF; // 设置PB端口位输出模式
PB_CR1 = 0xFF; // 设置PB端口位开漏输出
PB_CR2 = 0x00; // 设置PB端口端口输出速度位2MHz
//这个端口设置数码管的位选段
PF_DDR |= 0xF0; // 设置PF端口的高四位为输出模式
PF_CR1 |= 0xF0; // 设置PF端口的高四位为开漏输出
PF_CR2 &= 0x00; // 设置PF端口的高四位输出速度为2MHZ
//这个端口用于设置74HC53芯片使能
PE_DDR |= 0x01; // 设置PE0端口设置成输出模式
PE_CR1 |= 0x01; // 设置PE0端口设置成推挽输出
PE_CR2 &= 0x00; // 设置PE0端口输出速率为2mhz
PD_DDR |= 0x10; //
PD_CR1 |= 0x01;
PD_CR2 &= 0x00;
//使能数码管
PE_ODR &= 0xFE; // PE0=0,使能数码管
}
void Delay_Ms(unsigned int ms)
{
unsigned int x,y;
for(x=ms;x>0;x--)
{
for(y=300;y>0;y--)
{
}
}
}
void Delay_Us(unsigned char t)
{
unsigned char m=t;
while(m--);
}
void Display(unsigned int num)
{
unsigned char GeWei,ShiWei,BaiWei,QianWei;
GeWei = num%10;
ShiWei = num%100/10;
BaiWei = num%1000/100;
QianWei = num/1000;
PB_ODR = table1[GeWei];
PF_ODR = 0xE0;
Delay_Ms(5);
PB_ODR = 0;
PF_ODR = 0xF0;
Delay_Ms(1);
PB_ODR = table1[ShiWei];
PF_ODR = 0xD0;
Delay_Ms(5);
PB_ODR = 0;
PF_ODR = 0xF0;
Delay_Ms(1);
PB_ODR = table1[BaiWei];
PF_ODR = 0xB0;
Delay_Ms(5);
PB_ODR = 0;
PF_ODR = 0xF0;
Delay_Ms(1);
// PB_ODR = table0[QianWei];
// PF_ODR = 0x70;
// Delay_Ms(3);
// PB_ODR = 0;
// PF_ODR = 0xF0;
// Delay_Ms(1);
}