/**********************頭文件*************************/
#include <reg52.h>
#include <math.h>
#include <intrins.h>
#include <lcd.h> //1602顯示
#include <ADXL345.h> //測量角度
#include <HCSR04.h>
/*************************主函數***************************/
void main(void)
{
delay_ms(5); //上電延時
UART_init(); //串口初始化
ADXL345_init(); // ADXL345的初始化
LcdInit(); // LCD的初始化;
ID=Read_Data_Reg(0x00); // 讀出機器ID值,DEVID寄存器保存0xE5的固定器件ID代碼
while(1)
{
Read_Data(); //讀出X Y Z 軸加速度值
transform(); //數據重建過程
calculate_angle(XX,YY,ZZ); //計算x和y軸相對于水平面的傾角
calculate(); // ASCII碼計算
display_LCD(); // 顯示
get_temp_data(); //獲取超聲波測距距離 單位CM
dispaly_data(); //顯示超聲波數據
}
}
#include <reg52.h>
#include <intrins.h>
#include <lcd.h>
#include <HCSR04.h>
/*----------------------------
超聲波測距模塊
-----------------------------*/
uchar serial[4];
uchar cnt,sum,temp;
uint temp_data = 0;
bit flag1;
uchar Average_flag = 0;
uint sum_data = 0;
uint Average_data = 0;
/*----------------------------
UART 中斷服務程序
-----------------------------*/
void serial_serve() interrupt 4 //串口中斷4號
{
EA=0;//
RI=0;
temp=SBUF;//讀第一個字節,如果是0XFF的話,說明是啟使碼對了
switch(cnt)
{
case 0:serial[0]=temp;
if(serial[0]==0xff)
{
cnt=1;
flag1=0;
}
else
cnt=0; break;
case 1:serial[1]=temp;cnt=2;break;
case 2:serial[2]=temp;cnt=3;break;
case 3:serial[3]=temp;cnt=0;flag1=1;break;
}
EA=1;
}
void UART_init()
{
SCON = 0x50; //8位數據,可變波特率
AUXR |= 0x40; //定時器1時鐘為Fosc,即1T
AUXR &= 0xFE; //串口1選擇定時器1為波特率發生器
TMOD &= 0x0F; //設定定時器1為16位自動重裝方式
TL1 = 0xE0; //設定定時初值
TH1 = 0xFE; //設定定時初值
ET1 = 0; //禁止定時器1中斷
TR1 = 1; //啟動定時器1
EA = 1; //開總中斷
ES = 1; //開串口中斷
cnt=0;
}
void dispaly_data()
{
LcdWriteCom(0x80+0x40);
LcdWriteData('H');
LcdWriteData('=');
LcdWriteData('0'+Average_data/1000);
LcdWriteData('0'+Average_data/100%10);
LcdWriteData('0'+Average_data/10%10);
LcdWriteData('.');
LcdWriteData('0'+Average_data%10);
LcdWriteData('c');
LcdWriteData('m');
}
void get_temp_data(void)
{
if(flag1==1)
{ //進行校驗,如果校驗正確,則采集數據
sum=serial[0]+serial[1]+serial[2];
if(sum==serial[3])
{ //將兩個字節合并成一個16位的int
temp_data= serial[1] ;
temp_data<<=8;
temp_data= temp_data|serial[2] ;
// temp_data/=10;//毫米單位轉換成厘米單位
Average_flag++;
sum_data=sum_data+temp_data; //累加
if(Average_flag == 16)
{
Average_data=sum_data/16+20;
Average_flag = 0;
sum_data = 0;
temp = 0;
}
}
}
}
#include"lcd.h"
/*******************************************************************************
* 函 數 名 : Lcd1602_Delay1ms
* 函數功能 : 延時函數,延時1ms
* 輸 入 : c
* 輸 出 : 無
* 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c) //誤差 0us
{
uchar i,j;
for (; c>0; c--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
/*******************************************************************************
* 函 數 名 : LcdWriteCom
* 函數功能 : 向LCD寫入一個字節的命令
* 輸 入 : com
* 輸 出 : 無
*******************************************************************************/
#ifndef LCD1602_4PINS //當沒有定義這個LCD1602_4PINS時
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_E = 0; //使能
LCD1602_RS = 0; //選擇發送命令
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = com; //放入命令
Lcd1602_Delay1ms(1); //等待數據穩定
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5); //保持時間
LCD1602_E = 0;
}
#else
void LcdWriteCom(uchar com) //寫入命令
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 0; //選擇寫入命令
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = com; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
// Lcd1602_Delay1ms(1);
LCD1602_DATAPINS = com << 4; //發送低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 數 名 : LcdWriteData
* 函數功能 : 向LCD寫入一個字節的數據
* 輸 入 : dat
* 輸 出 : 無
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdWriteData(uchar dat) //寫入數據
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇輸入數據
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = dat; //寫入數據
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5); //保持時間
LCD1602_E = 0;
}
#else
void LcdWriteData(uchar dat) //寫入數據
{
LCD1602_E = 0; //使能清零
LCD1602_RS = 1; //選擇寫入數據
LCD1602_RW = 0; //選擇寫入
LCD1602_DATAPINS = dat; //由于4位的接線是接到P0口的高四位,所以傳送高四位不用改
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
LCD1602_DATAPINS = dat << 4; //寫入低四位
Lcd1602_Delay1ms(1);
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(5);
LCD1602_E = 0;
}
#endif
/*******************************************************************************
* 函 數 名 : LcdInit()
* 函數功能 : 初始化LCD屏
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
#ifndef LCD1602_4PINS
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x38); //開顯示
LcdWriteCom(0x0c); //開顯示不顯示光標
LcdWriteCom(0x06); //寫一個指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //設置數據指針起點
}
#else
void LcdInit() //LCD初始化子程序
{
LcdWriteCom(0x32); //將8位總線轉為4位總線
LcdWriteCom(0x28); //在四位線下的初始化
LcdWriteCom(0x0c); //開顯示不顯示光標
LcdWriteCom(0x06); //寫一個指針加1
LcdWriteCom(0x01); //清屏
LcdWriteCom(0x80); //設置數據指針起點
}
#endif
/**********************頭文件*************************/
#include <reg52.h>
#include <math.h>
#include <intrins.h>
#include <lcd.h>
#include <ADXL345.h>
/***********************宏定義***********************/
#define uchar unsigned char
#define uint unsigned int
/***********************函數聲明**********************/
//void write_comd(uchar);
//void write_data_LCD(uchar);
/***********************全局變量**********************/
uint Data_X_2[2]; // 讀出的數據儲存 X Y Z
uint Data_Y_2[2];
uint Data_Z_2[2];
int Data_X,Data_Y,Data_Z; // 數值轉換后的值
float XX,YY,ZZ; // 3軸的重力加速度分量
uchar ID;
float roll,pitch;
uchar dis1[16] = {"X+00.00 Y+00.00"};
/********************************************************************
* *
* 函數名: Delayms() *
* 功能描述:產生延遲 *
* 形參:ms 延遲的時間,單位ms *
* 返回值:無 *
* 局部變量:i *
* 全局變量:無 *
* 函數調用: 無 *
* *
********************************************************************/
void delay_ms(uchar ms)
{
uchar i;
while(ms--)
{
for(i = 0; i< 250; i++)
{
_nop_();
_nop_(); //空執行消耗CPU時間達到等待的效果
_nop_();
_nop_();
}
}
}
/********************************************************************
* *
* 函數名: Write_Data(uchar Data_write) *
* 功能描述:寫指令到寄存器 *
* 形參:Data_write 要寫的數據 8位 *
* 返回值:無 *
* 局部變量:i *
* 全局變量:無 *
* 函數調用: _nop_(); *
* *
********************************************************************/
/*************************寫數據函數*******************/
void Write_Data(uchar Adress_Reg,uchar Data_write)
{
uchar i=0;
Adress_Reg=(Adress_Reg & 0x7f); // 置最高位位0 寫狀態
Adress_Reg=(Adress_Reg & 0xbf); // 置第二高位0 單字節讀寫
CS=0;
_nop_();
SCLK=1;
_nop_();
for(i=0;i<8;i++) // 8位串行輸出 寄存器地址值
{
SCLK=0;
_nop_();
SDI=(bit)(Adress_Reg & 0x80);
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
Adress_Reg<<=1;
}
for(i=0;i<8;i++) // 8位串行輸出 指令值
{
SCLK=0;
_nop_();
SDI=(bit)(Data_write & 0x80);
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
Data_write<<=1;
}
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
SDI=1;
CS=1;
}
/********************************************************************
* *
* 函數名: Read_Data_Reg(uchar Adress_Reg) *
* 功能描述:往寄存器讀數據 *
* 形參:Adress_Reg 寄存器地址 *
* 返回值: Data_Read 讀取的數據 *
* 局部變量:i Data_Read 讀取的數據 *
* 全局變量:無 *
* 函數調用: _nop_(); *
* *
********************************************************************/
uchar Read_Data_Reg(uchar Adress_Reg)
{
uchar i=0;
uchar Data_Read;
Adress_Reg=(Adress_Reg|0x80); // 置最高位為1, 讀狀態
Adress_Reg=(Adress_Reg&0xbf); // 置第二高位位0, 單字節讀寫
CS=0;
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
for(i=0;i<8;i++) // 8位串行輸出 寄存器地址值
{
SCLK=0;
_nop_();
SDI=(bit)(Adress_Reg & 0x80);
_nop_();
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
Adress_Reg<<=1;
}
for(i=0;i<8;i++) // 8位串行讀入 數據(8位)
{
SCLK=0;
Data_Read<<=1;
_nop_();
Data_Read|=(uchar)SDI;
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
}
for(i=0;i<8;i++) // 產生8個脈沖 (手冊要求,目的不知道)
{
SCLK=0;
_nop_();
_nop_();
SCLK=1;
_nop_();
_nop_();
}
_nop_();
_nop_();
SCLK=1;
_nop_();
CS=1;
return Data_Read;
}
/********************************************************************
* *
* 函數名: Read_Data() *
* 功能描述:讀出6字節X Y Z 軸各兩字節的數據 *
* 形參: 無 *
* 返回值: 無 *
* 局部變量:無 *
* 全局變量:Data_X_2[2] Data_Y_2[2] Data_Z_2[2] 存放讀出值 *
* 函數調用:Read_Data_Reg(__);delay_ms(__); *
* *
********************************************************************/
void Read_Data()
{
/*DATAX0是X軸加速度的低字節寄存器,DATAX1是高字節寄存器*/
Data_X_2[0]=Read_Data_Reg(0x32); // 讀出X軸低位
Data_X_2[1]=Read_Data_Reg(0x33); // 讀出X軸高位
delay_ms(10);
Data_Y_2[0]=Read_Data_Reg(0x34); // 讀出Y軸低位
Data_Y_2[1]=Read_Data_Reg(0x35); // 讀出Y軸高位
delay_ms(10);
Data_Z_2[0]=Read_Data_Reg(0x36); // 讀出Z軸低位
Data_Z_2[1]=Read_Data_Reg(0x37); // 讀出Z軸高位
}
/********************************************************************
* *
* 函數名: ADXL345_init() *
* 功能描述:ADXL345 初始化 對寄存器寫指令 *
* 形參: 無 *
* 返回值: 無 *
* 局部變量:無 *
* 全局變量:無 *
* 函數調用: Write_Data_Reg(__,__); *
* *
********************************************************************/
void ADXL345_init()
{
Write_Data(0x31,0x4f); //測量范圍為正負16g 13位模式 3線SPI 中斷低有效 禁用自測力 左對齊(MSB)模式
delay_ms(10);
Write_Data(0x2C,0x08); //速率設定為25HZ,帶寬12.5HZ
delay_ms(10);
Write_Data(0x2D,0x08); //選擇電源模式
delay_ms(10);
Write_Data(0x2E,0x80); //使能 DATA_READY 中斷
delay_ms(10);
Write_Data(0x2f,0x00); //中斷功能設定,不使用中斷
delay_ms(10);
/*Write_Data(0x1E,0x00); //X 偏移量 根據測試傳感器的
delay_ms(10);
Write_Data(0x1F,0x00); //Y 偏移量 根據測試傳感器的
delay_ms(10);
Write_Data(0x20,0x00); //Z 偏移量 根據測試傳感器的
delay_ms(10);
Write_Data(0x21,0x00); //敲擊延時0:禁用; (1.25ms/LSB)
delay_ms(10);
Write_Data(0x22,0x00); //檢測第一次敲擊后的延時0:禁用; (1.25ms/LSB)
delay_ms(10);
Write_Data(0x23,0x00); //敲擊窗口0:禁用; (1.25ms/LSB)
delay_ms(10);
Write_Data(0x24,0x00); //保存檢測活動閥值; (62.5mg/LSB)
delay_ms(10);
Write_Data(0x25,0x00); //保存檢測靜止閥值; (62.5mg/LSB)
delay_ms(10);
Write_Data(0x26,0x2b); //檢測活動時間閥值; (1s/LSB)
delay_ms(10);
Write_Data(0x27,0x00); // 活動 靜止檢測禁止
delay_ms(10);
Write_Data(0x28,0x09); //保存檢測活動閥值; (62.5mg/LSB)
delay_ms(10);
Write_Data(0x29,0xff); //保存檢測靜止閥值; (62.5mg/LSB)
delay_ms(10);
Write_Data(0x2a,0x80);
delay_ms(10);*/
}
/********************************************************************
* *
* 函數名: transform(void) *
* 功能描述:數值整合和轉換 ,并轉換為加速度 放大1000倍 *
* 形參: 無 *
* 返回值: 無 *
* 局部變量:無 *
* 全局變量:Data_X=0,Data_Y=0,Data_Z 整合后的X Y Z 軸值 *
* 函數調用:無 *
* *
********************************************************************/
/*從數據寄存器中獲取加速度數據后,用戶必須對數據進行重建*/
/***************************數值轉換***********************/
void transform(void)
{
(int)Data_X=(Data_X_2[0])+(Data_X_2[1]<<8);
(int)Data_Y=(Data_Y_2[0])+(Data_Y_2[1]<<8);
(int)Data_Z=(Data_Z_2[0])+(Data_Z_2[1]<<8);
if(Data_X&0x2000)
{ // 若位負數 轉換為補碼
Data_X=(~Data_X)+1;
Data_X=Data_X*3.90625; // 乘比例因素
Data_X=-Data_X;
}
else
{
Data_X=Data_X*3.90625;
}
if(Data_Y&0x2000)
{ // 若位負數 轉換為補碼
Data_Y=(~Data_Y)+1;
Data_Y=Data_Y*3.90625; // 乘比例因素
Data_Y=-Data_Y;
}
else
{
Data_Y=Data_Y*3.90625;
}
if(Data_Z&0x2000)
{ // 若位負數 轉換為補碼
Data_Z=(~Data_Z)+1;
Data_Z=Data_Z*3.90625; // 乘比例因素
Data_Z=-Data_Z;
}
else
{
Data_Z=Data_Z*3.90625;
}
/*if(Data_X<0)
{
Data_X=-Data_X;
Data_X=(float)Data_X*3.9;//Data_X單位為1000倍的g,即mg
}
else
{
Data_X=(float)Data_X*3.9;
}
if(Data_Y<0)
{
Data_Y=-Data_Y;
Data_Y=(float)Data_Y*3.9;
}
else
{
Data_Y=(float)Data_Y*3.9;
}
if(Data_Z<0)
{
Data_Z=-Data_Z;
Data_Z=(float)Data_Z*3.9;
}
else
{
Data_Z=(float)Data_Z*3.9;
}*/
/*擴大1000倍后結果*/
/*檢測軸始終檢測到的是正加速度*/
XX=Data_X; // X軸重力加速度分量
YY=Data_Y; // Y軸重力加速度分量
ZZ=Data_Z; // Z軸重力加速度分量
}
/********************************************************************
* *
* 函數名: calculate_angle(float V_x,float V_y,float V_z) *
* 功能描述:計算橫滾角和俯仰角 *
* 形參:G_x G_x G_z X Y Z軸的加速度值 *
* 返回值:無 *
* 局部變量:無 *
* 全局變量:roll pitch 橫滾角和俯仰角 *
* 函數調用:atan2(_,_); *
* *
********************************************************************/
/*********計算角度函數***************/
void calculate_angle(float G_x,float G_y,float G_z)
{
roll=-(float)(((atan2(G_z,G_x)*180)/3.1415926535)-90);//弧度轉成角度
pitch=-(float)(((atan2(G_z,G_y)*180)/3.1415926535)-90);
roll=roll*100;
pitch=pitch*100;
}
/*******************計算函數********************/
void calculate()
{
//uchar flag_X,flag_Y;
if(roll<0)
{
roll=-roll;
dis1[1]='-';//flag_X=45;
}
else
{
dis1[1]='+';
}
if(pitch<0)
{
pitch=-pitch;
dis1[10]='-';//flag_Y=45;
}
else
{
dis1[10]='+';
}
dis1[0]='X';
//dis1[1]=flag_X;
dis1[2]=(int)roll%10000/1000+48;
dis1[3]=(int)roll%10000%1000/100+48;
dis1[4]='.';
dis1[5]=(int)roll%10000%1000%100/10+48;
dis1[6]=(int)roll%10000%1000%100%10+48;
dis1[9]='Y';
//dis1[10]=flag_Y;
dis1[11]=(int)pitch%10000/1000+48;
dis1[12]=(int)pitch%1000/100+48;
dis1[13]='.';
dis1[14]=(int)pitch%1000%100/10+48;
dis1[15]=(int)pitch%1000%100%10+48;
}
void display_LCD()
{
uint i;
LcdWriteCom(0x80);//初始化數據指針,寫在第一行
for(i=0;i<16;i++)
{
LcdWriteData(dis1[i]);
ADXL345_delay(1);
}
}
/*******************延時函數********************/
void ADXL345_delay(uint k)
{
uint j,i;
for(j=k;j>0;j--)
for(i=100;i>0;i--);
}
|