?? smb_test0.c
字號:
// C8051F020 通過SMBus 與三個EEPROM 接口的示例代碼。
// 該程序假設三個具有16 位地址空間的EEPROM 連在SCL 和SDA 線上,
// 被配置為具有如下從地址:
// CHIP_A = 1010000
// CHIP_B = 1010001
// CHIP_C = 1010010
// 從狀態和競爭狀態沒有定義。假設C8051F020 為系統中唯一的主器件。
// 功能:SM_Send 執行向指定EEPROM 的單字節寫操作
// SM_Receive 執行從指定EEPROM 地址讀一個字節的操作(兩者都用到存儲器地址)
//
// 包含測試代碼部分。
//--------------------------------------------------------------------
// 包含文件
//--------------------------------------------------------------------
#include <c8051f020.h> // SFR 聲明
//--------------------------------------------------------------------
// 全局常量
//--------------------------------------------------------------------
#define WRITE 0x00 // SMBus 寫命令
#define READ 0x01 // SMBus 讀命令
// 器件地址(7 位,最低位沒使用)
#define CHIP_A 0xA0 // 芯片A 的器件地址
#define CHIP_B 0xA2 // 芯片B 的器件地址
#define CHIP_C 0xA4 // 芯片C 的器件地址
// SMBus 狀態
// MT = 主發送器
// MR = 主接收器
#define SMB_BUS_ERROR 0x00 // (對所有方式)總線錯誤
#define SMB_START 0x08 // (MT & MR)起始條件已發送
#define SMB_RP_START 0x10 // (MT & MR)重復起始條件
#define SMB_MTADDACK 0x18 // (MT) 從地址+ W 已發送;收到ACK
#define SMB_MTADDNACK 0x20 // (MT) 從地址+ W 已發送;收到NACK
#define SMB_MTDBACK 0x28 // (MT) 數據字節已發送;收到ACK
#define SMB_MTDBNACK 0x30 // (MT) 數據字節已發送;收到NACK
#define SMB_MTARBLOST 0x38 // (MT) 競爭失敗
#define SMB_MRADDACK 0x40 // (MR) 從地址+ R 已發送;收到ACK
#define SMB_MRADDNACK 0x48 // (MR) 從地址+ W 已發送;收到NACK
#define SMB_MRDBACK 0x50 // (MR) 收到數據字節;ACK 已發送
#define SMB_MRDBNACK 0x58 // (MR) 收到數據字節;NACK 已發送
//--------------------------------------------------------------------
//全局變量
//--------------------------------------------------------------------
char COMMAND; // 在SMBus 中斷服務程序中用于
// 保存從地址+ R/W 位。
char WORD; // 保持SMBus 要發送的數據字節
// 或剛收到的數據
char BYTE_NUMBER; // 在中用于檢查發送的是什么數據
// 高地址字節、低地址字節或數據字節
unsigned char HIGH_ADD, LOW_ADD; // EEPROM 存儲器地址的高、低字節
bit SM_BUSY; // 該位在發送或接收開始時被置1,
// 操作結束后由中斷服務程序清0
//--------------------------------------------------------------------
// 函數原型
//--------------------------------------------------------------------
void SMBus_ISR (void);
void SM_Send (char chip_select, unsigned int byte_address, char out_byte);
char SM_Receive (char chip_select, unsigned int byte_address);
//--------------------------------------------------------------------
// 主程序
//--------------------------------------------------------------------
//
// 主程序配置交叉開關和SMBus,并測試SMBus 與三個EEPROM 之間的接口
void main (void)
{
unsigned char check; // 用于測試目的
WDTCN = 0xde; // 禁止看門狗定時器
WDTCN = 0xad;
OSCICN |= 0x03; // 設置內部振蕩器為最高頻率(16 MHz)
XBR0 = 0x01; // 通過交叉開關將SMBus 連到通用I/O 引腳;P0.0,P0.1
XBR2 = 0x40; // 允許交叉開關和弱上拉
SMB0CN = 0x44; // 允許SMBus 在應答周期發送ACK
SMB0CR = -80; // SMBus 時鐘頻率= 100kHz.
EIE1 |= 2; // SMBus 中斷允許
EA = 1; // 全局中斷允許
SM_BUSY = 0; // 為第一次傳輸釋放SMBus。
// 測試代碼-------------------------------------------------------------
SM_Send(CHIP_A, 0x0088, 0x53); //發送0x53(數據)到CHIP_A 的地址0x88
SM_Send(CHIP_B, 0x0001, 0x66); //發送0x66(數據)到CHIP_B 的地址0x01
SM_Send(CHIP_C, 0x0010, 0x77);
SM_Send(CHIP_B, 0x0333, 0xF0);
SM_Send(CHIP_A, 0x0242, 0xF0);
check = SM_Receive(CHIP_A, 0x0088); // 讀CHIP_A 的地址0x88
check = SM_Receive(CHIP_B, 0x0001); // 讀CHIP_B 的地址0x01
check = SM_Receive(CHIP_C, 0x0010);
check = SM_Receive(CHIP_B, 0x0333);
check = SM_Receive(CHIP_A, 0x0242);
// 代碼結束----------------------------------------------------------
}
// SMBus 字節寫函數-----------------------------------------------------
// 向給定存儲器地址寫一個字節
// out_byte = 待寫數據
// byte_address = 待寫存儲器地址(2 字節)
// chip_select = 待寫EEPROM 芯片的器件地址
void SM_Send (char chip_select, unsigned int byte_address, char out_byte)
{
while (SM_BUSY); // 等待SMBus 空閑
SM_BUSY = 1; // 占用SMBus(設置為忙)
SMB0CN = 0x44; // SMBus 允許,應答周期發ACK
BYTE_NUMBER = 2; // 2 地址字節
COMMAND = (chip_select | WRITE); // 片選+ WRITE
HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8 位地址
LOW_ADD = (byte_address & 0x00FF); // 低8 位地址
WORD = out_byte; // 待寫數據
STA = 1; // 啟動傳輸過程
}
// SMBus 隨機讀函數-----------------------------------------------------
// 從給定存儲器地址讀一個字節
// byte_address = 要讀取的存儲器地址
// chip_select = 待讀EEPROM 的器件地址
char SM_Receive (char chip_select, unsigned int byte_address)
{
while (SM_BUSY); // 等待總線空閑
SM_BUSY = 1; //占用SMBus(設置為忙)
SMB0CN = 0x44; // 允許SMBus,應答周期發ACK
BYTE_NUMBER = 2; // 2 地址字節
COMMAND = (chip_select | READ); // 片選+ READ
HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8 位地址
LOW_ADD = (byte_address & 0x00FF); // 低8 位地址
STA = 1; // 啟動傳輸過程
while (SM_BUSY); // 等待傳輸結束
return WORD;
}
//--------------------------------------------------------------------
// 中斷服務程序
//--------------------------------------------------------------------
// SMBus 中斷服務程序
void SMBUS_ISR (void) interrupt 7
{
switch (SMB0STA){ // SMBus 狀態碼(SMB0STA 寄存器)
// 主發送器/接收器:起始條件已發送
// 在該狀態發送的COMMAND 字的R/W 位總是為0(W),
// 因為對于讀和寫操作來說都必須先寫存儲器地址。
case SMB_START:
SMB0DAT = (COMMAND & 0xFE); // 裝入要訪問的從器件的地址
STA = 0; // 手動清除START 位
break;
//主發送器/接收器:重復起始條件已發送。
// 該狀態只應在讀操作期間出現,在存儲器地址已發送并得到確認之后
case SMB_RP_START:
SMB0DAT = COMMAND; // COMMAND 中應保持從地址+ R.
STA = 0;
break;
// 主發送器:從地址+ WRITE 已發送,收到ACK。
case SMB_MTADDACK:
SMB0DAT = HIGH_ADD; // 裝入待寫存儲器地址的高字節
break;
// 主發送器:從地址+ WRITE 已發送,收到NACK。
// 從器件不應答,發送STOP + START 重試
case SMB_MTADDNACK:
STO = 1;
STA = 1;
break;
// 主發送器:數據字節已發送,收到ACK。
// 該狀態在寫和讀操作中都要用到。BYTE_NUMBER 看存儲器地址狀態– 如果
// 只發送了HIGH_ADD,則裝入LOW_ADD。如果LOW_ADD 已發送,檢查COMMAND
// 中的R/W 值以決定下一狀態。
case SMB_MTDBACK:
switch (BYTE_NUMBER){
case 2: // 如果BYTE_NUMBER=2,
SMB0DAT = LOW_ADD; // 只發送了HIGH_ADD。
BYTE_NUMBER--; // 減1,為下一輪作準備
break;
case 1: // 如果BYTE_NUMBER=1,LOW_ADD 已發送。
if (COMMAND & 0x01) // 如果R/W=READ,發送重復起始條件
STA = 1;
else{
SMB0DAT = WORD; // 如果R/W=WRITE,裝入待寫字節
BYTE_NUMBER--;}
break;
default: // 如果BYTE_NUMBER=0,傳輸結束
STO = 1;
SM_BUSY = 0; // 釋放SMBus
}
break;
// 主發送器:數據字節已發送,收到NACK。
// 從器件不應答,發送STOP + START 重試
case SMB_MTDBNACK:
STO = 1;
STA = 1;
break;
// 主發送器:競爭失敗
// 不應出現。如果出現,重新開始傳輸過程
case SMB_MTARBLOST:
STO = 1;
STA = 1;
break;
// 主接收器:從地址+ READ 已發送。收到ACK。
// 設置為在下一次傳輸后發送NACK,因為那將是最后一個字節(唯一)。
case SMB_MRADDACK:
AA = 0; // 在應答周期NACK。
break;
// 主接收器:從地址+ READ 已發送。收到NACK。
// 從器件不應答,發送重復起始條件重試
case SMB_MRADDNACK:
STA = 1;
break;
// 收到數據字節。ACK 已發送。
// 該狀態不應出現,因為AA 已在前一狀態被清0。如果出現,發送停止條件。
case SMB_MRDBACK:
STO = 1;
SM_BUSY = 0;
break;
// 收到數據字節。NACK 已發送。
// 讀操作已完成。讀數據寄存器后發送停止條件。
case SMB_MRDBNACK:
WORD = SMB0DAT;
STO = 1;
SM_BUSY = 0; // 釋放SMBus
break;
// 在本應用中,所有其它狀態碼沒有意義。通信復位。
default:
STO = 1; // 通信復位。
SM_BUSY = 0;
break;
}
SI=0; // 清除中斷標志
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -