|
MSP430FR5969-LaunchPad模拟I2C
[复制链接]
MSP430FR5969虽然自带I2C,但总感觉用起来挺别扭,可能是习惯用自己写的模拟I2C。用51来模拟I2C实现起来比较方便,但在MSP430上相对复杂一点,不过也不是什么大问题。注意切换IO的输入和输出,在判断IO输入时稍加注意就可以。
以下程序读写FM24V05亲测可用,需要注意的是SDA,SCL引脚需要接上拉电阻。
I2C.C
#include
#define Uint8 unsigned char
#define Uint16 unsigned int
#define SDA_IN P1DIR &=~BIT6 // P1.6 IN
#define SDA_OUT P1DIR |=BIT6 // P1.6 OUT
#define SDA_LOW P1OUT &=~BIT6 // sda=0
#define SDA_HIGH P1OUT |=BIT6 // sda=1
#define SCL_IN P1DIR &=~BIT7 // P1.7 IN
#define SCL_OUT P1DIR |=BIT7 // P1.7 OUT
#define SCL_LOW P1OUT &=~BIT7
#define SCL_HIGH P1OUT |=BIT7
#define TURE 1
#define FALSE 0
#define GET_SDA P1IN&BIT6
#define SYS_MCLK 8000000 //系统时钟频率
#define DELAY_US SYS_MCLK/1000000
#define _Nop() _NOP(),_NOP(),_NOP(),_NOP(),_NOP()
unsigned char ack; /*应答标志位*/
//延时5us
void i2c_delay(unsigned char us)
{
//unsigned char tmp;
while(us--)
{
__delay_cycles(DELAY_US); // Wait 8 CPU Cycles
}
}
/*
*************************************************************************************
**函数名称:起动总线函数 **
**函数功能:启动I2C总线,即发送I2C起始条件. **
**入口参数:无 **
**返回参数:无 **
*************************************************************************************
*/
void Start_I2c(void)
{
SDA_OUT; //引脚为输出模式
SCL_OUT;
i2c_delay(4);
SDA_HIGH; //发送起始条件的数据信号
i2c_delay(1);
SCL_HIGH;
i2c_delay(1); //起始条件建立时间大于4.7us,延时
SDA_LOW; //发送起始信号
i2c_delay(1); // 起始条件锁定时间大于4μs
SCL_LOW; //钳住I2C总线,准备发送或接收数据
i2c_delay(2);
}
/*
*************************************************************************************
**函数名称:结束总线函数 **
**函数功能:结束I2C总线,即发送I2C结束条件. **
**入口参数:无 **
**返回参数:无 **
*************************************************************************************
*/
void Stop_I2c(void)
{
SDA_OUT; //引脚为输出模式
SDA_LOW; //发送结束条件的数据信号
i2c_delay(1); //发送结束条件的时钟信号
SCL_HIGH; //结束条件建立时间大于4μs
i2c_delay(1);
SDA_HIGH; //发送I2C总线结束信号
i2c_delay(1);
}
/*
*************************************************************************************
**函数名称:应答子函数 **
**函数功能:主控器进行应答信号(可以是应答或非应答信号,由位参数a决定) **
**入口参数:无 **
**返回参数:无 **
*************************************************************************************
*/
void Ack_I2c(Uint8 a)
{
SDA_OUT; //引脚为输出模式
if(a==0)SDA_LOW; //在此发出应答或非应答信号
else SDA_HIGH;
i2c_delay(1);
SCL_HIGH;
i2c_delay(1); //时钟低电平周期大于4μs
SCL_LOW; //清时钟线,钳住I2C总线以便继续接收
i2c_delay(1);
}
/*
*************************************************************************************
**函数名称:发送单字节函数 **
**函数功能:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对 **
** 此状态位进行操作.(不应答或非应答都使ack=0) **
**入口参数:Uint8 c发送数据 **
**返回参数:无 **
*************************************************************************************
*/
void SendByte(Uint8 c)
{
Uint8 BitCnt = 0;
SDA_OUT; //引脚为输出模式
for(BitCnt=0;BitCnt<8;BitCnt++){ //要传送的数据长度为8位
if((c<
else SDA_LOW;
i2c_delay(1);
SCL_HIGH; //置时钟线为高,通知被控器开始接收数据位
i2c_delay(1); //保证时钟高电平周期大于0.6μs
SCL_LOW;
}
i2c_delay(1);
SDA_HIGH; //8位发送完后释放数据线,准备接收应答位
i2c_delay(1);
SDA_IN;
SCL_HIGH;
i2c_delay(1);
if(GET_SDA)ack=0;
else ack=1; //判断是否接收到应答信号
SCL_LOW;
i2c_delay(1);
}
/*
*************************************************************************************
**函数名称:接收单字节函数 **
**函数功能:用来接收从器件传来的数据,并判断总线错误(不发应答信号), **
** 发完后请用应答函数应答从机。 **
**入口参数:无 **
**返回参数:无 **
*************************************************************************************
*/
Uint8 RcvByte(void)
{
Uint8 retc = 0;
Uint8 BitCnt = 0;
//retc=0;
SDA_HIGH; //置数据线为输入方式
SDA_IN;
for(BitCnt=0;BitCnt<8;BitCnt++){
_Nop();
SCL_LOW; //置时钟线为低,准备接收数据位
i2c_delay(1); //时钟低电平周期大于4.7μs
SCL_HIGH; //置时钟线为高使数据线上数据有效
_Nop();
_Nop();
retc=retc<<1;
if(GET_SDA)retc=retc+1; //读数据位,接收的数据位放入retc中
_Nop();
_Nop();
}
SCL_LOW;
_Nop();
_Nop();
return(retc);
}
/*
*************************************************************************************
**函数名称:向有子地址器件发送多字节数据函数 **
**函数功能:从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件 **
** 地址sla,子地址suba,发送内容是s指向的内容,p发送子地址 **
** 8位或16位选择,发送no个字节。 **
** 如果返回1表示操作成功,否则操作有误。 **
**注意: 使用前必须已结束总线。 **
**入口参数:... **
**返回参数:成功/失败 **
*************************************************************************************
*/
Uint8 ISendStr(Uint8 sla,Uint16 suba,Uint8 * s,Uint16 no,Uint8 p)
{
Uint16 i;
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(FALSE);
if(p){ //发送子地址
SendByte(suba/256);
if(ack==0)return(FALSE);
SendByte(suba%256);
if(ack==0)return(FALSE);
}
else{
SendByte((Uint8) suba);
if(ack==0)return(FALSE);
}
for(i=0;i
SendByte(*s); //发送数据
if(ack==0)return(FALSE);
s++;
}
Stop_I2c(); //结束总线
return(TRUER);
}
/*
*************************************************************************************
**函数名称:向有子地址器件读取多字节数据函数 **
**函数功能:从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件 **
** 地址sla,子地址suba,读出的内容放入s指向的存储区,p发送子地址 **
** 8位或16位选择,读no个字节。 **
** 如果返回1表示操作成功,否则操作有误。 **
**注意: 使用前必须已结束总线。 **
**入口参数:... **
**返回参数:成功/失败 **
*************************************************************************************
*/
Uint8 IRcvStr(Uint8 sla,Uint16 suba,Uint8 * s,Uint16 no,Uint8 p)
{
Uint16 i = 0;
Start_I2c(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(FALSE);
if(p){ //发送子地址
SendByte(suba/256);
if(ack==0)return(FALSE);
SendByte(suba%256);
if(ack==0)return(FALSE);
}
else{
SendByte((Uint8) suba);
if(ack==0)return(FALSE);
}
Start_I2c(); //重新启动总线
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i
*s=RcvByte(); //发送数据
Ack_I2c(0); //发送应答位
s++;
}
*s=RcvByte();
Ack_I2c(1); //发送非应位
Stop_I2c(); //结束总线
return(TRUER);
}
------------------------------------------------------------------------------------
下面是操作FM24V05的函数
#define MaxAddr (65536)
/***********************************************************************************/
/*函数名称:Uint8 DISK_Read(Uint16 Addr,Uint8 * Buf,Uint16 Count) */
/*函数功能:从存储器中读取数据 */
/*入口参数:Addr Buf Count */
/*返回参数:TRUER/FALSE */
/***********************************************************************************/
Uint8 DISK_Read(Uint16 Addr,Uint8 * Buf,Uint16 Count)//reentrant
{
Uint8 i=0;
//Uint16 j = Addr+Count;
if((Addr+Count) > MaxAddr) //超出存储范围
{
return FALSE;
}
while(!(IRcvStr(ADDR_FM24V05,Addr,Buf,Count,1)))
{
i ++;
if(i > 3)
{
return FALSE;
}
}
return TRUER;
}
/***********************************************************************************/
/*函数名称:Uint8 DISK_Write(Uint16 Addr,Uint8 * Buf,Uint16 Count) */
/*函数功能:向存储器中写入数据 */
/*入口参数:Addr Buf Count */
/*返回参数:TRUER/FALSE */
/***********************************************************************************/
Uint8 DISK_Write(Uint16 Addr,Uint8 * Buf,Uint16 Count)
{
Uint8 i=0;
//i = 0;
if((Addr+Count) > MaxAddr) //超出存储范围
{
return FALSE;
}
while(!(ISendStr(ADDR_FM24V05,Addr,Buf,Count,1)))
{
i ++;
if(i > 3)
{
return FALSE;
}
}
return TRUER;
}
|
|