接上篇,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设备都有一个设备类型码,存储在相应寄存器中。编写程序时可读取该寄存器检测程序正确与否。