關於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
相關文章
- 51微控制器學習筆記:連續讀寫STC89C52RC內部EEPROM儲存器筆記
- 日常問題分享
- 關於java的“原子操作”問題Java
- Arduino EEPROM 的操作UI
- AVR微控制器EEPROM學習VR
- 關於JQuery操作checkbox問題jQuery
- 公司內部一次關於OOM故障覆盤分享OOM
- 關於專案內模組引用的問題
- 關於彈窗的內部滑動穿透底層頁面的滑動的問題穿透
- 由於內部連線引起的Oracle RAC效能問題Oracle
- 一個關於風險和投資組合的內部知識分享文件
- 函式內部This的指向問題函式
- 關於input的一些問題解決方法分享
- 字符集問題的初步探討(七)-字符集更改的內部操作
- 關於離開頁面時執行的操作問題
- 關於敏捷的一次內部爭論敏捷
- 匿名內部類中關於new Runnable ( )
- 關於SQLServerDriver的問題SQLServer
- 關於 JavaMail 的問題JavaAI
- 關於session的問題Session
- C++雜談之關於檔案操作的若干問題C++
- 關於SAP生產訂單操作中的問題處理。
- 關於EL在JSP內呼叫RequestScope內建物件報錯的問題JS物件
- 關於內嵌物件(Embedded Object)快取設計的問題物件Object快取
- 關於redo log 檔案中記錄的內容問題 ?
- 騰訊雲容器團隊內部Istio專題分享
- AndroidStudio內gradle的內部操作AndroidGradle
- 關於javascript的this指向問題JavaScript
- 關於跨域的問題跨域
- 關於bit code的問題
- 關於序列同步的問題
- 關於IP地址的問題
- 關於橋模式的問題模式
- 求救 關於parallel的問題Parallel
- 關於web start的問題Web
- 關於action的error問題Error
- 關於ADAPTER的問題APT
- 關於session的奇怪問題Session