简介

STM32F103C8T6单片机核心板电路、ADXL345传感器电路、心率传感器电路、温度传感器和lcd1602电路组成。通过重力加速度传感器ADXL345检测人的状态,计算出走路步数、走路距离和平均速度。过心率传感器实时检测心率,通过温度传感器检测温度。通过LCD1602实时显示步数、距离和平均速度、心率以及温度值。

主要学习ADXL345,心率传感器等等。

设计背景及其意义

  • 计步器是一种颇受欢迎的日常锻炼进度监控器,可以激励人们挑战自己,增强体质,帮助瘦身。早期设计利用加重的机械开关检测步伐,并带有一个简单的计数器。晃动这些装置时,可以听到有一个金属球来回滑动,或者一个摆锤左右摆动敲击挡块。电子计步器主要组成部分是振动传感器和电子计数器。步行的时候人的重心会上下移动。以腰部的上下位移最为明显,所以记步器挂在腰带上最为适宜。所谓的振动传感器其实就是一个平衡锤在上下振动时平衡被破坏使一个触点能出现通/断动作,由电子计数器完成了主要的记录与显示功能,其他的属于热量消耗,路程换算均由电路完成。计步器中一般采用一种加速度计来感受外界的震动。常用的加速度计原理如下:在一段塑料管中密封着一小块磁铁,管外缠绕着线圈,当塑料管运动时,磁铁由于惯性在管中反向运动,切割线圈,由于电磁感应,线圈中产生电流,人体运动时,上下起伏的加速度近似为正弦过程,线圈的输出电流也是正弦波,测量正弦波的频率就可以得出运动的步数,再计算的出距离。
  • 心率(Heart Rate)是用来描述心动周期的专业术语,是指心脏每分钟跳动的次数,以第一声音为准。 心率,现代汉语将心率解释为“心脏跳动的频率”。频率就是在单位时间内,某件事情发生的次数。两种解释合起来就是,心脏在一定时间内跳动的次数,也就是在一定时间内,心脏跳动快慢的意思。
  • 健康成人的心率为60~100次/分,大多数为60~80次/分,女性稍快;3岁以下的小儿常在100次/分以上;老年人偏慢。成人每分钟心率超过100次(一般不超过 160次/分)或婴幼儿超过 150次/分者,称为窦性心动过速。常见于正常人运动、兴奋、激动、吸烟、饮酒和喝浓茶后。也可见于发热、休克、贫血、甲亢、心力衰竭及应用阿托品肾上腺素麻黄素等。如果心率在 160~220次/分,常称为阵发性心动过速。心率低于60次/分者(一般在40次/分以上),称为窦性心动过缓。可见于长期从事重体力劳动和运动员;病理性的见于甲状腺机能低下、颅内压增高阻塞性黄疸、以及洋地黄、奎尼丁心得安类药物过量或中毒。如心率低于40次/分,应考虑有房室传导阻滞

方案的设计与论证

由STM32F103C8T6单片机核心板电路+ADXL345传感器电路+心率传感器电路+温度传感器+lcd1602电路组成。

控制方式

STM32单片机,STM32系列处理器是意法半导体ST公司生产的一种基于ARM 7架构的32位、支持实时仿真和跟踪的微控制器。使用ARM最新的、先进架构的Cortex-M3内核,具有优异的实时性能、杰出的功耗控制、出众及创新的外设,并且最大程度的集成整合,十分易于开发,可使产品快速将进入市场。

显示方案

LCD液晶显示,由单片机驱动,它主要用来显示大量数据、文字、图形,能够显示的位数多,显示得清晰多样、美观,同时液晶显示器的编写程序简单,价格便宜,而且功率消耗小寿命长抗干扰能力强。

倾角传感器

采用基于ADI公司的倾角传感器ADXL345模块来检测老人的位置信息,adxl345功能很强大,内置很多寄存器,而且成本低,易于控制。

心率监测模块选择

采用红外模块采集心率信号,红外模块对管采集的心率信号抗干扰能力较强,测量到的心率波形比较稳定,波形也很好;对于设计而言这将是一个很理想的选择。

