STM32软件IIC的实现

接上篇,LIS331的例程终于可以正常运行了,接下来就是将其移植到STM32上了,不过第一次接触STM32的IIC,看例程比较简单,直接复制到工程后却读不出数据,一直停在等待从设备回复ACK的死循环。

经过一天的修改之后,终于还是舍去了硬件IIC改成了用软件实现,最终代码如下:

.h文件

#include "stm32f10x.h"
#define ANO_GPIO_I2C    GPIOB
#define I2C_Pin_SCL     GPIO_Pin_3
#define I2C_Pin_SDA     GPIO_Pin_4
#define ANO_RCC_I2C     RCC_APB2Periph_GPIOB
/*********************************************/

#define SCL_H         ANO_GPIO_I2C->BSRR = I2C_Pin_SCL
#define SCL_L         ANO_GPIO_I2C->BRR  = I2C_Pin_SCL
#define SDA_H         ANO_GPIO_I2C->BSRR = I2C_Pin_SDA
#define SDA_L         ANO_GPIO_I2C->BRR  = I2C_Pin_SDA
#define SCL_read      ANO_GPIO_I2C->IDR  & I2C_Pin_SCL
#define SDA_read      ANO_GPIO_I2C->IDR  & I2C_Pin_SDA

#define EEPROM_DEV_ADDR           0x3a           //??(????)
#define EEPROM_WR                 0x00                     //?
#define EEPROM_RD                 0x01                     //?
#define EEPROM_WORD_ADDR_SIZE      8
extern u8 databuff[3];
extern u8 x,y,z;
int I2C_Start(void);
void I2C_Stop(void);
void I2C_Ack(void);
void I2C_NoAck(void);
void I2C_SDA_OUT(void);
void I2C_SDA_IN(void);
uint8_t I2C_GetAck(void);
void I2C_SendByte(uint8_t Data);
uint8_t I2C_ReadByte(uint8_t ack);
void I2C_delay(void);
int EEPROM_ReadByte(uint16_t Addr, uint8_t *Data);
int EEPROM_WriteByte(uint16_t Addr, uint8_t Data);
void I2C_Initializes(void);
u8 Sanzhou_Start(void);
u8 Who_Am_I(void);
int Read_XYZ(void);
#endif

.c文件

#include "tb_delay.h"
#include "i2c.h"
void I2C_delay(void)
{
	u8 t = 2;
	while(t--);
	return;
}
int I2C_Start(void)
{
	I2C_SDA_OUT();
	
	SDA_H;
	SCL_H;
	I2C_delay();
	if(!SDA_read)
	{
		return DISABLE;
	}
	SDA_L;
	I2C_delay();
	if(SDA_read)
	{
		return DISABLE;
	}
	SCL_L;
	return ENABLE;
}
void I2C_Stop(void)
{
	I2C_SDA_OUT();	
	SCL_L;
	SDA_L;	
	SCL_H;
	I2C_delay();
	SDA_H;
	I2C_delay();
}

static void I2C_Ack()
{
	SCL_L;
	I2C_SDA_OUT();	
	
	SDA_L;
	I2C_delay();
	SCL_H;
	I2C_delay();
	SCL_L;
}
 
static void I2C_NoAck()
{
	SCL_L;
	I2C_SDA_OUT();
	
	I2C_delay();
	SDA_H;
	I2C_delay();
	SCL_H;
	I2C_delay();
	SCL_L;
}
uint8_t I2C_GetAck(void)
{
  uint8_t time = 0;
	I2C_SDA_IN();
	SDA_H;
	I2C_delay();
	SCL_H;
	I2C_delay();
	while(SDA_read)
	{
		time++;
		if(time > 250)
		{			
			SCL_L;
			return DISABLE;
		}
	}
	SCL_L;
	return ENABLE;
}
void I2C_SendByte(uint8_t Data)
{
  uint8_t cnt;
  I2C_SDA_OUT();	
  for(cnt=0; cnt<8; cnt++)
  {
    SCL_L;                              
    I2C_delay();
 
    if(Data & 0x80)
    {
      SDA_H;                         
    }
    else
    {
      SDA_L;                         
    }
    Data <<= 1;
    SCL_H;                              
    I2C_delay();
  }
  SCL_L;                                   
  I2C_delay();
}
 

