***************************************** pic單片機(jī)的模擬I2C通信 *****************************************;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; Copyright (C) 1997 by Innovatus; This code may be distributed and used freely provided that this; copyright notice stays intact and that any modifications are noted.; For more information about Innovatus: http://www.innovatus.com;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; File Name: i2c_low.asm; Author: Alan G. Smith; Purpose: This code is borrowed from Microchip with all of the fancy; stuff taken out.;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++InitI2CBusMaster;************************************************************TxmtStartBitbsf Bus_Busy ; on a start condition bus is busybsf STATUS, RP0 ; Select page 1bsf _SDA ; set SDA highbsf _SCL ; clock is highcall Delay40uSec ; This is necessary for setup timebcf _SDA ; This gives a falling edge on SDA while clock is highcall Delay47uSec ; Necessary for START HOLD timereturn;************************************************************TxmtStopBitbsf STATUS, RP0 ; Select page 1bcf _SCL ; clock is lowbcf _SDA ; set SDA lowbsf _SCL ; clock is pulled upcall Delay40uSec ; Setup time for STOP conditionbsf _SDA ; rising edge on SDA while CLOCK is highcall Delay47uSec ; makes sure a START isn't sent immediately after a STOPbcf Bus_Busy ; The bus isn't busy anymorereturn;************************************************************AbortI2Ccall TxmtStopBit ; Send a stop bitbsf Abort ; set the abort bitreturn;************************************************************TxmtSlaveAddrmovf SlaveAddr, w ; Move slave address to Wbcf ACK_Error ; reset Acknowledge error bitmovwf I2CData ; move W to I2C Databcf I2CData, LSB ; Set for writebtfsc Slave_RW ; If skip then write operationbsf I2CData, LSB ; Clear for readcall SendData ; send the addressbtfss Txmt_Success ; skip if successfulgoto AddrSendFail ; Oops, we failedretlw TRUE ; return trueAddrSendFailbtfss ACK_Error ; was there an error acknowledgingretlw FALSE ; No, so return 0call TxmtStopBit ; Address not acknowleged, so send STOP bitretlw FALSE ; Unsuccessful, so return 0;************************************************************SendData; We might should make a copy of the data here, the example does but I don't see why!!!bsf Txmt_Progress ; We are in the middle of transmittingbcf Txmt_Success ; reset success bitmovlw 0x08movwf I2CBitCount ; Set I2C Bit Count to 8bsf STATUS, RP0 ; Select page 1TxmtNextBit:bcf _SCL ; Set clock Lowrlf I2CData, F ; MSB First, Note that I2CData is Destroyedbcf _SDA ; Set clock based on what the MSB isbtfsc STATUS,C ; Was the MSB a 1bsf _SDA ; Nope set it highcall Delay47uSec ; guarantee min LOW TIME tLOW Setup timebsf _SCL ; set clock highcall Delay40uSec ; guarantee min HIGH TIME tHIGHdecfsz I2CBitCount, F ; are we done yetgoto TxmtNextBit ; nope, send the next bit;; Check For Acknowledge;bcf _SCL ; reset clockbsf _SDA ; Release SDA line for Slave to pull downcall Delay47uSec ; guarantee min LOW TIME tLOW Setup timebsf _SCL ; clock for slave to ACKcall Delay40uSec ; guarantee min HIGH TIME tHIGHbcf STATUS, RP0 ; Select PAGE 0 to test SDA pinbtfsc SdaPin ; SDA should be pulled low by slave if OKgoto TxmtErrorAck ; Uh oh, slave isn't behaving (or isn't there)bsf STATUS, RP0 ; Select PAGE 1bcf _SCL ; reset clockbcf Txmt_Progress ; reset progress bit in Bus Statusbsf Txmt_Success ; Transmission successfulbcf ACK_Error ; ACK OKreturnTxmtErrorAckbsf STATUS,RP0 ; select page 1bsf _SDA ; tristate SDAbsf _SCL ; tristate SCLbcf Txmt_Progress ; reset progress bit in Bus Statusbcf Txmt_Success ; Transmission NOT successfulbsf ACK_Error ; No ACK From Slavereturn;************************************************************GetDatabsf Rcv_Progress ; set Bus status for txmt progressbcf Rcv_Success ; reset status bitmovlw 0x08movwf I2CBitCountRcvNextBitbsf STATUS, RP0 ; page 1 for TRIS manipulationbcf _SCL ; lower clockbcf _SDA ; lower data linecall Delay47uSec ; guarantee min LOW TIME tLOW setup timebsf _SCL ; clock high, data sent by slavecall Delay40uSec ; guarantee min HIGH TIME tHIGHbcf STATUS, RP0 ; select page 0 to read Portsbcf STATUS, C ; 0 out Statusbtfsc SdaPin ; Check state of pinbsf STATUS, C ; Pin was high, set statusrlf I2CData, F ; left Shift data (MSB first)decfsz I2CBitCount, F ; Are we done yetgoto RcvNextBit ; Nope, go get the next one;; Generate ACK bit if not last byte to be read,; if last byte Gennerate NACK ; do not send ACK on last byte, main routine will send a STOP bit;bsf STATUS, RP0 ; Page 1 for TRIS manipulationbcf _SCL ; pull SCL lowbcf _SDA ; ACK by pulling SDA lowbtfsc Last_Byte_Rcv ; Is it the last byte to receivebsf _SDA ; If so, send NACK by setting SDA highcall Delay47uSec ; guarantee min LOW TIME tLOW Setup timebsf _SCL ; Raise Clock back upcall Delay40uSec ; guarantee min HIGH TIME tHIGHRcvEnd:bcf _SCL ; reset clockbcf Rcv_Progress ; reset bit in Bus Statusbsf Rcv_Success ; transmission successfulbcf ACK_Error ; ACK OKreturnDelay47uSec:movlw ((_47uS_Delay-5)/3 + 1) ; move delay into WDlyKmovwf DelayCount ; move what is in W to DelayCountdecfsz DelayCount, F ; Decrement DelayCountgoto $-1 ; Loop until 0return ; returnDelay40uSec:movlw ((_40uS_Delay-8)/3 + 1) ; move delay into Wgoto DlyK ; goto DlyK loop以下為測試程序(pic16f84);+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; Copyright (C) 1997 by Innovatus; All Rights Reserved.; This code may be distributed and used freely provided that this; copyright notice stays intact and that any modifications are noted.; For more information about Innovatus: http://www.innovatus.com;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++; File Name: testI2C.asm; Author: Alan G. Smith; Purpose: This is testing out the I2C code.;;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++LIST P=16f84, F=INHX8M, C=100, N=59#include "p16f84.inc"XTAL_FREQ equ 10000000 ; the crystal frequency we are usingClkOut equ XTAL_FREQ / 4 ; the number of cycles per second_40uS_Delay set (ClkOut/250000)_47uS_Delay set (ClkOut/212766)_50uS_Delay set (ClkOut/200000)#define SclPin PORTA, 0 ; Pin for SCL (I2C)#define SdaPin PORTA, 1 ; Pin for SDA (I2C)#define _SCL TRISA, 0 ; How do we toggle SCL#define _SDA TRISA, 1 ; How do we toggle SDA#define MSB 7#define LSB 0#define TRUE 1#define FALSE 0InitTrisA equ 0x07 ; The Initial state to TRIS port A.#define Bus_Busy BusStatus,0#define Abort BusStatus,1#define Txmt_Progress BusStatus,2#define Rcv_Progress BusStatus,3#define Txmt_Success BusStatus,4#define Rcv_Success BusStatus,5#define Fatal_Error BusStatus,6#define ACK_Error BusStatus,7#define Slave_RW BusControl,0#define Last_Byte_Rcv BusControl,1#define SlaveActive BusControl,2CBLOCK 0x0C ; I2C Ram neededBusStatus ; The I2C Status registerBusControl ; The I2C Control registerI2CBitCount ; Number of bits left to send (or receive)I2CData ; Data (note: This is DESTROYED when sending)SlaveAddr ; Slave AddressENDCCBLOCKDelayCount ; used to figure out precise time delaysENDCorg 0 ; Reset Vectorgoto start ; Goto Startstartbcf INTCON, GIE ; Turn off interrupts in this critical part of code!bcf STATUS, RP0 ; Select Page 0 of registersmovlw 0x0C ; Make sure there are 0's on SCL and SDAmovwf PORTA ; We write 1's to TX since 0 is a start bitbsf STATUS, RP0 ; Select Page 1 of registersmovlw InitTrisA ; Load W with the value for TRIS Amovwf TRISA ; movw the value from W into TRIS A;*************** DEBUG CODE (let us use LEDs) *******************clrf TRISB;****************************************************************clrf BusStatus ; Let's clear out busStatus before we startclrf BusControl ; Let's clear out busControl before we start;*************** TEST CODE *******************clrf PORTBmainmovlw 0xB0 ; address of EEPROMmovwf SlaveAddr ; move into SlaveAddress registercall IsSlaveActive ; Check and see if the slave is activemovlw 0xFF ; move FF into w (turn all LED's on)btfss SlaveActive ; If the slave is active, leave itmovlw 0xAA ; We didn't find it, turn off half.bcf STATUS, RP0 ; Select page 0 of registersmovwf PORTB ; move W to PortBdone ; Game over man!goto done ; endless loopIsSlaveActivebcf Slave_RW ; set for write operationcall TxmtStartBit ; Transmit Start Bitcall TxmtSlaveAddr ; Transmit Slave Addressbcf SlaveActive ; Assume not presentbtfss ACK_Error ; skip if NACK, device is not present or not respondingbsf SlaveActive ; ACK received, device present listeningcall TxmtStopBitreturn#include "i2c_low.asm"END
評論