硬件电路的设计

系统功能分析

  • 1、通过重力加速度传感器ADXL345检测人的状态,计算出走路步数、走路距离和平均速度。
  • 2、通过心率传感器实时检测心率,通过温度传感器检测温度。
  • 3、lcd1602实时显示步数、距离和平均速度、心率以及温度值。

系统总体结构

模块电路的设计

LCD1602液晶显示模块电路设计

LCD显示器分为字段显示和字符显示两种。其中字段显示与LED显示相似,只要送对应的信号到相应的管脚就能显示。字符显示是根据需要显示基本字符。本设计采用的是字符型显示。系统中采用LCD1602作为显示器件输出信息。与传统的LED数码管显示器件相比,液晶显示模块具有体积小、功耗低、显示内容丰富等优点,而且不需要外加驱动电路,现在液晶显示模块已经是单片机应用设计中最常用的显示器件了。LCD1602可以显示2行16个汉字。

LCD1602主要技术参数

  • (1)显示容量为16×2个字符;
  • (2)芯片工作电压为4.5~5.5V;
  • (3)工作电流为2.0mA(5.0V);
  • (4)模块最佳工作电压为5.0V;
  • (5)字符尺寸为2.95×4.35(W×H)mm。

LCD1602采用标准的14脚,其接口的引脚说明

  • (1)第1脚:VSS为地电源。
  • (2)第2脚:VDD接5V正电源。
  • (3)第3脚:V0为液晶显示器对比度调整端。
  • (4)第4脚:RS为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器。
  • (5)第5脚:RW为读写信号线,高电平时进行读操作,低电平时进行写操作。当RS和RW共同为低电平时可以写入指令或者显示地址,当RS为低电平RW为高电平时可以读忙信号,当RS为高电平RW为低电平时可以写入数据。
  • (6)第6脚:E端为使能端,当E端由高电平跳变成低电平时,液晶模块执行命令。
  • (7)第7~14脚:D0~D7为8位双向数据线。
  • (8)第15~16脚:空脚

控制指令说明

LCD1602液晶模块内部的控制器共有11条控制指令

序号 指令 RS R/W D7 D6 D5 D4 D3 D2 D1 D0
1 清显示 0 0 0 0 0 0 0 0 0 1
2 光标返回 0 0 0 0 0 0 0 0 1 *
3 置输入模式 0 0 0 0 0 0 0 1 I/D S
4 显示开/关控制 0 0 0 0 0 0 1 D C B
5 光标或字符移位 0 0 0 0 0 1 S/C R/L * *
6 置功能 0 0 0 0 1 DL N F * *
7 置字符发生存贮器地址 0 0 0 1 字符发生存贮器地址
8 置数据存贮器地址 0 0 1 显示数据存贮器地址
9 读忙标志或地址 0 1 BF 计数器地址
10 写数到CGRA或DDRAM) 1 0 要写的数据内容
11 从CGRAM或DDRAM读数 1 1 读出的数据内容

1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)

  • (1)指令1:清显示,指令码01H,光标复位到地址00H位置
  • (2)指令2:光标复位,光标返回到地址00H
  • (3)指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。
  • (4)指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
  • (5)指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标
  • (6)指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符
  • (7)指令7:字符发生器RAM地址设置
  • (8)指令8:DDRAM地址设置
  • (9)指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
  • (10)指令10:写数据
  • (11)指令11:读数据

系统中采用LCD1602作为显示器件输出信息。在本电路中电位器可以调节液晶显示的对比度即清晰度。

实物图

ADXL345倾角传感器模块电路

