>> Михаил Е. (24С256)
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено =L.A.= 22 июля 2004 г. 21:35

Такое пойдет?


#include
#include "delay.h"
#include "i2c.h"

/*
* I2C functions for HI-TECH PIC C - master mode only
*/

/*
* TIMING - see Philips Sem. 80C51-based 8-bit ucontrollers,
* or e.g. Philips PCF8574 data sheet
*/


/*
* Send stop condition
* - data low-high while clock high
*/

void
i2c_Stop(void)
{
/* don't assume SCL is high on entry */

SCL = 1;
SCL_DIR = I2C_OUTPUT;

SDA = 0; /* ensure the data is low first */
SDA_DIR = I2C_OUTPUT;

DelayUs(I2C_TM_DATA_SU);
SCL_DIR = I2C_INPUT; /* float clock high */
DelayUs(I2C_TM_STOP_SU);
SDA = 1; /* the low->high data transistion */
DelayUs(I2C_TM_BUS_FREE); /* bus free time before next start */

SDA_DIR = I2C_INPUT; /* float data high */

return;
}

/*
* Send (re)start condition
* - ensure data is high then issue a start condition
* - see also i2c_Start() macro
*/

void
i2c_Restart(void)
{
SCL = 0; /* ensure clock is low */
SCL_DIR = I2C_OUTPUT;

SDA = 1; /* ensure data is high */
DelayUs(I2C_TM_DATA_SU);

SCL_DIR = I2C_INPUT; /* clock pulse high */
DelayUs(I2C_TM_SCL_HIGH);

SDA = 0;
SDA_DIR = I2C_OUTPUT; /* the high->low transition */
DelayUs(I2C_TM_START_HD);

return;
}

/*
* Send a byte to the slave
* - returns true on error
*/

unsigned char
i2c_SendByte(unsigned char byte)
{
signed char i;

for(i=7; i>=0; i--)
{
SCL=0;
SCL_DIR = I2C_OUTPUT; /* drive clock low */
/* data hold time = 0, send data now */
SDA = ((byte>>i) & 0x01); /* bit to send */
SDA_DIR = I2C_OUTPUT;
DelayUs(I2C_TM_DATA_SU);
SCL_DIR = I2C_INPUT; /* float clock high */

if(i2c_WaitForSCL()) /* wait for clock release */
return TRUE; /* bus error */

DelayUs(I2C_TM_SCL_HIGH); /* clock high time */
}


return FALSE;
}

/*
* send an address and data direction to the slave
* - 7-bit address (lsb ignored)
* - direction (FALSE = write )
*/

unsigned char
i2c_SendAddress(unsigned char address, unsigned char rw)
{
return i2c_SendByte(address | (rw?1:0));
}

/*
* Check for an acknowledge
* - returns ack or ~ack, or ERROR if a bus error
*/

signed char
i2c_ReadAcknowledge(void)
{
unsigned char ack;

SCL = 0;
SCL_DIR = I2C_OUTPUT;
SDA=1;
SDA_DIR = I2C_INPUT; /* disable data line - listen for ack */

DelayUs(I2C_TM_SCL_TO_DATA); /* SCL low to data out valid */
SCL_DIR = I2C_INPUT; /* float clock high */
DelayUs(I2C_TM_DATA_SU);

ack = SDA; /* read the acknowledge */

/* wait for slave to release clock line after processing byte */
if(i2c_WaitForSCL())
return I2C_ERROR;

return ack;
}

/*
* Read a byte from the slave
* - returns the byte, or I2C_ERROR if a bus error
*/

int
i2c_ReadByte(void)
{
unsigned char i;
unsigned char byte = 0;

for(i=0; i<8; i++)
{
SCL = 0; /* drive clock low */
SCL_DIR = I2C_OUTPUT;
DelayUs(I2C_TM_SCL_LOW); /* min clock low period */
SDA=1;
SDA_DIR = I2C_INPUT; /* release data line */

SCL_DIR = I2C_INPUT; /* float clock high */
if(i2c_WaitForSCL())
return I2C_ERROR;

DelayUs(I2C_TM_SCL_HIGH);

byte = byte << 1; /* read the next bit */
byte |= SDA;
}

return (int)byte;
}

/*
* Send an (~)acknowledge to the slave
* - status of I2C_LAST implies this is the last byte to be sent
*/

void
i2c_SendAcknowledge(unsigned char status)
{
SCL=0;
SCL_DIR = I2C_OUTPUT;
if ( status & 0x01)
{
SDA=0;
}
else
{
SDA=1;
}
//SDA = (!status & 0x01); /* drive line low -> more to come */
SDA_DIR = I2C_OUTPUT;

DelayUs(I2C_TM_DATA_SU);

SCL_DIR = I2C_INPUT; /* float clock high */
DelayUs(I2C_TM_SCL_HIGH);

return;
}

/*
* Send a byte to the slave and acknowledges the transfer
* - returns I2C_ERROR, ack or ~ack
*/

signed char
i2c_PutByte(unsigned char data)
{
if(i2c_SendByte(data))
return I2C_ERROR;
return i2c_ReadAcknowledge(); /* returns ack, ~ack */
}

/*
* Get a byte from the slave and acknowledges the transfer
* - returns true on I2C_ERROR or byte
*/

