久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
一個基于STC12單片機的無線運動監測器設計 含源碼與視頻
[打印本頁]
作者:
sanshuige
時間:
2018-6-25 15:53
標題:
一個基于STC12單片機的無線運動監測器設計 含源碼與視頻
畢設結束了,本來是想搞一個簡單的計步器的,這功能加的太多給變成運動監測器了。使用2個STC12C5A60S2,4個HC05,還有NEO-7N,PULSE SENSOR,BMP180,ADXL345以及簡單的1602和幾個獨立按鍵,實現的功能相當全面,具體如下:
有效檢測人體的運動狀態信息,記錄行動步數,并且能夠顯示心率,具體定位信息(經緯度,時間,日期,海拔高度,運動速度),溫度,氣壓。大體原理是:
通過藍牙由一個發送單片機將記錄的經過處理的數據(步數信息和心率信息)無線發送,接收單片機一方面通過藍牙無線接收(發送單片機發送的數據),另一方面通過藍牙無線接收
GPS
的數據。并且將數據在
LCD1602
上顯示,獨立按鍵在接收單片機上負責
LCD1602
顯示翻頁的功能。
正常本科的畢業設計應該不會用到如此多的功能,選其中幾個功能實現一下就可以了,反正就是能混則混。具體的程序,原理圖還有視頻我會貼出來的。視頻我發個百度網盤的鏈接吧
https://pan.baidu.com/s/1rQXeFTQxPRO0yWu5yOeLZQ [qq]1851215323[/qq]
單片機源程序:
#include <stc12c5a60s2.h>
#include <math.h>
#include <stdio.h>
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
//**************************************
#define false 0
#define true 1
#define FOSC 11059200L //系統時鐘
#define BAUD 115200 //波特率
#define T0MS (65536-FOSC/12/500) //500HZ在12T模式下
//**************************************
#define ADC_POWER 0x80 //ADC功率控制位
#define ADC_FLAG 0x10 //ADC完成標志
#define ADC_START 0x08; //ADC開始控制位
#define ADC_SPEEDLL 0x00 //轉換速度控制位SPEED0和SPEED1,共四種狀態,對應四種轉換速度
#define ADC_SPEEDL 0x20
#define ADC_SPEEDH 0x40
#define ADC_SPEEDHH 0x60
#define ADC_MASK 0x01
//**************************************
sbit SCL=P1^1; //IIC時鐘引腳定義
sbit SDA=P1^2; //IIC數據引腳定義
//**************************************
#define SlaveAddress 0xA6 //定義器件在IIC總線中的從地址,根據ALT ADDRESS地址引腳不同修改
//ALT ADDRESS引腳接地時地址為0xA6,接電源時地址為0x3A
typedef unsigned char BYTE;
typedef unsigned short WORD;
#define length 10
uchar buffer[length];
unsigned char ADXL345_FLAG=0;
unsigned char START_FLAG=0;
unsigned char number=0;
unsigned char idata bad_flag[3];
unsigned int idata array0[3]={1,1,1};
unsigned int idata array1[3]={1,1,1};
unsigned int idata array2[3]={0,0,0};
unsigned int idata adresult[3];
unsigned int idata max[3]={0,0,0};
unsigned int idata min[3]={1000,1000,1000};
unsigned int idata dc[3]={500,500,500};
unsigned int idata vpp[3]={30,30,30};
unsigned int idata precision[3]={5,5,5};
unsigned int idata old_fixed[3];
unsigned int idata new_fixed[3];
unsigned int idata STEPS=0;
BYTE BUF[16]; //接收數據緩存區
uchar ge,shi,bai,qian,wan; //顯示變量
void delay(unsigned int n);
void Init_ADXL345(void); //初始化ADXL345
void Send_Byte(unsigned char *temp);
void conversion(uint temp_data);
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data); //單個寫入數據
uchar Single_Read_ADXL345(uchar REG_Address); //單個讀取內部寄存器數據
void Multiple_Read_ADXL345(); //連續的讀取內部寄存器數據
//------------------------------------
void Delay5us();
void Delay5ms();
void ADXL345_Start();
void ADXL345_Stop();
void ADXL345_SendACK(bit ack);
bit ADXL345_RecvACK();
void ADXL345_SendByte(BYTE dat);
BYTE ADXL345_RecvByte();
void ADXL345_ReadPage();
void ADXL345_WritePage();
void UART_init(void);
void ADC_init(unsigned char channel);
void T0_init(void);
//------------------------------------
unsigned char PulsePin = 0; // P1.0為傳感器輸入口
// 這些變量是在中斷服務程序執行期間使用的
volatile unsigned int BPM; // 用于保持脈搏
volatile unsigned int Signal; // 保存傳入的原始數據
volatile unsigned int IBI = 600; // 保存相鄰心跳之間的時間間隔
volatile bit Pulse = false; // 脈搏波高時為真,低時為假
volatile bit QS = false; // 當單片機發現一個心跳時變為真
volatile int rate[10]; //數組,保存最后10個IBI值
volatile unsigned long sampleCounter = 0; // 用于確定脈沖時間
volatile unsigned long lastBeatTime = 0; // 用于發現IBI
volatile int Peak =512; //用于發現脈搏波峰值
volatile int Trough = 512; // 用于發現脈搏波谷
volatile int thresh = 512; // 用于發現心跳的即時時刻
volatile int amp = 100; //用于保持脈沖波形的幅度
volatile bit firstBeat = true; // 用于開始合理的BPM
volatile bit secondBeat = false;
static unsigned char order=0;
unsigned char DisBuff[4]={0};
//------------------------------------
void conversion(uint temp_data)
{
wan=temp_data/10000+0x30 ;
temp_data=temp_data%10000; //取余運算
qian=temp_data/1000+0x30 ;
temp_data=temp_data%1000; //取余運算
bai=temp_data/100+0x30 ;
temp_data=temp_data%100; //取余運算
shi=temp_data/10+0x30 ;
temp_data=temp_data%10; //取余運算
ge=temp_data+0x30;
}
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
void Delay5ms()
{
WORD n = 560;
while (n--);
}
void ADXL345_Start() //起始信號
{
SDA = 1; //拉高數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 0; //產生下降沿
Delay5us(); //延時
SCL = 0; //拉低時鐘線
}
void ADXL345_Stop() //停止信號
{
SDA = 0; //拉低數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 1; //產生上升沿
Delay5us(); //延時
}
void ADXL345_SendACK(bit ack) //發送應答信號 入口參數:ack(0:ACK 1:NAK)
{
SDA = ack; //寫應答信號
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
bit ADXL345_RecvACK() //接收應答信號
{
SCL = 1; //拉高時鐘線
Delay5us(); //延時
CY = SDA; //讀應答信號
SCL = 0; //拉低時鐘線
Delay5us(); //延時
return CY;
}
void ADXL345_SendByte(BYTE dat) //向IIC總線發送一字節數據
{
BYTE i;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1; //移出數據的最高位
SDA = CY; //送數據口
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
ADXL345_RecvACK();
}
BYTE ADXL345_RecvByte() //從IIC總線接收一字節數據
{
BYTE i;
BYTE dat = 0;
SDA = 1; //使能內部上拉,準備讀取數據,
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1;
SCL = 1; //拉高時鐘線
Delay5us(); //延時
dat |= SDA; //讀數據
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
return dat;
}
void Single_Write_ADXL345(uchar REG_Address,uchar REG_data) //單字節寫入
{
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(REG_Address); //內部寄存器地址,請參考中文pdf22頁
ADXL345_SendByte(REG_data); //內部寄存器數據,請參考中文pdf22頁
ADXL345_Stop(); //發送停止信號
}
uchar Single_Read_ADXL345(uchar REG_Address) //單字節讀取
{ uchar REG_data;
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(REG_Address); //發送存儲單元地址,從0開始
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
REG_data=ADXL345_RecvByte(); //讀出寄存器數據
ADXL345_SendACK(1);
ADXL345_Stop(); //停止信號
return REG_data;
}
void Multiple_read_ADXL345(void) //連續讀出ADXL345內部加速度數據,地址范圍0x32~0x37
{ uchar i;
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress); //發送設備地址+寫信號
ADXL345_SendByte(0x32); //發送存儲單元地址,從0x32開始
ADXL345_Start(); //起始信號
ADXL345_SendByte(SlaveAddress+1); //發送設備地址+讀信號
for (i=0; i<6; i++) //連續讀取6個地址數據,存儲中BUF
{
BUF[i] = ADXL345_RecvByte(); //BUF[0]存儲0x32地址中的數據
if (i == 5)
{
ADXL345_SendACK(1); //最后一個數據需要回NOACK
}
else
{
ADXL345_SendACK(0); //回應ACK
}
}
ADXL345_Stop(); //停止信號
Delay5ms();
}
void Init_ADXL345() //初始化ADXL345,根據需要請參考pdf進行修改
{
Single_Write_ADXL345(0x31,0x0B); //測量范圍,正負16g,13位模式
Single_Write_ADXL345(0x2C,0x08); //速率設定為12.5 參考pdf13頁
Single_Write_ADXL345(0x2D,0x08); //選擇電源模式 參考pdf24頁
Single_Write_ADXL345(0x2E,0x80); //使能 DATA_READY 中斷
Single_Write_ADXL345(0x1E,0x00); //X 偏移量 根據測試傳感器的狀態寫入pdf29頁
Single_Write_ADXL345(0x1F,0x00); //Y 偏移量 根據測試傳感器的狀態寫入pdf29頁
Single_Write_ADXL345(0x20,0x05); //Z 偏移量 根據測試傳感器的狀態寫入pdf29頁
}
void step_counter(void)
{
static uchar sampling_counter=0;
uchar jtemp;
ADXL345_FLAG=0;
Multiple_read_ADXL345(); //連續讀取加速度
//--------------------------采樣濾波----------------------//
for(jtemp=0;jtemp<=2;jtemp++) //求平均值,計算最大值和最小值
{
array2[jtemp]=array1[jtemp]; // array0[3]={1,1,1}
array1[jtemp]=array0[jtemp]; // array1[3]={1,1,1}
array0[jtemp]=BUF[2*jtemp]+(BUF[2*jtemp+1]<<8); // array2[3]={0,0,0}
adresult[jtemp]=array0[jtemp]+array1[jtemp]+array2[jtemp];
adresult[jtemp]=adresult[jtemp]/3; //連續三個的平均值
if(adresult[jtemp]>max[jtemp]) //max[3]={0,0,0}
{
max[jtemp]=adresult[jtemp];
}
if(adresult[jtemp]<min[jtemp]) //min[3]={1000,1000,1000}
{
min[jtemp]=adresult[jtemp];
}
}
sampling_counter=sampling_counter+1;
//---------------------------------計算動態門限和動態精度-----------------------//
if(sampling_counter>=50) //每50個采樣更新一次
{
sampling_counter=0;
for(jtemp=0;jtemp<=2;jtemp++)
{
vpp[jtemp]=max[jtemp]-min[jtemp]; //vpp[3]={30,30,30}
dc[jtemp] =min[jtemp]+(vpp[jtemp]>>1); //dc[3]={500,500,500} 動態門限
min[jtemp]=1023;
bad_flag[jtemp]=0;
if(vpp[jtemp]>=160)
{
precision[jtemp]=vpp[jtemp]/32; //動態精度 precision[3]={5,5,5}
}
else if((vpp[jtemp]>=50)&& (vpp[jtemp]<160))
{
precision[jtemp]=4;
}
else if((vpp[jtemp]>=15) && (vpp[jtemp]<50))
{
precision[jtemp]=3;
}
else
{
precision[jtemp]=2;
bad_flag[jtemp]=1;
}
}
}
//--------------------------線性移位寄存器-------------------------------------
for(jtemp=0;jtemp<=2;jtemp++) //用動態精度來濾波
{
old_fixed[jtemp]=new_fixed[jtemp];
if(adresult[jtemp]>=new_fixed[jtemp])
{
if((adresult[jtemp]-new_fixed[jtemp])>=precision[jtemp])
{
new_fixed[jtemp]=adresult[jtemp];
}
}
else if(adresult[jtemp]<new_fixed[jtemp])
{
if((new_fixed[jtemp]-adresult[jtemp])>=precision[jtemp])
{
new_fixed[jtemp]=adresult[jtemp];
}
}
}
//------------------------- 動態門限判決----------------------------------
if((vpp[0]>=vpp[1])&&(vpp[0]>=vpp[2])) //x軸加速度變化最大
{
if((old_fixed[0]>=dc[0])&&(new_fixed[0]<dc[0])&&(bad_flag[0]==0)) //判決是否走步
{
STEPS=STEPS+1;
}
}
else if((vpp[1]>=vpp[0])&&(vpp[1]>=vpp[2])) //y軸加速度變化最大
{
if((old_fixed[1]>=dc[1])&&(new_fixed[1]<dc[1])&&(bad_flag[1]==0))
{
STEPS=STEPS+1;
}
}
else if((vpp[2]>=vpp[1])&&(vpp[2]>=vpp[0])) //z軸加速度變化最大
{
if((old_fixed[2]>=dc[2])&&(new_fixed[2]<dc[2])&&(bad_flag[2]==0))
{
STEPS=STEPS+1;
}
}
conversion(STEPS);
buffer[4] =wan;
buffer[5] =qian;
buffer[6] =bai;
buffer[7] =shi;
buffer[8] =ge;
buffer[9] ='\0'; //終止符
}
void delay(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<100;j++);
}
void sys_init()
{
UART_init(); //串口初始化
ADC_init(PulsePin);
T0_init(); // 定時器初始化,設置為每2ms讀取一次信號
Init_ADXL345();
}
void main(void)
{
uchar devid;
delay(500); //上電延時
sys_init(); //系統初始化
devid=Single_Read_ADXL345(0X00);//讀出的數據為0XE5,表示正確
while(1)
{
step_counter(); //步數計算
buffer[0]='
[/font]
; //判斷標志$
if (QS == true)
{ // 當單片機發現心跳時,量化自標記為true
buffer[1] =BPM/100+48;
buffer[2] =BPM%100/10+48;
buffer[3] =BPM%10+48;
QS = false; // 下一次重置量化自標記
}
Send_Byte(buffer); //發送數據
}
}
void UART_init(void) //串口初始化
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位數據,可變波特率
AUXR |= 0x04; //獨立波特率發生器時鐘為Fosc,即1T
BRT = 0xDC; //設置獨立波特率發生器重裝值
AUXR |= 0x01; //串口一選擇獨立波特率發生器為波特率發生器
AUXR |= 0x10; //啟用獨立波特率發生器
}
void Send_Byte(unsigned char *temp) //發送一串數據
{
unsigned char i=0;
ES=0; //禁止串口中斷
while(temp[i] != '\0')
{
SBUF=*(temp+i);
i++;
while(TI==0); //發送數據完畢時,TI會自動置高
TI=0; //發送數據完畢,將TI清零,準備下一次發送
}
ES=1; //清零串口中斷發送標志
}
void T0_init(void) //定時器初始化
{
TMOD |= 0x01; //16位定時器
TL0=T0MS;
TH0=T0MS>>8;
TR0=1; //啟動定時器0
ET0=1; //啟用定時器中斷
EA=1; //確保全局中斷已啟用
}
void ADC_init(unsigned char channel) //ADC初始化
{
P1ASF=ADC_MASK<<channel; //啟用PulsePin作為ADC輸入
ADC_RES=0; //清除之前的ADC結果
ADC_RESL=0; //清除之前的ADC結果
AUXR1 |= 0x04; //調整ADC結果的格式
ADC_CONTR=channel|ADC_POWER|ADC_SPEEDLL|ADC_START; //開啟AFC并開始轉換
}
unsigned int analogRead(unsigned char channel)
{
unsigned int result;
ADC_CONTR &=!ADC_FLAG; //清除ADC FLAG
result=ADC_RES;
result=result<<8;
result+=ADC_RESL;
ADC_CONTR|=channel|ADC_POWER|ADC_SPEEDLL|ADC_START;
return result;
}
// Timer 0中斷子程序,每2MS中斷一次,讀取AD值,計算心率值
void Timer0_rountine(void) interrupt 1
{
int N;
unsigned char i;
// 保持最后10個IBI值的runningtotal
unsigned int runningTotal = 0; // 清除runningTotal變量
EA=0; // 禁用中斷
TL0=T0MS;
TH0=T0MS>>8; //重新加載16位定時器0
Signal = analogRead(PulsePin); // 讀取傳感器值
sampleCounter += 2; // 以ms為單位跟蹤變量
N = sampleCounter - lastBeatTime; // 監視自上次跳動以來的時間以避免噪音
// 找到脈搏的波峰和波谷
if(Signal < thresh && N > (IBI/5)*3){ // 通過等待最后IBI的3/5以避免嚴重的噪音
if (Signal < Trough){ // T是低谷
Trough = Signal; // 跟蹤脈搏波的最低點
}
}
if(Signal > thresh && Signal > Peak){ // thresh條件有助于避免噪音
Peak = Signal; // P是峰值
} // 跟蹤脈搏波的最高點
// 每次出現脈沖信號時都會激增
if (N > 250){ // 避免高頻噪音
if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) )
{
Pulse = true; // 當我們認為有脈沖時設置脈沖標志
IBI = sampleCounter - lastBeatTime; //以ms為單位測量心跳之間的時間
lastBeatTime = sampleCounter; // 跟蹤下一個脈沖的時間
if(secondBeat){ // 如果這是第二次心跳
secondBeat = false; // 清除第二次心跳標志
for(i=0; i<=9; i++){ // 在啟動時記錄運行總數以獲得實際的BPM
rate[i] = IBI;
}
}
if(firstBeat){ // 如果這是我們第一次發現心跳
firstBeat = false; // 清除第一次心跳標志
secondBeat = true; // 設置第二次心跳標志
EA=1; // 再次啟用中斷
return; // IBI值不可靠,丟棄它
}
for(i=0; i<=8; i++){ // 移動速率數組中的數據
rate[i] = rate[i+1]; // 放棄最早的IBI值
runningTotal += rate[i]; //加載9個最早的ibi值
}
rate[9] = IBI; //將最新的IBI添加到速率數組中
runningTotal += rate[9]; // 將最新的IBI添加到runningtotal
runningTotal /= 10; //求最后10個IBI的平均值
BPM = 60000/runningTotal; // 一分鐘內可以發現多少個心跳,這就是BPM
if(BPM>200)BPM=200; //限制BPM最高顯示值
if(BPM<30)BPM=30; //限制BPM最低顯示值
DisBuff[2] = BPM%10+48;//取個位數
DisBuff[1] = BPM%100/10+48; //取十位數
DisBuff[0] = BPM/100+48; //百位數
if(DisBuff[0]==48)
DisBuff[0]=32;
QS = true; //設置量化自我標志
}
}
if (Signal < thresh && Pulse == true){ // 當數值下降時,心跳結束
Pulse = false; // 重置脈沖標志,以便下次執行
amp = Peak - Trough; // 得到脈搏波的幅度
thresh = amp/2 + Trough; // 將幅度設置為50%
Peak = thresh; // 重置以便下次使用
Trough = thresh;
}
if (N > 2500){ // 如果2.5秒內沒有心跳
thresh = 512; // 設置thresh默認值
Peak = 512; // 設置P默認值
Trough = 512; // 設置T默認值
lastBeatTime = sampleCounter; // 使lastBeatTime保持最新狀態
firstBeat = true; //設置這些以避免噪聲
secondBeat = false; // 當我們得到心跳回來
}
EA=1; // 完成后啟用中斷
}
#include <stc12c5a60s2.h>
#include <math.h>
#include <stdio.h>
#include <INTRINS.H>
#include <stdlib.h>
//------------------------------------
#define uchar unsigned char
#define uint unsigned int
#define S2RI 0x01 //串口2接收中斷請求標志位
#define S2TI 0x02 //串口2發送中斷請求標志位
unsigned char flag2,temp2;
unsigned char Buffer[10];
unsigned char RXCount = 0;
unsigned char Display_Buffer[10];
//------------------------------------
#define BMP180_SlaveAddress 0xee //定義器件在IIC總線中的地址
#define OSS 0 // 過采樣設置 代碼未設置為使用其他oss值
typedef unsigned char BYTE;
typedef unsigned short WORD;
uchar ge,shi,bai,qian,wan,shiwan; //顯示變量
int dis_data; //變量
short ac1;
short ac2;
short ac3;
unsigned short ac4;
unsigned short ac5;
unsigned short ac6;
short b1;
short b2;
short mb;
short mc;
short md;
//------------------------------------
//按鍵 IO設置
sbit KEY1 = P2^3;
sbit KEY2 = P2^2;
sbit KEY3 = P2^1;
sbit KEY4 = P2^0;
//LCD1602 IO設置
#define LCD1602_PORT P0
sbit LCD1602_RS = P2^5; //數據 命令選擇
sbit LCD1602_RW = P2^6; //讀 寫選擇
sbit LCD1602_EN = P2^7; //使能信號
//------------------------------------
sbit SCL=P1^4; //IIC時鐘引腳定義
sbit SDA=P1^5; //IIC數組引腳定義
//------------------------------------
void gps(void);
void display_receive(void);
extern void LCD1602_delay_ms(unsigned int n);
extern void LCD1602_write_com(unsigned char com);
extern void LCD1602_write_data(unsigned char dat);
extern void LCD1602_write_word(unsigned char *s);
extern void Init_LCD1602();
extern void Delay_ms(unsigned int n);
extern void Uart_Init();
//------------------------------------
unsigned char KEY_NUM = 0;
bit Page;
unsigned char xdata Display_GPGGA_Buffer[68];
unsigned char xdata Display_GPRMC_Buffer[68];
bit Flag_OV = 0;
bit Flag_Calc_GPGGA_OK = 0;
bit Flag_Calc_GPRMC_OK = 0;
unsigned char RX_Buffer[68];
unsigned char RX_Count = 0;
unsigned char Hour = 0,Min_High = 0,Min_Low = 0,Sec_High = 0,Sec_Low = 0;
unsigned char Month = 0,Day = 0,Month_High = 0, Month_Low = 0,Day_Low = 0 ,Day_High = 0, Year_High = 0,Year_Low = 0;
unsigned int Year = 0;
bit Flag_GPS_OK = 0;
unsigned char MaxDay = 0;
extern void Scan_Key();
extern void UTCDate2LocalDate(void);
extern bit IsLeapYear(unsigned int uiYear);
extern unsigned char GetMaxDay(unsigned char Month_Value,unsigned int Year_Value);
extern unsigned char RX_Buffer[68];
extern unsigned char RX_Count;
extern unsigned char Hour,Min_High,Min_Low,Sec_High,Sec_Low;
extern unsigned char Month,Day,Month_High, Month_Low,Day_Low ,Day_High, Year_High,Year_Low;
extern unsigned int Year;
extern unsigned char MaxDay;
extern bit Flag_GPS_OK;
//------------------------------------
void conversion(long temp_data);
void Single_Write(uchar SlaveAddress,uchar REG_Address,uchar REG_data);
uchar Single_Read(uchar REG_Address);
void Multiple_Read(uchar,uchar);
void delay(unsigned int k);
void Delay5us();
void Delay5ms();
void BMP180_Start();
void BMP180_Stop();
void BMP180_SendACK(bit ack);
bit BMP180_RecvACK();
void BMP180_SendByte(BYTE dat);
BYTE BMP180_RecvByte();
void BMP180_ReadPage();
void BMP180_WritePage();
void Init_BMP180(void);
void bmp180Convert(void);
//------------------------------------
void UTCDate2LocalDate(void) //UTC日期和當前日期的轉換
{
Day = (Day_High - 0x30) * 10 + (Day_Low-0x30) + 1; //日 加一
Month = (Month_High - 0x30) * 10 + (Month_Low - 0x30);
Year = 2000 + (Year_High - 0x30) * 10 + (Year_Low - 0x30);
MaxDay = GetMaxDay(Month,Year); //獲取當月 天數 最大值
if(Day > MaxDay) //溢出
{
Day = 1;
Month += 1;
if(Month > 12)
{
Year+=1;
}
}
Day_High = Day/10 + 0x30; //轉換日期值為ASCII
Day_Low = Day%10 + 0x30;
Month_High = Month/10 + 0x30; //轉換月份值為ASCII
Month_Low = Month%10 + 0x30;
Year_High = Year%100/10 + 0x30; //轉換年份值為ASCII
Year_Low = Year%10 + 0x30;
}
unsigned char GetMaxDay(unsigned char Month_Value,unsigned int Year_Value) //獲取當月日期的最大值
{
unsigned char iDays;
switch(Month_Value)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
{
iDays = 31;
}
break;
case 2:
{
//2月份比較特殊,需要根據是不是閏年來判斷當月是28天還29天
iDays = IsLeapYear(Year_Value)?29:28;
}
break;
case 4:
case 6:
case 9:
case 11:
{
iDays = 30;
}
break;
default : break;
}
return(iDays);
}
bit IsLeapYear(unsigned int uiYear) //閏年檢測
{
return (((uiYear%4)==0)&&((uiYear%100)!=0))||((uiYear%400)==0);
}
void Uart_Init() //串口初始化函數
{
SCON = 0X50; //UART方式1;8位UART
REN = 1; //允許串行口接收數據
PCON = 0x00; //SMOD=0;波特率不加倍
TMOD = 0x20; //T1方式2,用于產生波特率
TH1 = 0xFD; //裝初值
TL1 = 0xFD;
TR1 = 1; //啟動定時器1
EA = 1; //打開全局中斷控制
ES = 1; //打開串行口中斷
AUXR &= 0xF7; //波特率不倍速
S2CON = 0x50; //8位數據,可變波特率
AUXR &= 0xFB; //獨立波特率發生器時鐘為Fosc/12,即12T
BRT = 0xFD; //設定獨立波特率發生器重裝值
AUXR |= 0x10; //啟動獨立波特率發生器
IE2 =0x01; //開串口二中斷 ES2=1
EA=1;
}
void RECEIVE_DATA(void) interrupt 4 using 3 //串口一中斷接收,接收gps數據
{
unsigned char temp = 0;
ES=0;
temp = SBUF;
RI = 0;
if(temp == '
[/font]
)
{
RX_Count = 0;
Flag_GPS_OK = 0;
}
RX_Buffer[RX_Count++] = temp;
if(RX_Count >= 59)
{
RX_Count = 59;
Flag_GPS_OK = 1;
}
ES=1;
}
void UART_2Interrupt(void) interrupt 8 using 1 //串口二中斷接收
{
if(S2CON&S2RI)
{
S2CON&=~S2RI;
flag2=1;
temp2=S2BUF;
Buffer[RXCount++] = temp2;
}
if(S2CON&S2TI)
{
S2CON&=~S2TI;
}
}
void Delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<123;j++);
}
void LCD1602_delay_ms(unsigned int n)
{
unsigned int i,j;
for(i=0;i<n;i++)
for(j=0;j<123;j++);
}
void LCD1602_write_com(unsigned char com) //1602寫指令
{
LCD1602_RS = 0;
LCD1602_delay_ms(1);
LCD1602_EN = 1;
LCD1602_PORT = com;
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
void LCD1602_write_data(unsigned char dat) //1602寫數據
{
LCD1602_RS = 1;
LCD1602_delay_ms(1);
LCD1602_PORT = dat;
LCD1602_EN = 1;
LCD1602_delay_ms(1);
LCD1602_EN = 0;
}
void LCD1602_write_word(unsigned char *s) //1602連續寫字符
{
while(*s>0)
{
LCD1602_write_data(*s);
s++;
}
}
void Init_LCD1602() //初始化1602
{
LCD1602_EN = 0;
LCD1602_RW = 0; //設置為寫狀態
LCD1602_write_com(0x38); //顯示模式設定 16*2顯示 5*7點陣 8位數據口
LCD1602_write_com(0x0c); //開關顯示、光標有無設置、光標閃爍設置
LCD1602_write_com(0x06); //寫一個字符后指針加一
LCD1602_write_com(0x01); //清屏指令
}
void display_receive() //顯示串口二接收到的內容,即從另一個單片機接收到的步數和心率數據
{
if (Buffer[0]=='
[/font]
)
{unsigned char i;
for( i = 0; i < 10 ; i++)
{
Display_Buffer[i] = Buffer[i];
}
LCD1602_write_com(0X01); //清屏
Delay_ms(50);
LCD1602_write_com(0x80); //指針設置
LCD1602_write_word("STEPS:");
LCD1602_write_data(Display_Buffer[4]);
LCD1602_write_data(Display_Buffer[5]);
LCD1602_write_data(Display_Buffer[6]);
LCD1602_write_data(Display_Buffer[7]);
LCD1602_write_data(Display_Buffer[8]);
LCD1602_write_com(0x80+0x40); //設置指針 0xc0
LCD1602_write_word("BPM:");
LCD1602_write_data(Display_Buffer[1]);
LCD1602_write_data(Display_Buffer[2]);
LCD1602_write_data(Display_Buffer[3]);
}
}
void Scan_Key() //掃描按鍵
{
if( KEY1 == 0 ) //按鍵1掃描
{
Delay_ms(10); //延時去抖
if( KEY1 == 0 )
{
while(KEY1 == 0); //等待松手
KEY_NUM = 3;
Page = ~Page;
LCD1602_write_com(0X01); //清屏
}
}
}
void Delay5000ms() //@11.0592MHz stc12 延時5秒
{
unsigned char i, j, k;
i = 211;
j = 30;
k = 11;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
//------------------------------------
void main() //主程序
{
Init_LCD1602(); //初始化1602
Init_BMP180(); //初始化bmp180
Delay_ms(1000);
LCD1602_write_com(0x80); //顯示歡迎界面
LCD1602_write_word("WELCOME");
LCD1602_write_com(0x80+0x40);
LCD1602_write_word("sanshuige");
Delay_ms(10000);
LCD1602_write_com(0X01); //顯示溫度,氣壓界面
bmp180Convert();
Delay5000ms();
LCD1602_write_com(0X01);
Uart_Init(); //雙串口初始化
while(1)
{
gps(); //處理gps數據
Scan_Key(); //按鍵掃描
//顯示gps界面一,按下key1后顯示gps界面二。連續按key1,在2個界面之間來回切換顯示
if (KEY2==0)
{
while(1)
{
display_receive(); //如果按下key2,顯示步數和心率界面
Delay_ms(2000);
if (KEY1==0) //在步數和心率界面下按下key1,則跳回gps界面
{
break;
}
}
}
}
}
void gps() //處理和顯示串口一接收到的gps數據
{
unsigned char i = 0;
if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'G' && RX_Buffer[6] == ',' && RX_Buffer[13] == '.') //確定是否收到"GPGGA"這一幀數據
{
for( i = 0; i < 68 ; i++)
{
Display_GPGGA_Buffer[i] = RX_Buffer[i];
}
Hour = (Display_GPGGA_Buffer[7]-0x30)*10+(Display_GPGGA_Buffer[8]-0x30)+8; //UTC時間轉換到北京時間 UTC+8 0x30為ascii轉換為數字
if( Hour >= 24) //溢出
{
Hour %= 24; //獲取當前Hour
Flag_OV = 1; //日期進位
}
else
{
Flag_OV = 0;
}
Min_High = Display_GPGGA_Buffer[9];
Min_Low = Display_GPGGA_Buffer[10];
Sec_High = Display_GPGGA_Buffer[11];
Sec_Low = Display_GPGGA_Buffer[12];
Flag_Calc_GPGGA_OK = 1;
}
if(Page == 0 && Flag_Calc_GPGGA_OK == 1)
{
Flag_Calc_GPGGA_OK = 0;
LCD1602_write_com(0x80); //設置指針
LCD1602_write_data(Hour/10+0x30);
LCD1602_write_data(Hour%10+0x30);
LCD1602_write_data(':');
LCD1602_write_data(Min_High);
LCD1602_write_data(Min_Low);
LCD1602_write_data(':');
LCD1602_write_data(Sec_High);
LCD1602_write_data(Sec_Low);
LCD1602_write_word(" ");
LCD1602_write_data(Display_GPGGA_Buffer[54]);
LCD1602_write_data(Display_GPGGA_Buffer[55]);
LCD1602_write_data(Display_GPGGA_Buffer[56]);
LCD1602_write_data(Display_GPGGA_Buffer[57]);
LCD1602_write_word("m");
LCD1602_write_com(0x80+0x40); //設置指針
LCD1602_write_data(Display_GPGGA_Buffer[28]); //N 或者 S
LCD1602_write_data(Display_GPGGA_Buffer[17]); //緯度
LCD1602_write_data(Display_GPGGA_Buffer[18]); //緯度
LCD1602_write_data(0xdf); //度
LCD1602_write_data(Display_GPGGA_Buffer[19]); //緯度
LCD1602_write_data(Display_GPGGA_Buffer[20]); //緯度
LCD1602_write_word("'"); //秒
LCD1602_write_data(Display_GPGGA_Buffer[42]); //E 或者 W
LCD1602_write_data(Display_GPGGA_Buffer[30]); //經度
LCD1602_write_data(Display_GPGGA_Buffer[31]);
LCD1602_write_data(Display_GPGGA_Buffer[32]);
LCD1602_write_data(0xdf);
LCD1602_write_data(Display_GPGGA_Buffer[33]);
LCD1602_write_data(Display_GPGGA_Buffer[34]);
LCD1602_write_word("'");
}
if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'M' && RX_Buffer[52] == ',' && RX_Buffer[59] == ',') //確定是否收到"GPRMC"這一幀數據
{
for( i = 0; i < 68 ; i++)
{
Display_GPRMC_Buffer[i] = RX_Buffer[i];
}
Year_High = Display_GPRMC_Buffer[57];
Year_Low = Display_GPRMC_Buffer[58];
Month_High = Display_GPRMC_Buffer[55];
Month_Low = Display_GPRMC_Buffer[56];
Day_High = Display_GPRMC_Buffer[53];
Day_Low = Display_GPRMC_Buffer[54];
if(Flag_OV == 1) //有進位
{
UTCDate2LocalDate(); //UTC日期轉換為北京時間
}
Flag_Calc_GPRMC_OK = 1;
}
if(Page == 1 && Flag_Calc_GPRMC_OK == 1)
{
Flag_Calc_GPRMC_OK = 0;
LCD1602_write_com(0x80); //設置指針
LCD1602_write_word("20");
LCD1602_write_data(Year_High);
LCD1602_write_data(Year_Low);
LCD1602_write_data('-');
LCD1602_write_data(Month_High);
LCD1602_write_data(Month_Low);
LCD1602_write_data('-');
LCD1602_write_data(Day_High);
LCD1602_write_data(Day_Low);
LCD1602_write_com(0x80+0x40); //設置指針
LCD1602_write_word("Speed:"); //顯示內容
LCD1602_write_data(Display_GPRMC_Buffer[46]);
LCD1602_write_data(Display_GPRMC_Buffer[47]);
LCD1602_write_data(Display_GPRMC_Buffer[48]);
LCD1602_write_data(Display_GPRMC_Buffer[49]);
LCD1602_write_data(Display_GPRMC_Buffer[50]);
LCD1602_write_word("m/s");
}
}
void conversion(long temp_data) //轉變函數
{
shiwan=temp_data/100000+0x30 ;
temp_data=temp_data%100000; //取余運算
wan=temp_data/10000+0x30 ;
temp_data=temp_data%10000;
qian=temp_data/1000+0x30 ;
temp_data=temp_data%1000;
bai=temp_data/100+0x30 ;
temp_data=temp_data%100;
shi=temp_data/10+0x30 ;
temp_data=temp_data%10;
ge=temp_data+0x30;
}
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++)
{
for(j=0;j<121;j++)
{;}
}
}
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
void Delay5ms()
{
WORD n = 560;
while (n--);
}
void BMP180_Start() //起始信號
{
SDA = 1; //拉高數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 0; //產生下降沿
Delay5us(); //延時
SCL = 0; //拉低時鐘線
}
void BMP180_Stop() //停止信號
{
SDA = 0; //拉低數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 1; //產生上升沿
Delay5us(); //延時
}
void BMP180_SendACK(bit ack) //發送應答信號 入口參數:ack(0:ACK 1:NAK)
{
SDA = ack; //寫應答信號
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
bit BMP180_RecvACK() //接收應答信號
{
SCL = 1; //拉高時鐘線
Delay5us(); //延時
CY = SDA; //讀應答信號
SCL = 0; //拉低時鐘線
Delay5us(); //延時
return CY;
}
void BMP180_SendByte(BYTE dat) //向iic總線發送一個字節數據
{
BYTE i;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1; //移出數據的最高位
SDA = CY; //送數據口
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
BMP180_RecvACK();
}
BYTE BMP180_RecvByte() //從iic總線接收一個字節數據
{
BYTE i;
BYTE dat = 0;
SDA = 1; //使能內部上拉,準備讀取數據
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1;
SCL = 1; //拉高時鐘線
Delay5us(); //延時
dat |= SDA; //讀數據
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
return dat;
}
short Multiple_read(uchar ST_Address) //讀出bmp180內部數據 連續兩個
{
uchar msb, lsb;
short _data;
BMP180_Start(); //起始信號
BMP180_SendByte(BMP180_SlaveAddress); //發送設備地址+寫信號
BMP180_SendByte(ST_Address); //發送存儲單元地址
BMP180_Start(); //起始信號
BMP180_SendByte(BMP180_SlaveAddress+1); //發送設備地址+讀信號
msb = BMP180_RecvByte(); //BUF[0]存儲
BMP180_SendACK(0); //回應ACK
lsb = BMP180_RecvByte();
BMP180_SendACK(1); //最后一個數據需要回NOACK
BMP180_Stop(); //停止信號
Delay5ms();
_data = msb << 8;
_data |= lsb;
return _data;
}
long bmp180ReadTemp(void)
{
BMP180_Start(); //起始信號
BMP180_SendByte(BMP180_SlaveAddress); //發送設備地址+寫信號
BMP180_SendByte(0xF4); //寫寄存器地址
BMP180_SendByte(0x2E); // 寫入溫度的寄存器數據
BMP180_Stop(); //發送停止信號
delay(10);
return (long) Multiple_read(0xF6);
}
long bmp180ReadPressure(void)
{
long pressure = 0;
BMP180_Start(); //起始信號
BMP180_SendByte(BMP180_SlaveAddress); //發送設備地址+寫信號
BMP180_SendByte(0xF4); // 寫寄存器地址
BMP180_SendByte(0x34); // 寫入氣壓的寄存器數據
BMP180_Stop(); //發送停止信號
delay(10);
pressure = Multiple_read(0xF6);
pressure &= 0x0000FFFF;
return pressure;
}
void Init_BMP180() //初始化bmp180
{
ac1 = Multiple_read(0xAA);
ac2 = Multiple_read(0xAC);
ac3 = Multiple_read(0xAE);
ac4 = Multiple_read(0xB0);
ac5 = Multiple_read(0xB2);
ac6 = Multiple_read(0xB4);
b1 = Multiple_read(0xB6);
b2 = Multiple_read(0xB8);
mb = Multiple_read(0xBA);
mc = Multiple_read(0xBC);
md = Multiple_read(0xBE);
}
void bmp180Convert() //讀取并在1602上顯示溫度和氣壓數據
{
long ut;
long up;
long x1, x2, b5, b6, x3, b3, p;
unsigned long b4, b7;
long temperature;
long pressure;
ut = bmp180ReadTemp();
ut = bmp180ReadTemp(); //讀取溫度
up = bmp180ReadPressure();
up = bmp180ReadPressure(); //讀取大氣壓
x1 = ((long)ut - ac6) * ac5 >> 15;
x2 = ((long) mc << 11) / (x1 + md);
b5 = x1 + x2;
temperature = (b5 + 8) >> 4;
LCD1602_write_com(0X01); //清屏
Delay_ms(50);
conversion(temperature);
LCD1602_write_word("temp:");
LCD1602_write_data(bai);
LCD1602_write_data(shi);
LCD1602_write_word(".");
LCD1602_write_data(ge);
LCD1602_write_data(0XDF); //溫度單位
LCD1602_write_word("C");
b6 = b5 - 4000;
x1 = (b2 * (b6 * b6 >> 12)) >> 11;
x2 = ac2 * b6 >> 11;
x3 = x1 + x2;
b3 = (((long)ac1 * 4 + x3) + 2)/4;
x1 = ac3 * b6 >> 13;
x2 = (b1 * (b6 * b6 >> 12)) >> 16;
x3 = ((x1 + x2) + 2) >> 2;
b4 = (ac4 * (unsigned long) (x3 + 32768)) >> 15;
b7 = ((unsigned long) up - b3) * (50000 >> OSS);
if( b7 < 0x80000000)
p = (b7 * 2) / b4 ;
else
p = (b7 / b4) * 2;
x1 = (p >> 8) * (p >> 8);
x1 = (x1 * 3038) >> 16;
x2 = (-7357 * p) >> 16;
pressure = p + ((x1 + x2 + 3791) >> 4);
LCD1602_write_com(0x80+0x40); //設置指針
conversion(pressure);
LCD1602_write_word("atm:");
LCD1602_write_data(shiwan);
LCD1602_write_data(wan);
LCD1602_write_data(qian);
LCD1602_write_word(".");
LCD1602_write_data(bai);
LCD1602_write_data(shi);
LCD1602_write_word("Kpa");
}
復制代碼
全部資料51hei下載地址:
新建文件夾.rar
(936.23 KB, 下載次數: 47)
2018-6-25 15:30 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
xsj1877578806
時間:
2018-8-28 18:39
感謝分享很實用
作者:
宇宙浪子521
時間:
2019-11-26 20:24
這個是模塊化編程嗎
作者:
宇宙浪子521
時間:
2019-11-26 20:25
這個是模塊化編程嗎?
歡迎光臨 (http://m.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
欧美日本在线
|
av中文在线
|
韩国理论在线
|
欧美一级网站
|
av片在线观看
|
日韩视频免费看
|
国内外成人免费视频
|
黄色三级视频网站
|
一区二区三区在线免费
|
日韩精品久久
|
91天堂在线
|
天天操综合网
|
国产黄色一区
|
免费看a级片
|
91视频色
|
日韩欧美一区二区在线观看
|
中文字幕97
|
黄网站免费在线观看
|
婷婷五月在线视频
|
97精品国产97久久久久久免费
|
久久精品免费观看
|
免费av在线
|
黄色国产视频
|
在线不卡视频
|
天天干天天操天天摸
|
精品在线观看视频
|
国产深夜福利
|
午夜精品视频在线
|
精品www
|
欧美精品乱码99久久蜜桃
|
免费成人毛片
|
免费色片
|
日韩中文字幕在线
|
日日操日日操
|
亚色网站
|
亚洲黄色在线
|
av噜噜噜
|
91成人精品一区在线播放
|
日本一区二区三区四区五区
|
亚洲va韩国va欧美va精品
|
手机看片欧美
|