Keil C51 延時函數 delay_1ms

Posted by: 邱小新 at 下午3:01 in
利用 printf 計時,好像不太準耶,不知為啥。

12.0 MHz 延時 1ms 函數

void delay_1ms(unsigned int ms) { unsigned char i; while(ms--) { for(i = 0; i < 123; i++); } }

22.1184 MHz 延時 1ms 函數

void delay_1ms(unsigned int ms) { unsigned char i; while(ms--) { _nop_(); _nop_(); for(i=0; i<228; i++); } }

原文出處:http://www.dztang.com/article/dpj/jcycx/117.html
经过电子堂网站的实测,精确到us啊,足够了吧。

Keil C51 指標變數 (pointers to specific memory spaces)

Posted by: 邱小新 at 上午11:16 in
由於 mcs51 的記憶體分成五大部份(註一),所以搞的 SDCC 的指標也要分成好幾種。以下先簡介指標定義準則:

type
變數型態
located
指向位址
pointerphysical
變數位址
name
unsigned charxdata*datap

指標分類

  1. unsigned xdata char * data p;
    指向外部記憶體的指標變數,變數存放在內部記憶體。
  2. unsigned char data * xdata p;
    指向內部記憶體的指標變數,變數存放在外部記憶體。
  3. unsigned char code * xdata p;
    指向程式記憶體的指標變數,變數存放在外部記憶體。
  4. unsigned char code * code p;
    指向程式記憶體的指標變數,變數存放在程式記憶體,指標變數是唯讀,所以必須先設定初始值
  5. unsigned char * xdata p;
    指向任何記憶體的指標變數 (generic pointer),變數存放在外部記憶體。
  6. unsigned char * p;
    指向任何記憶體的指標變數 (generic pointer),變數存放由 memory model 決定。
  7. char (* data fp)(void);
    指向程式記憶體的函數指標變數,變數存放在內部記憶體。函數指標變數只能指向程式記憶體,無法修改喔
  8. 由於內部記憶體指標讀取都是使用間接定址 (indirect addressing),所以無法存取 SFR 空間的記憶體內容。

指標變數大小

data1
xdata2
code2
generic pointer3

  1. generic pointer 是設計用來可以做通用指標變數使用,可以任意變換指標指向位址,但是相對的需要佔用 3 個 bytes 的位置,而且在做讀取寫入時,需要另外執行一個函數來轉換位址,沒事就少用一點吧。

W79E632 code banking using Keil C51

Posted by: 邱小新 at 下午3:40 in ,
  1. copy C:\Keil\C51\LIB\L51_BANK.A51 到專案目錄下。

  2. 修改 L51_BANK.A51 中的設定。
    ?B_NBANKS EQU 4 改成 ?B_NBANKS EQU 2。

  3. 在 mcu_init 中加入 ROMCON = 0x0A;,藉此設定 P1.2 as A16 並開啟 code banking 功能。

  4. 將 L51_BANK.A51 加入 project source file 裏。

  5. 進入 Project --> Manage --> Components, Environment and Books。

  6. 在 Groups 裏新增 bank0 及 bank1,完成後會在 Project Workspace 會出現 bank0 及 bank1 二個目錄。

  7. 在 bank0 按右鍵,選擇 Options for Group 'bank0',在 Code Bank 處選擇 "Bank #0"。

  8. 在 bank1 按右鍵,選擇 Options for Group 'bank1',在 Code Bank 處選擇 "Bank #1"。

  9. 在 bank0 及 bank1 各新增一個 souce file。

  10. 完成編譯後,原本會產生一個 xxx.HEX,現在則產生 xxx.H00 及 xxx.H01 二個檔案。

範例程式碼下載

Keil C51 printf 使用要點

