【STC8A8K64D4开发板】第2-8讲:片内存储器

news2024/10/11 6:38:01

第2-8讲:片内EEPROM读写

    1. 学习目的
  1. 了解STC8A8K64D4片内EEPROM的分布和特点。
  2. 掌握STC8A8K64D4片内EEPROM分配以及读、写和擦除。
    1. 片内EEPROM概述

开发产品的时候,我们经常会遇到需要保存数据的应用场景,如一些重要的记录信息或软/硬件配置信息等。这些保存的数据在掉电的情况下是不能丢失的,并且,在需要的时候,用户也可以对数据进行更改。

STC8A8K64D4系列单片机考虑到了这样的应用场景,他利用 ISP/IAP 技术可将内部 Data Flash当 EEPROM,从而实现数据的掉电不丢失存储,EEPROM按照扇区组织的,每个扇区的大小是512字节,支持的擦写次数在 10 万次以上。

  1. 片内EEPROM分布

STC8A8K64D4 系列单片机片内集成了64K 字节的Flash(EEPROM),Flash和EEPROM的大小取决于具体的单片机型号,如下表所示。

不同型号的单片机的Flash和EEPROM大小不同,但是他们的和都是64K字节,该系列单片机中,STC8A8K64D4比较特殊,他的EEPROM大小是可以由用户设定的。

表1:STC8A8K64D4 系列单片机片内Flash和EEPROM分布

单片机型号

EEPROM大小

EEPROM扇区数量

STC8A8K16D4

48K

96

STC8A8K32D4

32K

64

STC8A8K48D4

16K

32

STC8A8K60D4

4K

8

STC8A8K64D4

用户自定义,大小必须是512的倍数。

  1. 片内EEPROM特点
  1. STC8A8K64D4 系列单片机片内EEPROM 的擦除是以扇区为单位进行的。
  2. EEPROM是逐字节读写的,写之前,写入地址所在的扇区需要先执行扇区擦除操作。这是因为EEPROM 的写操作只能将字节中的各个位由1 写为 0,而不能将0写为1,因此,写之前需要通过扇区擦除操作将整个扇区的位都写为1。
  1. EEPROM操作时间
  1. 读取 1 字节:4 个系统时钟(使用 MOVC 指令读取更方便快捷)。
  2. 编程 1 字节:约 30~40us(实际的编程时间为 6~7.5us,但还需要加上状态转换时间和各种控制信号的 SETUP 和 HOLD 时间)擦除 1 扇区( 512 字节): 约 4~6ms。

EEPROM 操作所需时间是硬件自动控制的,用户只需要正确设置 IAP_TPS 寄存器即可。IAP_TPS=系统工作频率/1000000(小数部分四舍五入进行取整)。

  1. 例如: 系统工作频率为 12MHz,则 IAP_TPS 设置为 12。
  2. 又例如: 系统工作频率为 22.1184MHz,则 IAP_TPS 设置为 22。
  1. EEPROM的访问

EEPROM 的访问方式有两种: IAP 方式和 MOVC 方式。IAP 方式可对 EEPROM 执行读、写、擦除操作,但 MOVC 只能对 EEPROM 进行读操作,而不能进行写和擦除操作。无论是使用 IAP 方式还是使用MOVC方式访问 EEPROM,首先都需要设置正确的目标地址。IAP方式时,目标地址与 EEPROM 实际的物理地址是一致的,均是从地址 0000H 开始访问,但若要使用 MOVC 指令进行读取 EEPROM 数据时,目标地址必须是在 EEPROM 实际的物理地址的基础上还有加上程序大小的偏移。

  1. 应用建议:
  1. 使用EEPROM存储数据时,可以考虑将关联性不强的数据分别存放在不同的扇区。这样,当某类数据需要更新时,就不需要对其他不相关的数据存放扇区进行操作。
  2. 存储数据时,应对数据更新的频率进行评估,以保证产品的生命周期内擦写次数不超过芯片支持的最大值(10万次)。如果数据更新频率高,可以考虑将数据在不同的扇区轮换存放,或者在同一个扇区的不同地址轮换存放,以降低使用的EEPROM扇区的擦写次数。
    1. 软件设计
      1. EEPROM读写步骤

