這裡將它寫出來給大家分享。
1.關於sbit用法
sbit可以將SFR裡面的某個bit做變數宣告,用以查看IO位置是高電位還是低電位,標準的8052或是8051裡面你會看到,90H和A0H恰好就是P1和P2存放位置,書上都然很快樂的就這樣設定
sbit P1_0 = P1^0; sbit P1_1 = P1^1; sbit P1_2 = P1^2; sbit P1_3 = P1^3; sbit P1_4 = P1^4; sbit P1_5 = P1^5; sbit P1_6 = P1^6; sbit P1_7 = P1^7;
但是問題來了,當你的MCU不只有P1是IO,P4 P5怎麼辦,你依樣畫葫蘆,去用sbit設定,然後卻不能用,為什麼??
後來發現可以這樣用的SFR是90H 98H A0H A8H...原來末碼是0或是8才可以這樣用,而P4 P5他們SFR的位置並不是如此,所以不能用。
如果你要看單個bit的狀態,就只能用P5&(0x04)這樣之類的方法了。
2.暫存器賦值的慣用手法
#define P21_PS3V_PWR_ON() ( P2 |= (0x01<<1) ) //P21 HIGH #define P21_PS3V_PWR_OFF() ( P2 &= ~(0x01<<1) ) //P21 LOW
當我們要對特定暫存器賦值的時候,常看到以上的寫法,搞了一堆or還有and這樣有比較厲害嗎?看起來是比較專業的樣子,只是有必要嗎?
根據我問了一些工程師,他們寫了兩三年他們說他們也不知道,剛開始看前輩這樣寫就這樣寫了,也有的說法說這樣子做比直接賦值效率快,減少程式運算時間,可是這樣子玩多了,可讀性就不高了。
那時我很單純的想
#define P21_PS3V_PWR_ON() ( P2 = 0x02 ) //P21 HIGH #define P21_PS3V_PWR_OFF() ( P2 = 0xFD ) //P21 LOW
這樣寫不就好了嗎?不是意思都一樣,後來我才知道,其實兩種寫法的效率真的感覺沒差多少,但是重點是牽一髮動全身,用下面的方法賦值,就不管P20 P22 P23 P24 P25 P26 P27他們的死活了,所以 |= 和 &= ~ 這兩個是成雙成對的,唯有這樣才可以對單一SFR的其中一個bit做賦值,這也呼應了前面講到sbit不能用時,對SFR的賦值方法。
0.0b 恩你碰到了不可 bit addressable 的位址
回覆刪除當碰到類似文中所述類似 P4 P5
不能 bit addressable 的記憶體空間
夜風也可以考慮系統化技巧,
使用一種稱為 "代理操作" 的技術
更複雜的晶片基本上都會用上這種技巧像
32-bit ColdFire C32MX, 16-bit dsPIC
不過因為這些晶片有 DMA 控制器等於它們有
硬體版的代理操作,DMA 控制器會有自己
專屬 DMA RAM 跟 CPU 式完全分離的喔
你可以想像成自己宣告的 BYTE Port4 就類似
那些擁有 DMA RAM 的 CPU。
會使用這種技巧以後當你碰到有DMA控制器的CPU
你就可以馬上上手,因為那個只是把下面那種技巧
做成硬體而已,指定好暫存器跟哪個DMA RAM關聯
就可以直接使用。
Ex:
typedef unsigned char BYTE;
typedef union tagMYPORT
{
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;
}bitVal;
unsigned char u8Val;
}MYPORT;
#define DelegatePort(X) (*((MYPORT*)( &(X) )))
void main(void)
{
BYTE Port4; // C51 編譯器會讓初始值為零
// 使用代理操作
DelegatePort(Port4).u8Val = 0x80; // 此時 Port4 = 0x80
DelegatePort(Port4).bitVal.bit6 = 1; // 此時 Port4 = 0xC0
P4 = Port4; // 移動值到 P4
P4 = 0x80; // 假設把 0x80 移給 P4
Port4 = P4; // Port4 接收 P4 (Port4=0x80)
DelegatePort(Port4).bitVal.bit6 = 1; // Port4 利用代理操作更動 bit6 (Port4 變成 0xC0)
}
這個程式碼會把值交給 Port4 去代理
這樣處理 bit 就會變成輕而易舉
不管是你要比較某個 bit 或是修改某個 bit
夜風可以用 Simulator 跑跑看 但是 Keil 的
Simulator只能模擬標準 51 ; 也就是 P4
可要改成 P0~P3 其中之一 當然你的8051有專屬
ICD/ICE 的話就沒這種問題~~~
話說夜風那顆 8051 GPIO還真多 :)
話說我那篇好像也快回來囉 (希望會上XD)
夜風學很快阿 有這種觀念 其實學 CAN bus
應該會很快 CAN 的 Mask Filter 會用到很多這種
位元移動的技巧
參考資料 Keil Technical Support
回覆刪除http://www.keil.com/support/docs/2799.htm
多多看官方的 Technical Support 會進步很快
還有 Keil 安裝完那本
Cx51 Compiler User’s Guide
專心看 compiler 手冊其實可以發現很多技巧
都隱藏在字裡行間,一個很好的例子就是
data char *x; is equivalent to char *data x;
原來在 Keil C 編譯器裡面
這樣
data char *x;
或
char *data x;
都是可以的語法 :)