选择倾角传感器ADXL345模块实时检测相关的状态信息。ADXL345是一款小而薄的超低功耗3轴加速度计,分辨率高(13位),测量范围达± 16g。数字输出数据为16位二进制补码格式,可通过SPI(3线或4线)或I2C数字接口访问。ADXL345非常适合移动设备应用。它可以在倾斜检测应用中测量静态重力加速度,还可以测量运动或冲击导致的动态加速度。其高分辨率(3.9mg/LSB),能够测量不到1.0°的倾斜角度变化。该器件提供多种特殊检测功能。活动和非活动检测功能通过比较任意轴上的加速度与用户设置的阈值来检测有无运动发生。敲击检测功能可以检测任意方向的单振和双振动作。自由落体检测功能可以检测器件是否正在掉落。这些功能可以独立映射到两个中断输出引脚中的一个。正在申请专利的集成式存储器管理系统采用一个32级先进先出(FIFO)缓冲器,可用于存储数据,从而将主机处理器负荷降至最低,并降低整体系统功耗。低功耗模式支持基于运动的智能电源管理,从而以极低的功耗进行阈值感测和运动加速度测量。

ADXL345模块内部电路图。U2即为稳压芯片,实现5V直流电转化为3.3V直流电,C1-C4为滤波电容。R2、R3为上拉电阻,让信号输入更加稳定。D1为电源指示灯,R1为限流电阻,来保护LED灯D1。

ADXL345模块

Pulsesensor脉搏心率传感器模块电路设计

脉搏心率传感器是用来测试心跳速率的传感器,实质是一款集成了放大电路和噪声消除电路的光学心率传感器。可以通过此传感器开发出和心率有关的互动作品。传感器可以戴在手指或者耳垂上。光电传感器将脉搏信号转换为电信号,此装置需要把手指放在传感器表盘上,光电传感器,此传感器是集成了放大电路和噪声消除电路的光学心率传感器,光电传感器一侧的发光二极管发光,当脉搏跳动时,指尖或者耳垂的动脉血管血容量发生周期性变化,透过指尖的光强度同时发生变化。另一侧的光电三极管将接收到的红外光信号转化为电信号。

接口说明

  • (1)+ 外接5V
  • (2)- 外接GND
  • (3)S 输出接口(0和1)

Pulsesensor脉搏心率传感器模块接口原理图

Pulsesensor脉搏心率传感器模块实物图

此脉搏心率传感器理论上输出的波形

LM393比较器模块对Pulsesensor脉搏心率传感器模块滤波的电路原理图

LM393比较器模块具体内部原理图如下图所示。其中R1电阻为分压电阻,将比较器模块检测到的模拟信息转化为模拟电压信号,模拟量信号接入LM393比较器后,即可与LM393比较器芯片2号引脚所接的电位器分压后的模拟电压进行比较,进而得出数字信号(即方波信号)。C1、C2为滤波电容,C1电容对电源进行滤波,让电源输出更稳定。C2电容对模拟信号进行滤波,保证模拟信号输出的稳定性。R2、R3均为限流电阻,来保护LED灯,防止LED灯烧坏,LED灯均为低电平有效。R4为上拉电阻,上拉就是将不确定的信号通过一个电阻钳位在高电平,同时起限流作用。保证LM393比较器输出的高低电平信号在与单片机引脚连接时电平信号的读取更加稳定。

LM393比较器模块实物图

DS18B20温度传感器模块电路

DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。

主要根据应用场合的不同而改变其外观。封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。

DS18B20技术参数

  • (1)独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
  • (2)测温范围 -55℃~+125℃,固有测温误差(注意,不是分辨率,这里之前是错误的)1℃。
  • (3)支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
  • (4)工作电源: 3.0~5.5V/DC (可以数据线寄生电源)
  • (5)在使用中不需要任何外围元件
  • (6) 测量结果以9~12位数字量方式串行传送

DS18B20温度传感器可编程的分辨率为9~12位,温度转换为12位数字格式最大值为750毫秒,用户可定义的非易失性温度报警设置,应用范围包括恒温控制、工业系统、消费电子产品温度计、或任何热敏感系统。试验证明DS18B20温度传感器满足本设计要求。

DS18B20温度传感器封装一般有2种,使用上都是一样的。可以根据使用环境随意选择。第一种是直接是裸露的芯片,主要用于空气温度检测。第2种是不锈钢钢管封装好的,防水,一般用于水温灯液体温度检测。实物图如下:

DS18B20传感器实物图(防水)