EEPROM操作需要按照下面几个步骤进行,包含规划写入数据的EEPROM空间、擦除EEPROM、写EEPROM以及读EEPROM。

图1:EEPROM读写操作步骤

        1. 规划写入数据的EEPROM空间

操作EEPROM之前,我们需要从片内Flash中划分出EEPROM空间,STC8A8K64D4系列单片机中,STC8A8K64D4型号单片机的EEPROM是需要用户自己设定的,其他型号都是已经分配好的,固定大小的。

STC8A8K64D4型号单片机的EEPROM空间划分下载程序时在STC-ISP 软件中设置的,如下图所示。

图2:EEPROM划分方法

EEPROM 分配总是从顶端向下分配的,下图是STC8A8K64D4型号单片机分配4K字节EEPROM的示例。

图3:分配4K字节EEPROM

我们在分配EEPROM空间时需要注意以下几点:

  1. 分配的EEPROM空间必须是512的倍数,即分配的单位是扇区。
  2. 分配的EEPROM空间不能占用程序存储的空间。
        1. 擦除EEPROM扇区

EEPROM擦除扇区时,只能使用IAP方式。擦除流程中需要注意的是,执行扇区擦除时,输入该扇区的任意地址即可,如擦除EEPROM的第一个扇区,地址输入“0x0000~0x01FF”中的任意地址都可以。通常,我们编程时,为了方便指定擦除的扇区,习惯于使用扇区的首地址作为擦除该扇区的地址,如擦除EEPROM的第一个扇区,地址输入“0x0000”。

图4:EEPROM擦除流程

  1. 使能和关闭IAP

EEPROM擦除扇区前需要使能IAP,擦除完成后需要关闭IAP。使能和关闭IAP由“EEPROM 控制寄存器( IAP_CONTR)”的位7(IAPEN)控制,如下图所示。

EEPROM 控制寄存器( IAP_CONTR):

  1. 设置等待时间

等待时间由“EEPROM 等待时间控制寄存器(IAP_TPS)”的位5~位0(IAPTPS[5:0])设置,如下图所示。

EEPROM 等待时间控制寄存器( IAP_TPS):

IAP_TPS=系统工作频率/1000000(小数部分四舍五入进行取整)。如本例中使用的系统工作频率为 24MHz,因此 IAP_TPS 设置为 24。

  1. 设置IAP命令(擦除扇区)

IAP命令由“EEPROM 命令寄存器(IAP_CMD)”的位1~位0(CMD[1:0])设置,如下图所示。

EEPROM 命令寄存器(IAP_CMD):

  1. CMD[1:0]:发送EEPROM操作命令
  1. 00: 空操作。
  2. 01: 读 EEPROM 命令。读取目标地址所在的 1 字节。
  3. 10: 写 EEPROM 命令。写目标地址所在的 1 字节。 注意:写操作只能将目标字节中的 1 写为 0,而不能将 0 写为 1。一般当目标字节不为 FFH 时,必须先擦除该目标地址所在的扇区。
  4. 11:擦除 EEPROM。擦除目标地址所在的扇区。注意:擦除操作会一次擦除 1个扇区(512 字节),整个扇区的内容全部变成 FFH。
  1. 设置扇区地址

扇区地址由“EEPROM 地址寄存器(IAP_ADDR)”设置,地址是16位的,IAP_ADDRH 保存扇区地址的高字节, IAP_ADDRL保存扇区地址的低字节,如下图所示。

EEPROM 地址寄存器(IAP_ADDR):

  1. 扇区地址设置示例:擦除EEPROM的第一个扇区(使用该扇区的任意地址都可以,习惯上使用起始地址)

IAP_ADDRH = 0xF0; //地址的高8位写入IAP_ADDRH寄存器

IAP_ADDRL = 0x00; //地址的高8位写入IAP_ADDRL寄存器

  1. 触发EEPROM操作

完成前面的4步配置之后,向EEPROM 触发寄存器(IAP_TRIG)先写入 5AH,再写入 A5H即可触发扇区擦除。EEPROM 触发寄存器(IAP_TRIG)如下图所示。

EEPROM 触发寄存器(IAP_TRIG):

