STM32下模拟I2C的C语言实现

8 篇文章 0 订阅

近来主要在写一些STM32上的开发程序,由于STM32的固件库中,I2C模块实在是不好用,所以在采用了软件模拟的方法来实现。

具体的代码如下(在Keil下调试通过):

#include "stm32f10x_lib.h"

//条件编译 1:使用软件模拟I2C
//#define PIN_SCL 	GPIO_Pin_6
//#define PIN_SDA 	GPIO_Pin_7


static __inline void TWI_SCL_0(void)		{ GPIOB->BRR=PIN_SCL; }
static __inline void TWI_SCL_1(void) 		{ GPIOB->BSRR=PIN_SCL;}
static __inline void TWI_SDA_0(void) 		{ GPIOB->BRR=PIN_SDA; }
static __inline void TWI_SDA_1(void) 		{ GPIOB->BSRR=PIN_SDA;}
static __inline u8   TWI_SDA_STATE(void)        { return (GPIOB->IDR & PIN_SDA) != 0; }
//static __inline void TWI_NOP(void) 		{  TWI_Delay(); }

static const u8 TWI_ACK   	=0;
static const u8 TWI_READY 	=0;
static const u8 TWI_NACK 	=1;
static const u8 TWI_BUS_BUSY  	=2;
static const u8 TWI_BUS_ERROR 	=3;

static const u8  TWI_RETRY_COUNT = 3; //重试次数

extern void Delay_mS(u32 n);

static void TWI_Initialize(void);
static u8 TWI_START(void);
static u8 TWI_START_SHT(void);
static void TWI_STOP(void);
static u8  TWI_SendByte(u8 Data);
static u8 TWI_ReceiveByte(void);
static void TWI_SendACK(void);
static void TWI_SendNACK(void);


/*******************************************************************************
 * 函数名称:TWI_Delay                                                                     
 * 描    述:延时函数                                                                     
 *                                                                               
 * 输    入:无                                                                     
 * 输    出:无                                                                     
 * 返    回:无                                                                     
 * 作    者:                                                                     
 * 修改日期:2010年6月8日                                                                    
 *******************************************************************************/
static void TWI_NOP(void)
{
 vu32 i, j;
 vu32 sum = 0;
 i = 20;
 while(i--)
 {
     for (j = 0; j < 10; j++)
	 sum += i; 
 }
 sum = i;
}

/*******************************************************************************
 * 函数名称:TWI_Initialize                                                                     
 * 描    述:I2C初始化函数                                                                     
 *                                                                               
 * 输    入:无                                                                     
 * 输    出:无                                                                     
 * 返    回:无                                                                     
 * 作    者:                                                                     
 * 修改日期:2010年6月8日                                                                    
 *******************************************************************************/
static 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 = PIN_SDA;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Pin = PIN_SCL;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  TWI_SDA_1();
  TWI_SCL_0(); 
  
  //DebugPrint("Software TWI Initializing...\n"); 
}

/*******************************************************************************
 * 函数名称:TWI_START                                                                     
 * 描    述:发送启动                                                                     
 *                                                                               
 * 输    入:无                                                                     
 * 输    出:无                                                                     
 * 返    回:无                                                                     
 * 作    者:                                                                     
 * 修改日期:2010年6月8日                                                                    
 *******************************************************************************/
static 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;
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_START_SHT 
 * 
 * @Returns:   
 */
