本帖最后由 407871699 于 2021-3-20 16:40 編輯
最近研究了STC8G的片上EEPROM,比片外ROM方便多了。
但剛開始使用STC官網下載的例程時候老報錯,還是不熟悉啊。
然后和官方的手冊上的例程比較:手冊提供了3個函數,寫1個字節函數void IapProgramByte(WORD addr, BYTE dat),讀1個字節函數BYTE IapReadByte(WORD addr),擦除扇區函數void IapEraseSector(WORD addr)。 手冊上這3個函數不方便與主函數進行數據交換,還要在編數據交換函數;因此結合手冊例程,把官網下載的EEPROM例程改動了一下,編成EEPROM.H,就可以直接調用
片上EEPROM寫入時,重點是必須先用扇區擦除,否則寫入的數值錯誤。
單片機源程序如下:
#include<STC8xxxx.h> //建議到官網下載,則包含sfr IAP_TPS = 0xF5;
//sfr IAP_TPS = 0xF5; //這個是STC8新增的寄存器,按CPU頻率計算等待時間
#define EEPROM_ADD_0 0x0000 //EROM ADDRESS 起始地址,大家可以根據需要改存儲位置,但是要符合MCU手冊
#define MAIN_Fosc 11059200L //定義MCU頻率;這句可以放在初始化配置中或主程序中
#define IAP_EN (1<<7) //啟動IAP;等價于IAP_EN=0X80;
#define IAP_ENABLE() IAP_CONTR = IAP_EN; IAP_TPS = MAIN_Fosc / 1000000 //使能+等待
void DisableEEPROM(void) //禁止IAP操作
{
IAP_CONTR = 0; //禁止IAP操作
IAP_CMD = 0; //去除IAP命令
IAP_TRIG = 0; //防止IAP命令誤觸發
IAP_ADDRH = 0xff; //清0地址高字節
IAP_ADDRL = 0xff; //清0地址低字節,指向非EEPROM區,防止誤操作
}
void EEPROM_Trig(void) //觸發EEPROM
{
F0 = EA; //保存全局中斷
EA = 0; //禁止中斷, 避免觸發命令無效
IAP_TRIG = 0x5A; //先送5AH,再送A5H到IAP觸發寄存器,每次都需要如此
IAP_TRIG = 0xA5; //送完A5H后,IAP命令立即被觸發啟動//CPU等待IAP完成后,才會繼續執行程序。
_nop_(); _nop_(); //2個空指令等待一下
EA = F0; //恢復全局中斷
}
// 參數: EE_address: 讀取EEPROM的首地址.
// DataAddress: 讀取數據后給到 數組首地址.
// number: 讀取的字節長度.
void EEPROM_read_n(unsigned int EE_address,unsigned char *DataAddress,unsigned int number)
{
IAP_ENABLE(); //設置等待時間,允許IAP操作,送一次就夠
IAP_CMD = 1; //=1讀;送字節讀命令,命令不需改變時,不需重新送命令
do
{
IAP_ADDRH = EE_address / 256; //送地址高字節(地址需要改變時才需重新送地址)
IAP_ADDRL = EE_address % 256; //送地址低字節
EEPROM_Trig(); //觸發EEPROM操作
*DataAddress = IAP_DATA; //讀出的數據送往
EE_address++;
DataAddress++;
}while(--number);
DisableEEPROM();
}
void EEPROM_SectorErase(unsigned int EE_address)
{
IAP_ENABLE(); //設置等待時間,允許IAP操作,送一次就夠
IAP_CMD = 3; //宏調用, =3,送扇區擦除命令,命令不需改變時,不需重新送命令
//只有扇區擦除,沒有字節擦除,512字節/扇區。
//扇區中任意一個字節地址都是扇區地址。
IAP_ADDRH = EE_address / 256; //送扇區地址高字節(地址需要改變時才需重新送地址)
IAP_ADDRL = EE_address % 256; //送扇區地址低字節
EEPROM_Trig(); //觸發EEPROM操作
DisableEEPROM(); //禁止EEPROM操作
}
// 參數: EE_address: 寫入EEPROM的首地址.
// DataAddress: 寫入源數據的緩沖的首地址. 就是從數組讀取數據,
// number: 寫入的字節長度.
void EEPROM_write_n(unsigned int EE_address,unsigned char *DataAddress,unsigned int number)
{
IAP_ENABLE(); //設置等待時間,允許IAP操作,送一次就夠
IAP_CMD = 2; //宏調用, =2,送字節寫命令
do
{
IAP_ADDRH = EE_address / 256; //送地址高字節(地址需要改變時才需重新送地址)
IAP_ADDRL = EE_address % 256; //送地址低字節
IAP_DATA = *DataAddress; //送數據到IAP_DATA,只有數據改變時才需重新送
EEPROM_Trig(); //觸發EEPROM操作
EE_address++; //下一個地址
DataAddress++; //下一個數據
}while(--number); //直到結束
DisableEEPROM();
}
調用舉例:(建議定義一個數組)
unsigned char ROM_num[6]; //存儲數據的數組,最后與EEPROM進行數據交換
EEPROM_read_n(EEPROM_ADD_0,ROM_num,6); //讀取ROM信息到數組
void _write_ROM() //編制專門的寫入函數
{
EEPROM_SectorErase(EEPROM_ADD_0); //必須先擦除數據(由MCU自動,512字節被擦除),之后再寫入,才能寫正確
ROM_num[0]=test_1/256; //將4個測試數值分別給到臨時交換數組。
ROM_num[1]=test_1%256;
ROM_num[2]=test_2; //test_1、3是16位的數據(2個字節);
ROM_num[3]=test_3/256;
ROM_num[4]=test_3%256;
ROM_num[5]=test_4; //test_2、test_4是單字節數據(8位)
EEPROM_write_n(EEPROM_ADD_0,ROM_num,6); //從數組寫如到ROM中
}
|