#include <avr/io.h>
//#include "IIC.h"
/***********模拟IIC IO **************/
#define AT_SCL_H PORTC|=(1<<0) //PC0
#define AT_SCL_L PORTC&=~(1<<0)
#define AT_SDA_H PORTC|=(1<<1) //PC1
#define AT_SDA_L PORTC&=~(1<<1)
#define SDA_IN DDRC&=~(1<<1);PORTC |=0x02//上拉电阻
#define SDA_OUT DDRC|=(1<<1)
#define SDA_DATA (PINC&0x02)
#define SCL_OUT DDRC|=(1<<1)
/***************** Address ******************/
#define WD_DEVICE_ADDR 0xD0//0xA6 MPU6050地址为0x68
#define RD_DEVICE_ADDR 0XD1//0xA7 //看手册即可知道
//unsigned char WD_DEVICE_ADDR=0xD0,RD_DEVICE_ADDR=0XD1; //为了改变IIC写入读出地址方便
unsigned char BUF[16],Data[6];
void delay_us(unsigned int us)//1us
{
while(us--);
asm("nop");
/* unsigned int i;
for (i=0;i<40;i++)asm ("nop");*/
}
void delay_1ms(void) //1ms延时函数
{
unsigned int i;
for (i=0;i<1140;i++)asm ("nop");
}
void delay_nms(unsigned int n) //N ms延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1ms();
}
/**************************************
起始信号
**************************************/
void AT24C04_Start()
{
SDA_OUT;
SCL_OUT;
AT_SDA_H; //拉高数据线
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
AT_SDA_L; //产生下降沿
delay_us(5); //延时
AT_SCL_L; //拉低时钟线
}
/**/
/**************************************
停止信号
**************************************/
void AT24C04_Stop()
{
SDA_OUT;
SCL_OUT;
AT_SDA_L; //拉低数据线
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
AT_SDA_H; //产生上升沿
delay_us(5); //延时
}
/**/
/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void AT24C04_SendACK(unsigned char ack)
{
SCL_OUT;
SDA_OUT;
if(ack==1)AT_SDA_H;
else AT_SDA_L; //写应答信号
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
AT_SCL_L; //拉低时钟线
delay_us(5); //延时
}
/**/
/**************************************
接收应答信号
**************************************/
unsigned char AT24C04_RecvACK()
{
SCL_OUT;
unsigned char i=0;
SDA_IN;
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
//i = SDA_DATA; //读应答信号
if(SDA_DATA) i=1;
AT_SCL_L; //拉低时钟线
delay_us(5); //延时
SDA_OUT;
return i;
}
/**/
/**************************************
向IIC总线发送一个字节数据
**************************************/
void AT24C04_SendByte(unsigned char dat)
{
unsigned char i;
SDA_OUT;
SCL_OUT;
for (i=0; i<8; i++) //8位计数器
{
if(dat&0x80)AT_SDA_H;else AT_SDA_L;
dat <<= 1; //移出数据的最高位
//送数据口
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
AT_SCL_L; //拉低时钟线
delay_us(4); //延时 此处延时长了点
}
AT24C04_RecvACK();
}
/**/
/**************************************
从IIC总线接收一个字节数据 注意 SDA SCL IO 改变
**************************************/
unsigned char AT24C04_RecvByte()
{
unsigned char i;
unsigned char dat = 0;
SDA_IN;
SCL_OUT;
AT_SDA_H;
//DDRC&=0xFD; //使能内部上拉,准备读取数据
for (i=0; i<8; i++) //8位计数器
{
dat <<= 1;
AT_SCL_H; //拉高时钟线
delay_us(5); //延时
if(SDA_DATA)
dat |=0x01;
//dat |= (SDA_DATA>>4); //读数据 /////////////////////////////////////???????
AT_SCL_L; //拉低时钟线
delay_us(5); //延时 ///////
}
//DDRC|=0x02;
SDA_OUT;
return dat;
}/**/
//***************************************************
void WriteByte(unsigned char REG_Address,unsigned char REG_data)
{
AT24C04_Start(); //起始信号
AT24C04_SendByte(WD_DEVICE_ADDR); //发送设备地址+写信号
AT24C04_SendByte(REG_Address); //内部寄存器地址,请参考中文pdf
AT24C04_SendByte(REG_data); //内部寄存器数据,请参考中文pdf
AT24C04_Stop(); //发送停止信号
}
//********单字节读取内部寄存器*************************
unsigned char Single_Read(unsigned char REG_Address)
{ unsigned char REG_data;
AT24C04_Start(); //起始信号
AT24C04_SendByte(WD_DEVICE_ADDR); //发送设备地址+写信号
AT24C04_SendByte(REG_Address); //发送存储单元地址,从0开始
AT24C04_Start(); //起始信号
AT24C04_SendByte(WD_DEVICE_ADDR+1); //发送设备地址+读信号
REG_data=AT24C04_RecvByte(); //读出寄存器数据
AT24C04_SendACK(1);
AT24C04_Stop(); //停止信号
return REG_data;
}
/**************************************
向AT24C04写1页(16字节)数据
将TESTDATA开始的16个测试数据写如设备的00~0F地址中
**************************************/
/*void AT24C04_WritePage()
{
unsigned char i;
AT24C04_Start(); //起始信号
AT24C04_SendByte(0xa0); //发送设备地址+写信号
AT24C04_SendByte(0x00); //发送存储单元地址
for (i=0; i<16; i++)
{
AT24C04_SendByte(TESTDATA[i]);
}
AT24C04_Stop(); //停止信号
}
*/
/**************************************
从 ADXL345 读取0x32~0x37数据 并存放 Data[6]
**************************************/
void ADXL345_ReadPage()
{
unsigned char i;
AT24C04_Start(); //起始信号
AT24C04_SendByte(WD_DEVICE_ADDR); //发送设备地址+写信号
AT24C04_SendByte(0x32); //发送存储单元地址,从0x32开始
AT24C04_Start(); //起始信号
AT24C04_SendByte(WD_DEVICE_ADDR+1); //发送设备地址+读信号
for (i=0; i<6; i++)
{
Data[i] = AT24C04_RecvByte();
//send_date(BUF[i]);
if (i == 5)
{
AT24C04_SendACK(1); //最后一个数据需要会NAK
}
else
{
AT24C04_SendACK(0); //回应ACK
}
}
AT24C04_Stop(); //停止信号
delay_nms(5);
}
//#include "IIC.h"
#include<avr/interrupt.h>
//#define CLK 7372800
#define CLK 8000000
//****************************************
// 定义MPU6050内部地址
//****************************************
#define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress 0xD0 //IIC写入时的地址字节数据,+1为读取
#define L_on PORTD |=0x80//
#define L_off PORTD &=0x7F
#define Key (PIND&0x01)
unsigned char value;
void init_uart(unsigned int baud)
{
UCSRB=0x00;
UCSRA=0x00; //控制寄存器清零
UCSRC=(1<<URSEL)|(0<<UPM0)|(3<<UCSZ0); //选择UCSRC,异步模式,禁止校验,1位停止位,8位数据位
UBRRL=(CLK/16/baud-1)%256;
UBRRH=(CLK/16/baud-1)/256; //设置波特率
UCSRB=(1<<TXEN)|(1<<RXEN)|(1<<RXCIE); //接收、发送使能,接收中断使能
sei(); //全局中断开放
DDRD|=0X02; //配置TX为输出(很重要)TX--PD1,RX--PD0
}
void send_date(unsigned char date)
{
while(!(UCSRA&(1<<UDRE))); //等待数据寄存器空
UDR=date;
while(!(UCSRA&(1<<TXC))); //等待发送结束
UCSRA|=(1<<TXC); //写1清零
}
//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345()
{
WriteByte(0x31,0x0B); //测量范围,正负16g,13位模式
WriteByte(0x2C,0x08); //速率设定为12.5 参考pdf13页
WriteByte(0x2D,0x08); //选择电源模式 参考pdf24页
WriteByte(0x2E,0x80); //使能 DATA_READY 中断
WriteByte(0x1E,0x00); //X 偏移量 根据测试传感器的状态写入pdf29页
WriteByte(0x1F,0x00); //Y 偏移量 根据测试传感器的状态写入pdf29页
WriteByte(0x20,0x05); //Z 偏移量 根据测试传感器的状态写入pdf29页
}
/***************** 等待延时 12000≈80S********************/
unsigned char waitkey ( unsigned int i1 )
{
while ( i1-- )
{
if ( !Key)
{return 1;}
delay_nms ( 5 );
}
return 0;
}
void n_to_c(int i)//数值转为字符并通过串口输出
{
float i1;
unsigned char temp1;
// i=i/64;
if(i<0){i=-i;send_date('-');}
else send_date(' ');
i1=(float)i/64; //for 加速度测量 1 LSB 代表3.9 mg
i=(int)i1;
temp1=i/10000;
if(temp1==0)send_date(' '); else send_date(temp1+'0');
i %=10000;
send_date(i/1000+'0');
send_date('.');
i %=1000;
send_date(i/100+'0');
i %=100;
send_date(i/10+'0');
send_date(i%10+'0');
//小数点
send_date('g');
}
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
WriteByte(PWR_MGMT_1, 0x00); //解除休眠状态
WriteByte(SMPLRT_DIV, 0x07);
WriteByte(CONFIG, 0x06);
WriteByte(GYRO_CONFIG, 0x18);
WriteByte(ACCEL_CONFIG, 0x01);
}
/*******************通过MPU6050辅助IIC接口写数据到 从机0***********************/
/***********本函数针对 从机0编写,若要操作从机 1-4请查阅6050寄存器数据手册,注意从机4叫特殊只能读取一个字节的值*********/
void Auxiliary_I2C_Write(unsigned char add,unsigned char da)
{
WriteByte(0x25,0x53);//写入从机0地址 写模式
WriteByte(0x26,add);//数据从 I2C_SLV0_REG指定的地址
WriteByte(0x27,0x81);//使能数据传输 字节长度1
WriteByte(0x63,da); //要写入的值 注意先使能数据传输 后写值到I2C_SLV0_DO !
}
int main(void)
{
unsigned char i=0,i1=0;
int temp=0;
// DDRD |=0xC0;//??????
// PORTD &=0xBF;
DDRD|=(1<<1);
PORTD |=(1<<1);
// DDRC |=0x30;//IIC port init 要改成PC0--SCL,PC1--SDA!!!!
init_uart(9600);
InitMPU6050(); //初始化MPU6050
Init_ADXL345();
WriteByte(0x6A,0x20);//I2C_MST_EN 使能I2C主机模式 0x20
//WriteByte(0x37,0x02);//I2C_BYPASS_EN 为了直接接到辅助IIC接口,此时可不要
/// Pass-Through Mode:I2C_MST_EN=0 I2C_BYPASS_EN =1即可直接接到旁路IIC,注意修改IIC读/写的从机地址
//通过 auxiliary I2C Interface 初始化ADXl345
/*
Auxiliary_I2C_Write(0x31,0x0B);
Auxiliary_I2C_Write(0x2C,0x08);
Auxiliary_I2C_Write(0x2D,0x08);
Auxiliary_I2C_Write(0x2E,0x80);
Auxiliary_I2C_Write(0x1E,0);
Auxiliary_I2C_Write(0x1F,0);
Auxiliary_I2C_Write(0x20,0x05);
*/
//MPU6050 读取并显示,由于本程序以介绍MPU6050辅助IIC接口为主,所以屏蔽了此部分
while(1)
{
ADXL345_ReadPage();
waitkey(400);
Data[0]=Single_Read(ACCEL_XOUT_H);
Data[1]=Single_Read(ACCEL_XOUT_L);
Data[2]=Single_Read(ACCEL_YOUT_H);
Data[3]=Single_Read(ACCEL_YOUT_L);
Data[4]=Single_Read(ACCEL_ZOUT_H);
Data[5]=Single_Read(ACCEL_ZOUT_L);
temp=(Data[0]<<8)+Data[1];
send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[2]<<8)+Data[3];
send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[4]<<8)+Data[5];
send_date('Z');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');send_date(' ');send_date(' ');
Data[0]=Single_Read(GYRO_XOUT_H);
Data[1]=Single_Read(GYRO_XOUT_L);
Data[2]=Single_Read(GYRO_YOUT_H);
Data[3]=Single_Read(GYRO_YOUT_L);
Data[4]=Single_Read(GYRO_ZOUT_H);
Data[5]=Single_Read(GYRO_ZOUT_L);
temp=(Data[0]<<8)+Data[1];
send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[2]<<8)+Data[3];
send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[4]<<8)+Data[5];
send_date('Z');send_date(':');n_to_c(temp);
send_date(0x0d);send_date(0x0a);//换行
}
/* while(1)
{*/
/*****************6050 master mode 下从从机0(0x53)读取起始位置0x32的6字节数据******************/
/* WriteByte(0x25,0xD3);//读出从机地址 读模式
WriteByte(0x26,0x32);//数据从 I2C_SLV0_REG指定的地址
WriteByte(0x27,0x86);//使能数据传输 字节长度6(bit 3-0 为字节数)
L_on;
waitkey(100);
*/
/*** 在MPU6050 master mode 下读取 ADXL345 EXT_SENS_DATA_00~EXT_SENS_DATA_05***/
/* Data[0]=Single_Read(0x49);delay_nms(10);
Data[1]=Single_Read(0x4A);delay_nms(10);
Data[2]=Single_Read(0x4B);delay_nms(10);
Data[3]=Single_Read(0x4C);delay_nms(10);
Data[4]=Single_Read(0x4D);delay_nms(10);
Data[5]=Single_Read(0x4E);
//显示输出部分
temp=(Data[1]<<8)+Data[0];//1 LSB 代表3.9 mg
send_date('X');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[3]<<8)+Data[2];//1 LSB 代表3.9 mg
send_date('Y');send_date(':');n_to_c(temp);send_date(' ');send_date(' ');send_date(' ');
temp=(Data[5]<<8)+Data[4];//1 LSB 代表3.9 mg
send_date('Z');send_date(':');n_to_c(temp);
send_date(0x0d);send_date(0x0a);
L_off;
waitkey(100);
}
*/
}
/***************串口接收中断***************/
/********捕捉同步字,接收1000字节内结束*******/
SIGNAL ( USART_RXC_vect )
{
UCSRB&=~ ( 1<<RXCIE ); //关接受结束中断使能
value=UDR;
//send_date(value);/////////////////
UCSRB|= ( 1<<RXCIE ); // 开接受结束中断使能
}
|