uint8_t I2C_ReadByte(uint8_t ack)
{
  uint8_t cnt;
  uint16_t data;
  I2C_SDA_IN();	
	
  for(cnt=0; cnt<8; cnt++)
  {
    SCL_L;                                
    I2C_delay();
		
    SCL_H;                             
    data <<= 1;
    if(SDA_read)
    {
      data |= 0x01;                              
    }
    I2C_delay();
  }
  if(ack == 1)
  {
     I2C_NoAck();
  }
  else
  {
     I2C_Ack();
  }
  return data;                                  
}
void I2C_GPIO_Configuration(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
  GPIO_InitStructure.GPIO_Pin = I2C_Pin_SCL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(ANO_GPIO_I2C,&GPIO_InitStructure);
	
  GPIO_InitStructure.GPIO_Pin = I2C_Pin_SDA;
  GPIO_Init(ANO_GPIO_I2C, &GPIO_InitStructure);
}
 
 
void I2C_SDA_IN()
{
   GPIO_InitTypeDef  GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Pin = I2C_Pin_SDA;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
   GPIO_Init(ANO_GPIO_I2C, &GPIO_InitStructure);	
}
 
void I2C_SDA_OUT()
{
   GPIO_InitTypeDef  GPIO_InitStructure;
   GPIO_InitStructure.GPIO_Pin = I2C_Pin_SDA;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
   GPIO_Init(ANO_GPIO_I2C, &GPIO_InitStructure);	
}
void I2C_Initializes(void)
{
	I2C_GPIO_Configuration();
  SCL_H; 
	SDA_H;
}
int EEPROM_WriteByte(uint16_t Addr, uint8_t Data)
{
	I2C_Start();
	I2C_SendByte(EEPROM_DEV_ADDR | EEPROM_WR);
  if(!I2C_GetAck())
  {
	I2C_Stop();
	return DISABLE;
  }
  #if (8 == EEPROM_WORD_ADDR_SIZE)
  I2C_SendByte((uint8_t)(Addr&0x00FF));   
  #else
  I2C_SendByte((uint8_t)(Addr>>8));     
  I2C_SendByte((uint8_t)(Addr&0x00FF));
  #endif
  I2C_GetAck();
  I2C_SendByte(Data);
  I2C_Stop();
	return 1;
}

int EEPROM_ReadByte(uint16_t Addr, uint8_t *Data)
{
  I2C_Start(); 
	I2C_SendByte(EEPROM_DEV_ADDR | EEPROM_WR);
  if(!I2C_GetAck())
  {
	I2C_Stop();
	return DISABLE;
  }
  #if (8 == EEPROM_WORD_ADDR_SIZE)
  I2C_SendByte((uint8_t)(Addr&0x00FF)); 
  #else
  I2C_SendByte((uint8_t)(Addr>>8));   
	I2C_SendByte((uint8_t)(Addr&0x00FF));
  #endif
  I2C_Start();
	I2C_SendByte(EEPROM_DEV_ADDR | EEPROM_RD);
	
	if(!I2C_GetAck())
	{
	I2C_Stop();
	return DISABLE;
  }
  *Data = I2C_ReadByte(0); 
	I2C_Stop();
	return 1;
}
u8 Who_Am_I(void)
{
	u8 who;
	EEPROM_ReadByte(0x20, &who);
	return who;
}
u8 Sanzhou_Start()
{
	u8 id;
	id = Who_Am_I();
	if(id)
	{
		EEPROM_WriteByte(0x20, 0xE7);
		return ENABLE;
	}
	else
		return DISABLE;
}
int Read_XYZ(void)
{
 	EEPROM_ReadByte(0x29, &x);
	databuff[0] = x;
 	EEPROM_ReadByte(0x2b, &y);
	databuff[1] = y;
 	EEPROM_ReadByte(0x2d, &z);
	databuff[2] = z;
	return ENABLE;
}

另外;

源码本是IF,可能是写错了否则进不了循环,我改成了while。在通信过程中可能因两设备接受与发送频率的不同,造成从设备在接受到数据时会发送应答,而主设备检测应答信号时,总线上并没有将测到信号。该段代码的目的正是延长一段时间等待从设备的回复。

iic设备都有一个设备类型码,存储在相应寄存器中。编写程序时可读取该寄存器检测程序正确与否。

猜你喜欢

转载自blog.csdn.net/qq_41281601/article/details/81670998