int
i2c_GetByte(unsigned char more)
{
int byte;

if((byte = i2c_ReadByte()) == I2C_ERROR)
return I2C_ERROR;

i2c_SendAcknowledge(more);

return byte;
}

/*
* Send an array of bytes to the slave and acknowledges the transfer
* - returns number of bytes not successfully transmitted
*/

int
i2c_PutString(const unsigned char *str, unsigned char length)
{
signed char error;

while(length)
{
if((error = i2c_PutByte(*str)) == I2C_ERROR)
return -(int)length; /* bus error */
else
if(error)
return (int)length; /* non acknowledge */
str++;
length--;
}

return FALSE; /* everything OK */
}

/*
* Reads number bytes from the slave, stores them at str and acknowledges the transfer
* - returns number of bytes not successfully read in
*/

unsigned char
i2c_GetString(unsigned char *str, unsigned char number)
{
int byte;

while(number)
{
if((byte = i2c_GetByte(number-1)) == I2C_ERROR)
return number; /* bus error */
else
*str = (unsigned char)byte;
str++;
number--;
}

return FALSE; /* everything OK */
}

/*
* Opens communication with a device at address. mode
* indicates I2C_READ or I2C_WRITE.
* - returns TRUE if address is not acknowledged
*/

unsigned char
i2c_Open(unsigned char address, unsigned char mode)
{
i2c_Start();
i2c_SendAddress(address, mode);
if(i2c_ReadAcknowledge())
return TRUE;

return FALSE;
}

/*
* wait for the clock line to be released by slow slaves
* - returns TRUE if SCL was not released after the
* time out period.
* - returns FALSE if and when SCL released
*/

unsigned char
i2c_WaitForSCL(void)
{
/* SCL_DIR should be input here */

if(!SCL)
{
DelayUs(I2C_TM_SCL_TMO);
/* if the clock is still low -> bus error */
if(!SCL)
return TRUE;
}
return FALSE;
}
void
i2c_Free()
{
unsigned char ucI;
SCL_DIR=I2C_OUTPUT;
SDA=1;
SDA_DIR=I2C_INPUT;
for(ucI=0;ucI!=9;ucI++)
{
SCL=1;
DelayUs(5);
SCL=0;
DelayUs(5);
}
}

unsigned char i2c_read(unsigned char ucAdr)
{
unsigned char ucDat;

if (i2c_ReadFrom(ucAdr)==0)
{
ucDat=i2c_GetByte(I2C_MORE);
i2c_Stop();

}

return(ucDat);
}


//=================================================

#ifndef _I2C_H_
#define _I2C_H_

/*
* SDA (data) and SCL (clock) bits
*
* Special note!!!
*
* If the clock and data lines are in the same port, you will need
* to beware of the Read/Modify/Write issue in the PIC - since
* a bit set or clear on any one bit in a port will read and write
* back all other bits, any bits configured as input which
*/

#define SCL RB2 /* clock on port B bit 2 */
#define SCL_DIR TRISB2

#define SDA RB1 /* data on port B bit 1 */
#define SDA_DIR TRISB1

#define I2CTRIS TRISB
#define M_SDA_INP 0x02
#define M_SDA_OUT 0xFD
#define M_SCL_INP 0x04
#define M_SCL_OUT 0xFB

#define I2C_INPUT 1 /* data direction input */
#define I2C_OUTPUT 0 /* data direction output */

#define I2C_READ 0x01 /* read bit used with address */
#define I2C_WRITE 0x00 /* write bit used with address */

#define FALSE 0
#define TRUE !FALSE

#define I2C_ERROR (-1)
#define I2C_LAST FALSE /* SendAck: no more bytes to send */
#define I2C_MORE TRUE /* SendAck: more bytes to send */

#define i2c_Start() i2c_Restart()
#define i2c_WriteTo(address) i2c_Open((address), I2C_WRITE)
#define i2c_ReadFrom(address) i2c_Open((address), I2C_READ)

/*
* Timings for the i2c bus. Times are rounded up to the nearest
* micro second.
*/

#define I2C_TM_BUS_FREE 5
#define I2C_TM_START_SU 5
#define I2C_TM_START_HD 4
#define I2C_TM_SCL_LOW 5
#define I2C_TM_SCL_HIGH 4
#define I2C_TM_DATA_SU 1
#define I2C_TM_DATA_HD 0
#define I2C_TM_SCL_TO_DATA 4 /* SCL low to data valid */
#define I2C_TM_STOP_SU 4
#define I2C_TM_SCL_TMO 10 /* clock time out */

extern signed char i2c_ReadAcknowledge(void);
extern unsigned char i2c_SendAddress(unsigned char, unsigned char);
extern unsigned char i2c_SendByte(unsigned char);
extern int i2c_ReadByte(void);
extern void i2c_Restart(void);
extern void i2c_Stop(void);
extern void i2c_SendAcknowledge(unsigned char);
extern signed char i2c_PutByte(unsigned char);
extern int i2c_GetByte(unsigned char);
extern unsigned char i2c_Open(unsigned char, unsigned char);
extern unsigned char i2c_GetString(unsigned char *, unsigned char);
extern int i2c_PutString(const unsigned char *, unsigned char);
extern unsigned char i2c_WaitForSCL(void);
extern void i2c_Free();
#endif /* _I2C_H_ */




Составить ответ  |||  Конференция  |||  Архив

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru