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設備都有一個設備類型碼,存儲在相應寄存器中。編寫程序時可讀取該寄存器檢測程序正確與否。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章