DS18B20温度传感器原理图如下。10K电阻为上拉电阻,保证DS18B20传感器数据读取更稳定。

程序流程图

系统运行流程图

Code

main.c

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include <stdio.h>
#include "timer.h"
#include "key.h"
#include "exti.h"
#include "adxl345.h"
#include "lcd1602.h"
#include "ds18b20.h" 

unsigned char ReadAdxl345;       //定时读取adxl345数据
unsigned char ErrorNum=0;   //记录错误次数
unsigned char CheckNum=0;   //检测次数

char dis0[16];//液晶数组显示暂存
char dis1[35];

unsigned int xlTab[5];//心率数组
unsigned char count=0;    //心率滤波计数
unsigned int xinLater=0;//    心率延时处理
unsigned int xinLv =0;    //心率值

unsigned int BuShu=0;//步数
unsigned int Normal_num=0;            //正常次数
unsigned int Error_num=0;            //倾斜次数

unsigned int disBuShu = 0;  //显示步数
float disJuLi = 0;//显示距离
float temperature;  //温度
unsigned char readTemp = 0;    //读取温度标志

int main(void)
 { 
    delay_init();             //延时函数初始化      
    uart_init(9600);         //串口初始化为9600
  TIM3_Int_Init(49,7199);//50ms      
    EXTIX_Init();        // 初始化外部中断
    LED_Init();                  //初始化与LED连接的硬件接口
    KEY_Init();            //初始化按键

    Lcd_GPIO_init();  //初始化lcd引脚
    Lcd_Init();          //初始化lcd屏幕
    delay_ms(200);

  Init_ADXL345();
  if(Single_Read_ADXL345(0X00)==0xe5)    
  {
    delay_ms(5);
  }
  else
  {
    delay_ms(3);
  }

    while(1)
    {

    if(ReadAdxl345== 1)   //定时读取adxl345数据
    {
      ReadAdxl345= 0;
      ReadData_x();                          //三轴检测函数
      CheckNum++;
      if((temp_Y>450)||(temp_Y<-450)) //查看正常次数     
      {
        Normal_num++;  //正常次数++
      }
      else
      {
        Error_num++;//倾斜次数
      }
      if((Error_num!=0)&&(Normal_num!=0))//检测到步数
      {
                BuShu++;   //步数脉冲量++
        Error_num=0;    //清除一个周期检测
        Normal_num=0;
      }
    }

        if(disFlag==1)       //显示标志
        {
            disFlag = 0;

            readTemp++;  //定时计数
            if(readTemp >= 8)//约800ms处理一次数据 温度
            {
                readTemp =0;//重新计数
                temperature=(float)DS18B20_Get_Temp()/10;    //缩小10倍为实际值            
            }

            disBuShu = BuShu/2;  //显示步数
            disJuLi = disBuShu*0.45;//显示距离

            sprintf(dis0,"X:%03d/min %4.1f C",xinLv,temperature);//打印
            Lcd_Puts(0,0,(unsigned char *)dis0);    //显示
            Lcd_1Put(14,0,0xdf);//显示符号
            sprintf(dis1,"BS:%03d JL:%4.1fm  ",disBuShu,disJuLi);//打印
            Lcd_Puts(0,1,(unsigned char *)dis1);    //显示

        }    
    }                                                
}

adxl345.c

#include "stm32f10x.h"
#include "delay.h"
#include "adxl345.h"

#define SDA_RCC            RCC_APB2Periph_GPIOA
#define SDA_GPIO        GPIOA
#define SDA_GPIO_PIN    GPIO_Pin_5

#define SCL_RCC            RCC_APB2Periph_GPIOA
#define SCL_GPIO        GPIOA
#define SCL_GPIO_PIN    GPIO_Pin_4

#define SCL_OUT() SCL_Set_Output() //置位scl
#define SET_SCL() GPIO_SetBits(SCL_GPIO, SCL_GPIO_PIN) //置位scl
#define CLE_SCL() GPIO_ResetBits(SCL_GPIO, SCL_GPIO_PIN)//清楚scl

