關於STC微控制器的內部EEPROM操作問題日常分享
最近再用stc15f2K60s2做專案,其中用到了stc內部的EEPROM操作(大小1K,兩個扇區,詳細如上圖),翻看其器件手冊借鑑其例程寫了一個測試程式。但是發現了一個問題,在第一次測試程式時好用,再在原地址重新寫別的資料時就不好用了。因為之前沒怎麼用過EEPROM,所以使我比較迷惑。
當我改變其寫資料的地址,再寫資料時,發現好用,但是再次在這個地址寫其他資料竟然又不好使了。我就開始考慮是不是EEPROM每個地址資料只能寫入一次(那就太悲催了,寫錯一次就要換一塊微控制器),經過查閱資料發現並非如此(放下心來)。
經過多次測試發現,每次想向已有資料的地址寫其他資料時需清除此地址的資料後才可再次寫入。然而stc15f2K60s2只有扇區資料清除操作,沒有地址資料清除指令,所以每次寫資料時就應將整個扇區的資料清除,加上stc15f2K60s2只有兩個扇區,這就產生了另一個令人頭疼的問題:當此扇區存有幾個或多個不同資料,而只想改變其中一個的資料時,就要把整個扇區的資料清除,相應的其他資料也就丟失,需重新寫入。
為了解決此問題,許多大神就想出來了許多的解決辦法,最常見的有:
1.掉電瞬間儲存資料(最優)
在微控制器上電時,先讀取EEPROM內的資料,並儲存下來,再清除扇區資料,程式執行期間不向EEPROM寫資料,只改變儲存的。當微控制器掉電時,通過相應的硬體手段,保證微控制器再保持短暫的有電狀態,再此短暫的時間內微控制器將需要儲存的資料存入EEPROM內,再掉電。
2.實時儲存(不建議用)
在微控制器執行期間就不停的執行扇區擦除,重新寫入的操作
最後貼上我根據stc官方手冊整理的EEPROM驅動程式碼
EEPROM.c
#include "stc15f2k60s2.h"
#include "intrins.h"
#include "eeprom.h"
/*************************************此檔案只針對stc15f2k60s2編寫,其他型號不通用**********************************************************/
#define CMD_IDLE 0 //空閒模式
#define CMD_READ 1 //IAP位元組讀命令
#define CMD_PROGRAM 2 //IAP位元組程式設計命令
#define CMD_ERASE 3 //IAP扇區擦除命令
//#define ENABLE_IAP 0x80 //如果系統時鐘<30MHz選這個
//#define ENABLE_IAP 0x81 //如果系統時鐘<24MHz選這個
#define ENABLE_IAP 0x82 //如果系統時鐘<20MHz選這個
//#define ENABLE_IAP 0x83 //如果系統時鐘<12MHz選這個
//#define ENABLE_IAP 0x84 //如果系統時鐘<6MHz選這個
//#define ENABLE_IAP 0x85 //如果系統時鐘<3MHz選這個
//#define ENABLE_IAP 0x86 //如果系統時鐘<2MHz選這個
//#define ENABLE_IAP 0x87 //如果系統時鐘<1MHz選這個
//關閉IAP函式(禁止對EEPROM操作)
void IapIdle(void)
{
IAP_CONTR = 0 ; //關閉IAP功能
IAP_CMD = 0 ; //清除命令暫存器
IAP_TRIG = 0 ; //清除觸發暫存器
IAP_ADDRH = 0x80 ; //將地址設定到非IAP地址區域
IAP_ADDRL = 0 ;
}
//從ISP/IAP/EEPROM區域讀取1位元組
unsigned char IapReadByte(unsigned int addr)
{
unsigned char dat;
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_READ; //設定IAP命令為“讀”
IAP_ADDRL = addr ; //設定IAP低位地址
IAP_ADDRH = addr>>8 ; //設定IAP高位地址
IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發命令(0xa5)[觸發命令必須先送0x5a 再送0xa5才能成功觸發]
_nop_(); //等待ISP/IAP/EEPROM操作完成
dat = IAP_DATA; //讀取ISP/IAP/EEPROM資料
IapIdle(); //關閉IAP功能
return dat;
}
//寫1位元組資料到從ISP/IAP/EEPROM區域
void IapProgramByte(unsigned int addr,unsigned char dat)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_PROGRAM; //設定IAP命令為“寫”
IAP_ADDRL = addr ; //設定IAP低位地址
IAP_ADDRH = addr>>8 ; //設定IAP高位地址
IAP_DATA = dat; //寫ISP/IAP/EEPROM資料
IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發命令(0xa5)[觸發命令必須先送0x5a 再送0xa5才能成功觸發]
_nop_(); //等待ISP/IAP/EEPROM操作完成
IapIdle(); //關閉IAP功能
}
//扇區擦除(使用擦除扇區命令擦除整個扇區,stc15f2k60s2總共兩個扇區,0x0000-0x01FF和0x0200-0x03FF,故addr=0x0000 或 0x0200)
//注意!在扇區地址存有資料後不可再次向此地址寫資料,需全部清空所在扇區資料才可重新向此地址寫入資料
void IapEraseSector(unsigned int addr)
{
IAP_CONTR = ENABLE_IAP; //使能IAP
IAP_CMD = CMD_ERASE; //設定IAP命令為“擦除”
IAP_ADDRL = addr ; //設定IAP低位地址
IAP_ADDRH = addr>>8 ; //設定IAP高位地址
IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
IAP_TRIG = 0xa5; //寫觸發命令(0xa5)[觸發命令必須先送0x5a 再送0xa5才能成功觸發]
_nop_(); //等待ISP/IAP/EEPROM操作完成
IapIdle(); //關閉IAP功能
}
EEPROM.h
#ifndef __EEPROM__
#define __EEPROM__
void IapIdle(void); //關閉IAP函式(禁止對EEPROM操作)
unsigned char IapReadByte(unsigned int addr); //從ISP/IAP/EEPROM區域讀取1位元組
void IapProgramByte(unsigned int addr,unsigned char dat); //寫1位元組資料到從ISP/IAP/EEPROM區域
void IapEraseSector(unsigned int addr); //扇區擦除
#endif
相關文章
- 日常問題分享
- 基於STC51微控制器的霓虹燈
- 關於JQuery操作checkbox問題jQuery
- 關於操作駁回遇到的問題
- 關於彈窗的內部滑動穿透底層頁面的滑動的問題穿透
- 公司內部一次關於OOM故障覆盤分享OOM
- 日常的問題也是日常的修行
- 函式內部This的指向問題函式
- 關於input的一些問題解決方法分享
- 讀取微控制器內部程式的方法
- 關於 SSR 內容一致性的問題
- 關於EL在JSP內呼叫RequestScope內建物件報錯的問題JS物件
- 關於this指向的問題
- 一個關於風險和投資組合的內部知識分享文件
- Python—關於Pandas缺失值問題(國內唯一)Python
- 匿名內部類中關於new Runnable ( )
- 關於DrawerLayout的小問題
- 關於javascript的this指向問題JavaScript
- 關於 Puerts 的效能問題
- 關於盒模型相關的問題模型
- [分享]關於新版本 Composer 會導致 Class not found 的問題
- esp8266使用ARDUINO關於SSD1306操作問題UI
- STM32 IIC讀取Eeprom失敗問題
- erp是企業內部最重要的使用程式,它對日常運作至關重要
- 關於 Laravel 分頁的問題?Laravel
- [20191129]關於hugepages的問題.txt
- 關於hanlp2.0的問題HanLP
- 關於PHP佇列的問題PHP佇列
- 關於安裝nbextensions的問題
- 關於css權值的問題CSS
- 關於影像識別的問題
- 關於搜尋地址的問題
- Java中內部類的騷操作Java
- 我在組內的Java問題排查分享Java
- 關於PHP的OpenSSL的加密問題PHP加密
- 日常操作
- 關於跨域問題跨域
- 剛需,jackjsonjson轉化內部類問題JSON