2010年6月5日 星期六

C# -- String.Format ( format to hex )


int x = 10; // hex == 0xA
string s = ""
s = String.Format("{0:X2}",x);
MessageBox.show(s);
== result ==
1 ==> 01
A ==> 0A
B ==> 0B

=====
int x = 10;
string s = x.ToString("X2");
結果也是一樣... 0A

2010年5月12日 星期三

Union & Structure 應用

union {

struct {

unsigned b0: 1;

unsigned b1: 1;

unsigned b2: 1;

unsigned b3: 1;

unsigned b4: 1;

unsigned b5: 1;

unsigned b6: 1;

unsigned b7: 1;

} oneBit;

unsigned char allBits;

} myFlag;

這種定義方式就可以很容易的進行位元操作.

e.g 要設定某個bit 為1時只需要:

myFlag.oneBit.b3 = 1;

透過另一個等長度的 allBits 就可以將這個byte的資料做取出或是清除.

e.g myFlag.allBits = 0; //將整個byte的資料全數清除. 設定成金

當然,也可以一個一個來做 e.g.

myFlag.oneBit.b0 = 0;

myFlag.oneBit.b1 = 0;

myFlag.oneBit.b2 = 0;

myFlag.oneBit.b3 = 0;

myFlag.oneBit.b4 = 0;

myFlag.oneBit.b5 = 0;

myFlag.oneBit.b6 = 0;

myFlag.oneBit.b7 = 0;

我將這種用法用在計算DIP switch 目前的狀態. 感覺很好用...

2010年4月20日 星期二

25AA040A/25LC040A 4K SPI Bus Serial EEPROM





25AA040A/25LC040A 4K SPI Bus Serial EEPROM



25AA040A腳位圖











這裡比較特別的是, A8 是指要傳送的EEPROM位址的第 9個bit是存放在指令中的第 4個bit. 所以除非你要存取資料的EEPROM位置只在 0x00(0) ~ 0xFF(255)(0b000000000 ~ 0b011111111)的範圍內, 如果要存放的位置是0x80 (0b10000000) 時就得自行處理這address欄位中的第9個bit.





讀取順序(Read Sequence)
1. 先將CS腳位pull low.
2. 傳送8 bit 的Read指令
3. 傳送一個0x00的資料(主要是要將資料從buffer中推出來)
4. MCU端的SDI開始接收資料直到資料讀取完成
5. 最後將CS腳位pull high


寫入順序(Write Sequence)
1. 先將CS腳位pull low
2. 傳送WREN指令 (這裡是做Write Enable的命令發送)
3. 再將CS腳位pull high (如果這裡沒有先做將CS腳位pull high則接下來的寫入工作將都無法完成)
4. 接著再將CS腳位pull low
5. 傳送WRITE指令
6. 接著開始 “1個byte 1個byte將資料送到SDO上”
7. 完成所有資料寫入後再將CS腳位pull high



這裡需要注意的地方是:
1. 圖上所指的Lower Address Byte 中的A8 是指要傳送的EEPROM位址的第 9個bit是存放在指令中的第 4個bit. 所以除非你要存取資料的EEPROM位置只在 0x00(0) ~ 0xFF(255)(0b000000000 ~ 0b011111111)的範圍內, 如果要存放的位置是0x80 (0b10000000) 時就得自行處理這address欄位中的第9個bit.
簡單來說, 如果Lower Address Byte為256時,則要記得處理A8這個bit啦.
用最簡單的方法就是:
如果address >255時就設定A8這個位元.
2. 寫入(Write)資料時有分成兩種行為:
甲、 1個byte的資料寫入
乙、 1次寫一個page (一次寫一個page時要需注意page size)
{???}一個page有多大? 參考下圖就大概能明白… 裡頭寫著最大為16個bytes



讀取暫存器資料: EEPROM也有狀態暫存器(Status Register)
讀取暫存器資料順序: (RDSR)
1. 下達RDSR命令
2. 檢查:
a. WIP(Write In Progress)是否為 1 ? 如果WIP為1時則表示目前EEPROM正在進行寫入工作.


寫入保護(Write Protect)
一般而言,EEPROM都有一個WP的腳位,這主要是用來防止非期望的資料寫入.所以正常來說,比較嚴謹的做法應該要考慮到平常時設定EEPROM的狀態為Write Protect. 只有真正有需要要寫資料時才將WP腳位pull low.完成後再pull high. (當然啦,如果懶得做,好像也不會發生什麼事才是…)

2010年4月16日 星期五

位元操作 (Bitwise Operation)