写完触发命令后, CPU 会处于 IDLE 等待状态,直到相应的 IAP 操作执行完成后 CPU 才会从 IDLE 状态返回正常状态继续执行 CPU 指令。

        1. 写EEPROM

EEPROM编程只能使用IAP方式。EEPROM编程步骤如下图所示,他和擦除步骤类似,图中红色字体标注的步骤是和擦除操作不一样的。这里,我们只描述不一样的部分,其他步骤读者参照擦除操作即可。

图5:EEPROM写流程

  1. 设置IAP命令(编程EEPROM)

编程EEPROM 时,“EEPROM 命令寄存器(IAP_CMD)”的位1~位0(CMD[1:0])写入数值“10”。

编程时需要注意,待编程的地址所在的EEPROM扇区必须是擦除过的,否则,可能会导致错误。

  1. 设置EEPROM编程地址

和擦除操作地址一样,EEPROM编程地址也是由“EEPROM 地址寄存器(IAP_ADDR)”设置的。每次编程完成后,IAP_ADDRL 和 EEPROM 命令寄存器IAP_CMD 的内容不变,即地址不会自动递增,因此,在连续的地址上批量写入数据时,需手动更新地址寄存器IAP_ADDRH 和寄存器 IAP_ADDRL 的值。

  1. 待编程数据写入IAP_DATA寄存器

待编程数据在触发 EEPROM 的写操作前,必须写入到“EEPROM 数据寄存器(IAP_DATA)”,每次只能写入一个字节数据。

        1. 读EEPROM

EEPROM读取数据可以使用IAP方式或 MOVC 方式。IAP方式读步骤如下图所示,他和擦除、写步骤类似,图中红色字体标注的步骤是和擦除、写操作不一样的。这里,我们只描述不一样的部分,其他步骤读者参照擦除、写操作即可。

图6:EEPROM读流程

  1. 设置IAP命令(读EEPROM)

读EEPROM 时,“EEPROM 命令寄存器(IAP_CMD)”的位1~位0(CMD[1:0])写入数值“01”。

  1. 设置读地址

EEPROM读地址同样是由“EEPROM 地址寄存器(IAP_ADDR)”设置的。每次读完成后,IAP_ADDRL 和 EEPROM 命令寄存器IAP_CMD 的内容不变,即地址不会自动递增,因此,在连续的地址上批量读出数据时,需手动更新地址寄存器IAP_ADDRH 和寄存器 IAP_ADDRL 的值。

  1. 从IAP_DATA寄存器读出数据

读 EEPROM时,读命令执行完成后读出的 EEPROM 数据保存在 IAP_DATA 寄存器中。程序中,可以从IAP_DATA 寄存器获取读取的数据。

从EEPROM读取数据,还可以使用MOVC方式,MOVC方式读取速度要快于IAP方式。使用MOVC方式读取时,需要注意地址和IAP模式是不一样的,MOVC方式需要加上偏移地址。如下图所示,当从Flash划分4K字节的EEPROM后,IAP方式操作EEPROM是从地址0开始的,MOVC方式操作EEPROM的地址是从0xF000开始的。

图7:IAP方式和MOVC方式操作EEPROM时的地址

      1. EEPROM读写实验
  • 注:本节的实验是在“实验2-6-1:串口1数据收发实验”的基础上修改,本节对应的实验源码是:“实验2-8-1:片内EEPROM读写”。
        1. 实验内容

本例中,从Flash中划分4K字节的EEPROM(共8个扇区)。程序中检测KEY1按键的状态,当KEY1按键按下后,擦除EEPROM的第1个扇区,然后从该扇区的起始地址开始连续写入256字节数据,之后分别通过IAP方式和MOVC方式读出数据并通过串口输出。

        1. 代码编写
  1. 新建一个名称为“eeprom.c”的文件及其头文件“eeprom.h”并保存到工程的“Source”文件夹,并将“eeprom.c”加入到Keil工程中的“SOURCE”组。
  2. 引用头文件

因为在“main.c”文件中使用了“eeprom.c”文件中的函数,所以需要引用下面的头文件“eeprom.h”。

代码清单:引用头文件

  1. //引用EEPROM的头文件  
  2. #include    "eeprom.h"  

  1. 编写禁止访问EEPROM的函数