#define SDA_OUT() SDA_Set_Output()
#define SDA_INT() SDA_Set_Input()
#define SET_SDA() GPIO_SetBits(SDA_GPIO, SDA_GPIO_PIN)//置位sda
#define CLE_SDA() GPIO_ResetBits(SDA_GPIO, SDA_GPIO_PIN)//清楚sda
#define SDA_VAL() GPIO_ReadInputDataBit(SDA_GPIO, SDA_GPIO_PIN)

#define    SlaveAddress   0xA6      //定义器件在IIC总线中的从地址,根据ALT  ADDRESS地址引脚不同修改                  //ALT  ADDRESS引脚接地时地址为0xA6,接电源时地址为0x3A

unsigned char BUF[8];                         //接收数据缓存区          
unsigned char ge,shi,bai,qian,wan;           //显示变量
unsigned char err;
float temp_X,temp_Y,temp_Z;

void SCL_Set_Output(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = SCL_GPIO_PIN;                 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         
    GPIO_Init(SCL_GPIO, &GPIO_InitStructure);                                         
}    

void SDA_Set_Output(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = SDA_GPIO_PIN;                 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         
    GPIO_Init(SDA_GPIO, &GPIO_InitStructure);                                         
}    

void SDA_Set_Input(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = SDA_GPIO_PIN;                 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;          
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         
    GPIO_Init(SDA_GPIO, &GPIO_InitStructure);                     
}

/**************************************
起始信号
**************************************/
void ADXL345_Start(void)
{
    SCL_OUT();
    SDA_OUT();
    SET_SDA();//SDA = 1;                    //拉高数据线
    SET_SCL();//SCL = 1;                    //拉高时钟线
    delay_us(2);//Delay5us();                 //延时
    CLE_SDA();//SDA = 0;                    //产生下降沿
    delay_us(2);//Delay5us();                 //延时
    CLE_SCL();//SCL = 0;                    //拉低时钟线
}

/**************************************
停止信号
**************************************/
void ADXL345_Stop(void)
{
    SCL_OUT();
    SDA_OUT();
    CLE_SDA();//SDA = 0;                    //拉低数据线
    SET_SCL();//SCL = 1;                    //拉高时钟线
    delay_us(2);//Delay5us();                 //延时
    SET_SDA();//SDA = 1;                    //产生上升沿
    delay_us(2);//Delay5us();                 //延时
    CLE_SCL();
}

/**************************************
发送应答信号
入口参数:ack (0:ACK 1:NAK)
**************************************/
void ADXL345_SendACK(uchar ack)
{   
    SCL_OUT();
    SDA_OUT();
    if(ack==0)//SDA = ack;                  //写应答信号
    {
      CLE_SDA();
    }
    else
    {
      SET_SDA();
    }
    SET_SCL();//SCL = 1;                    //拉高时钟线
    delay_us(2);//Delay5us();                 //延时
    CLE_SCL();//SCL = 0;                    //拉低时钟线
    delay_us(5);//Delay5us();                 //延时
}

/**************************************
接收应答信号
**************************************/
uchar ADXL345_RecvACK(void)
{
    SDA_INT();
    SCL_OUT();
    SET_SCL();//SCL = 1;                    //拉高时钟线
    delay_us(2);//    Delay5us();                 //延时
    SET_SCL();
    if(SDA_VAL()== Bit_SET)   //CY = SDA;                   //读应答信号
    {
      err = 1;
    }
    else
    {
      err = 0;
    }

    CLE_SCL() ;//SCL = 0;                    //拉低时钟线
    delay_us(5);//    Delay5us();                 //延时
    SDA_OUT();
    return err;
}

/**************************************
向IIC总线发送一个字节数据
**************************************/
void ADXL345_SendByte(unsigned char dat)
{
    unsigned char i;
    SCL_OUT();
    SDA_OUT();
    for (i=0; i<8; i++)         //8位计数器
    {
        delay_us(5);             //延时
        if(dat&0x80)  //SDA = CY;               //送数据口
        {SET_SDA();}
        else
        {CLE_SDA();}       
        delay_us(5);             //延时
        SET_SCL();//SCL = 1;                //拉高时钟线
        delay_us(5);             //延时
        CLE_SCL();//SCL = 0;                //拉低时钟线
        dat <<= 1;              //移出数据的最高位
    }
    ADXL345_RecvACK();
}

