#include "stdio.h"
void main(){
unsigned int *ptr; //定義一個名為 ptr 的指標變數,指向 unsigned int 型別
int i;
unsigned int buf[4] = { 0x123f, 0x3fa4, 0xfab6, 0xffff }; //定義一個陣列
ptr = buf; //使 ptr 指向 buf
// 取得 buf 第一個元素的地址
printf("The address of the first element of 'buf' = %p , (0x%x in ptr) \n", buf, ptr);
// 以指標(位址) 列印出 buf 陣列的各個元素
for ( i = 0; i < sizeof(buf)/sizeof(buf[0]); i++){
printf("0x%x\n", *(ptr + i) );
}
// 由上述結果我們得知,陣列 buf 的起始位址為 0x0028FF28
// 因 unsigned int 所佔的長度為 4 bytes, 故陣列中第二個元素的地址為
// 0x0028FF28 + 0x04 = 0x0028FF2C
// 嘗試將 ptr 指向 0x0028FF2C
ptr = 0x0028FF2C;
printf("ptr = 0x%x \n", ptr);
// 列印看看此時 ptr 所對應到的內容
printf("0x%x \n", *ptr);
// 嘗試以此地址修改該位址的數據
*ptr = 0x789A;
printf("Now, buf = \n");
// 以指標(位址) 列印出 buf 陣列的各個元素
for ( i = 0; i < sizeof(buf)/sizeof(buf[0]); i++){
printf("0x%x\n", *(buf+i) );
}
}
在 MCU 的應用領域,我們常對一個 "暫存器位址" 進行値的讀取或是修改
其作法可為以下(對一個 32 bits ( int* )的暫存器進行値的修改,其位址為 0x0028ff2c
#include "stdio.h"
void main(){
// 宣告一個指標變數 ptr ,指向 unsigned int 型別
// 因 unsigned int 為 32 bits,故此定義適用於 32 bits 的暫存器
// 若要操作的是 8 位元 MCU ,則此處應改成 unsigned char
unsigned int *ptr;
ptr = (unsigned int*)0x0028ff2c; //指向地址 0x0028ff2c
*ptr = 265462; // 修改位於 0x0028ff2c 的暫存器的值
int value = *ptr; //讀取位於 0x0028ff2c 的暫存器的值
printf("The value in address 0x%x = %d", ptr, value);
}
對 8bits 的暫存器進行修改
以下為很經典的寫法,搭配了 Base address 對各個暫存器讀寫
以下為很經典的寫法,搭配了 Base address 對各個暫存器讀寫
#include "stdio.h"
#define getValue(base,offset) (*(volatile unsigned char *)(base + offset))
#define DDRB getValue(BasePtr, 6)
int main(){
unsigned char BASE[] = { 0x00, 0x01, 0x02, 0x03, 0x1A, 0x56, 0x77, 0xff };
unsigned char* const BasePtr = BASE;
printf("BASE address = %p\n", BasePtr);
printf("DDRB = BASE address offset 6 = 0x%x\n\n", DDRB );
// DDRB = (*(volatile unsigned char *)(BasePtr + 6));
DDRB = 0x99; // 修改 DDRB 的值
printf("DDRB = BASE address offset 6 = 0x%x\n\n", DDRB );
DDRB = DDRB & 0x01; // 修改 DDRB 的值
printf("DDRB = BASE address offset 6 = 0x%x", DDRB );
return 0;
}
針對關鍵語句說明
#define getValue(base,offset) (*(volatile unsigned char *)(base + offset))
#define DDRB getValue(BasePtr, 6)
第一個語句意謂著我們定義一個函數 getValue 其具有兩個輸入參數,分別為 Base address 與要 offset 的大小
後續的部分需要拆為兩個部份來看,首先
(volatile unsigned char *)(base + offset)
意謂著將 (base + offset) 數據強制轉型為 (unsigned char *) 指標,表明 (base + offset) 是一個位址而不是普通的數值,volatile 會在此出現的原因請參考此連結 與 此連結
接著我們就可以用 "*(取值運算子)" 來對該位址進行取值了
第二個語句我們定義 DDRB 為 getValue(BasePtr, 6) ,簡而言之就是呼叫了第一個語句
當然,我們可以不要搞得這麼複雜
假設 DDRB 的位址為 0x0028FF3A,我們可以直接這樣進行定義
#define DDRB (*(volatile unsigned char *)(0x0028FF3A))
但擴充性較為不足,或許更常出現的是如以下的定義
#define BASE 0x0028FF34
#define PORTA (*(volatile unsigned char *)(BASE + 0x01))
#define PORTB (*(volatile unsigned char *)(BASE + 0x02))
#define PORTC (*(volatile unsigned char *)(BASE + 0x03))
#define PORTD (*(volatile unsigned char *)(BASE + 0x04))
#define DDRA (*(volatile unsigned char *)(BASE + 0x05))
#define DDRB (*(volatile unsigned char *)(BASE + 0x06))
#define DDRC (*(volatile unsigned char *)(BASE + 0x07))
指標定義最終整理