主函数部分
#define MMA7660ADRW 0x98 // write address
#define MMA7660ADRR 0x99 // read address
#define True 1
#define False 0
#define CHSBIT6 0x0040
#define True 1
#define False 0
#define ZERO 0
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
#define SIX 6
#define SEVEN 7
#define EIGHT 8
#define NINE 9
#define TEN 10
#define HUNDRED 100
#define THOUSAND 1000
#define HALFBYTEMAX 15
#define ONEBYTEMAX 255
//输出方向值
enum{
DIRT0, //正向
DIRT1, //左向
DIRT2, //右向
DIRT3 //反向
};
//重力传感器Pola状态(过去.现在)
u8 Pre_PoLaStatus, Cur_PoLaStatus;
//方向输出控制
u8 DirtOutputFlag = False;
//系统方向值
u8 Dirt_Vaule = DIRT0;
//内部寄存器地址 Xout/TILT
const u8 AddressXout[] = {0x00}, AddressTILT[] = {0x03};
//方向检测控制
u8 Dirt_CheckFlag = True;
//开启模块并执行初始化
void DirtModeOn(void)
{
/* 0x07模式寄存器,待机模式, 自动睡眠计数器分频系数为 1 */
u8 Data1[]= {0x07,0x00};
/*0x05--Sleep Count Register ,0xff--32秒后进入睡眠状态,0x03--前后左右上下方向改变,产生中断*/
u8 Data2[]= {0x05,0xff,0x03};
/*0x08--Sample Rate Register,在活跃状态下 8 samples/second ,
在睡眠状态下,1 sample/second,2个测量样本相匹配,则更新TILT寄存器 */
u8 Data3[]= {0x08,0x3c,0xe0,0x00};
/* 0x07模式寄存器,活跃模式,自动睡眠使能,自动唤醒使能, 自动睡眠计数器分频系数为 1 */
/*中断推挽输出,低电平有效(下降沿)*/
u8 Data4[]={0x07,0x59};
//I2C_ON();
I2C_Send(MMA7660ADRW,Data1,TWO); //在对其他寄存器进行操作前,应该先让mma7660处于待命模式
I2C_Send(MMA7660ADRW,Data2,THREE); //初始化自动 睡眠寄存器(0x05)和中断 配置寄存器(0x06)
I2C_Send(MMA7660ADRW,Data3,FOUR); //设置采样率,不使能tap检测,
I2C_Send(MMA7660ADRW,Data4,TWO); //进入active模式
//Driver_I2COFF();
}
//x/y/z-out加速度对应值
//0 +:1-22 -:63-42
const u16 G_Num[] = {0, 47, 94, 141, 188, 234, 281, 328, 375, 422, 469, 516, 563, 609, 656, 703, 750, 797, 844, 891, 938, 984, 1000};
//当前加速度值0-2000
u16 XOut = 0;
u16 YOut = 0;
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72); //延时初始化
IIC_Init();
LED_Init(); //初始化与LED连接的硬件接口
usmart_dev.init(72); //初始化USMART
//方向传感器
DirtModeOn();
while(1)
{
u8 Buff[4];
u32 DelayTimer;
//读一次重力传感器的Xout.Yout.Zout.TILT
I2C_Send(MMA7660ADRW, (u8*)AddressXout, 1);
I2C_Recv(MMA7660ADRR, Buff, 4);
if(Buff[3]&CHSBIT6)
{
//若设备正在更新状态,再读一次TILT
I2C_Send(MMA7660ADRW, (u8*)AddressTILT, 1);
I2C_Recv(MMA7660ADRR, &Buff[3], 1);
}
//获取POLA状态位 可用于简单判断方向值
Cur_PoLaStatus = ((Buff[3])>>2)&0x07;
//这里我们获取x/y/z-out值,存于Buff[0],Buff[1],Buff[2]中
//本实验只需用到x-out与y-out值
printf("%d\r\n",Buff[0]);
printf("%d\r\n",Buff[1]);
printf("%d\r\n",Buff[2]);
if(!(Buff[0]&CHSBIT6))
{
//bit6为零 x-out为有效值
static u8 Num = 0;
static s16 Temp[10];
//采集加速度值并转换(-1000~1000)
if(Buff[0] == 0 || (Buff[0] >=1 && Buff[0] <= 22))
Temp[Num++] = G_Num[Buff[0]];
else if(Buff[0] >=42 && Buff[0] <= 63)
{
Buff[0] -= 41;
Buff[0] = 23 - Buff[0];
Temp[Num++] = -G_Num[Buff[0]];
}
//消抖求平均值
if(Num == 10)
{
u8 i;
s16 BuffTemp;
//找出最小值
for(i=0; i<9; i++)
if(Temp < Temp[i+1])
{
BuffTemp = Temp[i+1];
Temp[i+1] = Temp;
Temp = BuffTemp;
}
//找出最大值
for(i=0; i<8; i++)
if(Temp > Temp[i+1])
{
BuffTemp = Temp[i+1];
Temp[i+1] = Temp;
Temp = BuffTemp;
}
//计算平均值
XOut = (Temp[0] + Temp[1] + Temp[2] + Temp[3] + Temp[4] + Temp[5] + Temp[6] + Temp[7])/8 + 1000;
//led显示
if(XOut <= 1000)
{
// printf("%d",(1000-XOut));
}
else
{
printf("%d",(XOut-1000));
}
Num = 0;
}
}
/*IIC部分*******************************************************************************************/
//初始化IIC
void IIC_Init(void)
{
RCC->APB2ENR|=1<<3;//先使能外设IO PORTB时钟
GPIOB->CRL&=0X00FFFFFF;//PB1/11 推挽输出
GPIOB->CRL|=0X33000000;
// GPIOB->ODR|=3<<6; //PB10,11 输出高
}
//产生IIC起始信号
void I2C_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void I2C_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;delay_us(1);
IIC_SCL=1;delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
I2C_Stop();
return 1;
}
}
IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void I2C_ACK(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//不产生ACK应答
void I2C_NACK(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void I2C_SendAByter(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 I2C_ReadAByter(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
I2C_NACK();//发送nACK
else
I2C_ACK(); //发送ACK
return receive;
}
void I2C_Send(u8 Address, u8 *DataBuff, u16 DataLen)
{
//发启始条件
I2C_Start();
//发从地址
I2C_SendAByter(Address);
//等待ACK应答
IIC_Wait_Ack();
//发送数据
for(; DataLen>0; DataLen--, DataBuff++)
{
//发数据
I2C_SendAByter(*DataBuff);
//等待ACK应答
IIC_Wait_Ack();
}
//发停止
I2C_Stop();
}
void I2C_Recv(u8 Address, u8 *DataBuff, u16 DataLen)
{
//发启始条件
I2C_Start();
//发从地址
I2C_SendAByter(Address);
//等待ACK应答
IIC_Wait_Ack();
//接收数据,读DataLen-1个数
for(;DataLen>1;DataLen--,DataBuff++)
{
//等待寄存器为满
*DataBuff = I2C_ReadAByter(1);
//发应答
}
*DataBuff = I2C_ReadAByter(0);
//发停止
I2C_Stop();
}
/*IIC头文件***************************************************************/
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=8<<7;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=3<<7;}
//IO操作函数
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //输入SDA
//IIC所有操作函数
void IIC_Init(void);
void I2C_Send(u8 Address,u8 *DataBuff,u16 DataLen);
void I2C_Recv(u8 Address,u8 *DataBuff,u16 DataLen);
#endif
主函数部分我是从库函数程序那边复制过来的。
|