20151121
以下附上的是模拟IIC通信模块程序,是我在TI官网提供的投影仪评估板例程中拿出来的,本人还没有验证,暂且认为他可以工作,估计下个星期就会去验证他,到时候再修改。
其实贴出这个程序的主要目的是,我刚开始不理解他对于SCL、SDA的高低电平的操作方法,下一篇文章我将解释。
i2c_master.h
#ifndef __i2c_master
#define __i2c_master
#ifdef __cplusplus
extern "C" {
#endif
// defines
#define I2C_NO_ACK 0
// functions
void I2C_Master_Start(void);
void I2C_Master_Stop(void);
uint08 I2C_MasterTransmitByte(uint08 data);
uint08 I2C_MasterReceiveByte(void);
uint08 I2C_PolledMasterWrite(uint08 device_addr, uint08* write_data, uint08 num_bytes);
uint08 I2C_PolledMasterRead(uint08 device_addr, uint08* read_data, uint08 num_bytes);
//uint08 I2C_Write_DPP(uint08 subaddr, uint32 data);
//uint08 I2C_Read_DPP(uint08 subaddr, uint32* data);
void I2C_Master_Init (void);
void I2C_SetSDA_High (void);
void I2C_SetSDA_Low (void);
BOOL I2C_GetSDA_Input (void);
void I2C_SetSCL_High (void);
void I2C_SetSCL_Low (void);
BOOL I2C_GetSCL_Input (void);
#ifdef __cplusplus /* matches __cplusplus construct above */
}
#endif
#endif // #ifndef __i2c_master
i2c_master.c
#include "common.h"
#include "i2c_master.h"
#include "msp430x22x4.h" //org ==> //#include "msp430f2132.h"
#include "ddp343xEVM_pins.h"
#define SDA_HI I2C_SetSDA_High()
#define SDA_LO I2C_SetSDA_Low()
#define SDA_IN I2C_GetSDA_Input()
#define SCL_HI I2C_SetSCL_High()
#define SCL_LO I2C_SetSCL_Low()
#define SCL_IN I2C_GetSCL_Input()
// local functions
//uint08 i2c_master_check_nak_timeout(uint08 timeout, uint08 check_nak);
//void i2c_master_cleanup(void);
void I2C_Master_Start(void) // Set up start condition for I2C
/**
* Generates the start condition for I2C read/write
*
*/
{
volatile uint08 i;
SDA_HI;
__no_operation();
SCL_HI;
for (i=0; i<5; i++)
{
__no_operation();
SDA_LO;
__no_operation();
__no_operation();
SCL_LO;
//after end of start condition both SDA and SCL will be low
}
}
void I2C_Master_Stop(void) // Set up stop condition for I2C
/**
* Generates the stop condition for I2C read/write
*
*/
{
volatile uint08 i;
SDA_LO;
__no_operation();
SCL_HI;
for (i=0; i<8; i++) {
__no_operation();
}
SDA_HI;
i=0;
//ensure bus is in default condition ( freed by slave)
while(!SDA_IN) // i is just a variable to control the while loop run time.
{
SCL_HI;
__no_operation();
__no_operation();
SCL_LO;
__no_operation();
__no_operation();
i++;
if( i > 25)
{
break;
}
}
SCL_HI;
//After generating stop condition SCL and SDA are both high. Default condition for I2C bus.
}
uint08 I2C_PolledMasterWrite(uint08 device_addr, uint08* write_data, uint08 num_bytes)
/**
* Writes data to the specified device address
*
* @param device_addr - I - 7 Bit device Address
* @param write_data - I - Pointer to data buffer to be written to slave
* @param num_bytes - I - Number of bytes to be written
* @return PASS - Completed successfully
* I2C_NO_ACK - Slave NAck'ed
*
*/
{
uint08 ByteCount;
uint08 *data_ptr;
uint08 status=PASS;
// initialize pointer to the data and start the transfer
data_ptr = write_data;
// Generate START condition //
// Data line loow when clock is high //
I2C_Master_Start();
// Before writing address ensure the bit 0 is set to zero
// Bit 0 =0 means master is writing , Bit 0 =1 means master wants to read
// BIT0 = 0x1
if (I2C_MasterTransmitByte(device_addr & ~0x1) == I2C_NO_ACK)
{
// If not Acknowledged by slave//
status = I2C_NO_ACK;
}
else
// Tranmit all the data bytes as slave has acknowledged//
{
for (ByteCount=0; ByteCount<num_bytes; ByteCount++)
{
if (I2C_MasterTransmitByte(*data_ptr)== I2C_NO_ACK)
{
// If not Acknowledged by slave//
status = I2C_NO_ACK;
break;
}
else
data_ptr++;
}
}
// Generate STOP Condition
// Data line high, when clock is high
I2C_Master_Stop();
return status;
}
uint08 I2C_PolledMasterRead(uint08 device_addr, uint08* read_data, uint08 num_bytes)
/**
* Reads data from the specified device address
*
* @param device_addr - I - 7 Bit device Address
* @param read_data - I - Pointer to buffer to hold received data from slave
* @param num_bytes - I - Number of bytes to be read
* @return PASS - Completed successfully
* I2C_NO_ACK - Slave NAck'ed
*
*/
{
uint08* data_ptr;
uint08 status=PASS;
uint08 ByteCount;
data_ptr = read_data;
// Generate START condition //
// Data line low when clock is high //
I2C_Master_Start();
// Transmit the slave address //
// Before writing address ensure the bit 0 is set to 1
// Bit 0 =0 means master is writing , Bit 0 =1 means master is reading
// BIT0 = 0x1
if(I2C_MasterTransmitByte(device_addr | 0x1) == I2C_NO_ACK)
{
// If not Acknowledged //
status = I2C_NO_ACK;
}
else
{
// Receive all the data bytes //
for(ByteCount = 0; ByteCount < num_bytes; ByteCount++)
{
*data_ptr = I2C_MasterReceiveByte();
data_ptr++;
}
}
// Generate STOP Condition
// Data line high, when clock is high
I2C_Master_Stop();
return status;
}
uint08 I2C_MasterTransmitByte(uint08 data)
/**
* This routine transmits one byte of data over the given clock and data lines and
* receives the ack from slave.
*
* @param data - I - The 8 bit data to be transmitted
* @return I2C_NO_ACK - Not Acknowledgeed
* PASS - Acknowledged
*
*/
{
uint08 Ack=1;
uint08 i;
uint08 Byte = data;
// Send Byte It is assumed that the start condition would have made SCL and SDA low.
// SDA should change only when SCA is low.
SCL_LO;
for(i = 0; i < 8 ; i++)
{
if( Byte & 0x80)
SDA_HI;
else
SDA_LO;
__no_operation();
__no_operation();
SCL_HI;
Byte <<= 1;
__no_operation(); //need to optimize the delay.
__no_operation();
__no_operation();
__no_operation();
SCL_LO;
//leave SDA at the end
if(i == 7)
{
SDA_HI;
}
__no_operation();
__no_operation();
}
//Receive Ack
__no_operation();
__no_operation();
SCL_HI;
__no_operation();
__no_operation(); // delay added bcoz without this delay ack was received wrong.
__no_operation(); // need to optimize the delay.
// If data line is pulled low by slave- it is acknowledged
if (SDA_IN)
Ack = 0; //ack not received
else
Ack = 1; //ack received
SCL_LO;
__no_operation();
__no_operation();
SDA_LO;
//After transmitting one byte of data SCL and SDA are both low.
return Ack;
}
uint08 I2C_MasterReceiveByte()
/**
* This routine receives one byte of data over the given clock and data lines and
* sends the ack to slave.
*
* @return one byte of data received from slave.
*
*/
{
uint08 Data=0;
uint08 i;
//Make SDA as input
SDA_HI;
__no_operation();
__no_operation();
for(i = 0; i < 8 ; i ++)
{
SCL_HI;
__no_operation();
__no_operation();
Data <<= 1;
if (SDA_IN)
Data |=1;
else
Data |=0;
SCL_LO;
__no_operation();
__no_operation();
}
//After the eight bits are transferred by slave, slave will pull SDA high ( default condition for I2C bus)
// Generate ack for slave.
SDA_LO;
__no_operation();
__no_operation();
SCL_HI;
__no_operation();
__no_operation();
SCL_LO;
//After receiving one byte of data SCL and SDA are both low.
return Data;
}
//
void I2C_Master_Init(void)
/**
* Initializes I2C. Makes SCL and SDA high.
*/
{
//bit banging
P3SEL &= ~(SCL | SDA); // Set GPIO function
P3OUT &= ~(SDA | SCL);
I2C_SetSCL_Low(); //although not required but want to make sure SCL is low when SDA goes high
I2C_SetSDA_High();
__no_operation();
I2C_SetSCL_High();
__no_operation();
}
//
/* I2C SDA and SCL Lines */
void I2C_SetSDA_High (void)
{
P3DIR &= ~SDA;
}
//
void I2C_SetSDA_Low (void)
{
P3DIR |= SDA;
}
//
BOOL I2C_GetSDA_Input (void)
{
return (P3IN & SDA ? 1 : 0);
}
//
void I2C_SetSCL_High (void)
{
P3DIR &= ~SCL;
}
//
void I2C_SetSCL_Low (void)
{
P3DIR |= SCL;
}
//
BOOL I2C_GetSCL_Input (void)
{
return (P3IN & SCL ? 1 : 0);
}