使用IAP方式操作EEPROM时,每次操作完成后都需要关闭对EEPROM的访问,并清零相关的寄存器,为了方便程序操作,我们编写一个禁止访问EEPROM的函数“EEPROM_Disable ()”供EEPROM操作调用,代码清单如下。

代码清单:禁止访问EEPROM

  1. /************************************************************************** 
  2. * 描  述 : 禁止访问EEPROM 
  3. * 参  数 : 无 
  4. * 返回值 : 无 
  5. *************************************************************************/  
  6. void EEPROM_Disable(void)  
  7. {  
  8.    IAP_CONTR = 0x00;           //禁止EEPROM操作  
  9.    IAP_CMD   = 0x00;           //清零EEPROM命令寄存器  
  10.    IAP_TRIG  = 0x00;           //清零EEPROM触发寄存器,防止ISP/IAP命令误触发  
  11.    IAP_ADDRH = 0xFF;         //将地址设置到非IAP区域,防止误操作  
  12.    IAP_ADDRL = 0xFF;           
  13. }  
  1. 擦除EEPROM扇区

因为EEPROM的编程原理是只能将各个bit由1写为 0,而不能将0写为1。因此在EEPROM编程之前,为了保证写入的正确性,如果扇区的内容不是0xFF,则必须将对应的扇区擦除,使得扇区的内容全部恢复为0xFF,扇区擦除代码清单如下。

