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