陵谷紛紜新事改,筑臺土石未應遲。
目錄
- sfr與sbit?
- 不靠定時器的delay_ms延時函數
- 所謂寄存器
sfr與sbit?
這第一課咱們主要來先理解一下sfr與sbit,以下可能是咱們這些新手朋友常見的點燈代碼:
#include<regx52.h>//reg52.h只定義sfr而沒定義sbit可尋址空間的位變量
int main()
{while(1){P2_0 = 0;//P幾取決于寧板子上led的對應的gpio}
}
或者是更底層更難理解一點的:
sfr P2=0xA0;
sbit P2_0=P2^0;
int main()
{while(1){P2_0=0;//賦值也有可能是1,這主要取決于led的二極管的連接電路}
}
可能有一些只有c語言基礎的朋友就已經開始迷惑了,sfr和sbit是什么?
先來打個比方:想象單片機是一個儲存有許多不同魔法的魔法書,每張書頁都對應一個特殊功能:有的控制燈光(GPIO),有的管理時鐘(Timer)。而sfr(特殊功能寄存器)?就是這些這本書的頁碼。在單片機的sfr寄存器中有著許許多多的空間,空間里充斥著二進制數,這些二進制數控制著單片機接口輸出高低電平,當然空間里的二進制數也會因為接口接收的高低電平改變;而sfr,一款由keil編譯器開發的擴展關鍵字,它的作用類似于c語言中的取別名define,只不過它取別名的對象是儲存八位二進制數的寄存器中的地址,比如咱們點燈用到的P2接口(GPIO,General Purpose Input Output ,通用功能輸出輸出 )所對應的sfr的地址就是0xA0,這個地址儲存了一個八位二進制數,對應了八個led(對于一般的51單片機板子而言,咱手中這塊是40腳的stc89c52rc);但是,目前咱們只想點一個led怎么辦呢?所以咱們需要另一款keil擴展關鍵字sbit,它的操作與^(規范的位尋址運算符)綁定,功能是也是取別名,但對象是sfr特殊寄存器地址中的某一位,這樣咱們就可以直接操控確定的一位二進制數。
知道了sfr和sbit的作用與簡單gpio的功能引腳定義,咱們現在就可以寫出一些花活來:
sfr LED_GPIO=0xA0;
sbit LED0=P2^0;
int main()
{while(1){LED0=0;}
}
當然這是顯然不規范的,蛤蛤蛤,如果是咱們自己興趣的項目這樣寫寫無傷大雅,但是在企業化的規范化開發中這顯然是不能通過檢查的。
但其實,像c中的頭文件引用一樣,單片機的開發也有自己的頭文件,在51單片機系列中,通用的頭文件<regx52.h>或者是<reg52.h>,前者既定義了sfr有定義了sbit;后者僅定義了sfr;這里藏著單片機開發的第一個隱藏關卡:
?reg52.h:標準AT89C52頭文件 僅定義SFR基地址,如sfr P1 = 0x90; 需要手動位定義:sbit P1_0 =
P1^0;(很多新手漏掉這一步導致編譯報錯)
不靠定時器的delay_ms延時函數
在單片機編程中,延時是最基礎的需求。比如讓LED閃爍時,需要點亮后保持一段時間再熄滅。但單片機沒有現成的delay_ms()函數,需要手動實現。咱們這里使用的方式是利用空循環消耗CPU時間。
示例代碼分析:
void delay_ms(unsigned int ms) {unsigned int i, j;//unsigned關鍵字占用內存更少,符合單片機資源緊張需要空間高效利用性for(i = 0; i < ms; i++)for(j = 0; j < 280; j++); //280次空操作循環約為1ms
}
所謂寄存器
舉個不恰當的例子,寄存器就相當于一個api,咱們只需要知道參數(功能引腳初始化定義和sfr何如初始化設置)就可以玩轉,在以后的學習中咱會以“api參數”為起始然后再闡述編程的框架!