電腦資料都是以二進位儲存,想當然程式語言的變數也都是以二進位儲存。在C/C++當中有幾個位元運算子:<< SHIFT LEFT、>> SHIFT RIGHT、& AND、| OR、^ XOR、~ NOT,可以對變數進行位元運算。
過去寫應用程式時一直都沒太多機會用到,一直到現在開始接觸MCU的程式才開始對位元操作(Bitwise Operation)有些了解. 接下來要介紹位元運算的一些用途,與用法

1.左移 <<

5 << 1 = 10 // 00101 的全部位元向左移動一位數變成 01010.
5 << 2 = 20 // 00101 的全部位元向左移動兩位數變成 10100.
[註]左移和 "乘法" 的概念很像吧.. 事實上應該就是乘法了

2.右移 >> SHIFT RIGHT

5 >> 1 = 2 // 00101 的全部位元向右移動一位數變成 00010。
5 >> 2 = 1 // 00101 的全部位元向右移動一位數變成 00001。
[註]右移和 "除法" 的概念很像吧.. 事實上應該就是除法了

3. 及 & AND
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

4. 或 | OR
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

5. 互斥 ^ XOR
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

6. 反向 ~ NOT
~ 0 = 1
~ 1 = 0

==== 上述的內容大部份都可以在書上找到 ====
那麼... 如果是下面的算式結果是如何?
x=5
x&=0x07 ( x = x & 0x07) --> 0x05
x|=0x07 ( x = x | 0x07) --> 0x07

如果再遇到一個... x&= ~0x03 ?
x&=~0x03 其實是 x &= (~0x03) 也等於 x = x & (~0x03)

以上述的列子來說..整個過程大致上是這樣的...
1. (~0x03) 會先做: 指的是將 0b00000011 (0x03) 的bit 0 與 bit 1 做反向
2. 所以結果會變成 0b11111100
3. 然後才又與前的 x &= 做運算

這種用法很常在寫MCU程式時用到.. 做為將某n個位元做ON或OFF的工作..
當然,有沒有好處? 就個人的理解上來看,省了很多變數的使用.. 用bitwise operation就可以達到bit的操作.

寫到這裡讓我想到... 在學校裡好像都不曾聽老師教過.. 這bitwise 到底是要用在哪兒.... :(
這應該又是一個"讀書少" 的例子吧...

http://www.csie.ntnu.edu.tw/~u91029/index.html
這裡可以看到一些很不錯的資料...

共用空間(Union) 與 結構子(Structure) 與MSB , LSB

== Union ==
我在學習 Microchip PIC 的程式設計時才開始接觸到, 坦白說,一開始不是很懂實際的應用好處.
經過"首席"的細心講解後,才晃然明白... (原來當年學校教的資料結構還可以用在這裡... 真是"自幼失學讀書少"

在這面的例子裡頭,可以這樣來用.

假設, 我有一個資料為 myResult = 0x40;
如果要拿到Hi byte 與 Lo Byte 時,可以直接用Union 很容易的就能取到要的資料.

((BYTE_ODR_T) myResult)->msb_u16.hi8; //這樣當myResult被轉型成BYTE_ODR_T 型別後,便可以直接取到要取的資料 (這裡是以LSB 的方式呈現)
((BYTE_ODR_T) myResult)->msb_u16.lo8;

typedef union
{
struct
{
unsigned char hi8;
unsigned char lo8;
}msb_u16;

struct
{
unsigned char lo8;
unsigned char hi8;
}lsb_u16;
}BYTE_ODR_T;

我發現透過這樣的方式進行資料的存取會變得很容易.
當然,因為我目前用的是Microchip PIC 的microcontroller 所以是以LSB方式.(Little Endian)
但相信很容易可以發現,如果遇到的環境是MSB方式時,則只需要更動Union裡頭Structure的順序便可完成.
以上述的例子來說,我己經將 msb與lsb的順序都己經定議在這個BYTE_ODR_T 的Union裡頭.
所以未來在使用時,只需要選擇所需要的格式即可.

LSB的資料的存放順序如下:

Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0

MSB的資料存放順序如下:
Bit0 Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7




資料的差異?
如果要放進去的資料為 0x74 那麼...
LSB的資料的存放順序如下:
Hi Byte Low Byte
Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0
0 1 1 1 0 1 0 0
7 4

MSB的資料的存放順序如下:
Low Byte Hi Byte
Bit0 Bit1 Bit2 Bit3 Bit4 Bit5 Bit6 Bit7
0 0 1 0 0 1 1 1
4 7