/**************************************
从IIC总线接收一个字节数据
**************************************/
unsigned char ADXL345_RecvByte(void)
{
    unsigned char i;
    unsigned char Mid;
    unsigned char dat = 0;
    SDA_INT();
    SCL_OUT();

    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        delay_us(5);            //延时
        SET_SCL();

            if(SDA_VAL()== Bit_SET)   //CY = SDA;                   //读应答信号
            {
                Mid = 1;
            }
            else
            {
                Mid = 0;
            }

//        Mid=SDA_VAL();
        if(Mid) dat++;
        delay_us(5);     
        CLE_SCL();//SCL = 0;                //拉低时钟线
    }
    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; 
}
//*********************************************************
//
//连续读出ADXL345内部加速度数据,地址范围0x32~0x37
//
//*********************************************************
void Multiple_Read_ADXL345(void)
{   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();                          //停止信号
    delay_ms(5);
}


//*****************************************************************

//初始化ADXL345,根据需要请参考pdf进行修改************************
void Init_ADXL345(void)
{
   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页
}
//***********************************************************************
//显示x轴
void ReadData_x(void)
{   
  int  dis_data;                       //变量
  Multiple_Read_ADXL345();           //连续读出数据,存储在BUF中
  dis_data=(BUF[1]<<8)+BUF[0];  //合成数据   
//  if(dis_data<0)
//  {
//    dis_data=-dis_data;
//  }
  temp_X=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
  dis_data=(BUF[3]<<8)+BUF[2];  //合成数据   
//  if(dis_data<0)
//  {
//    dis_data=-dis_data;
//  }
  temp_Y=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
  dis_data=(BUF[5]<<8)+BUF[4];    //合成数据   
//  if(dis_data<0)
//  {
//    dis_data=-dis_data;
//  }
  temp_Z=(float)dis_data*3.9;  //计算数据和显示,查考ADXL345快速入门第4页
}

adxl345.h

#define uint unsigned int
#define uchar unsigned char

extern float temp_X,temp_Y,temp_Z;


void SCL_Set_Output(void);
void SDA_Set_Output(void);
void SDA_Set_Input(void);
void Init_ADXL345(void);    
void  Single_Write_ADXL345(uchar REG_Address,uchar REG_data);   //??????
uchar Single_Read_ADXL345(uchar REG_Address);                   //???????????
void  Multiple_Read_ADXL345(void);                                  //????????????
void ADXL345_Start(void);
void ADXL345_Stop(void);
void ADXL345_SendACK(uchar ack);
uchar  ADXL345_RecvACK(void);
void ADXL345_SendByte(uchar dat);
uchar ADXL345_RecvByte(void);
void ADXL345_ReadPage(void);
void ADXL345_WritePage(void);
void ReadData_x(void);

ds18b20.c

#include "ds18b20.h"
#include "delay.h"    

//IO方向设置
//#define DS18B20_IO_IN()  {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=8<<0;}
//#define DS18B20_IO_OUT() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=3<<0;}

void DS18B20_IO_IN(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

     RCC_APB2PeriphClockCmd(RCC_GPIO_DQ,ENABLE);//使能PORTA,PORTC时钟

    GPIO_InitStructure.GPIO_Pin  = GPIO_DQ_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     GPIO_Init(GPIO_DQ, &GPIO_InitStructure);//初始化
}

