**************************************** * pic单片机的模拟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 ;************************************************************ TxmtStartBit bsf Bus_Busy ; on a start condition bus is busy bsf STATUS, RP0 ; Select page 1 bsf _SDA ; set SDA high bsf _SCL ; clock is high call Delay40uSec ; This is necessary for setup time bcf _SDA ; This gives a falling edge on SDA while clock is high call Delay47uSec ; Necessary for START HOLD time return ;************************************************************ TxmtStopBit bsf STATUS, RP0 ; Select page 1 bcf _SCL ; clock is low bcf _SDA ; set SDA low bsf _SCL ; clock is pulled up call Delay40uSec ; Setup time for STOP condition bsf _SDA ; rising edge on SDA while CLOCK is high call Delay47uSec ; makes sure a START isn't sent immediately after a STOP bcf Bus_Busy ; The bus isn't busy anymore return ;************************************************************ AbortI2C call TxmtStopBit ; Send a stop bit bsf Abort ; set the abort bit return ;************************************************************ TxmtSlaveAddr movf SlaveAddr, w ; Move slave address to W bcf ACK_Error ; reset Acknowledge error bit movwf I2CData ; move W to I2C Data bcf I2CData, LSB ; Set for write btfsc Slave_RW ; If skip then write operation bsf I2CData, LSB ; Clear for read call SendData ; send the address btfss Txmt_Success ; skip if successful goto AddrSendFail ; Oops, we failed retlw TRUE ; return true AddrSendFail btfss ACK_Error ; was there an error acknowledging retlw FALSE ; No, so return 0 call TxmtStopBit ; Address not acknowleged, so send STOP bit retlw 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 transmitting bcf Txmt_Success ; reset success bit movlw 0x08 movwf I2CBitCount ; Set I2C Bit Count to 8 bsf STATUS, RP0 ; Select page 1 TxmtNextBit: bcf _SCL ; Set clock Low rlf I2CData, F ; MSB First, Note that I2CData is Destroyed bcf _SDA ; Set clock based on what the MSB is btfsc STATUS,C ; Was the MSB a 1 bsf _SDA ; Nope set it high call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; set clock high call Delay40uSec ; guarantee min HIGH TIME tHIGH decfsz I2CBitCount, F ; are we done yet goto TxmtNextBit ; nope, send the next bit ; ; Check For Acknowledge ; bcf _SCL ; reset clock bsf _SDA ; Release SDA line for Slave to pull down call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; clock for slave to ACK call Delay40uSec ; guarantee min HIGH TIME tHIGH bcf STATUS, RP0 ; Select PAGE 0 to test SDA pin btfsc SdaPin ; SDA should be pulled low by slave if OK goto TxmtErrorAck ; Uh oh, slave isn't behaving (or isn't there) bsf STATUS, RP0 ; Select PAGE 1 bcf _SCL ; reset clock bcf Txmt_Progress ; reset progress bit in Bus Status bsf Txmt_Success ; Transmission successful bcf ACK_Error ; ACK OK return TxmtErrorAck bsf STATUS,RP0 ; select page 1 bsf _SDA ; tristate SDA bsf _SCL ; tristate SCL bcf Txmt_Progress ; reset progress bit in Bus Status bcf Txmt_Success ; Transmission NOT successful bsf ACK_Error ; No ACK From Slave return ;************************************************************ GetData bsf Rcv_Progress ; set Bus status for txmt progress bcf Rcv_Success ; reset status bit movlw 0x08 movwf I2CBitCount RcvNextBit bsf STATUS, RP0 ; page 1 for TRIS manipulation bcf _SCL ; lower clock bcf _SDA ; lower data line call Delay47uSec ; guarantee min LOW TIME tLOW & setup time bsf _SCL ; clock high, data sent by slave call Delay40uSec ; guarantee min HIGH TIME tHIGH bcf STATUS, RP0 ; select page 0 to read Ports bcf STATUS, C ; 0 out Status btfsc SdaPin ; Check state of pin bsf STATUS, C ; Pin was high, set status rlf I2CData, F ; left Shift data (MSB first) decfsz I2CBitCount, F ; Are we done yet goto 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 manipulation bcf _SCL ; pull SCL low bcf _SDA ; ACK by pulling SDA low btfsc Last_Byte_Rcv ; Is it the last byte to receive bsf _SDA ; If so, send NACK by setting SDA high call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; Raise Clock back up call Delay40uSec ; guarantee min HIGH TIME tHIGH RcvEnd: bcf _SCL ; reset clock bcf Rcv_Progress ; reset bit in Bus Status bsf Rcv_Success ; transmission successful bcf ACK_Error ; ACK OK return Delay47uSec: movlw ((_47uS_Delay-5)/3 + 1) ; move delay into W DlyK movwf DelayCount ; move what is in W to DelayCount decfsz DelayCount, F ; Decrement DelayCount goto $-1 ; Loop until 0 return ; return Delay40uSec: movlw ((_40uS_Delay-8)/3 + 1) ; move delay into W goto 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 using ClkOut 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 0 InitTrisA 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,2 CBLOCK 0x0C ; I2C Ram needed BusStatus ; The I2C Status register BusControl ; The I2C Control register I2CBitCount ; Number of bits left to send (or receive) I2CData ; Data (note: This is DESTROYED when sending) SlaveAddr ; Slave Address ENDC CBLOCK DelayCount ; used to figure out precise time delays ENDC org 0 ; Reset Vector goto start ; Goto Start start bcf INTCON, GIE ; Turn off interrupts in this critical part of code! bcf STATUS, RP0 ; Select Page 0 of registers movlw 0x0C ; Make sure there are 0's on SCL and SDA movwf PORTA ; We write 1's to TX since 0 is a start bit bsf STATUS, RP0 ; Select Page 1 of registers movlw InitTrisA ; Load W with the value for TRIS A movwf 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 start clrf BusControl ; Let's clear out busControl before we start ;*************** TEST CODE ******************* clrf PORTB main movlw 0xB0 ; address of EEPROM movwf SlaveAddr ; move into SlaveAddress register call IsSlaveActive ; Check and see if the slave is active movlw 0xFF ; move FF into w (turn all LED's on) btfss SlaveActive ; If the slave is active, leave it movlw 0xAA ; We didn't find it, turn off half. bcf STATUS, RP0 ; Select page 0 of registers movwf PORTB ; move W to PortB done ; Game over man! goto done ; endless loop IsSlaveActive bcf Slave_RW ; set for write operation call TxmtStartBit ; Transmit Start Bit call TxmtSlaveAddr ; Transmit Slave Address bcf SlaveActive ; Assume not present btfss ACK_Error ; skip if NACK, device is not present or not responding bsf SlaveActive ; ACK received, device present & listening call TxmtStopBit return #include "i2c_low.asm" END
小广播
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐
最新单片机文章
更多精选电路图
更多热门文章
更多每日新闻
更多往期活动
11月27日历史上的今天
厂商技术中心