摘要:SDCC (小型設備C編譯器)是為8位微控制器開發的免費C編譯器。本應用筆記演示如何使用SDCC來開發DS89C430/450系列超高速8051兼容微控制器固件。文中還介紹了如何安裝免費SDCC C編譯器。
SDCC是命令行固件開發工具,含預處理器、編譯器、匯編器、鏈接器和優化器。安裝文件中還捆綁了SDCDB、類似于gdb (GNU調試器)的源碼級調試器。無錯的程序采用SDCC編譯、鏈接后,生成一個Intel十六進制格式的加載模塊。之后可采用串行加載器將該文件加載至DS89C430/450微控制器閃存。(參見DS89C430/450文檔和應用筆記,了解固件下載至器件的詳細信息。)
關于SDCC的最新信息,請訪問http://sdcc.sourceforge.net,或者閱讀SDCC手冊sdccman.pdf (在安裝過程中復制到您的硬盤上)。也可以將問題提交給SDCC在線消息論壇,或發郵件至SDCC網頁“Support”列出的郵件地址。
在“Download”頁為不同的操作系統提供不同的SDCC。如果您使用運行Microsoft Windows的PC,請下載并運行win32自解壓SDCC安裝文件。
安裝程序時會出現一個提示,詢問是否將含有程序二進制文件的目錄添加到您的路徑中。建議同意添加,本應用筆記假設用戶路徑中已添加該目錄。
圖1. 通過版本檢查確認SDCC是否正確安裝
為測試包含路徑,生成名為sdcctest.c的文件,并將以下源代碼復制到該文件中。
圖2. 編譯簡單的SDCC程序
當源代碼編譯成功時,SDCC會生成多個文件。在編譯目錄中可找到以下文件:
與一些商用8051微控制器開發工具不同,SDCC僅支持聲明位和字節可尋址特殊功能寄存器。盡管8051匯編語言支持,但SDCC并不支持共享位和字節可尋址RAM。為證實這一點,請觀察以下代碼實例和編譯完的匯編代碼。
C源程序:
注意,本應用筆記在“絕對尋址”一節介紹了一種可真正實現存儲器位尋址的方法。
near/data
以near或data存儲類型聲明的變量將被放在8051內核的直接尋址RAM中。DS89C430/450系列微控制器具有128字節直接尋址存儲器,這是8051能夠訪問的速度最快的存儲器,生成的匯編代碼只需一個MOV指令即可讀寫該RAM中的數據。
far/xdata
以far或xdata存儲類型聲明的變量將被放在外部RAM中。這樣開發人員能夠訪問更大的RAM空間,但生成的匯編代碼需要使用MOVX指令來讀寫該存儲器,這要求將外部存儲器地址裝入數據指針。
DS89C430/450系列微控制器含有1K字節的內部SRAM,可被用于以far/xdata聲明的變量。注意,電源管理寄存器(PMR)中的DME1:0位在該存儲器初始化或使用之前,必須先被置為內部SRAM模式。
以idata存儲類型聲明的變量將被放在8051內核的間接尋址存儲器中。間接可尋址存儲器與直接尋址存儲器類似,在8051內核中共有128字節(不包括特殊功能寄存器)。但是,訪問idata需要額外的MOV命令將RAM地址移至工作寄存器中。
存儲類型pdata用于訪問分頁的外部數據存儲器。該存儲類型超出了本應用筆記范疇,有興趣的讀者可以閱讀SDCC文檔的pdata部分。
code
以code存儲類型聲明的變量將被放在程序存儲器(DS89C430/450微控制器內部的閃存)中。對于SDCC來說,這類變量只讀,因此常使用code來聲明常量(如:查找表)。
以bit存儲類型聲明的變量被放在8051內核的位尋址存儲器中。8051內核的16字節直接尋址RAM可用作位尋址存儲器(字節0x20至0x2F),提供128個可尋址位。使用該類變量作為標志位可高效利用存儲空間。
存儲類型sfr被用來定義8051內核專有的特殊功能寄存器(SFR)。附錄A定義文件中使用sfr標識符定義了DS89C430/450微控制器中的所有SFR。
注意,下面的實例已定義了SFR,因此沒有必要包含定義文件sdcc_reg420.h。
存儲類型sbit用于定義可位尋址SFR中的特殊位。在8051內核中,地址以0或者8 (十六進制)結束的所有SFR均可位尋址。附錄A定義文件中使用sbit標識符定義了DS89C430/450微控制器SFR的所有可尋址位。
以下程序顯示了有趣的潛在錯誤。
如果查看SDCC生成的.map文件中以下幾行語句(顯示每個變量的實際地址),便會明白這種情況的原因。
絕對尋址可用于仿真位尋址變量。在下面的例子中,在位尋址存儲器的最后一個字節處定義變量n_byte。然后,在8051內核位尋址存儲器的最后8位定義n_bit0至n_bit7。由于這種重疊,可采用變量n_bit0至n_bit7對變量n_byte進行位尋址。
采用SDCC編譯時,默認為小模式。如果要強制SDCC使用特定的存儲器模式,可使用以下命令行參數:
表1. DS89C430/450中斷服務程序的中斷號
SDCC處理與ISR編程相關的許多細節,如使用堆棧保存和恢復累加器及數據指針。(實際上所有函數均進行此操作。請參考SDCC手冊中的_naked關鍵字來禁止在堆棧中保存這些變量)。其它細節不由SDCC處理(因為合理的原因),這對嵌入式編程開發新手帶來一定難度。許多這類問題屬于高級編程范疇,已超出本文討論的范圍,SDCC手冊和嵌入式編程教材可提供更深入的內容。
使用中斷時,應遵循以下原則。
下面的例子定義了一個處理串行通信接口1 (SCI_1)的中斷服務程序(ISR)。程序接收來自SCI_1接收器的一個字節,將接收字節加1,通過SCI_1發射器連續發送出去。
附錄A:DS89C430/450的SFR定義文件(sdcc_reg420.h)
簡介
SDCC (小型設備C編譯器)是為8位微控制器開發的免費C編譯器。盡管兼容多種不同體系結構,但SDCC C編譯器更適合8051內核。本應用筆記主要介紹采用SDCC來開發Maxim/Dallas Semiconductor的DS89C430/450系列超高速8051兼容微控制器固件。SDCC是命令行固件開發工具,含預處理器、編譯器、匯編器、鏈接器和優化器。安裝文件中還捆綁了SDCDB、類似于gdb (GNU調試器)的源碼級調試器。無錯的程序采用SDCC編譯、鏈接后,生成一個Intel十六進制格式的加載模塊。之后可采用串行加載器將該文件加載至DS89C430/450微控制器閃存。(參見DS89C430/450文檔和應用筆記,了解固件下載至器件的詳細信息。)
關于SDCC的最新信息,請訪問http://sdcc.sourceforge.net,或者閱讀SDCC手冊sdccman.pdf (在安裝過程中復制到您的硬盤上)。也可以將問題提交給SDCC在線消息論壇,或發郵件至SDCC網頁“Support”列出的郵件地址。
安裝SDCC免費C編譯器
如果需要安裝SDCC,請從網址http://sdcc.sourceforge.net下載SDCC最新版本。雖然也可使用該軟件的日常構建(nightly builds)版,但通常最安全的方式是下載經過完全測試的最新發布版。在“Download”頁為不同的操作系統提供不同的SDCC。如果您使用運行Microsoft Windows的PC,請下載并運行win32自解壓SDCC安裝文件。
安裝程序時會出現一個提示,詢問是否將含有程序二進制文件的目錄添加到您的路徑中。建議同意添加,本應用筆記假設用戶路徑中已添加該目錄。
采用SDCC編譯器編譯一個簡單的C程序
為確保SDCC已在您的硬盤上正確安裝,請在命令提示符下鍵入sdcc --version,然后回車,窗口中應出現圖1所示文本(實際文本與您下載的SDCC版本有關):圖1. 通過版本檢查確認SDCC是否正確安裝
為測試包含路徑,生成名為sdcctest.c的文件,并將以下源代碼復制到該文件中。
#include以普通ASCII格式(如使用Microsoft記事本程序)保存該文件。在命令提示符下,鍵入sdcc sdcctest.c,然后回車。如像圖2那樣沒有任何反應,則說明程序編譯成功。char str[6] = "MAXIM"; bit flag; void main(void) { if (strcmp(str,"MAXIM") == 0) flag = 0; else flag = 1; while(1); // program loop }
圖2. 編譯簡單的SDCC程序
當源代碼編譯成功時,SDCC會生成多個文件。在編譯目錄中可找到以下文件:
- sdcctest.asm:程序的匯編文件
- sdcctest.lst:程序的列表文件
- sdcctest.rst:被鏈接器更新的列表文件
- sdcctest.map:被鏈接器更新的最終存儲器映射
- sdcctest.ihx:Intel十六進制格式的加載模塊。該文件必須被下載到微控制器中。
SDCC專有數據類型
SDCC支持多數ANSI-C數據類型。此外,SDCC支持多種擴展數據類型(也稱為存儲類型),以充分利用8051體系結構的優勢,這將在后面以實例說明。與一些商用8051微控制器開發工具不同,SDCC僅支持聲明位和字節可尋址特殊功能寄存器。盡管8051匯編語言支持,但SDCC并不支持共享位和字節可尋址RAM。為證實這一點,請觀察以下代碼實例和編譯完的匯編代碼。
C源程序:
union { unsigned char a_byte; struct { unsigned char bit0 : 1; unsigned char bit1 : 1; unsigned char bit2 : 1; unsigned char bit3 : 1; unsigned char bit4 : 1; unsigned char bit5 : 1; unsigned char bit6 : 1; unsigned char bit7 : 1; } a_bit; } a; bit b; void main(void) { a.a_byte = 0x05; a.a_bit.bit6 = 1; b = 1; while(1); // program loop } Assembly listing (.rst file): ... 159 ;sdcctest.c:21: a.a_byte = 5; 160 ; genPointerSet 161 ; genNearPointerSet 162 ; genDataPointerSet 0031 75 21 05 163 mov _a,#0x05 164 ;sdcctest.c:23: a.a_bit.bit6 = 1; 165 ; genPointerSet 166 ; genNearPointerSet 0034 78 21 167 mov r0,#_a 168 ; genPackBits 0036 E6 169 mov a,@r0 0037 44 40 170 orl a,#0x40 0039 F6 171 mov @r0,a 172 ;sdcctest.c:25: b = 1; 173 ; genAssign 003A D2 00 174 setb _b 175 ;sdcctest.c:27: while(1); // program loop ...盡管在聲明中“a”看起來是位尋址存儲器,但匯編列表文件(來自由SDCC生成的.rst文件)表明變量并沒有使用位尋址。在列表中不要混淆“a”和“_a”?!癮”指累加器,而“_a”指變量。
注意,本應用筆記在“絕對尋址”一節介紹了一種可真正實現存儲器位尋址的方法。
near/data
以near或data存儲類型聲明的變量將被放在8051內核的直接尋址RAM中。DS89C430/450系列微控制器具有128字節直接尋址存儲器,這是8051能夠訪問的速度最快的存儲器,生成的匯編代碼只需一個MOV指令即可讀寫該RAM中的數據。
#include "sdcc_reg420.h" data unsigned char outPort0 = 0x4A; void main(void) { P0 = outPort0; while (1); // program loop }該例中使用的定義文件sdcc_reg420.h見附錄A。
far/xdata
以far或xdata存儲類型聲明的變量將被放在外部RAM中。這樣開發人員能夠訪問更大的RAM空間,但生成的匯編代碼需要使用MOVX指令來讀寫該存儲器,這要求將外部存儲器地址裝入數據指針。
DS89C430/450系列微控制器含有1K字節的內部SRAM,可被用于以far/xdata聲明的變量。注意,電源管理寄存器(PMR)中的DME1:0位在該存儲器初始化或使用之前,必須先被置為內部SRAM模式。
#include "sdcc_reg420.h" xdata unsigned char ioPorts[2]; void main(void) { PMR |= 0x01; // Enable internal 1K SRAM ioPorts[0] = 0x4A; ioPorts[1] = 0x56; P0 = ioPorts[0]; P1 = ioPorts[1]; while (1); // program loop }idata
以idata存儲類型聲明的變量將被放在8051內核的間接尋址存儲器中。間接可尋址存儲器與直接尋址存儲器類似,在8051內核中共有128字節(不包括特殊功能寄存器)。但是,訪問idata需要額外的MOV命令將RAM地址移至工作寄存器中。
#include "sdcc_reg420.h" idata unsigned int port0_x2; void main(void) { while (1) // program loop { port0_x2 = P0 * 2; } }pdata
存儲類型pdata用于訪問分頁的外部數據存儲器。該存儲類型超出了本應用筆記范疇,有興趣的讀者可以閱讀SDCC文檔的pdata部分。
code
以code存儲類型聲明的變量將被放在程序存儲器(DS89C430/450微控制器內部的閃存)中。對于SDCC來說,這類變量只讀,因此常使用code來聲明常量(如:查找表)。
#include "sdcc_reg420.h" code unsigned char out[10] = {0x03,0x45,0xFA,0x43,0xDD, 0x1A,0xE0,0x00,0x87,0x91}; void main(void) { data unsigned char i = 0; while (1) // program loop { P0 = out[i++]; if (i==10) i=0; } }bit
以bit存儲類型聲明的變量被放在8051內核的位尋址存儲器中。8051內核的16字節直接尋址RAM可用作位尋址存儲器(字節0x20至0x2F),提供128個可尋址位。使用該類變量作為標志位可高效利用存儲空間。
#include "sdcc_reg420.h" #define ESCAPE 0x1B bit esc_char_flag = 0; void main(void) { P1 = 0x00; while (!esc_char_flag) { if (P0 == ESCAPE) esc_char_flag = 1; } P1 = 0xFF; while (1); // program loop }sfr
存儲類型sfr被用來定義8051內核專有的特殊功能寄存器(SFR)。附錄A定義文件中使用sfr標識符定義了DS89C430/450微控制器中的所有SFR。
注意,下面的實例已定義了SFR,因此沒有必要包含定義文件sdcc_reg420.h。
sfr at 0x80 P0; sfr at 0x90 P1; void main(void) { P0 = 0x00; P1 = 0xFF; while (1); // program loop }sbit
存儲類型sbit用于定義可位尋址SFR中的特殊位。在8051內核中,地址以0或者8 (十六進制)結束的所有SFR均可位尋址。附錄A定義文件中使用sbit標識符定義了DS89C430/450微控制器SFR的所有可尋址位。
sfr at 0x80 P0; // Port 0 sbit at 0x80 P0_0; // Port 0 bit 0 sbit at 0x81 P0_1; // Port 0 bit 1 sbit at 0x82 P0_2; // Port 0 bit 2 sbit at 0x83 P0_3; // Port 0 bit 3 sbit at 0x84 P0_4; // Port 0 bit 4 sbit at 0x85 P0_5; // Port 0 bit 5 sbit at 0x86 P0_6; // Port 0 bit 6 sbit at 0x87 P0_7; // Port 0 bit 7 void main(void) { P0 = 0x00; // P0 = 0x00 P0_4 = 1; // P0 = 0x10 while (1); // program loop }
絕對尋址
SDCC支持采用at標識符的絕對尋址。但是,SDCC不跟蹤聲明的絕對尋址變量,而且可能在其地址聲明其它變量,造成相互覆蓋。以下程序顯示了有趣的潛在錯誤。
#include "sdcc_reg420.h" unsigned char a = 0x4A; unsigned int b = 0x0000; unsigned char c[64] = {0x00}; unsigned char at 0x0010 y; unsigned char at 0x0010 z; void main(void) { for(b=0; b<64; b++) c[b] = 0xAA; y = 0xF1; z = 0xF2; a = c[5]; while (1); // program loop }使用SDCC時,盡管變量"y"和"z"分配同一個位置,也可進行無錯誤或警告的編譯。如果要運行該程序,我們認為程序(a = c[5])中"a"最終將被設置為0xAA。但情況并非如此。"a"最終被分配的值為0xF2。
如果查看SDCC生成的.map文件中以下幾行語句(顯示每個變量的實際地址),便會明白這種情況的原因。
Area Addr Size Decimal Bytes (Attributes) -------------------------------- ---- ---- ------- ----- ------------ . .ABS. 0000 0000 = 0. bytes (ABS,OVR) Value Global -------- -------------------------------- ... 0010 _y 0010 _z ... Area Addr Size Decimal Bytes (Attributes) -------------------------------- ---- ---- ------- ----- ------------ DSEG 0008 0043 = 67. bytes (REL,CON) Value Global -------- -------------------------------- 0008 _a 0009 _b 000B _c注意,變量名稱前的下劃線是由編譯器添加的。如果"c"位于地址0x000B,長度為64字節,那么它將覆蓋位于地址0x0010處的變量"y"和"z"。
絕對尋址可用于仿真位尋址變量。在下面的例子中,在位尋址存儲器的最后一個字節處定義變量n_byte。然后,在8051內核位尋址存儲器的最后8位定義n_bit0至n_bit7。由于這種重疊,可采用變量n_bit0至n_bit7對變量n_byte進行位尋址。
#include "sdcc_reg420.h" data unsigned char at 0x002F n_byte; bit at 0x78 n_bit0; bit at 0x79 n_bit1; bit at 0x7A n_bit2; bit at 0x7B n_bit3; bit at 0x7C n_bit4; bit at 0x7D n_bit5; bit at 0x7E n_bit6; bit at 0x7F n_bit7; void main(void) { n_byte = 0x00; n_bit4 = 1; P0 = n_byte; // P0 = 0x10 while (1); // program loop }
存儲器模式
SDCC支持兩種存儲器模式:小模式和大模式。使用存儲器小模式時,SDCC在內部RAM中聲明所有不帶存儲類型的變量(如,data、idata、xdata、pdata、bit、code)。使用存儲器大模式時,SDCC在外部RAM中聲明所有不帶存儲類型的變量。采用SDCC編譯時,默認為小模式。如果要強制SDCC使用特定的存儲器模式,可使用以下命令行參數:
sdcc --model-small sdcctest.c或者
sdcc --model-large sdcctest.c不要鏈接使用不同存儲器模式編譯的模塊或目標文件。
SDCC的中斷
定義中斷服務程序(ISR)時,應使用以下格式:void interrupt_identifier (void) interrupt interrupt_number using bank_number { ... }其中interrupt_identifier可以是任意有效的SDCC函數名,interrupt_number代表中斷在中斷向量表中的位置。表1列出了DS89C430/450系列微控制器支持的每個中斷的中斷號??蛇x參數bank_number用于指示SDCC采用哪個寄存器區存儲ISR中的局部變量。
表1. DS89C430/450中斷服務程序的中斷號
Interrupt Name | Interrupt Vector | Interrupt Number |
External Interrupt 0 | 0x03 | 0 |
Timer 0 Overflow | 0x0B | 1 |
External Interrupt 1 | 0x13 | 2 |
Timer 1 Overflow | 0x1B | 3 |
Serial Port 0 | 0x23 | 4 |
Timer 2 Overflow | 0x2B | 5 |
Power Fail | 0x33 | 6 |
Serial Port 1 | 0x3B | 7 |
External Interrupt 2 | 0x43 | 8 |
External Interrupt 3 | 0x4B | 9 |
External Interrupt 4 | 0x53 | 10 |
External Interrupt 5 | 0x5B | 11 |
Watchdog Interrupt | 0x63 | 12 |
SDCC處理與ISR編程相關的許多細節,如使用堆棧保存和恢復累加器及數據指針。(實際上所有函數均進行此操作。請參考SDCC手冊中的_naked關鍵字來禁止在堆棧中保存這些變量)。其它細節不由SDCC處理(因為合理的原因),這對嵌入式編程開發新手帶來一定難度。許多這類問題屬于高級編程范疇,已超出本文討論的范圍,SDCC手冊和嵌入式編程教材可提供更深入的內容。
使用中斷時,應遵循以下原則。
- 可在ISR內部寫、并可在ISR外部訪問的每個全局變量必須被聲明為volatile,以確保優化器不會刪除與該變量相關的指令。
- 以非原子(non-atomic)方式使用數據時(如,訪問16位/32位變量)應禁止中斷。當對變量的訪問為原子方式時,處理器無法中斷(帶有ISR)對存儲器的數據存取。
- 避免在ISR內部調用函數。如果必須這樣做,需要將函數聲明為reentrant (參見SDCC手冊),這樣函數中的所有局部變量被分配在堆棧中,而不是在RAM中。
下面的例子定義了一個處理串行通信接口1 (SCI_1)的中斷服務程序(ISR)。程序接收來自SCI_1接收器的一個字節,將接收字節加1,通過SCI_1發射器連續發送出去。
#include "sdcc_reg420.h" volatile unsigned char n = 0x4A; void sci1ISR (void) interrupt 7 { if (RI_1) { n = SBUF1+1; // Save Rx byte RI_1 = 0; // Reset SCI_1 Rx interrupt flag } else if (TI_1) { SBUF1 = n; // Load byte to Tx TI_1 = 0; // Reset SCI_1 Tx interrupt flag } } void main(void) { // 1. Init Serial Port EA = 0; // Enable global interrupt mask SCON1 = 0x50; // Set SCI_1 to 8N1, Rx enabled TMOD |= 0x20; // Set Timer 1 as Mode 2 TH1 = 0xDD; // Set SCI_1 for 2400 baud TR1 = 1; // Enable Timer 1 ES1 = 1; // Enable interrupts for SCI_1 EA = 1; // Disable global interrupt mask // 2. Initiate SCI_1 Tx SBUF1 = n; // 3. Program loop... while (1); }
內嵌匯編
SDCC完全支持內嵌匯編。使用該功能時,匯編代碼應嵌在_asm和_endasm標識符之間。注意,通過在變量名前加下劃線,內嵌匯編代碼也可以訪問C變量。以下實例采用內嵌匯編執行nop指令(用于在微控制器內部占用一個時鐘周期),然后將變量"a"加1。#include "sdcc_reg420.h" unsigned char a; void main(void) { // program loop... while (1) { a = P0; _asm nop nop nop inc _a _endasm; P1 = a; } }SDCC還可用于C和匯編函數接口,這是較深入的問題;請參考SDCC手冊,了解詳細信息。
附錄A:DS89C430/450的SFR定義文件(sdcc_reg420.h)
/* * sdcc_reg420.h * * MAXIM INTEGRATED PRODUCTS * * Special Function Register definitions file * DS89C430/450 Ultra-High Speed 8051-compatible uCs * */ #ifndef __REG420_H__ #define __REG420_H__ /* BYTE Registers */ sfr at 0x80 P0; sfr at 0x81 SP; sfr at 0x82 DPL; sfr at 0x83 DPH; sfr at 0x84 DPL1; sfr at 0x85 DPH1; sfr at 0x86 DPS; sfr at 0x87 PCON; sfr at 0x88 TCON; sfr at 0x89 TMOD; sfr at 0x8A TL0; sfr at 0x8B TL1; sfr at 0x8C TH0; sfr at 0x8D TH1; sfr at 0x8E CKCON; sfr at 0x90 P1; sfr at 0x91 EXIF; sfr at 0x96 CKMOD; sfr at 0x98 SCON0; sfr at 0x99 SBUF0; sfr at 0x9D ACON; sfr at 0xA0 P2; sfr at 0xA8 IE; sfr at 0xA9 SADDR0; sfr at 0xAA SADDR1; sfr at 0xB0 P3; sfr at 0xB1 IP1; sfr at 0xB8 IP0; sfr at 0xB9 SADEN0; sfr at 0xBA SADEN1; sfr at 0xC0 SCON1; sfr at 0xC1 SBUF1; sfr at 0xC2 ROMSIZE; sfr at 0xC4 PMR; sfr at 0xC5 STATUS; sfr at 0xC7 TA; sfr at 0xC8 T2CON; sfr at 0xC9 T2MOD; sfr at 0xCA RCAP2L; sfr at 0xCB RCAP2H; sfr at 0xCC TL2; sfr at 0xCD TH2; sfr at 0xD0 PSW; sfr at 0xD5 FCNTL; sfr at 0xD6 FDATA; sfr at 0xD8 WDCON; sfr at 0xE0 ACC; sfr at 0xE8 EIE; sfr at 0xF0 B; sfr at 0xF1 EIP1; sfr at 0xF8 EIP0; /* BIT Registers */ /* P0 */ sbit at 0x80 P0_0; sbit at 0x81 P0_1; sbit at 0x82 P0_2; sbit at 0x83 P0_3; sbit at 0x84 P0_4; sbit at 0x85 P0_5; sbit at 0x86 P0_6; sbit at 0x87 P0_7; /* TCON */ sbit at 0x88 IT0; sbit at 0x89 IE0; sbit at 0x8A IT1; sbit at 0x8B IE1; sbit at 0x8C TR0; sbit at 0x8D TF0; sbit at 0x8E TR1; sbit at 0x8F TF1; /* P1 */ sbit at 0x90 P1_0; sbit at 0x91 P1_1; sbit at 0x92 P1_2; sbit at 0x93 P1_3; sbit at 0x94 P1_4; sbit at 0x95 P1_5; sbit at 0x96 P1_6; sbit at 0x97 P1_7; /* SCON0 */ sbit at 0x98 RI_0; sbit at 0x99 TI_0; sbit at 0x9A RB8_0; sbit at 0x9B TB8_0; sbit at 0x9C REN_0; sbit at 0x9D SM2_0; sbit at 0x9E SM1_0; sbit at 0x9F SM0_0; sbit at 0x9F FE_0; /* P2 */ sbit at 0xA0 P2_0; sbit at 0xA1 P2_1; sbit at 0xA2 P2_2; sbit at 0xA3 P2_3; sbit at 0xA4 P2_4; sbit at 0xA5 P2_5; sbit at 0xA6 P2_6; sbit at 0xA7 P2_7; /* IE */ sbit at 0xA8 EX0; sbit at 0xA9 ET0; sbit at 0xAA EX1; sbit at 0xAB ET1; sbit at 0xAC ES0; sbit at 0xAD ET2; sbit at 0xAE ES1; sbit at 0xAF EA; /* P3 */ sbit at 0xB0 P3_0; sbit at 0xB1 P3_1; sbit at 0xB2 P3_2; sbit at 0xB3 P3_3; sbit at 0xB4 P3_4; sbit at 0xB5 P3_5; sbit at 0xB6 P3_6; sbit at 0xB7 P3_7; /* IP0 */ sbit at 0xB8 LPX0; sbit at 0xB9 LPT0; sbit at 0xBA LPX1; sbit at 0xBB LPT1; sbit at 0xBC LPS0; sbit at 0xBD LPT2; sbit at 0xBE LPS1; /* SCON1 */ sbit at 0xC0 RI_1; sbit at 0xC1 TI_1; sbit at 0xC2 RB8_1; sbit at 0xC3 TB8_1; sbit at 0xC4 REN_1; sbit at 0xC5 SM2_1; sbit at 0xC6 SM1_1; sbit at 0xC7 SM0_1; /* T2CON */ sbit at 0xC8 CP_RL_2; sbit at 0xC9 C_T_2; sbit at 0xCA TR_2; sbit at 0xCB EXEN_2; sbit at 0xCC TCLK; sbit at 0xCD RCLK; sbit at 0xCE EXF_2; sbit at 0xCF TF_2; /* PSW */ sbit at 0xD0 PARITY; sbit at 0xD0 P; sbit at 0xD1 F1; sbit at 0xD2 OV; sbit at 0xD3 RS0; sbit at 0xD4 RS1; sbit at 0xD5 F0; sbit at 0xD6 AC; sbit at 0xD7 CY; /* WDCON */ sbit at 0xD8 RWT; sbit at 0xD9 EWT; sbit at 0xDA WTRF; sbit at 0xDB WDIF; sbit at 0xDC PFI; sbit at 0xDD EPFI; sbit at 0xDE POR; sbit at 0xDF SMOD_1; /* EIE */ sbit at 0xE8 EX2; sbit at 0xE9 EX3; sbit at 0xEA EX4; sbit at 0xEB EX5; sbit at 0xEC EWDI; /* EIP0 */ sbit at 0xF8 LPX2; sbit at 0xF9 LPX3; sbit at 0xFA LPX4; sbit at 0xFB LPX5; sbit at 0xFC LPWDI; #endif
評論
查看更多