本文以MMA8452为例,介绍如何使用STM32通过IIC驱动:
一、什么是IIC
IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的一种简单、双向、二线制、同步串行总线,主要是用来连接整体电路,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。
简单理解就是一个控制信号SCL,一个传输信号SDA,主机通过总线,根据从机地址(slave address)写入\读取数据
二、IIC使用方式&注意事项
IIC要实现数据传输,只要记住几个要点就可以:开始条件,结束条件,握手,传输数据格式
*注意:无论在哪个数据传送时,SCL控制信号一定要是有效的,即SCL = 1;
开始条件:在SCL = 1时,SDA电平由1变为0。
结束条件:在SCL = 1时,SDA电平由0变为1。
握手(ASK):主机发送时,从机接收到8bit数据后,需要告诉主机已经收完,给出响应ASK。此时SDA从输出模式转换为输入模式,将响应电平输入到主机,主机判断是否有ASK = 1/0,然后再继续后面动作,否则数据容易错乱。
主机接收数据时,主机接收到8bit数据后,需要告诉从机已经收到,给出响应,并结束数据传送。
数据传输格式:每一个字节必须保证是8位数据长度,数据传送时,先传送最高位(MSB),每个字节后面必须有握手位(ASK),即一帧共有9位。
三、实例驱动
驱动思路:1、找到正确被驱动IC地址 2、了解驱动寄存器 3、掌握时序
实例:
#include "stm32f10x.h"
#include "GPIO_Config.h"
#include
#define SlaveAddress 0x3A//SA0拉高,从机地址为0X3A
#define MMA8452_SDA_H GPIOB -> BSRR = GPIO_Pin_12//置高
#define MMA8452_SDA_L GPIOB -> BRR = GPIO_Pin_12//置低
#define MMA8452_SCL_H GPIOB -> BSRR = GPIO_Pin_13 //置高
#define MMA8452_SCL_L GPIOB -> BRR = GPIO_Pin_13//置低
#define MMA8452_IO_SDA GPIO_Pin_12//定义PB12为SDA
#define MMA8452_IO_SCL GPIO_Pin_13//定义PB13为SCL
#define MMA8452_IO_Port GPIOB
#define MMA8452_RCC_Port RCC_APB2Periph_GPIOB
#define Get_I2C_SDA() GPIO_ReadInputDataBit(MMA8452_IO_Port,MMA8452_IO_SDA)//SDA作为应答读取数据
s16 data_x,data_y,data_z;
volatile float Pitch; //Pitch为俯仰角
extern vu8 error; //错误标志
/************ MMA8452 initialize ***************/
void MMA8452_init(void)
{
MMA8452_I2C_Configuration();
MMA8452_Single_Write(0x2A,0x2D); //ACTIVE模式,Output Data Tata频率为12.5Hz,LNOISE
MMA8452_Single_Write(0x2B,0x02); //High Resolution模式
MMA8452_Single_Write(0x0E,0x00); //2g模式,output data high-pass filtered
MMA8452_Single_Write(0x0D,0x2A);
if(MMA8452_Single_Read(0x0D) == 0x2A)
{
error &= ~0x02;//MMA8452通讯正常
}
else
{
error |= 0x02;//MMA8452通讯错误
}
}
/************ 模拟IO配置 ***************/
void MMA8452_I2C_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(MMA8452_RCC_Port,ENABLE);
GPIO_InitStructure.GPIO_Pin = MMA8452_IO_SCL | MMA8452_IO_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MMA8452_IO_Port, &GPIO_InitStructure);
MMA8452_SCL_H;//初始化时置高
MMA8452_SDA_H;//初始化时置高
}
/************ MMA8452_SDA设置为输入模式,作为ACK使用 ***************/
void MMA8452_SDA_Mode_In(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(MMA8452_RCC_Port,ENABLE);
GPIO_InitStructure.GPIO_Pin = MMA8452_IO_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MMA8452_IO_Port, &GPIO_InitStructure);
}
/************ MMA8452_SDA作为数据口输出模式 ***************/
void MMA8452_SDA_Mode_Out(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(MMA8452_RCC_Port,ENABLE);
GPIO_InitStructure.GPIO_Pin = MMA8452_IO_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MMA8452_IO_Port, &GPIO_InitStructure);
}
/************ IIC-start ***************/
void MMA8452_I2C_Start(void)
{
MMA8452_SDA_H; //SDA=1
MMA8452_SCL_H; //SCL=1
Delay_us(5);
MMA8452_SDA_L; //SDA=0
Delay_us(5);
}
/************ IIC-stop ***************/
void MMA8452_I2C_Stop(void)
{
MMA8452_SDA_L; //SDA=0
MMA8452_SCL_H; //SCL=1
Delay_us(5);
MMA8452_SDA_H; //SDA=1
Delay_us(5);
}
/************* IIC-SendASK ***************/
/**********ack = 0 ACK, ack = 1 NACK********/
void MMA8452_SendAck(uchar ack)
{
MMA8452_SDA_Mode_Out();//SDA配置为输出模式
if(ack == 0)
{
MMA8452_SDA_L;
}
else
{
MMA8452_SDA_H;
}
Delay_us(5);
MMA8452_SCL_H;
Delay_us(5);
MMA8452_SCL_L;
}
/************* IIC-ReceiveASK *********/
BYTE RecvAck(void)
{
uchar ACK_Flag = 0;
MMA8452_SDA_Mode_In();//SDA设置为输入模式
MMA8452_SCL_L;
MMA8452_SDA_H;
Delay_us(5);
MMA8452_SCL_H;
Delay_us(5);
if(MMA8452_SDA == 0)
ACK_Flag = 1;
else
ACK_Flag = 0;
MMA8452_SCL_L;
return ACK_Flag;
}
/************ IIC-send 1 byte ***************/
void MMA8452_SendByte(u8 dat)
{
u8 i = 8;
MMA8452_SDA_Mode_Out(); //SDA配置成上拉输出
for(i = 0; i < 8; i++)
{
if(dat & 0x80)
{
MMA8452_SDA_H; //SDA=1
}
else
{
MMA8452_SDA_L; //SDA=0
}
MMA8452_SCL_L; //SCL=0
Delay_us(5);
MMA8452_SCL_H; //SCL=1
Delay_us(5);
MMA8452_SCL_L; //SCL=0
dat <<= 1;
}
RecvAck();
}
/************ IIC-receive 1 byte ***************/
BYTE MMA8452_RecvByte(void)
{
u8 i = 8;
BYTE data = 0;
MMA8452_SDA_Mode_Out();//SDA配置成上拉输出模式
MMA8452_SDA_H; //SDA=1
MMA8452_SDA_Mode_In();//SDA配置成上拉输入模式
for(i = 0; i < 8; i++)
{
data <<= 1;
MMA8452_SCL_H; //SCL=1
Delay_us(5);
if(Get_I2C_SDA() == 1) //读数据
{
data |= 1;
}
else
{
data |= 0;
}
MMA8452_SCL_L; //SCL=0
Delay_us(5);
}
MMA8452_SDA_Mode_Out();//SDA配置成上拉输出模式
return data;
}
/****************** 单字节写入 *******************/
void MMA8452_Single_Write(uchar REG_Address,uchar REG_data)
{
MMA8452_I2C_Start(); //起始信号
MMA8452_SendByte(SlaveAddress); //写入从机地址+写
MMA8452_SendByte(REG_Address); //写入内部寄存器地址
MMA8452_SendByte(REG_data); //写入数据到内部寄存器
MMA8452_I2C_Stop(); //停止信号
}
/****************** 单字节读取 *******************/
uchar MMA8452_Single_Read(uchar REG_Address)
{
uchar REG_data;
MMA8452_I2C_Start(); //起始信号
MMA8452_SendByte(SlaveAddress); //写入从机地址+写
MMA8452_SendByte(REG_Address); //写入内部寄存器地址
MMA8452_I2C_Start(); //起始新号
MMA8452_SendByte(SlaveAddress+1); //写入从机地址+读
REG_data=MMA8452_RecvByte(); //接收一个字节
MMA8452_SendAck(1); //ASK反馈信号
MMA8452_I2C_Stop(); //停止信号
return REG_data;
}
/*
*功能:MMA8452三轴数据
*输入:无
*输出:无
*/
void MMA8452_read_xyz_12bit(void)
{
u8 data_x_l,data_y_l,data_z_l;
u16 data_x_h,data_y_h,data_z_h;
data_x_h = MMA8452_Single_Read(0x01) & 0x00ff;//x轴高8位
data_x_l = MMA8452_Single_Read(0x02) & 0x00f0;//x轴低8位
data_y_h = MMA8452_Single_Read(0x03) & 0x00ff;
data_y_l = MMA8452_Single_Read(0x04) & 0x00f0;
data_z_h = MMA8452_Single_Read(0x05) & 0x00ff;
data_z_l = MMA8452_Single_Read(0x06) & 0x00f0;
data_x = (data_x_h << 8) | data_x_l;
data_y = (data_y_h << 8) | data_y_l;
data_z = (data_z_h << 8) | data_z_l;
}
/*
*功能;获取角度
*输入:无
*输出:无
*/
void MMA8452_Get(void)
{
//u8 i;
float Q,K;
//int64_t x_sum = 0,y_sum = 0,z_sum = 0;
//for(i = 0; i <= 1; i++)
//{
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
delay10ms();
MMA8452_read_xyz_12bit();
//x_sum = x_sum + data_x;
//y_sum = y_sum + data_y;
//z_sum = z_sum + data_z;
//}
//data_x = x_sum / 2;
//data_y = y_sum / 2;
//data_z = z_sum / 2;
Q = (float)data_x * 3.9;
//T = (float)data_y * 3.9;
K = (float)data_z * 3.9;
Q=-Q;
//T = -T;
Pitch = (float)((atan2(Q,K) * 180) / 3.14159265); //Ö»ÐèÒªÕâ¸öÖá
}