毕设结束了,本来是想搞一个简单的计步器的,这功能加的太多给变成运动监测器了。使用2个STC12C5A60S2,4个HC05,还有NEO-7N,PULSE SENSOR,BMP180,ADXL345以及简单的1602和几个独立按键,实现的功能相当全面,具体如下:有效检测人体的运动状态信息,记录行动步数,并且能够显示心率,具体定位信息(经纬度,时间,日期,海拔高度,运动速度),温度,气压。大体原理是:通过蓝牙由一个发送单片机将记录的经过处理的数据(步数信息和心率信息)无线发送,接收单片机一方面通过蓝牙无线接收(发送单片机发送的数据),另一方面通过蓝牙无线接收GPS的数据。并且将数据在LCD1602上显示,独立按键在接收单片机上负责LCD1602显示翻页的功能。正常本科的毕业设计应该不会用到如此多的功能,选其中几个功能实现一下就可以了,反正就是能混则混。具体的程序,原理图还有视频我会贴出来的。视频我发个百度网盘的链接吧 https://pan.baidu.com/s/1rQXeFTQxPRO0yWu5yOeLZQ
单片机源程序:
- #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, 下载次数: 44)
|