本文以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 <math.h>
#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); //Ö»ÐèÒªÕâ¸öÖá
}