STM32的硬件I2C不太好用,N多人深受其困扰,本人也不例外.所以干脆一不做二不休,用模拟的I2C算了,虽然速度不及硬件I2C,在一般的应用中还是不错的.帖上代码和协议分析图,造福广大受STM32的I2C困扰的朋友,哈哈!为了跟硬件I2C有所区别,本人把模拟的I2C名字写成TWI.
H文件内容如下:
#i nclude "stm32f10x.h" #ifndef _TWI_H_ #define _TWI_H_
//条件编译 1:使用软件模拟I2C #define TWI_ENABLE 1
#define TWI_SCL_0 GPIOB->BRR=GPIO_Pin_8 #define TWI_SCL_1 GPIOB->BSRR=GPIO_Pin_8 #define TWI_SDA_0 GPIOB->BRR=GPIO_Pin_9 #define TWI_SDA_1 GPIOB->BSRR=GPIO_Pin_9 #define TWI_SDA_STATE (GPIOB->IDR&GPIO_Pin_9)
enum ENUM_TWI_REPLY { TWI_NACK=0 ,TWI_ACK=1 };
enum ENUM_TWI_BUS_STATE { TWI_READY=0 ,TWI_BUS_BUSY=1 ,TWI_BUS_ERROR=2 };
#define TWI_RETRY_COUNT 3 //重试次数
extern void Delay_mS(u32 n); #define DELAY Delay_mS(40) #define RETRY_DELAY Delay_mS(50)
void TWI_Initialize(void); u8 TWI_START(void); void TWI_STOP(void); u8 TWI_SendByte(u8 Data); u8 TWI_ReceiveByte(void); void TWI_SendACK(void); void TWI_SendNACK(void); #endif
C文件如下:
#i nclude "TWI.h" #i nclude "Global.h" #define TWI_NOP TWI_Delay()
/******************************************************************************* * 函数名称:TWI_Delay * 描 述:延时函数 * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ void TWI_Delay(void) { u32 i=5; while(i--); }
/******************************************************************************* * 函数名称:TWI_Initialize * 描 述:I2C初始化函数 * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ void TWI_Initialize(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; TWI_SDA_1; TWI_SCL_1; GPIO_Init(GPIOB, &GPIO_InitStructure); //////DebugPrint("Software TWI Initializing...\n"); }
/******************************************************************************* * 函数名称:TWI_START * 描 述:发送启动 * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ u8 TWI_START(void) { TWI_SDA_1; TWI_NOP; TWI_SCL_1; TWI_NOP;
if(!TWI_SDA_STATE) { ////DebugPrint("TWI_START:BUSY\n"); return TWI_BUS_BUSY; } TWI_SDA_0; TWI_NOP; TWI_SCL_0; TWI_NOP;
if(TWI_SDA_STATE) { ////DebugPrint("TWI_START:BUS ERROR\n"); return TWI_BUS_ERROR; } return TWI_READY; }
/******************************************************************************* * 函数名称:TWI_STOP * 描 述:发送停止位 * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ void TWI_STOP(void) { TWI_SDA_0; TWI_NOP; TWI_SCL_1; TWI_NOP;
TWI_SDA_1; TWI_NOP; // TWI_SCL_0; // TWI_NOP;
//////DebugPrint("TWI_STOP\n"); }
/******************************************************************************* * 函数名称:TWI_SendACK * 描 述:收到数据,发送ACK * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ void TWI_SendACK(void) { TWI_SDA_0; TWI_NOP; TWI_SCL_1; TWI_NOP; TWI_SCL_0; TWI_NOP; //////DebugPrint("TWI_SendACK\n"); }
/******************************************************************************* * 函数名称:TWI_SendNACK * 描 述:收到数据,发送NACK * * 输 入:无 * 输 出:无 * 返 回:无 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ void TWI_SendNACK(void) { TWI_SDA_1; TWI_NOP; TWI_SCL_1; TWI_NOP; TWI_SCL_0; TWI_NOP; //////DebugPrint("TWI_SendNACK\n"); }
/******************************************************************************* * 函数名称:TWI_SendByte * 描 述:发送一个字节 * * 输 入:无 * 输 出:无 * 返 回:TWI_ACK/TWI_NACK * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ u8 TWI_SendByte(u8 Data) { u8 i; TWI_SCL_0; for(i=0;i<8;i++) { //---------数据建立---------- if(Data&0x80) { TWI_SDA_1; } else { TWI_SDA_0; } Data<<=1; TWI_NOP; //---数据建立保持一定延时---- //----产生一个上升沿[正脉冲] TWI_SCL_1; TWI_NOP; TWI_SCL_0; TWI_NOP;//延时,防止SCL还没变成低时改变SDA,从而产生START/STOP信号 //--------------------------- } //接收从机的应答 TWI_SDA_1; TWI_NOP; TWI_SCL_1; TWI_NOP; if(TWI_SDA_STATE) { TWI_SCL_0; //////DebugPrint("TWI_NACK!\n"); return TWI_NACK; } else { TWI_SCL_0; //////DebugPrint("TWI_ACK!\n"); return TWI_ACK; } }
/******************************************************************************* * 函数名称:TWI_ReceiveByte * 描 述:接收一个字节 * * 输 入:无 * 输 出:无 * 返 回:返回接收到的数据 * 作 者:梅川酷子 * 修改日期:2010年6月8日 *******************************************************************************/ u8 TWI_ReceiveByte(void) { u8 i,Dat; TWI_SDA_1; TWI_SCL_0; Dat=0; for(i=0;i<8;i++) { TWI_SCL_1;//产生时钟上升沿[正脉冲],让从机准备好数据 TWI_NOP; Dat<<=1; if(TWI_SDA_STATE) //读引脚状态 { Dat|=0x01; } TWI_SCL_0;//准备好再次接收数据 TWI_NOP;//等待数据准备好 } //////DebugPrint("TWI_Dat:%x\n",Dat); return Dat; }
|
用户377235 2013-11-8 17:26
有用,谢谢分享!
用户1694343 2013-10-25 16:35
用户422975 2013-2-18 19:08