代码清单:擦除指定的EEPROM扇区

  1. /*************************************************************************** 
  2.  * 描  述 : 擦除指定的EEPROM扇区
  3.  * 参  数 : EE_address: 待擦除扇区的首地址(使用扇区内任意地址都可以,习惯上使用首地址) 
  4.  * 返回值 : 无 
  5.  **************************************************************************/  
  6. void EEPROM_SectorErase(u16 EE_address)  
  7. {  
  8.    EA = 0;                         //禁止总中断  
  9.    IAP_CONTR |= 0x80;              //允许EEPROM操作  
  10.    IAP_TPS = 24;                   //系统时钟使用的是:24MHz,IAP_TPS=24000000/1000000 = 24  
  11.    IAP_CMD = 0x03;                 //写入命令:扇区擦除命令  
  12.       
  13.    IAP_ADDRH = EE_address / 256;   //地址寄存器高8位赋值  
  14.    IAP_ADDRL = EE_address % 256;   //地址寄存器低8位赋值  
  15.       
  16.    IAP_TRIG = 0x5A;                //触发EEPROM操作,IAP_TRIG先写入0x5A,再写入0xA5  
  17.    IAP_TRIG = 0xA5;                                                                        
  18.    _nop_();                       //空操作,延时  
  19.    EEPROM_Disable();              //禁止访问EEPROM  
  20.    EA = 1;                        //开启总中断  
  1. 批量写入数据

批量写入数据实现了以给定的地址作为起始地址连续写入指定长度数据的功能,代码清单如下。注意写入数据时不要超过划分的EEPROM的边界。

代码清单:批量写入数据

  1. /*************************************************************************** 
  2.  * 描  述 : 以指定的EEPROM地址为起始地址连续写入指定长度的数据 
  3.  * 参  数 : EE_address: EEPROM地址 
  4.             p_buf: 指向存放待写入数据的缓存 
  5.             w_size: 写入的字节数 
  6.  * 返回值 : 无 
  7. ***************************************************************************/  
  8. void EEPROM_write_bytes(u16 EE_address,u8 *p_buf,u16 w_size)  
  9. {  
  10.    EA = 0;                     //禁止总中断  
  11.    IAP_CONTR |= 0x80;          //允许EEPROM操作  
  12.    IAP_TPS = 24;               //系统时钟使用的是:24MHz,IAP_TPS=24000000/1000000 = 24  
  13.    IAP_CMD = 0x02;             //写入命令:写EEPROM命令  
  14.    do                          //循环写入数据
  15.    {  
  16.       IAP_ADDRH = EE_address / 256;       //地址寄存器高8位赋值  
  17.       IAP_ADDRL = EE_address % 256;       //地址寄存器低8位赋值  
  18.       IAP_DATA = *p_buf;                  //待编程数据写入EEPROM数据寄存器  
  19.       IAP_TRIG = 0x5A;                    //触发EEPROM操作,IAP_TRIG先写入0x5A,再写入0xA5  
  20.       IAP_TRIG = 0xA5;
  21.       _nop_();                            //空操作,延时  
  22.       EE_address++;  
  23.       p_buf++;  
  24.    }while(--w_size);  
  25.    EEPROM_Disable();             //禁止访问EEPROM  
  26.    EA = 1;                       //开启总中断  
  27. }
  1. 批量读取数据

批量读取数据实现了从以给定的EEPROM地址为起始地址连续读出指定长度的数据的功能,读出的数据保存到p_buf指向的缓存。

读取数据可以使用IAP方式或MOVC方式,下面是两种方式的代码清单,读者可以对比一下,不难发现,MOVC方式比IAP方式简单,并且读取速度快于IAP方式。

代码清单:批量读取数据:IAP方式

  1. /*************************************************************************** 
  2. * 描  述 : IAP方式读取数据。以给定的EEPROM地址为起始地址连续读出指定长度的数据,
  3. *        : 读出的数据保存到p_buf指向的缓存 
  4. * 参  数 : EE_address: EEPROM地址 
  5. *        : p_buf: 指向保存读出数据的缓存
  6. *        : r_size: 读出的字节
  7. * 返回值 : 无 
  8. ***************************************************************************/  
  9. void EEPROM_read_bytes_iap(u16 EE_address,u8 *p_buf,u16 r_size)  
  10. {  
  11.    EA = 0;                     //禁止总中断  
  12.    IAP_CONTR |= 0x80;          //允许EEPROM操作  
  13.    IAP_TPS = 24;               //系统时钟使用的是:24MHz,IAP_TPS=24000000/1000000 = 24  
  14.    IAP_CMD = 0x01;             //写入IAP命令:读EEPROM  
  15.    do  
  16.    {  
  17.       IAP_ADDRH = EE_address / 256;   //地址寄存器高8位赋值  
  18.       IAP_ADDRL = EE_address % 256;   //地址寄存器低8位赋值  
  19.       IAP_TRIG = 0x5A;                //触发EEPROM操作,IAP_TRIG先写入0x5A,再写入0xA5  
  20.       IAP_TRIG = 0xA5;
  21.       _nop_();                        //空操作,延时  
  22.       *p_buf = IAP_DATA;              //读出EEPROM数据寄存器的值保存到指定缓存  
  23.       EE_address++;                   //地址加1  
  24.       p_buf++;                        //数据缓存地址加1  
  25.    }while(--r_size);  
  26.    EEPROM_Disable();                  //禁止访问ISP/IAP  
  27.    EA = 1;                            //开启总中断  
  28. }  

MOVC方式读取EEPROM的代码清单如下:

代码清单:批量读取数据:MOVC方式

  1. /*************************************************************************** 
  2. * 描  述 : MOVC方式读取数据。以给定的EEPROM地址为起始地址连续读出指定长度的数据, 
  3. *        : 读出的数据保存到p_buf指向的缓存 
  4. * 参  数 : EE_address: 给定的读取数据的起始地址 
  5. *        : p_buf: 指向保存读出数据的缓存 
  6. *        : r_size: 读出的字节数 
  7. * 返回值  : 无 
  8. **************************************************************************/  
  9. void EEPROM_read_bytes_movc(u16 EE_address,u8 *p_buf,u16 r_size)  
  10. {  
  11.    u8 code *p_dat;  
  12.       
  13.    p_dat = (u8 *)EE_address;  
  14.    while(r_size--)      //循环读出数据  
  15.    {  
  16.       *p_buf = *p_dat;  //读出ISP/IAP数据寄存器的值送往指定缓存  
  17.       p_dat++;  
  18.       p_buf++;  
  19.    }  
  20. }  

主函数中,检测到KEY1按键按下后,擦除EEPROM第一个扇区,接着从该扇区的起始地址开始连续写入256字节数据,之后分别通过IAP方式和MOVC方式读出数据并通过串口输出。

本例中,从Flash中划分4K字节的EEPROM(共8个扇区)。IAP方式读取数据时,第一个扇区的起始地址是0x0000。使用MOVC方式读取数据时,第一个扇区的起始地址是0xF000。程序代码清单如下。

代码清单:EEPROM读写测试

  1. //定义EEPROM读写软件缓存,大小各为256字节  
  2. xdata u8 read_buf[256],write_buf[256];  
  3.   
  4. /************************************************************************** 
  5. 功能描述:主函数 
  6. 参    数:无 
  7. 返 回 值:int类型 
  8. **************************************************************************/  
  9. int main(void)  
  10. {  
  11.    u8 btn_val,j;  
  12.    u16 i,test_len;  
  13.       
  14.    P2M1 &= 0x3F;   P2M0 &= 0x3F;     //设置P2.6~P2.7为准双向口(指示灯D1和D2)  
  15.    P7M1 &= 0xF9;   P7M0 &= 0xF9;     //设置P7.1~P7.2为准双向口(指示灯D4和D3)  
  16.    P3M1 &= 0xFE;   P3M0 &= 0xFE;     //设置P3.0为准双向口(串口1的RxD)  
  17.    P3M1 &= 0xFD;   P3M0 |= 0x02;     //设置P3.1为推挽输出(串口1的TxD)  
  18.       
  19.    P3M1 &= 0x3F; P3M0 &= 0x3F;     //设置P3.6~P3.7为准双向口(按键KEY2和KEY1)  
  20.    P0M1 &= 0x5F;   P0M0 &= 0x5F;   //设置P0.5,P0.7为准双向口(按键KEY4和KEY3)  
  21.       
  22. //如果按键电路上没有外部上拉电阻,需要开启GPIO的片内上拉。  
  23. //开发板的按键电路设计了上拉电阻,因此,无需开启片内上拉     
  24. //  P_SW2 |= 0x80;                  //将EAXFR位置1,以访问在XDATA区域的扩展SFR  
  25. //  P0PU |= 0xA0;                 //开启P0.5、P0.7的上拉电阻  
  26. //  P3PU |= 0xC0;                 //开启P3.6、P3.7的上拉电阻  
  27. //  P_SW2 &= 0x7F;                  //将EAXFR位置0,恢复访问XRAM      
  28.       
  29.    uart1_init();                   //串口1初始化  
  30.    EA = 1;                         //使能总中断  
  31.    test_len = 256;                 //EEPROM读写测试长度为256个字节  
  32.    while(1)  
  33.    {  
  34.       btn_val=buttons_scan(0);      //获取开发板用户按键检测值,不支持连按  
  35.       //按下KEY1:测试按页写入。扇区0的第一页写入256个字节,之后读出数据并通过串口输出 
  36.       if(btn_val == BUTTON1_PRESSED)          
  37.       {  
  38.          led_toggle(LED_1);  //翻转指示灯D1的状态,指示按键按下  
  39.          //写之前需要先执行擦除操作,擦除EEPROM第一个扇区  
  40.          EEPROM_SectorErase(0x0000);  
  41.          //测试数据赋值  
  42.          j = 0;  
  43.          for(i=0;i<256;i++)write_buf[i] = j++;  
  44.   
  45.          //写入测试数据  
  46.          EEPROM_write_bytes(0x0000,write_buf,test_len);  
  47.          //读出测试数据:IAP方式
  48.          //在EEPROM的首地址为0x1000处读取5个字节存入buffer数组中
  49.          EEPROM_read_bytes_iap(0x0000,read_buf,test_len);            
  50.          //串口打印读取的数据  
  51.          for(i=0;i<test_len;i++)printf("%02bX ",read_buf[i]);   
  52.          printf("\r\n");  
  53.          //读出测试数据:MOVC方式  
  54.          EEPROM_read_bytes_movc(0xF000,read_buf,test_len);  
  55.          //串口打印读取的数据  
  56.          for(i=0;i<test_len;i++)printf("%02bX ",read_buf[i]);        
  57.      }  
  58.    }  
        1. 硬件连接

本实验需要使用LED指示灯D1、按键KEY1和USB转串口,按下下图所示短接对应的跳线帽。

图8:D1和KEY1跳线帽短接

图9:USB转串口跳线帽短接

        1. 实验步骤
  1. 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-8-1:片内EEPROM读写”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
  2. 双击“…\eeprom\Project\object”目录下的工程文件“eeprom.uvproj”。
  3. 点击编译按钮编译工程,编译成功后生成的HEX文件“eeprom.hex”位于工程的“…\eeprom\project”目录下。
  4. 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz,用户EEPROM大小设置为4K。
  5. 电脑上打开串口调试助手,选择开发板对应的串口号,将波特率设置为9600bps。
  6. 程序运行后,按下KEY1按键,会擦除EEPROM的第一个扇区,接着从第一个扇区起始地址开始连续写入256个字节数据,之后分别使用IAP方式和MOVC方式读出数据并通过串口输出数据。

图11:串口接收的数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/993387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生】Kubeadmin部署Kubernetes集群

目录 ​编辑 一、环境准备 1.2调整内核参数 二、所有节点部署docker 三、所有节点安装kubeadm&#xff0c;kubelet和kubectl 3.1定义kubernetes源 3.2开机自启kubelet 四、部署K8S集群 4.1查看初始化需要的镜像 4.2在 master 节点上传 v1.20.11.zip 压缩包至 /opt 目录…

Linux系统中驱动之设备树添加按键驱动方法

​大家好&#xff0c;每日一个简单的驱动&#xff0c;日久方长&#xff0c;对Linux驱动就越来越熟悉&#xff0c;也越来容易学会写驱动程序。今日进行简单的按键驱动。 一、Linux 下按键驱动原理 按键驱动和 LED 驱动原理上来讲基本都是一样的&#xff0c;都是操作 GPIO&…

Nmap漏洞检测实战

任务要求 环境要求 1、PC终端一个&#xff08;博主是Win11电脑&#xff0c;读者要注意&#xff09; 1、nmap安装包&#xff08;7.9.2版本&#xff09;下载地址 提取码&#xff1a;hqlk 2、VM虚拟机&#xff08;一台为 Kali Linux&#xff0c;一台为Windows XP SP2&#xff09…

Selenium 隐藏浏览器指纹特征的几种方式

我们使用 Selenium 对网页进行爬虫时&#xff0c;如果不做任何处理直接进行爬取&#xff0c;会导致很多特征是暴露的 对一些做了反爬的网站&#xff0c;做了特征检测&#xff0c;用来阻止一些恶意爬虫 本篇文章将介绍几种常用的隐藏浏览器指纹特征的方式 1. 直接爬取 目标对…

计算机竞赛 基于深度学习的行人重识别(person reid)

文章目录 0 前言1 技术背景2 技术介绍3 重识别技术实现3.1 数据集3.2 Person REID3.2.1 算法原理3.2.2 算法流程图 4 实现效果5 部分代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的行人重识别 该项目较为新颖&#xff0c;适合…

【动手学深度学习】--长短期记忆网络LSTM

文章目录 长短期记忆网络LSTM1.门控记忆元1.1输入门、忘记门、输出门1.2候选记忆元1.3记忆元1.4隐状态 2.从零实现2.1加载数据集2.2初始化模型参数2.3定义模型2.4 训练与预测 3.简洁实现 长短期记忆网络LSTM 学习视频&#xff1a;长短期记忆网络&#xff08;LSTM&#xff09;【…

DP-modeler建模

1、打开软件&#xff0c;新建工程&#xff0c;导入模型&#xff0c;如下&#xff1a; 2、建立一个立体模型&#xff0c;结果如下图&#xff1a;

jmeter安装了插件,但是添加时无插件选项

想用阶梯加压&#xff0c;然后需要安装插件&#xff0c;按照网上教程&#xff0c;下载插件管理器&#xff0c;使用插件管理器安装好jpgc后&#xff08;如图一&#xff0c;已勾选&#xff0c;说明已安装&#xff09;&#xff0c; 然后重启打开jmeter&#xff0c;添加线程组下一级…

python知识:有效使用property装饰器

一、说明 Python是唯一有习语&#xff08;idioms&#xff09;的语言。这增强了它的可读性&#xff0c;也许还有它的美感。装饰师遵循Python的禅宗&#xff0c;又名“Pythonic”方式。装饰器从 Python 2.2 开始可用。PEP318增强了它们。下面是一个以初学者为中心的教程&#xff…

Jdk1.7之ConcurrentHashMap源码总结

文章目录 一、常见属性1. 初始化容量2. 加载因子3. 并发级别 二、重要方法1. 构造方法2. ConcurrentHashMap#put方法2.1 ConcurrentHashMap#put#ensureSegment2.2 ConcurrentHashMap#Segment#put2.2.1 Segment#put#scanAndLockForPut2.2.2 Segment#put#rehash 3. ConcurrentHas…

linux内核如何根据文件名索引到文件内容

https://zhuanlan.zhihu.com/p/78724124 根据文件名索引到文件内容 表面上&#xff0c;用户通过文件名&#xff0c;打开文件。实际上&#xff0c;系统内部这个过程分成三步&#xff1a;首先&#xff0c;系统找到这个文件名对应的inode号码&#xff1b;其次&#xff0c;通过in…

迅为RK3568开发板驱动指南第六篇-平台总线

文档教程更新至第六篇 第1篇 驱动基础篇 第2篇 字符设备基础 第3篇 并发与竞争 第4篇 高级字符设备进阶 第5篇 中断 第6篇 平台总线 未完待续&#xff0c;持续更新中... 视频教程更新至十一期 第一期_驱动基础 第二期_字符设备基础 第三期_并发与竞争 第四期_高级字…

解释模块化开发及其优势,并介绍常用的模块化规范。

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 模块化开发⭐ 模块化开发的优势⭐ 常用的模块化规范⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是…

公众号hanniman往期精选

目录 一、AI产品分析&#xff08;10篇&#xff09; 二、AI产品经理&#xff08;10篇&#xff09; 三、AI技术&#xff08;10篇&#xff09; 四、AI行业及个人成长&#xff08;10篇&#xff09; 一、AI产品分析 1、【重点】深度 | 关于AIGC商业化的13个非共识认知&#xff08;80…

华为OD机试 - 滑动窗口最大和

滑动窗口的经典题型&#xff0c;重复题目 #include <stdio.h> #include <string.h> #include <stdlib.h>#define MAX(a,b) ((a) > (b) ? (a) : (b)) int main() {int n;scanf("%d", &n);int *list malloc(sizeof(int) * n);for (int i …

[学习笔记]DeepWalk图神经网络论文精读

参考资料&#xff1a;DeepWalk【图神经网络论文精读】 word2vec 相关论文&#xff1a; Efficient Estimation of Word Representations in Vector Space Distributed Representations of Words and Phrases and their Compositionality 随机游走Ramdom Walk简述 通过随机游…

LLMs之Falcon 180B:Falcon 180B的简介、安装、使用方法之详细攻略

LLMs之Falcon 180B&#xff1a;Falcon 180B的简介、安装、使用方法之详细攻略 导读&#xff1a;Falcon-180B是一个由TII发布的模型&#xff0c;它是Falcon系列的升级版本&#xff0c;是一个参数规模庞大、性能优越的开放语言模型&#xff0c;适用于各种自然语言处理任务&#x…

Net跨平台UI框架Avalonia入门-样式详解

设计器的使用 设计器预览 在window和usercontrol中&#xff0c;在代码中修改了控件&#xff0c;代码正确情况下&#xff0c;设计器中就可以实时看到变化&#xff0c;但是在样式&#xff08;Styles&#xff09;文件中&#xff0c;无法直接看到&#xff0c;需要使用设计器预览D…

uni-app 前面项目(vue)部署到本地win系统Nginx上

若依移动端的项目&#xff1a;整合了uview开源ui框架&#xff0c; 配置后端请求接口基本路径地址&#xff1a; 打包复现到nginx下&#xff1a; 安装个稳定版本的&#xff1a;nginx-1.24.0 部署配置&#xff1a; 增加了网站&#xff1a;8083端口的&#xff0c; 网站目录在ngi…

Reactor

1.epoll底层工作原理 creat: 红黑树 就绪队列 回调机制 control: 用户告诉内核做什么事情&#xff0c;就是操作红黑树 wait: 操作就绪队列 2.LT ET模式 3.Reactor 4.前摄式