Posted by: 邱小新 at 下午2:43 in
  1. 需要先初始化 uart 功能,TI 需設成 1,printf 輸出才有資料。
  2. 不需要像 SDCC 需要另外寫 putchar 及 getchar 函數,已經內建寫好了。
  3. 使用時要 inlcude stdio.h 標頭檔案,才不會找不到 prototype。
  4. printf 要輸出 8-bits 變數時,需寫成 %bd,不可以寫成 %d,會造成輸出錯誤,原因不明。
  5. getchar 函數在讀取到一個字元後,會自動輸出原字元做回應。(好像理論上不需要如此做,是為了仿造 PC 上有回應字元嗎?)

參考範例,使用 W79E632A,@40.0MHz,19200 bps。

void uart_init(void) { RCAP2L = 0xbf; RCAP2H = 0xff; TH2 = RCAP2H; TL2 = RCAP2L; T2CON = 0x34; SCON = 0x52; RI = TI = 1; } void main(void) { EA = 0; uart_init(); EA = 1; while (1) { printf("enter one charcter:"); getchar(); printf("\n\r"); } }

Keil C51 Code Banking

Posted by: 邱小新 at 上午9:50 in

當有三個函數為 A2() 位於 common 區,A0() 位於 bank0,A1() 位於 bank1,而且三個函數同時寫在 AA.c 裏,只是利用 CODE(?PR?A2?AA) bank0(?PR?A0?RAM) bank1(?PR?A1?RAM) 來分開,並且在 A2() 函數裏會呼叫 A1() 及 A0() 函數時,必須把 AA.c 放在 common 區裏,不可以放在 bank0 or bank1 這樣會造成 compiler 誤判,沒有呼叫 bank_switch 來切換 A1()/A2(),而造成不可預期的錯誤。

雜記

  1. 在 bank0 的函數可以互相呼叫 bank1 函數,沒有限制喔。
  2. 將 keil C51 內建 printf 移到 bank 裏時,最好避免一起把 code constants 一起移到 bank 裏去,不然就會發生最下面紅字警告的問題。

Common Area

common code area 主要是給所有的 bank 使用的函數或是固定資料。下面是一些會放在 common area 的函數及資料。
  1. Reset and Interrupt Vectors 重置及中斷指標
    主要是給硬體中斷時直接存取使用,所以必須放在 common area。

  2. Interrupt Functions 中斷函數
    主要是給硬體中斷時直接存取使用,所以必須放在 common area。

  3. Bank Switch Code 切換區塊函數
    這樣一定要放 common area,不然怎麼做切換啊。

  4. Library Functions 程式庫函數
    因為無法預知那個區塊會用到,所以都放在 common area。

  5. Code Constants 程式區資料變數
    這個不知為啥都放在 common area,可以經由參數設定放置在 bank 裏。

Code Constants 移至 bank 裏

code constants 主要就是經由宣告成 code 的變數,如字串,表格等。另外包含在 printf 裏面的字串也會放在 code constants,所以常常發現沒有宣告 code 變數,卻出現 ?CO?MYCODE 在 prog_name.m51 裏。
  1. 假設專案名稱為 prog,原始碼檔案為 test.c,晶片為 winbond W79E632。
  2. 在 prog.m51 裏的 C O D E M E M O R Y 區塊裏放置 common area 的資料描述。
  3. 在 test.c 裏的 code constants 會被統一放置在 ?CO?TEST 裏。
  4. Project --> Options for Target 'W79E632' --> BL51 Misc。
  5. 在 Misc controls 裏填入 BANK0(?CO?TEST (0x8000)) 即可,0x8000 是指定放在 bank0 的位址,也可以不填,由 keil 自動調配。
  6. 如果有多個 code constants,則使用逗號來分別,如 BANK0(?CO?TSUMU58EJ_CONF , ?CO?MODE_CONF, ?CO?MSTAR)。

要非常注意 code constants 移到 bank0 裏時,只能給 bank0 的函數使用,如果 bank1 函數要使用同樣的資料,會造成找到錯誤的資料而發生不可預期的問題。還有也要檢查 bank0 函數使用時,有無呼叫到 bank1 的函數,該函數是否把 code constants 當成參數傳到 bank1 函數去使用,如此也會產生大問題。