[elektro] szoftver I2C C-ben
Moczik Gabor
pm_levlista at progzmaster.hu
Fri Aug 21 15:40:29 CEST 2009
Huszti Andras wrote:
> Hali!
>
> Master vagy slave kell?
Nekem van master és slave is, de nem mondhatnám hogy egy szép és jól
átgondolt megoldás, éppencsak működik.
Most nem tudom felrakni, beillesztem ide, kb. 10k az egész, remélem nem
lesz sok anyázás miatta.
i2c.h
---------------------
#ifndef __I2C_H__
#define __I2C_H__
#include <pic18.h>
// I2C operation modes
#define I2C_MASTER 0x01
#define I2C_SLAVE 0x02
#define I2C_MULTIMASTER 0x03
// I2C interrupt level modes
#define I2C_LOW_PRIORITY 0x00
#define I2C_HIGH_PRIORITY 0x01
// R/W bit value
#define I2C_READ 0x01
#define I2C_WRITE 0x00
// I2C system state
#define I2CS_IDLE 0x00
#define I2CS_MASTER_TX 0x01
#define I2CS_START 0x02
#define I2CS_WAITING_DATA 0x03
#define I2CS_DATA_RECEIVED 0x04
#define I2CS_DATA_REQUEST 0x05
#define I2CS_NACK 0x06
#define I2CS_COLLISION 0x07
extern unsigned char i2c_state;
extern unsigned char i2c_databuf;
void i2c_init(unsigned char mode, unsigned char isr_priority, unsigned
char address);
void i2c_set_master_brg(unsigned char brg);
// I2C results
#define I2CR_ACK 0x00 /* acknowledge */
#define I2CR_NAK 0x01 /* no ack */
#define I2CR_COLL 0x02 /* bus collision */
unsigned char i2c_start(unsigned char addr_rw);
unsigned char i2c_restart(unsigned char addr_rw);
unsigned char i2c_sendbyte(unsigned char addr, unsigned char data);
// ON SUCCESS: returns 1 and result placed in i2c_databuf
unsigned char i2c_readbyte(unsigned char addr, unsigned char data);
// this must be called from ISR after checking SSPIF & BCLIF bits
void i2c_isr();
// I2C data request must be fulfilled with this macro (slave transmitter
function)
#define i2c_slave_tx(data) { SSPBUF=data; CKP=1; SSPIF=0; }
//#define i2c_slave_rx() SSPBUF
#define i2c_slave_rx() i2c_databuf
#define i2c_release_bus() { CKP=1; SSPIF=0; }
#endif
-----------------------
i2c.c
-----------------------
#include "i2c.h"
#define I2C_NOT_IDLE ((SSPCON2&0x1F)|(SSPSTAT&0x04))
// I2C settings
unsigned char i2c_mode;
unsigned char i2c_address;
unsigned char i2c_brg;
// I2C status
unsigned char i2c_state;
bit i2c_transmit; /* value of R/W bit after the S condition
0=write 1=read */
unsigned char i2c_databuf;
void i2c_init(unsigned char mode, unsigned char isr_priority, unsigned
char address)
{
i2c_mode=mode;
i2c_address=address;
SSPSTAT=0b10000000;
SSPIF=0;
BCLIF=0;
// set interrupt priority
SSPIP=(isr_priority==I2C_HIGH_PRIORITY ? 1 : 0);
BCLIP=SSPIP;
switch(i2c_mode) {
case I2C_SLAVE :// I2C slave mode without start/stop
interrupts
SSPCON1=0b00110110;
// enable clock stretching
SSPCON2=0b00000001;
SSPADD=i2c_address; // address
SSPIE=1;
break;
case I2C_MASTER :// master mode
SSPCON1=0b00111000;
SSPCON2=0b00000000;
break;
case I2C_MULTIMASTER :// I2C slave mode with start/stop interrupts
SSPCON1=0b00111110;
// enable clock stretching
SSPCON2=0b00000001;
SSPADD=i2c_address;
BCLIE=1;
SSPIE=1;
break;
}
i2c_state=I2CS_IDLE;
//SSPIE=1;
}
void i2c_set_master_brg(unsigned char brg)
{
// FIXME! - if transmission in progress?
i2c_brg=brg;
SSPADD=brg;
}
void i2c_isr()
{
// check status (excluding SMP and CKE bit)
switch(SSPSTAT & 0b00111111) {
case 0b00001000 :// START condition
i2c_state=I2CS_START;
SSPIF=0;
break;
case 0b00001001 :// address match AND write
// read SSPBUF to clear BF (value doesn't
matter, it's our address)
SSPBUF;
// master want to write (receive operation)
// the only action needed is clear
interrupt flag and wait for the data
i2c_state=I2CS_WAITING_DATA;
SSPIF=0;
CKP=1;
break;
case 0b00001100 :// address match AND read
// master want to read (transmit operation)
i2c_state=I2CS_DATA_REQUEST;
// after this isr routine exits with this
state
// the user must use the i2c_slave_tx() to
fulfill the request.
// SSPIF will be cleared only in the
i2c_slave_tx() macro
break;
case 0b00101001 :// data received AND write
i2c_state=I2CS_DATA_RECEIVED;
// after this, the user must read the
data, and release the bus with
// i2c_release_bus() macro, otherwise the
I2C bus will locked
i2c_databuf=SSPBUF;
SSPIF=0;
break;
case 0b00101000 :// this indicates that the master sent
NACK response to the slave transmitter
// which must be interpreted as the master
doesn't wish to read further data
i2c_state=I2CS_NACK;
SSPIF=0;
break;
default :// probably STOP condition (which can
occur in any situation)
i2c_state=I2CS_IDLE;
SSPIF=0;
}
}
unsigned char i2c_start(unsigned char addr_rw)
{
while(I2C_NOT_IDLE && !BCLIF);
if (!BCLIF) {
// initiate start condition
SEN=1;
while(SEN && !BCLIF);
if (!BCLIF) {
SSPBUF=addr_rw;
SSPIF=0;
while(!SSPIF && !BCLIF);
if (!BCLIF) {
return ACKSTAT;
}
}
}
if (BCLIF) {
BCLIF=0;
return I2CR_COLL;
}
}
unsigned char i2c_restart(unsigned char addr_rw)
{
while(I2C_NOT_IDLE && !BCLIF);
if (!BCLIF) {
// initiate start condition
RSEN=1;
while(RSEN && !BCLIF);
if (!BCLIF) {
SSPBUF=addr_rw;
SSPIF=0;
while(!SSPIF && !BCLIF);
if (!BCLIF) {
return ACKSTAT;
}
}
}
if (BCLIF) {
BCLIF=0;
return I2CR_COLL;
}
}
void i2c_stop()
{
PEN=1;
while(!SSPIF && !BCLIF);
SSPIF=0;
if (BCLIF) {
BCLIF=0;
}
}
unsigned char i2c_write(unsigned char data)
{
SSPBUF=data;
SSPIF=0;
while(!SSPIF && !BCLIF);
if (BCLIF) {
BCLIF=0;
return I2CR_COLL;
} else return ACKSTAT;
}
unsigned char i2c_read(unsigned char nack)
{
SSPIF=0;
RCEN=1;
while(!SSPIF && !BCLIF);
if (!BCLIF) {
i2c_databuf=SSPBUF;
SSPIF=0;
ACKDT=nack;
ACKEN=1;
while(!SSPIF && !BCLIF);
if (!BCLIF) {
SSPIF=0;
return I2CR_ACK;
}
};
if (BCLIF) {
BCLIF=0;
return I2CR_COLL;
}
}
unsigned char i2c_sendbyte(unsigned char addr, unsigned char data)
{
unsigned char result;
if ((result=i2c_start(addr|I2C_WRITE))==I2CR_ACK) {
result=i2c_write(data);
}
SSPIF=0;
if (result!=I2CR_COLL) i2c_stop();
return result;
}
unsigned char i2c_readbyte(unsigned char addr, unsigned char data)
{
unsigned char result;
if ((result=i2c_start(addr|I2C_WRITE))==I2CR_ACK) {
if ((result=i2c_write(data))==I2CR_ACK) {
if ((result=i2c_restart(addr|I2C_READ))==I2CR_ACK) {
result=i2c_read(1);
SSPIF=0;
}
}
}
if (result!=I2CR_COLL) i2c_stop();
return result;
}
---------------------
More information about the Elektro
mailing list