void DS18B20_IO_OUT(void)
{
 GPIO_InitTypeDef  GPIO_InitStructure;

 RCC_APB2PeriphClockCmd(RCC_GPIO_DQ, ENABLE);     //使能

 GPIO_InitStructure.GPIO_Pin = GPIO_DQ_PIN;                 
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度为50MHz
 GPIO_Init(GPIO_DQ, &GPIO_InitStructure);                     //根据设定参数初始化
}
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在         
u8 DS18B20_Init(void)
{
     GPIO_InitTypeDef  GPIO_InitStructure;

     RCC_APB2PeriphClockCmd(RCC_GPIO_DQ, ENABLE);     //使能PORTA口时钟 

     GPIO_InitStructure.GPIO_Pin = GPIO_DQ_PIN;                //PORTA0 推挽输出
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;           
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_Init(GPIO_DQ, &GPIO_InitStructure);

     GPIO_SetBits(GPIO_DQ,GPIO_DQ_PIN);    //输出1

    DS18B20_Rst();

    return DS18B20_Check();
}  


//复位DS18B20
void DS18B20_Rst(void)       
{                 
    DS18B20_IO_OUT(); //SET PA0 OUTPUT
    DS18B20_DQ_OUT=0; //拉低DQ
    delay_us(750);    //拉低750us
    DS18B20_DQ_OUT=1; //DQ=1 
    delay_us(15);     //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)        
{   
    u8 retry=0;
    DS18B20_IO_IN();//SET PA0 INPUT     
    while (DS18B20_DQ_IN&&retry<200)
    {
        retry++;
        delay_us(1);
    };     
    if(retry>=200)return 1;
    else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
    {
        retry++;
        delay_us(1);
    };
    if(retry>=240)return 1;        
    return 0;
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void)              // read one bit
{
    u8 data;
    DS18B20_IO_OUT();//SET PA0 OUTPUT
    DS18B20_DQ_OUT=0; 
    delay_us(2);
    DS18B20_DQ_OUT=1; 
    DS18B20_IO_IN();//SET PA0 INPUT
    delay_us(12);
    if(DS18B20_DQ_IN)data=1;
    else data=0;     
    delay_us(50);           
    return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)    // read one byte
{        
    u8 i,j,dat;
    dat=0;
    for (i=1;i<=8;i++) 
    {
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }                            
    return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
    DS18B20_IO_OUT();//SET PA0 OUTPUT;
    for (j=1;j<=8;j++) 
    {
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            DS18B20_DQ_OUT=0;// Write 1
            delay_us(2);                            
            DS18B20_DQ_OUT=1;
            delay_us(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;// Write 0
            delay_us(60);             
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}
//开始温度转换
void DS18B20_Start(void)// ds1820 start convert
{                                          
    DS18B20_Rst();       
    DS18B20_Check();     
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0x44);// convert
} 

//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250) 
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
    short tem;
    DS18B20_Start ();                    // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();     
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0xbe);// convert        
    TL=DS18B20_Read_Byte(); // LSB   
    TH=DS18B20_Read_Byte(); // MSB  

    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;//温度为负  
    }else temp=1;//温度为正            
    tem=TH; //获得高八位
    tem<<=8;    
    tem+=TL;//获得底八位
    tem=(float)tem*0.625;//转换     
    if(temp)return tem; //返回温度值
    else return -tem;    
}

ds18b20.h

#ifndef __DS18B20_H
#define __DS18B20_H 
#include "sys.h"   

#define GPIO_DQ       GPIOC                 //  使能端口组
#define GPIO_DQ_PIN   GPIO_Pin_13            //  使能端口号
#define RCC_GPIO_DQ   RCC_APB2Periph_GPIOC  //  使能时钟组                                           
#define    DS18B20_DQ_OUT PCout(13) //数据端口    
#define    DS18B20_DQ_IN  PCin(13)  //数据端口    

void DS18B20_IO_IN(void);
void DS18B20_IO_OUT(void);


u8 DS18B20_Init(void);            //初始化DS18B20
short DS18B20_Get_Temp(void);    //获取温度
void DS18B20_Start(void);        //开始温度转换
void DS18B20_Write_Byte(u8 dat);//写入一个字节
u8 DS18B20_Read_Byte(void);        //读出一个字节
u8 DS18B20_Read_Bit(void);        //读出一个位
u8 DS18B20_Check(void);            //检测是否存在DS18B20
void DS18B20_Rst(void);            //复位DS18B20    
#endif