/* --------------------------------------------------------------------------*/
static u8 TWI_START_SHT(void)
{
    TWI_SDA_1();
    TWI_SCL_0();
    TWI_NOP();

    TWI_SDA_1(); 
    TWI_SCL_1(); 
    TWI_NOP();

    if(!TWI_SDA_STATE())
    {
	    return TWI_BUS_BUSY;
    }
    TWI_SDA_0();
    TWI_NOP();

    TWI_SCL_0();  
    TWI_NOP(); 

    TWI_SCL_1();
    TWI_NOP();

    TWI_SDA_1();
    TWI_NOP();

    TWI_SCL_0();
    TWI_NOP();

    return TWI_READY;
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_STOP 
 */
/* --------------------------------------------------------------------------*/
static void TWI_STOP(void)
{
 TWI_SDA_0(); 
 TWI_NOP();
   
 TWI_SCL_1(); 
 TWI_NOP();    

 TWI_SDA_1();
 TWI_NOP();
  
 //DebugPrint("TWI_STOP\n");   
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_SendACK 
 */
/* --------------------------------------------------------------------------*/
static void TWI_SendACK(void)
{
 TWI_SDA_0();
 TWI_NOP();
 TWI_SCL_1();
 TWI_NOP();
 TWI_SCL_0(); 
 TWI_NOP(); 
 TWI_SDA_1();
 //DebugPrint("TWI_SendACK\n");   
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_SendNACK 
 */
/* --------------------------------------------------------------------------*/
static void TWI_SendNACK(void)
{
 TWI_SDA_1();
 TWI_NOP();
 TWI_SCL_1();
 TWI_NOP();
 TWI_SCL_0(); 
 TWI_NOP();
 //DebugPrint("TWI_SendNACK\n");    
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_SendByte 
 * 
 * @Param: Data
 * 
 * @Returns:   
 */
/* --------------------------------------------------------------------------*/
static 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();
  TWI_SDA_1();
  //DebugPrint("TWI_NACK!\n");
  return TWI_NACK;
 }
 else
 {
  TWI_SCL_0();
  TWI_SDA_1();
  //DebugPrint("TWI_ACK!\n");
  return TWI_ACK;  
 }    
}

/* --------------------------------------------------------------------------*/
/** 
 * @Brief:  TWI_ReceiveByte 
 * 
 * @Returns:   
 */
/* --------------------------------------------------------------------------*/
static 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;
}


  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
C语言是一种广泛应用于嵌入式系统开发的编程语言,而STM32F103C8T6是一款常用的基于ARM Cortex-M3内核的微控制器。在STM32F103C8T6上实现软件I2C通信可以通过GPIO口模拟I2C总线的时钟和数据线来实现。 下面是一个简单的示例代码,演示了如何在STM32F103C8T6上使用C语言实现软件I2C通信: ```c #include "stm32f10x.h" #define I2C_SCL_PIN GPIO_Pin_6 #define I2C_SDA_PIN GPIO_Pin_7 #define I2C_GPIO_PORT GPIOB void I2C_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN); } void I2C_Start(void) { GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN); GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN); GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); } void I2C_Stop(void) { GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN); GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN | I2C_SDA_PIN); } void I2C_SendByte(uint8_t byte) { uint8_t i; for (i = 0; i < 8; i++) { GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); if (byte & 0x80) GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN); else GPIO_ResetBits(I2C_GPIO_PORT, I2C_SDA_PIN); GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN); byte <<= 1; } GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); } uint8_t I2C_ReceiveByte(void) { uint8_t i, byte = 0; GPIO_SetBits(I2C_GPIO_PORT, I2C_SDA_PIN); for (i = 0; i < 8; i++) { byte <<= 1; GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); if (GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN)) byte |= 0x01; GPIO_SetBits(I2C_GPIO_PORT, I2C_SCL_PIN); } GPIO_ResetBits(I2C_GPIO_PORT, I2C_SCL_PIN); return byte; } void I2C_WriteByte(uint8_t deviceAddr, uint8_t regAddr, uint8_t data) { I2C_Start(); I2C_SendByte(deviceAddr); I2C_SendByte(regAddr); I2C_SendByte(data); I2C_Stop(); } uint8_t I2C_ReadByte(uint8_t deviceAddr, uint8_t regAddr) { uint8_t data; I2C_Start(); I2C_SendByte(deviceAddr); I2C_SendByte(regAddr); I2C_Start(); I2C_SendByte(deviceAddr | 0x01); data = I2C_ReceiveByte(); I2C_Stop(); return data; } int main(void) { I2C_Init(); // 使用示例:向设备地址为0x50的I2C设备的寄存器0x00写入数据0xAA I2C_WriteByte(0x50, 0x00, 0xAA); // 使用示例:从设备地址为0x50的I2C设备的寄存器0x00读取数据 uint8_t data = I2C_ReadByte(0x50, 0x00); while (1) { // 主循环 } } ``` 上述代码中,我们首先定义了软件I2C通信所需的引脚和端口,然后实现了初始化函数`I2C_Init()`、起始信号函数`I2C_Start()`、停止信号函数`I2C_Stop()`、发送字节函数`I2C_SendByte()`、接收字节函数`I2C_ReceiveByte()`、写入字节函数`I2C_WriteByte()`和读取字节函数`I2C_ReadByte()`。 在`main()`函数中,我们通过调用`I2C_WriteByte()`函数向设备地址为0x50的I2C设备的寄存器0x00写入数据0xAA,并通过调用`I2C_ReadByte()`函数从设备地址为0x50的I2C设备的寄存器0x00读取数据。 请注意,以上代码仅为示例,具体的软件I2C实现可能会因硬件平台和需求而有所不同。在实际应用中,您可能需要根据具体情况进行适当的修改。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值