第7章 單片機(jī)內(nèi)部比較器與DataFlash存儲(chǔ)器
0.png (138.6 KB, 下載次數(shù): 189)
下載附件
2016-3-28 03:03 上傳
1 比較器
7.1.1 比較器結(jié)構(gòu)圖
7.1.2 寄存器說明
7.1.3 比較器測試實(shí)驗(yàn)
2 DataFlash存儲(chǔ)器
單片機(jī)內(nèi)部比較器的重要用途是對(duì)單片機(jī)供電電源進(jìn)行監(jiān)測,當(dāng)監(jiān)測到外部
斷電時(shí)立即產(chǎn)生中斷,通知CPU保存程序運(yùn)行過程中的重要數(shù)據(jù)(由于電路板 上有電容存儲(chǔ)能量,外部斷電時(shí)單片機(jī)還可繼續(xù)運(yùn)行一個(gè)短暫時(shí)間),我們選擇 數(shù)據(jù)保存位置為單片機(jī)內(nèi)部DataFlash存儲(chǔ)器,舉個(gè)例子:某產(chǎn)品需要進(jìn)行壽命 測試,產(chǎn)品運(yùn)行一個(gè)循環(huán)單片機(jī)記錄一次,但運(yùn)行過程中可能會(huì)突然斷電,要求 重新上電后壽命測試?yán)^續(xù)運(yùn)行,并且要求實(shí)際運(yùn)行次數(shù)準(zhǔn)確,這就需要用到單片 機(jī)內(nèi)部比較器與DataFlash存儲(chǔ)器斷電瞬間存儲(chǔ)數(shù)據(jù)的功能。
1 STC15W系列單片機(jī)內(nèi)部比較器
7 7.1.1 比較器結(jié)構(gòu)圖
STC15W系列的比較器結(jié)構(gòu)如圖7-1所示。
0.png (259.42 KB, 下載次數(shù): 212)
下載附件
2016-3-28 02:42 上傳
表7-1 比較控制寄存器1:CMPCR1 (復(fù)位值是:0000 0000B)
位 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
位名稱 | CMPEN | CMPIF | PIE | NIE | PIS | NIS | CMPOE | CMPRES |
n CMPEN:比較器模塊使能位。1:使能比較器模塊;0:禁用比較器模塊,比較器的電源
關(guān)閉。
n CMPIF :比較器中斷標(biāo)志位。當(dāng)比較器的比較結(jié)果由LOW變成HIGH時(shí),若是PIE被設(shè)置成
1,那么內(nèi)部的一個(gè) 叫做CMPIF_p的位會(huì)被設(shè)置成1,當(dāng)比較器的比較結(jié)果由HIGH變成LOW 時(shí),若是NIE被設(shè)置成1,那么內(nèi)部的一個(gè) 叫做CMPIF_n的位會(huì)被設(shè)置成1,當(dāng)CPU去讀此中斷 標(biāo)志位CMPIF時(shí),會(huì)讀到(CMPIF_p || CMPIF n),當(dāng)CPU對(duì)此中斷標(biāo)志位CMPIF寫0后, CMPIF_p以及CMPIF_n都會(huì)被清除為O,而中斷產(chǎn)生的條件是[(EA==1)&& (((PIE=l)&&(CMPIF_p==l)) || ((NIE==1)&&(CMPIF_n==l)))],CPU進(jìn)入中斷函數(shù)后,并不 會(huì)自動(dòng)清除此CMPIF標(biāo)志,用戶必須用軟件寫”0”去清除它。
n PIE:比較器上升沿中斷使能位。1:使能比較器由LOW變HIGH的事件引發(fā)CMPIF_p
= 1產(chǎn)生中斷,0:禁用比較器由LOW變HIGH的事件引發(fā)CMPIF_p = 1產(chǎn)生中斷。
n NIE:比較器下降沿中斷使能位。1,使能比較器由HIGH變LOW的事件引發(fā)CMPIF_n
= 1產(chǎn)生中斷;0:禁用比較器由HIGH變LOW的事件引發(fā)CMPIF_n = 1產(chǎn)生中斷。
n PIS: 比較器正極選擇位。1:選擇ADC_CONTR[2:0]所選擇到的ADC輸入引腳作為比 較器的正極輸入源; 0:選擇外部P5.5為比較器的正極輸入源。
n NIS: 比較器負(fù)極選擇位。1:選擇外部管腳P5.4為比較器的負(fù)極輸入源,0:選擇 內(nèi)部約1.27V的BandGap參考電壓為比較器的負(fù)極輸入源。
n CMPOE:比較結(jié)果輸出控制位。1,使能比較器的比較結(jié)果輸出到P1.2, 0,禁止比 較器的比較結(jié)果輸出。
n CMPRES:比較器比較結(jié)果標(biāo)志位。1: CMP+的電平高于CMP-的電平(或內(nèi)部1.27V 的BandGap參考電壓); 0: CMP+的電平低于CMP-的電平(或內(nèi)部1.27V的BandGap 參考電壓)。此bit是一個(gè)“只讀”的bit;軟件對(duì)它做寫入的動(dòng)作沒有任何意義, 軟件所讀到的結(jié)果是“經(jīng)過延時(shí)控制后的結(jié)果”,而非模擬比較器的直接輸出結(jié) 果。
表7-2 比較控制寄存器2:CMPCR2(地址為E7H,復(fù)位值是:0000 1001B)
0.png (46.67 KB, 下載次數(shù): 174)
下載附件
2016-3-28 02:43 上傳
nINVCMPO:比較器輸出取反控制位。l:比較器取反后再輸出到P1.2,0:比較器正常輸
出,比較器的輸出是經(jīng)過延時(shí)控制后的結(jié)果,而非模擬比較器的直接輸出結(jié)果。
n DISFLT:去除比較器輸出的0.luS 延時(shí)控制。1:去除比較器輸出的O.luS延時(shí)控制(可以 讓比較器速度有少許提升);0:比較器的輸出有O.luS延時(shí)控制。
n LCDTY[5:0]:比較器輸出端 Level-Change control的延時(shí)時(shí)鐘選擇,假設(shè)設(shè)置值為 bbbbbb,當(dāng)比較器由LOW變HIGH后必須偵測到HIGH持續(xù)至少bbbbbb個(gè)時(shí)鐘,此芯片線路才認(rèn)定 比較器的輸出是由LOW轉(zhuǎn)成HIGH,如果在bbbbbb個(gè)時(shí)鐘內(nèi),模擬比較器的輸出又回復(fù)到LOW, 此線路認(rèn)為甚么都沒發(fā)生,視同比較器的輸出一直維持在LOW,當(dāng)比較器由HIGH變LOW,必須 偵測到LOW持續(xù)至少bbbbbb個(gè)時(shí)鐘,此線路才認(rèn)定比較器的輸出是由HIGH轉(zhuǎn)成LOW,如果在 bbbbbb個(gè)時(shí)鐘內(nèi),比較器的輸出又回復(fù)到HIGH,此線路認(rèn)為甚么都沒發(fā)生,視同比較器的輸 出一直維持在HIGH. 若是設(shè)定成000000,代表沒有Level-Change Control。
7.1.3 比較器測試實(shí)驗(yàn)
下圖是STC15W系列典型掉電檢測電路,正常供電使用5V電壓,我們假設(shè)VCC從5V下跌到4.3V時(shí) 進(jìn)入掉電保存處理程序,P5.5作比較器的信號(hào)輸入正端,比較器的信號(hào)輸入負(fù)端在程序中設(shè)置為
1.27V基準(zhǔn)電壓。
例7.1 利用IAP15W4K58S4的比較器實(shí)現(xiàn)掉電檢測功能 (中斷方式),要求當(dāng)VCC低于大約4.3V時(shí)點(diǎn)亮一個(gè)LED,
高于大約4.3V時(shí)LED熄滅,本實(shí)驗(yàn)要求VCC使用0—5V直流 可調(diào)電源(最大不要超過5.5V),也可使用第14章的精
密電壓表模塊直接下載這里的代碼測試。
0.png (82.55 KB, 下載次數(shù): 200)
下載附件
2016-3-28 02:44 上傳
#include "STC15W4K.H" // 注意宏定義后面沒分號(hào)
sbit LED=P4^1;
void main()
{
CMPCR1=0xB0; // 10110000,開比較器中斷
CMPCR2=0x00; // 0000 0000,比較器只延時(shí)0.1uS
EA=1;
while(1);
}
void cmp()interrupt 21
{
CMPCR1 &=0xBF; // 清除中斷標(biāo)志, 1011 1111
LED = CMPCR1&0x01; // 將比較器結(jié)果CMPRES輸出到測試口顯示
}
實(shí)驗(yàn)結(jié)果:當(dāng)VCC < 4.20V時(shí)LED點(diǎn)亮,當(dāng)VCC > 4.20V時(shí)LED熄滅。對(duì)程序稍作修改,不使用中 斷也能達(dá)到相同的實(shí)驗(yàn)結(jié)果。
例7.2 利用IAP15W4K58S4的比較器實(shí)現(xiàn)掉電檢測功能(查詢方式)。
void main()
{
CMPCR1=0x80; // 10000000
// D5(PIE) =0; 關(guān)閉比較器輸出由LOW變HIGH的事件引發(fā)CMPIF_p = 1產(chǎn)生中斷
// D4(NIE) =0; 關(guān)閉比較器輸出由HIGH變LOW的事件引發(fā)CMPIF_n = 1產(chǎn)生中斷
CMPCR2=0x00; // 0000 0000,比較器只延時(shí)0.1uS
while(1)
{
LED = CMPCR1&0x01; // 將比較器結(jié)果CMPRES輸出到測試口顯示
}
}
2 DataFlash存儲(chǔ)器與相關(guān)實(shí)驗(yàn)
STC15F2K60S2單片機(jī)內(nèi)部集成了1K字節(jié)的數(shù)據(jù)Flash存儲(chǔ)器(也稱作DataFlash)可當(dāng)作EEPROM使 用,地址范圍是0000H~03FFH,與程序Flash存儲(chǔ)器空間是分開的,這1K字節(jié)的數(shù)據(jù)Flash存儲(chǔ)器分 為2個(gè)扇區(qū),每個(gè)扇區(qū)包含512字節(jié),對(duì)應(yīng)的地址范圍分別為:第一扇區(qū):0000H~01FFH,第二扇區(qū):
0200H~03FFH,數(shù)據(jù)Flash存儲(chǔ)器的擦除操作是按扇區(qū)進(jìn)行的,數(shù)據(jù)Flash存儲(chǔ)器擦寫次數(shù)在10萬次 以上,可用于保存一些需要在應(yīng)用過程中修改并且斷電不丟失的一些參數(shù)數(shù)據(jù)。STC15W4K32S系列單 片機(jī)原理與STC15F2K60S2系列完全相同。
對(duì)于IAP15W4K58S4芯片,內(nèi)部沒有數(shù)據(jù)Flash,是將程序存儲(chǔ)器Flash的剩余空間當(dāng)作EEPROM使 用,IAP的意思是“在應(yīng)用編程”, 即在程序運(yùn)行時(shí)“程序存儲(chǔ)器Flash”可由程序自身進(jìn)行擦寫, 正是因?yàn)橛辛薎AP,從而可以將數(shù)據(jù)寫入到程序存儲(chǔ)器Flash中,使得數(shù)據(jù)如同燒入的程序一樣,掉 電不丟失,IAP可將所有程序存儲(chǔ)器Flash空間當(dāng)作EEPROM修改,因此要注意不要把自己的有效程序 擦除掉了,型號(hào)不是IAP開頭的芯片無法對(duì)“程序存儲(chǔ)器Flash”進(jìn)行任何操作。
Flash存儲(chǔ)器的操作提示:
① 對(duì)Flash存儲(chǔ)器進(jìn)行字節(jié)編程時(shí),只能將1改為0,或1保持為1、0保持為0。如果該字節(jié)是
11111111B,則可將其中的1編程為0,如果該字節(jié)中有的位為0,要將其改為1,則須先將整個(gè)扇區(qū)擦 除,因?yàn)橹挥小吧葏^(qū)擦除”才可以將0變?yōu)?。
② 如果在一個(gè)扇區(qū)中存放了大量的數(shù)據(jù),某次只需要修改其中的一個(gè)字節(jié)或一部分字節(jié)時(shí),則另外 的不需要修改的數(shù)據(jù)須先讀出放在單片機(jī)的RAM中,然后擦除整個(gè)扇區(qū),再將需要保留的數(shù)據(jù)和需修 改的數(shù)據(jù)一并寫回該扇區(qū)中,這時(shí),每個(gè)扇區(qū)使用的字節(jié)數(shù)越少越方便(不需讀出一大堆需保留數(shù) 據(jù))。
③ 同一次修改的數(shù)據(jù)放在同一扇區(qū)中,不是同一次修改的數(shù)據(jù)放在另外的扇區(qū),扇區(qū)不一定用滿, 這樣,可不需讀出保護(hù)。
7.2.2 DataFlash操作實(shí)驗(yàn)(斷電瞬間存儲(chǔ)數(shù)據(jù)) 例7.3 STC15F2K60S2單片機(jī)內(nèi)部DataFlash讀寫測試
本程序上電時(shí)先擦除DataFlash的第1個(gè)扇區(qū),然后將第1個(gè)扇區(qū)的前半扇區(qū)與后半扇區(qū)分別寫入數(shù) 據(jù)0~255,然后讀出數(shù)據(jù)并判斷與寫入的數(shù)據(jù)是否一致,并通過串口助手顯示程序運(yùn)行過程中的數(shù) 據(jù)與最終結(jié)果是否正常,R/C時(shí)鐘頻率22.1184MHz,串口通信波特率9600。
程序主要使用到2個(gè)模塊文件FLASH.H與FLASH.C,在程序移植過程中,F(xiàn)LASH.H里需要定義R/C時(shí)鐘 頻率和FLASH存儲(chǔ)單元地址,F(xiàn)LASH.C無需作任何更改。
#define SYSclk 22118400L // 定義CPU實(shí)際運(yùn)行的系統(tǒng)時(shí)鐘
#define EEP_address 0x0000 // 主程序從0000地址開始讀寫數(shù)據(jù)
/////////////////////////// 主程序:Flash_Test.C ///////////////////////////////
#include "FLASH.H"
#include "uart_debug.h" void main()
{
unsigned char a;
unsigned int i;
UART_init(); // 波特率:9600 /22.1184MHZ(占用定時(shí)器1) UART_Send_Str("開始擦除\n");
EEPROM_SectorErase(EEP_address); // 扇區(qū)擦除 UART_Send_Str("擦除完畢\n");
for (i=0; i<512; i++) // 檢測是否擦除成功(全FF檢測)
{
EEPROM_read_n(EEP_address+i,&a,1); // 地址、數(shù)據(jù)、長度 UART_Send_StrNum("擦除值:",a) ;
if (a!=0xff) goto Error; // 如果校驗(yàn)錯(cuò)誤,則退出
}
UART_Send_Str("開始寫入\n");
for (i=0; i<512; i++) // 編程512字節(jié)
{
a=i;
EEPROM_write_n(EEP_address+i,&a,1);
//
地址、數(shù)據(jù)、長度
}
UART_Send_Str("寫入完畢\n");
for (i=0; i<512; i++)
//
校驗(yàn)512字節(jié)
{
EEPROM_read_n(EEP_address+i,&a,1);
//
地址、數(shù)據(jù)、長度
UART_Send_StrNum("數(shù)據(jù):",a);
if (a!=i%256) goto Error;
//
如果校驗(yàn)錯(cuò)誤,則退出
}
UART_Send_Str("讀出結(jié)束,測試正常");
while (1); Error:
UART_Send_Str("數(shù)據(jù)錯(cuò)誤"); // IAP操作失敗
while (1);
}
本程序使用“串口調(diào)試助手sscom33”在電腦上顯示接收到的數(shù)據(jù),文本模式,9600波特率,測
試結(jié)果正常,由于接收的數(shù)據(jù)量較大,其它串口助手可能會(huì)出現(xiàn)亂碼或開始接收到的數(shù)據(jù)被后來的
數(shù)據(jù)覆蓋掉而不能完整顯示的問題。
例7.5 使用IAP15W4K58S4單片機(jī)內(nèi)部比較器與DataFlash實(shí)現(xiàn)斷電瞬間存儲(chǔ)數(shù)據(jù)。
說明:IAP15W4K58S4與STC15F2K60S2內(nèi)部DataFlash唯一不同的只有地址值不一樣,為了防 止誤寫有效程序區(qū),程序編譯完成后進(jìn)入軟件調(diào)試環(huán)境,打開存儲(chǔ)器窗口,我們會(huì)看到有 效的程序代碼都存放在存儲(chǔ)單元地址的低端,從原則上來說,凡是地址高端的FLASH空白區(qū) 域都可以當(dāng)做EEPROM使用,對(duì)于IAP15W4K58S4芯片,具有58K字節(jié)的FLASH存儲(chǔ)空間,由于
1K=1024字節(jié),58×1024=59392字節(jié),存儲(chǔ)單元地址從0開始算起,地址范圍是0~59391, 用16進(jìn)制表示為0000H~E7FFH,因?yàn)槊總(gè)扇區(qū)包含512個(gè)字節(jié),59392/512=116個(gè)扇區(qū),最 后3個(gè)扇區(qū)地址范圍如表7-6所示,一般我們使用最后3個(gè)扇區(qū)地址已經(jīng)夠用了,比如本例, 我們使用最后一個(gè)扇區(qū),程序中使用代碼:
#define EEP_address 0xE600 即可。
表7-6 IAP15W4K58S4單片機(jī)內(nèi)部DataFlash地址末尾3個(gè)扇區(qū)地址
|
| |
| |
|
起始地址 | 結(jié)束地址 | 起始地址 | 結(jié)束地址 | 起始地址 | 結(jié)束地址 |
E200H | E3FFH | E400H | E5FFH | E600H | E7FFH |
主要程序代碼如下:
#include "PowerDown_save.H"
#include "FLASH.H"
#include "myfun.h"
struct POWER_UP Power_up;
void cmp_init() // 掉電檢測比較器初始化
{
CMPCR1=0xB0; // 10110000 ,開比較器中斷 CMPCR2=0x00; // 0000 0000,比較器只延時(shí)0.1uS EA=1;
}
void cmp()interrupt 21 | // | 較器中斷函數(shù) |
{ |
|
|
CMPCR1 &=0xBF; | // | 清除中斷標(biāo)志, 1011 1111 |
LED0 = CMPCR1&0x01; | // | 將比較器結(jié)果CMPRES輸出到測試口顯示 |
if (LED0==0) |
| // 掉電 |
{ |
|
|
EA=0; | // | 防止更高級(jí)的中斷打斷 |
EEPROM_write_n(EEP_address,(u8 *)&Power_up,sizeof(struct
POWER_UP));
// 掉電保存值
delay1S(); // 延時(shí)1秒后確認(rèn)真的斷電還是瞬間電源干擾
while(1)
{
if (CMPCR1&0x01==1)
// ==0,真正掉電,死循環(huán)等待程序停止運(yùn)行
// ==1,供電正常,單片機(jī)程序沒任何問題,退出循環(huán)繼續(xù)按原程序運(yùn)行
{
CMPCR1 &=0xBF;
// 清除中斷標(biāo)志, 1011 1111,清除可能多次產(chǎn)生的中斷標(biāo)志,防止中斷死機(jī) EA=1;
break;
}
}
}
}
void main()
{
UART_init();//波特率:9600 /22.1184MHZ(占用定時(shí)器1)
cmp_init();//掉電檢測比較器初始化
EA=0;//防止剛上電讀ROM時(shí)就產(chǎn)生斷電存儲(chǔ)操作,可能造成函數(shù)重入問題。
EEPROM_read_n(EEP_address,(u8 *)&Power_up,sizeof(struct POWER_UP)); // 讀出保存值
EA=1; // 進(jìn)入正常工作時(shí)打開總中斷 EEPROM_SectorErase(EEP_address); // 當(dāng)?shù)綦姾箅妷航德浔容^快時(shí),在這里先擦除 UART_Send_StrNum("計(jì)數(shù)值:",Power_up.times);
// 串口輸出計(jì)數(shù)值,波特率:9600 /22.1184MHZ
for(;;)
{
LED0=1; LED1=1; // 熄滅調(diào)試指示燈
delay1S();
Power_up.times++; // 秒計(jì)時(shí)器加1
UART_Send_StrNum("計(jì)數(shù)值:",Power_up.times);
}
}