外部存儲器擴(kuò)展:27C512與6264實戰(zhàn))
簡介這是一份面向單片機(jī)初、中級學(xué)習(xí)者的Keil C51與Proteus仿真擴(kuò)展存儲器教學(xué)案例重點演示如何用C語言驅(qū)動27C512EPROM和6264SRAM進(jìn)行外部存儲器擴(kuò)展覆蓋地址譯碼、總線連接、讀寫時序等核心知識點。資源共18個文件壓縮包僅53KB其中既有Proteus仿真電路DSN文件、C語言源文件、A51啟動代碼和編譯生成的HEX文件也有LST、OBJ、M51等中間文件還附有工程配置、備份文件與歷史記錄文件類型較齊全便于直接打開項目從源代碼、原理圖到調(diào)試信息進(jìn)行完整鏈路學(xué)習(xí)。目前已有898人學(xué)習(xí)下載。通過該案例學(xué)習(xí)者可以獲得C語言讀寫外部存儲器的完整程序并在Proteus中實際驗證地址譯碼、片選信號與總線時序直觀理解EPROM和SRAM在單片機(jī)系統(tǒng)中的應(yīng)用方式。作為教材配套實例它適合電子、自動化等專業(yè)學(xué)生結(jié)合理論學(xué)習(xí)動手實踐提升單片機(jī)系統(tǒng)設(shè)計與Proteus仿真調(diào)試的綜合能力。1. 項目整體思路拆解為什么要在Proteus里折騰外部存儲器先把這個項目說透。很多朋友學(xué)51單片機(jī)用的都是內(nèi)部ROM和內(nèi)部RAM代碼量小、數(shù)據(jù)量少根本接觸不到外部存儲器擴(kuò)展。但現(xiàn)實中的產(chǎn)品尤其是做數(shù)據(jù)采集、儀器儀表、工控板卡的外部程序存儲器和數(shù)據(jù)存儲器太常見了。27C512是64KB的EPROM6264是8KB的SRAM這兩顆芯片在Proteus里搭一個仿真工程用Keil C51寫C語言程序驅(qū)動讀寫本質(zhì)上是在模擬“單片機(jī)外部存儲器”這套經(jīng)典硬件組合。為什么推薦用Proteus而不是直接買開發(fā)板兩個原因。第一Proteus里你能直接看到總線時序、片選信號的走向邏輯分析儀一掛哪根線拉高了、哪根線沒使能一目了然。第二27C512這種EPROM實體芯片是要紫外線擦除的買回來寫錯了就得照紫外線燈折騰半天。仿真里點幾下鼠標(biāo)就能重新加載程序效率完全不是一個量級。這個項目適合誰三類人。一是剛學(xué)完單片機(jī)基礎(chǔ)、想更進(jìn)一步理解總線與存儲器映射的學(xué)生二是準(zhǔn)備做畢業(yè)設(shè)計、需要擴(kuò)展程序存儲器和數(shù)據(jù)存儲器的工程師三是純粹想搞懂“Keil C51生成hex文件之后仿真時程序到底跑到哪去了”的好奇黨。三個角色的需求點不同但底層都繞不開三個核心問題地址怎么分配、片選怎么接、數(shù)據(jù)怎么讀寫。整套方案的核心思路其實很樸素用P0口做低8位地址/數(shù)據(jù)分時復(fù)用用P2口的高位地址線做存儲器的地址輸入再用74LS373鎖存低8位地址最后把讀信號、寫信號、片選信號按存儲器的時序要求接好。剩下的活兒就是寫C代碼告訴Keil“xdata區(qū)域在哪、怎么訪問”。這里要先建立一個認(rèn)知51單片機(jī)的程序存儲器和數(shù)據(jù)存儲器是分開編址的。程序存儲器用PSEN外部程序讀選通信號激活地址空間從0000H到FFFFH共64KB數(shù)據(jù)存儲器用RD和WR信號訪問同樣有64KB的地址空間。這兩個64KB是獨立的所以27C512接到程序存儲器側(cè)6264接到數(shù)據(jù)存儲器側(cè)互不沖突。硬件上唯一的坑在于外部程序存儲器的代碼由PSEN讀取外部數(shù)據(jù)存儲器由RD/WR讀寫兩者不會同時訪問所以片選信號看似可以共用實際必須嚴(yán)格按照訪問類型來區(qū)分否則會出亂子。2. 硬件方案與芯片選型27C512和6264的本質(zhì)區(qū)別2.1 27C512掉電不丟的程序倉庫27C512是一顆512Kbit也就是64KB的紫外線可擦除EPROM數(shù)據(jù)總線8位地址線需要16根A0-A15。51單片機(jī)的程序地址空間正好也是64KB理論上可以直接把16根地址線全接上但實際工程里很少有人這么干因為單片機(jī)程序一般用不了64KB那么大通常的做法是把最高位地址線A15直接接地只用低32KB或者用P2口的某些引腳做簡單譯碼。Proteus仿真里同樣可以簡化A15接地其余15根地址線接單片機(jī)的P2.0-P2.7和74LS373的輸出Q0-Q7。為什么選27C512而不是更常見的28C648KB EEPROM因為27C512能直觀展示“大容量程序存儲器”的概念。當(dāng)程序超過內(nèi)部4KB/8KB的限制時你會發(fā)現(xiàn)自己寫的代碼真的被放到了外部ROM里此時PSEN引腳會不停跳變邏輯分析儀能看到清晰的取指脈沖。這個體驗比小容量芯片強烈得多。在Proteus里27C512的使用有個關(guān)鍵操作雙擊芯片符號在“Advanced Properties”或“Initial Contents”中加載hex文件。很多新手掛在第一步——仿真一運行程序根本執(zhí)行不了單片機(jī)始終處于復(fù)位狀態(tài)就是因為沒給27C512填程序。這一步本質(zhì)上是模擬“用編程器把hex文件寫進(jìn)EPROM”的過程Proteus把編程器功能做成了可視化加載但很多教程沒講透。2.2 62648KB的臨時數(shù)據(jù)倉庫6264是8KB的CMOS靜態(tài)RAM需要A0-A12共13根地址線數(shù)據(jù)線8根。它的引腳里有兩個使能端CE片選使能低有效和OE輸出使能低有效一個寫使能WE低有效。讀操作時CE和OE都拉低WE拉高寫操作時CE拉低WE拉低OE可以拉高。6264和27C512的功耗等級不同27C512的讀取電流在30mA左右6264在CMOS模式下只有幾微安但這些都是靜態(tài)參數(shù)仿真里不用太關(guān)心實際畫板子時需要考慮電源去耦。仿真里反而要注意的是6264上電后內(nèi)容是隨機(jī)的讀出來可能是0x00可能是0xFF也可能是亂七八糟的值。這和在真實硬件上的行為一致所以調(diào)試時不要指望RAM上電就是干凈的程序里要主動初始化。2.3 Proteus里的連線設(shè)計74LS373是關(guān)鍵樞紐沒有74LS373P0口既當(dāng)?shù)刂酚之?dāng)數(shù)據(jù)是沒法工作的。P0口在ALE地址鎖存使能為高時輸出低8位地址ALE由高變低時74LS373鎖存這8位地址并穩(wěn)定輸出隨后P0口切換為數(shù)據(jù)總線傳輸8位數(shù)據(jù)。這個“先地址、后數(shù)據(jù)”的過程就是教科書上反復(fù)強調(diào)的“分時復(fù)用”。Proteus中的連線建議P0.0-P0.7 → 74LS373的D0-D7同時 → 27C512和6264的D0-D7ALE → 74LS373的G鎖存使能74LS373的Q0-Q7 → 27C512的A0-A7、6264的A0-A7P2.0-P2.7 → 27C512的A8-A15其中A15接地也可以P2.0-P2.4 → 6264的A8-A12P2.5-P2.7 → 譯碼邏輯或直接做片選注意系統(tǒng)性設(shè)計這里有個細(xì)節(jié)容易被忽略6264的A12接哪根地址線決定了它的映射地址范圍。如果你把P2.4接到A12那么6264占用的地址空間是P2.7-P2.5為任意值P2.41時的區(qū)間如果P2.5-P2.7懸空或做譯碼不當(dāng)可能出現(xiàn)多個地址都指向同一顆芯片。Proteus不會報錯但邏輯上很危險。3. Keil C51工程配置從裸機(jī)到外部存儲器的關(guān)鍵設(shè)置3.1 創(chuàng)建工程時的芯片選擇與內(nèi)存模型打開Keil C51新建工程芯片型號選擇Atmel 89C52或者AT89C51我習(xí)慣用AT89C52因為內(nèi)部RAM有256字節(jié)比89C51多128字節(jié)的間接尋址區(qū)IDATA調(diào)試時更從容。但這個內(nèi)部容量對項目來說完全不夠用所以重點在Target選項卡里設(shè)置Memory Model選擇“Large: variables in XDATA”這樣默認(rèn)變量類型如果未指定存儲區(qū)編譯器就會分配到外部RAM。Code Rom Size選擇“Large: 64K program”這樣代碼可以超過2KB、8KB的限制指示鏈接器把代碼放到外部程序存儲器的可用空間。Off-chip Code memory填入程序存儲器的起始地址一般從0x0000開始大小視27C512的映射而定。如果A15接地實際可用的程序空間是0x0000-0x7FFF共32KB在“Start”填0x0000“Size”填0x8000。Off-chip Xdata memory填入6264的起始地址。如果P2.4接A12且P2.5-P2.7都為0時選中6264那起始地址是0x0000大小0x20008KB。注意不要以為填了地址Keil就會自動生成片選邏輯Keil只負(fù)責(zé)生成尋址指令真正的片選信號是硬件電路決定的。你填的地址必須和硬件的譯碼結(jié)果一致否則程序運行后訪問的存儲器和你想的完全不是一回事。3.2 使用xdata關(guān)鍵字控制變量的存儲位置C51里訪問外部RAM可以顯式聲明變量到xdata段unsigned char xdata buffer[256]; // 分配到外部RAM也可以使用指針訪問任意絕對地址#define SRAM_BASE 0x0000 void write_sram(unsigned int addr, unsigned char dat) { unsigned char xdata *p (unsigned char xdata *)(SRAM_BASE addr); *p dat; } unsigned char read_sram(unsigned int addr) { unsigned char xdata *p (unsigned char xdata *)(SRAM_BASE addr); return *p; }這樣寫的好處是直觀但連續(xù)多次調(diào)用會生成比較冗長的匯編代碼。更高效的方式是用Keil提供的絕對地址訪問宏#include absacc.h // 向6264的0x0000地址寫一個字節(jié) XBYTE[0x0000] 0x55; // 從6264的0x0100地址讀一個字節(jié) unsigned char val XBYTE[0x0100];XBYTE宏展開后就是通過DPTR間接訪問Keil會針對xdata訪問自動選擇MOVX指令不需要你手動控制DPTR高低字節(jié)省事很多。但要注意訪問xdata變量時Keil的優(yōu)化器可能改變訪問順序如果要求嚴(yán)格的時序比如連續(xù)寫多個寄存器需要在關(guān)鍵位置加volatile聲明或直接寫內(nèi)嵌匯編。3.3 跟外部存儲器的第一次親密接觸掃描與驗證在Proteus里成功運行前建議先寫一個最簡單的存儲器掃描程序確認(rèn)地址映射完全正確。下面這段代碼把整個6264逐字節(jié)寫入特定模式再讀出來校驗一旦出錯就能精準(zhǔn)定位到是地址線接錯還是數(shù)據(jù)線接錯#include reg52.h #include absacc.h // 6264大小8KB起始地址0x0000 #define SRAM_SIZE 0x2000 void check(signed char pattern) { unsigned int i; bit error_flag 0; for (i 0; i SRAM_SIZE; i) { XBYTE[i] pattern; } for (i 0; i SRAM_SIZE; i) { if (XBYTE[i] ! pattern) { error_flag 1; P1 i 0xFF; // 出錯地址的低8位輸出到P1 while (1); // 停在這里便于觀察 } } if (!error_flag) { P1 pattern; // 全部通過P1輸出當(dāng)前模式值 } } void main() { // 三個經(jīng)典模式0x00、0xFF、0xAA分別能排查不同的接線問題 check(0x00); // 全0模式如果數(shù)據(jù)線短路到地可能誤判通過 check(0xFF); // 全1模式 check(0xAA); // 0101模式能測出相鄰數(shù)據(jù)線的短路 while (1); }這個程序雖然簡單但在Proteus里跑一遍你能直觀看到P1口的變化。如果程序停在中間的while(1)里說明出現(xiàn)了寫入和讀出不一致的地址這時候就要檢查你配置的Keil地址范圍是否和硬件的片選邏輯匹配。4. 實操過程與關(guān)鍵代碼把27C512和6264同時用起來4.1 仿真中給27C512加載代碼的正確流程這一步是很多教程不愿意細(xì)講的但恰恰是最容易卡住初學(xué)者的。在Proteus里直接雙擊27C512芯片會彈出一個屬性對話框。在“Memory Contents”區(qū)域點擊文件夾圖標(biāo)選擇Keil編譯生成的hex文件。如果看不到hex文件多半是Keil沒有在Output選項卡里勾選“Create HEX File”。關(guān)鍵提示加載hex文件前先確認(rèn)Keil工程中“Off-chip Code memory”的起始地址設(shè)置的和27C512在仿真里的接法一致。比如P2.7、P2.6、P2.5被用作片選而實際A15接了P2.7那么你的代碼地址范圍可能是0x0000-0x7FFF也可能是從0x8000開始的某段。Proteus只會把hex文件里的代碼按地址放進(jìn)ROM模型如果你的代碼段地址超過了硬件允許的范圍仿真時指令就會跑飛現(xiàn)象是單片機(jī)不斷復(fù)位或者程序跳到一個莫名其妙的地址。Proteus的51模型加載hex文件后上電復(fù)位的動作和真實芯片幾乎一樣PC從0x0000開始先讀取外部ROM的第一個字節(jié)執(zhí)行跳轉(zhuǎn)指令然后進(jìn)入你的main函數(shù)。所以只要hex文件沒問題、連線沒問題仿真就能跑起來。4.2 程序代碼結(jié)構(gòu)按“讀ROM、寫RAM、回顯”三個步驟組織我完整跑過的示例工程主邏輯就分三段。第一段循環(huán)讀出27C512中的一串固定字符事先在Proteus的Memory Contents里手工填入通過串口發(fā)送到虛擬終端第二段把接收到的串口數(shù)據(jù)寫入6264第三段再讀回來輸出到LCD1620或虛擬終端顯示。用代碼說話#include reg52.h #include absacc.h #include string.h #define ROM_BASE 0x0000 #define RAM_BASE 0x0000 sfr16 DPTR 0x82; // 定義16位DPTR // 串口初始化9600bps12MHz晶振 void uart_init() { SCON 0x50; // 模式1允許接收 TMOD 0x20; // 定時器1工作在模式2 TH1 0xFD; // 波特率9600 TL1 0xFD; TR1 1; } void uart_send(unsigned char c) { SBUF c; while (!TI); TI 0; } // 從27C512中讀取一個字節(jié) unsigned char read_rom(unsigned int addr) { unsigned char code *p (unsigned char code *)(ROM_BASE addr); return *p; } // 向6264寫一個字節(jié) void write_ram(unsigned int addr, unsigned char dat) { unsigned char xdata *p (unsigned char xdata *)(RAM_BASE addr); *p dat; } // 也可以直接用XBYTE宏 #define WRITE_RAM(addr, dat) XBYTE[(addr)] (dat) #define READ_RAM(addr) XBYTE[(addr)] void main() { unsigned char i; unsigned char ch; uart_init(); // 假設(shè)27C512從0x0020開始存放了一個字符串 for (i 0; i 16; i) { ch read_rom(0x0020 i); uart_send(ch); WRITE_RAM(i, ch); // 復(fù)制到6264中 } // 從6264讀回來驗證 for (i 0; i 16; i) { ch READ_RAM(i); uart_send(ch); } while (1); }重點說一下read_rom函數(shù)。這里用了一個code指針指向外部程序存儲器地址。C51對code指針有專門的取指指令MOVC所以從27C512讀數(shù)據(jù)是完全透明的編譯器負(fù)責(zé)處理。而write_ram/READ_RAM用的是MOVX指令對應(yīng)外部數(shù)據(jù)存儲器。這種“一個項目里同時用MOVC和MOVX”的寫法正是理解51總線結(jié)構(gòu)的最好練習(xí)。4.3 把FreeRTOS思想和存儲器擴(kuò)展結(jié)合起來如果你想把實驗往更接近產(chǎn)品的方向推可以做一個微型任務(wù)調(diào)度器用6264作為任務(wù)控制塊的存儲區(qū)typedef struct { unsigned char id; unsigned char state; unsigned int counter; } TCB; TCB xdata task_table[8]; void task_scheduler() { unsigned char i; for (i 0; i 8; i) { task_table[i].state 0x01; task_table[i].counter 0; } // 模擬一輪“任務(wù)遍歷與自增” while (1) { for (i 0; i 8; i) { task_table[i].counter; } } }TCB數(shù)組分配在xdata區(qū)硬件上就是6264。你可以在Proteus中右鍵點擊6264在“Memory Contents”中實時觀察這些字節(jié)的變化。這個操作比單純用debugger看變量有趣得多也更能直觀理解外部RAM和內(nèi)部RAM的差別。5. 常見問題與排查技巧實錄5.1 仿真一運行程序“原地踏步”不動現(xiàn)象點擊運行后程序計數(shù)器PC一直顯示0x0000或者重復(fù)執(zhí)行第一條跳轉(zhuǎn)指令。排查思路確認(rèn)27C512里有沒有加載hex。雙擊芯片查看Memory Contents如果是空的肯定跑不起來。確認(rèn)ALE信號是否正常。在Proteus里添加數(shù)字探針觀察P0口和74LS373的輸出。如果ALE一直是低電平鎖存器不工作地址就永遠(yuǎn)無效。確認(rèn)PSEN引腳有沒有脈沖。如果沒有脈沖說明單片機(jī)根本沒嘗試讀外部ROM可能是EA引腳被拉高導(dǎo)致內(nèi)部ROM訪問優(yōu)先。芯片89C52內(nèi)部的4KB/8KB ROM空間如果不為空并且程序小于內(nèi)部容量單片機(jī)根本不會去讀外部ROM。解決辦法把EA引腳接地強制從外部ROM啟動。這里必須強調(diào)一個反直覺的坑Proteus里AT89C52默認(rèn)內(nèi)部程序存儲器有代碼比如一個空的main函數(shù)如果你生成的hex文件小于4KB編譯器會把它放到內(nèi)部ROM區(qū)Keil不會自動用外部ROM。要想驗證27C512被外部讀取必須把EA引腳拉低。5.2 6264寫入沒問題但讀出全是0xFF這個現(xiàn)象在Proteus里很常見原因是6264的OE和WE信號沒有正確區(qū)分或者片選信號接反了。檢查以下幾點OE是否接到單片機(jī)的RD引腳P3.7。WE是否接到單片機(jī)的WR引腳P3.6。CE是否接到了有效的片選信號如果是直接接地那6264始終被選中讀寫邏輯不會出錯如果通過譯碼器控制確認(rèn)譯碼器的輸出極性正確。還有一種可能是Keil的目標(biāo)配置里外部數(shù)據(jù)存儲器大小沒填。如果Off-chip Xdata memory的Size設(shè)置成0編譯器會認(rèn)為xdata區(qū)不存在所有xdata訪問都會報錯或生成錯誤代碼。正確配置是Start: 0x0000Size: 0x2000。5.3 程序運行正常但往6264寫數(shù)據(jù)后讀回來的數(shù)據(jù)錯位這是地址線接錯導(dǎo)致的典型癥狀。比如你把6264的A12接到了P2.3原本期望從0x0000開始訪問實際上6264的內(nèi)部地址是0x0000-0x1FFF但由于P2.3參與尋址你訪問0x0000時可能需要P2.30而訪問0x2000時P2.31于是在0x1000和0x3000都可能映射到同一個物理單元。遇到這種錯位問題最快的排查方法是用我上面給的掃描程序把0x00、0xFF、0xAA分別寫入全地址再讀回。如果錯誤地址非常有規(guī)律比如每隔0x1000錯一次基本上就是某一根高位地址線的問題。在Proteus中可以用鼠標(biāo)拖拽連線快速調(diào)整重新仿真比焊板子快太多了。5.4 程序里有XDATA變量編譯卻報錯“RAMSIZE”Keil C51的Target選項卡里有個“Use on-chip ROM”的選項旁邊的“RAMSIZE”必須設(shè)置為256字節(jié)對于89C52或128字節(jié)對于89C51。如果這個值小于你的內(nèi)部RAM使用量編譯就會報錯。但要注意這個設(shè)置只管內(nèi)部RAM跟外部6264沒關(guān)系外部RAM的容量是在Off-chip Xdata memory里單獨定義的。很多新手在這里填錯把RAMSIZE當(dāng)成外部RAM大小造成編譯錯誤或內(nèi)存覆蓋。5.5 虛擬終端顯示亂碼串口波特率對不上Proteus里的虛擬終端不會自動跟隨Keil的波特率必須手動在虛擬終端屬性里設(shè)置。常見的坑是晶振頻率Keil代碼里用12MHz晶振計算波特率但Proteus的AT89C52默認(rèn)晶振可能是11.0592MHz。11.0592MHz能精確分頻出9600波特率12MHz則會產(chǎn)生3%左右的誤差這個誤差在真實硬件上可能還能工作但在Proteus里有時也會導(dǎo)致亂碼。推薦統(tǒng)一使用11.0592MHz晶振。6. 工具選型與版本差異Keil C51 v9.61和Proteus 8.x的使用細(xì)節(jié)Keil C51現(xiàn)在最常見的版本是v9.61這個版本對Windows 10/11的兼容性都很好編譯51系列完全夠用。需要注意的一點是v9.61安裝包本身是評估版代碼量限制在4KB以內(nèi)但寄存器窗口、調(diào)試器功能都是完整的。如果你要編譯超過4KB的代碼要么用破解補丁不推薦這里不多說要么換用其他家的免費工具鏈。好消息是本文里的示例代碼量都不大用評估版也完全跑得動。Proteus方面7.x和8.x在仿真51核心時邏輯模型基本一致。區(qū)別在于8.x版本支持更現(xiàn)代的界面和更流暢的仿真并且對存儲器加載hex文件的操作方式略有不同。7.8版本在Windows 10上偶爾會有界面閃爍問題建議直接上8.x以上版本。Proteus的元件搜索關(guān)鍵詞AT89C52、27C512、6264、74LS373、RESPACK-8、LOGICPROBE、VIRTUAL TERMINAL。有一個Proteus特有的操作技巧連線時按CtrlW可以在兩個點之間畫自動布線這在復(fù)雜總線連線時能省下大量時間。另外右鍵點擊導(dǎo)線選擇“Wire Label”可以給總線命名。強烈建議給地址總線和數(shù)據(jù)總線分別命名A0-A15、D0-D7而不是依靠物理連線。命名后即使物理連線位置有偏差只要標(biāo)簽一致電氣上就是連通的這樣可以極大降低連線的視覺復(fù)雜度。7. 仿真之外這個實驗在生產(chǎn)環(huán)境里的真實對應(yīng)很多人覺得Proteus仿真就是“玩”實際工作中根本用不上。但我要說這個實驗的思路和現(xiàn)代嵌入式系統(tǒng)的啟動流程是高度一致的?,F(xiàn)代MCU內(nèi)部集成Flash和SRAM但外部擴(kuò)展存儲器的應(yīng)用場景依然大量存在——比如用SPI NOR Flash存固件鏡像、用并行SRAM做圖像緩沖、用NAND Flash做文件系統(tǒng)這些都是27C512和6264的“現(xiàn)代升級版”。理解地址映射、片選譯碼、總線時序是理解這些復(fù)雜系統(tǒng)的底層基礎(chǔ)。更進(jìn)一步如果你把27C512看作一個“外部Boot ROM”把6264看作“共享內(nèi)存”那這套架構(gòu)就可以類比成早期的計算機(jī)主板總線結(jié)構(gòu)。CPU通過地址總線尋址、數(shù)據(jù)總線傳輸、控制總線協(xié)調(diào)和51單片機(jī)訪問外部存儲器的原理如出一轍。在實際硬件調(diào)試中我吃過一次大虧。當(dāng)時畫了一塊板子外擴(kuò)了一顆64KB的SRAM片選信號用了138譯碼器。結(jié)果在調(diào)試時發(fā)現(xiàn)程序能運行但RAM的某個地址范圍出現(xiàn)的全是0x00折騰了兩天最后查出來是譯碼器的一個使能端接到了單片機(jī)的PSEN上。PSEN在讀外部RAM時不活動導(dǎo)致譯碼器一直沒有輸出那片RAM實際上從未被真正選中。仿真里這個問題很容易發(fā)現(xiàn)因為Proteus會如實反映邏輯電平但如果你想省事用“或門”邏輯直接拼片選很容易犯類似錯誤。所以我個人的建議是務(wù)必在Proteus里把片選邏輯完整搭出來不要圖省事直接把CE接地。雖然CE接地在只有一顆RAM的仿真里也能跑通但這樣一來你對“為什么存儲器會映射到某個地址范圍”的理解就完全建立不起來。只有親手接上譯碼器或門電路看著地址線變化時片選信號的電平跳變你才會對總線地址空間有肌肉記憶般的理解。最后再分享一個小技巧。Proteus的邏輯分析儀Logic Analyzer不是只能接數(shù)字信號你可以把ALE、PSEN、RD、WR、P2.7都拖進(jìn)去運行時直接觀察時序關(guān)系。我見過很多人調(diào)這個項目時對著代碼發(fā)呆其實打開邏輯分析儀看一眼ALE和P0口的數(shù)據(jù)關(guān)系基本就能定位90%的問題。這比反復(fù)改代碼重新編譯高效得多。本文還有配套的精品資源點擊獲取