?? i2c.inc
字號:
;*************************************************************************
; I2C.INC
; 標準80C51單片機模擬I2C總線的主機程序頭文件
; Copyright (c) 2006,廣州周立功單片機發展有限公司
; All rights reserved.
; 本程序僅供學習參考,不提供任何可靠性方面的擔保;請勿用于商業目的
;*************************************************************************
;*************************************************************************
;模擬I2C總線的引腳定義
;*************************************************************************
I2C_SCL BIT P3.4
I2C_SDA BIT P3.5
;*************************************************************************
;定義I2C總線時鐘的延時值,要根據實際情況修改,取值1~255
;SCL信號周期約為(I2C_DELAY_VALUE*4+12)個機器周期
;*************************************************************************
I2C_DELAY_VALUE EQU 5
;*************************************************************************
;定義I2C總線停止后在下一次開始之前的等待時間,取值1~65535
;等待時間約為(I2C_STOP_WAIT_VALUE*8)個機器周期
;對于多數器件取值為1即可;但對于某些器件來說,較長的延時是必須的
;*************************************************************************
I2C_STOP_WAIT_VALUE EQU 1
;*************************************************************************
;定義延時變量,用于宏I2C_Delay()
;*************************************************************************
;unsigned char data I2C_Delay_t;
I2C_Delay_t DATA GLOBAL_IRAM ;在主文件里要用SET定義GLOBAL_IRAM的初值
GLOBAL_IRAM SET GLOBAL_IRAM+1
;*************************************************************************
;宏定義:I2C_Delay
;功能:延時,模擬I2C總線專用
;*************************************************************************
I2C_Delay MACRO
MOV I2C_Delay_t, #I2C_DELAY_VALUE
DJNZ I2C_Delay_t, $
ENDM
;*************************************************************************
;函數:I2C_Init()
;功能:I2C總線初始化,使總線處于空閑狀態
;說明:在main()函數的開始處,通常應當要執行一次本函數
;*************************************************************************
;void I2C_Init()
I2C_Init:
;{
; I2C_SCL = 1;
; I2C_Delay();
; I2C_SDA = 1;
; I2C_Delay();
SETB I2C_SCL
I2C_Delay
SETB I2C_SDA
I2C_Delay
;}
RET
;*************************************************************************
;函數:I2C_Start()
;功能:產生I2C總線的起始狀態
;說明:
; SCL處于高電平期間,當SDA出現下降沿時啟動I2C總線
; 不論SDA和SCL處于什么電平狀態,本函數總能正確產生起始狀態
; 本函數也可以用來產生重復起始狀態
; 本函數執行后,I2C總線處于忙狀態
;*************************************************************************
;void I2C_Start()
;{
I2C_Start:
; I2C_SDA = 1;
; I2C_Delay();
; I2C_SCL = 1;
; I2C_Delay();
; I2C_SDA = 0;
; I2C_Delay();
; I2C_SCL = 0;
; I2C_Delay();
SETB I2C_SDA
I2C_Delay
SETB I2C_SCL
I2C_Delay
CLR I2C_SDA
I2C_Delay
CLR I2C_SCL
I2C_Delay
;}
RET
;*************************************************************************
;函數:I2C_Write()
;功能:向I2C總線寫1個字節的數據
;參數:
; dat:要寫到總線上的數據
;*************************************************************************
;void I2C_Write(unsigned char dat)
;dat = R7
I2C_Write:
;{
; unsigned char t = 8;
; 分配:t = R1
MOV R1, #8
MOV A, R7
; do
I2C_Write_do:
; {
; I2C_SDA = (bit)(dat & 0x80);
; dat <<= 1;
MOV C, ACC.7
MOV I2C_SDA, C
ADD A, ACC
; I2C_SCL = 1;
; I2C_Delay();
; I2C_SCL = 0;
; I2C_Delay();
SETB I2C_SCL
I2C_Delay
CLR I2C_SCL
I2C_Delay
; } while ( --t != 0 );
DJNZ R1, I2C_Write_do
;}
RET
;*************************************************************************
;函數:I2C_Read()
;功能:從從機讀取1個字節的數據
;返回:讀取的一個字節數據
;*************************************************************************
;unsigned char I2C_Read()
;返回值 = ACC
I2C_Read:
;{
; unsigned char dat;
; unsigned char t = 8;
; 分配:dat = ACC
; 分配:t = R1
MOV R1, #8
; I2C_SDA = 1; //在讀取數據之前,要把SDA拉高
SETB I2C_SDA
; do
I2C_Read_do:
; {
; I2C_SCL = 1;
; I2C_Delay();
; dat <<= 1;
; if ( I2C_SDA ) dat |= 0x01;
SETB I2C_SCL
I2C_Delay
ADD A, ACC
JNB I2C_SDA, I2C_Read_endif
INC A
I2C_Read_endif:
; I2C_SCL = 0;
; I2C_Delay();
CLR I2C_SCL
I2C_Delay
; } while ( --t != 0 );
DJNZ R1, I2C_Read_do
; return dat;
;}
RET
;*************************************************************************
;函數:I2C_GetAck()
;功能:讀取從機應答位
;返回:
; 0:從機應答
; 1:從機非應答
;說明:
; 從機在收到每個字節的數據后,要產生應答位
; 從機在收到最后1個字節的數據后,一般要產生非應答位
;*************************************************************************
;bit I2C_GetAck()
;返回值 = CY
I2C_GetAck:
;{
; bit ack;
; 分配:ack = CY
; I2C_SDA = 1;
; I2C_Delay();
; I2C_SCL = 1;
; I2C_Delay();
; ack = I2C_SDA;
; I2C_SCL = 0;
; I2C_Delay();
SETB I2C_SDA
I2C_Delay
SETB I2C_SCL
I2C_Delay
MOV C, I2C_SDA
CLR I2C_SCL
I2C_Delay
; return ack;
;}
RET
;*************************************************************************
;函數:I2C_PutAck()
;功能:主機產生應答位或非應答位
;參數:
; ack=0:主機產生應答位
; ack=1:主機產生非應答位
;說明:
; 主機在接收完每一個字節的數據后,都應當產生應答位
; 主機在接收完最后一個字節的數據后,應當產生非應答位
;*************************************************************************
;void I2C_PutAck(bit ack)
;ack = 0x20.0
I2C_PutAck:
;{
; I2C_SDA = ack;
; I2C_Delay();
; I2C_SCL = 1;
; I2C_Delay();
; I2C_SCL = 0;
; I2C_Delay();
MOV C, 0x20.0
MOV I2C_SDA, C
I2C_Delay
SETB I2C_SCL
I2C_Delay
CLR I2C_SCL
I2C_Delay
;}
RET
;*************************************************************************
;函數:I2C_Stop()
;功能:產生I2C總線的停止狀態
;說明:
; SCL處于高電平期間,當SDA出現上升沿時停止I2C總線
; 不論SDA和SCL處于什么電平狀態,本函數總能正確產生停止狀態
; 本函數執行后,I2C總線處于空閑狀態
;*************************************************************************
;void I2C_Stop()
I2C_Stop:
;{
; unsigned int t;
; 分配:t = (R0,R1)
; I2C_SDA = 0;
; I2C_Delay();
; I2C_SCL = 1;
; I2C_Delay();
; I2C_SDA = 1;
; I2C_Delay();
CLR I2C_SDA
I2C_Delay
SETB I2C_SCL
I2C_Delay
SETB I2C_SDA
I2C_Delay
; t = I2C_STOP_WAIT_VALUE;
MOV R0, #HIGH(I2C_STOP_WAIT_VALUE)
MOV R1, #LOW(I2C_STOP_WAIT_VALUE)
; while ( --t != 0 ); //在下一次產生Start之前,要加一定的延時
I2C_Stop_while:
DJNZ_W R0,R1, I2C_Stop_while ;宏DJNZ_W的定義見Branch.INC
;}
RET
;*************************************************************************
;函數:I2C_Puts()
;功能:主機通過I2C總線向從機發送多個字節的數據
;參數:
; SlaveAddr:從機地址(高7位是從機地址,最低位是寫標志0)
; SubAddr:從機的子地址
; Size:數據的字節數
; *dat:要發送的數據
;返回:
; 0:發送成功
; 1:在發送過程中出現異常
;*************************************************************************
;bit I2C_Puts(unsigned char SlaveAddr, unsigned char SubAddr, unsigned char Size, char *dat)
;SlaveAddr = R7
;SubAddr = R6
;Size = R5
;*dat = (0x08,0x09,0x0A)
I2C_Puts:
;{
;//檢查長度
; if ( Size == 0 ) return 0;
CJNE R5, #0, I2C_Puts_endif1
CLR C
RET
I2C_Puts_endif1:
;//確保從機地址最低位是0
; SlaveAddr &= 0xFE;
ANL 0x07, #0xFE
;//啟動I2C總線
; I2C_Start();
LCALL I2C_Start
;//發送從機地址
; I2C_Write(SlaveAddr);
LCALL I2C_Write
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Puts_endif2
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Puts_endif2:
;//發送子地址
; I2C_Write(SubAddr);
MOV A, R6
MOV R7, A
LCALL I2C_Write
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Puts_endif3
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Puts_endif3:
;//發送數據
; do
I2C_Puts_do:
; {
; I2C_Write(*dat++);
MOV R1, 0x08
MOV DPH, 0x09
MOV DPL, 0x0A
LCALL BytePtrLD ;函數BytePtrLD()的定義見Pointer.INC
MOV R7, A
LCALL I2C_Write
INC_W 0x09,0x0A ;宏INC_W的定義見Calc.INC
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Puts_endif4
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Puts_endif4:
; } while ( --Size != 0 );
DJNZ R5, I2C_Puts_do
;//發送完畢,停止I2C總線,并返回結果
; I2C_Stop();
LCALL I2C_Stop
; return 0;
CLR C
;}
RET
;*************************************************************************
;函數:I2C_Put()
;功能:主機通過I2C總線向從機發送1個字節的數據
;參數:
; SlaveAddr:從機地址(高7位是從機地址,最低位是寫標志0)
; SubAddr:從機的子地址
; dat:要發送的數據
;返回:
; 0:發送成功
; 1:在發送過程中出現異常
;*************************************************************************
;bit I2C_Put(unsigned char SlaveAddr, unsigned char SubAddr, char dat)
;SlaveAddr = R7
;SubAddr = R6
;dat = R5
I2C_Put:
;{
PUSH 0x08
PUSH 0x09
PUSH 0x0A
; return I2C_Puts(SlaveAddr,SubAddr,1,&dat);
MOV 0x08, #PtrTypeIDATA ;PtrTypeIDATA的定義見Pointer.INC
MOV 0x09, #0
PUSH 0x05
MOV 0x0A, SP
MOV R5, #1
LCALL I2C_Puts
DEC SP
POP 0x0A
POP 0x09
POP 0x08
;}
RET
;*************************************************************************
;函數:I2C_Gets()
;功能:主機通過I2C總線從從機接收多個字節的數據
;參數:
; SlaveAddr:從機地址(高7位是從機地址,最低位是讀標志1)
; SubAddr:從機的子地址
; Size:數據的字節數
; *dat:保存接收到的數據
;返回:
; 0:接收成功
; 1:在接收過程中出現異常
;*************************************************************************
;bit I2C_Gets(unsigned char SlaveAddr, unsigned char SubAddr, unsigned char Size, char *dat)
;SlaveAddr = R7
;SubAddr = R6
;Size = R5
;*dat = (0x08,0x09,0x0A)
I2C_Gets:
;{
;//檢查長度
; if ( Size == 0 ) return 0;
CJNE R5, #0, I2C_Gets_endif1
;注:CJNE執行后,CY會自動清0
RET
I2C_Gets_endif1:
;//確保從機地址最低位是0
; SlaveAddr &= 0xFE;
ANL 0x07, #0xFE
;//啟動I2C總線
; I2C_Start();
LCALL I2C_Start
;//發送從機地址
; I2C_Write(SlaveAddr);
LCALL I2C_Write
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Gets_endif2
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Gets_endif2:
;//發送子地址
; I2C_Write(SubAddr);
PUSH 0x07
MOV A, R6
MOV R7, A
LCALL I2C_Write
POP 0x07
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Gets_endif3
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Gets_endif3:
;//發送重復起始條件
; I2C_Start();
LCALL I2C_Start
;//發送從機地址
; SlaveAddr |= 0x01;
INC R7
; I2C_Write(SlaveAddr);
LCALL I2C_Write
; if ( I2C_GetAck() )
LCALL I2C_GetAck
JNC I2C_Gets_endif4
; {
; I2C_Stop();
LCALL I2C_Stop
; return 1;
SETB C
RET
; }
I2C_Gets_endif4:
;//接收數據
; for (;;)
I2C_Gets_for:
; {
; *dat++ = I2C_Read();
LCALL I2C_Read
MOV R1, 0x08
MOV DPH, 0x09
MOV DPL, 0x0A
LCALL BytePtrST ;函數BytePtrST()的定義見Pointer.INC
INC_W 0x09,0x0A ;宏INC_W的定義見Calc.INC
; if ( --Size == 0 )
DJNZ R5, I2C_Gets_endif5
; {
; I2C_PutAck(1);
PUSH 0x20
SETB 0x20.0
LCALL I2C_PutAck
POP 0x20
; break;
SJMP I2C_Gets_endfor
; }
I2C_Gets_endif5:
; I2C_PutAck(0);
PUSH 0x20
CLR 0x20.0
LCALL I2C_PutAck
POP 0x20
; }
SJMP I2C_Gets_for
I2C_Gets_endfor:
;//接收完畢,停止I2C總線,并返回結果
; I2C_Stop();
LCALL I2C_Stop
; return 0;
CLR C
;}
RET
;*************************************************************************
;函數:I2C_Get()
;功能:主機通過I2C總線從從機接收1個字節的數據
;參數:
; SlaveAddr:從機地址(高7位是從機地址,最低位是讀標志1)
; SubAddr:從機的子地址
; *dat:保存接收到的數據
;返回:
; 0:接收成功
; 1:在接收過程中出現異常
;*************************************************************************
;bit I2C_Get(unsigned char SlaveAddr, unsigned char SubAddr, char *dat)
;SlaveAddr = R7
;SubAddr = R6
;*dat = (0x08,0x09,0x0A)
I2C_Get:
;{
PUSH 0x05
; return I2C_Gets(SlaveAddr,SubAddr,1,dat);
MOV R5, #1
LCALL I2C_Gets
POP 0x05
;}
RET
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -