前言
温度是一个和人们生活环境有着密切关系的物理量,也是一种在生产、科研、生活中需要测量和控制的物理量。温度的变化给我们的生活、生产、工作等带来重大影响,因此对温度的测量至关重要,其测量控制一般使用各式各样的温度传感器。 本文基于STM32F103RCT6设计了一款远程温度监测设备,可实时采集某一点的温度数据,通过NRF24L01进行远距离传输,发送至另一端设备,方便实时读取某一点的温度数据。
一、实际效果图

二、系统总体结构图
系统设计采用主、从分布式设计,即温度检测点放置独立工作从机,将数据发送至主机。
三、模块使用说明
1、NRF24L01
 
Enhanced ShockBurst?模式下发送数据流程
A. 把地址和要发送的数据按时序送入NRF24L01; B. 配置CONFIG寄存器,使之进入发送模式; C. MCU把CE置高(至少10us),激发Enhanced ShockBurst?发射; D. Enhanced ShockBurst?发射: a)给射频前端供电; b)射频数据打包(加字头、CRC校验码); c)高速发射数据包; d)发射完成,NRF24L01进入空闲状态
Enhanced ShockBurst?模式下接收数据流程
A. 配置接收地址和要接收的数据包大小; B. 配置CONFIG寄存器,使之进入接收模式,把CE置高; C. 130us后,NRF24L01进入监视状态,等待数据包的到来; D. 当接收到正确的数据包(正确的地址和CRC校验码),NRF24L01自动移去字头、地址和CRC校验位 E. NRF24L01通过把STATUS寄存器的RX_DR置位(STATUS一般引起MCU中断)通知MCU; F. MCU把数据从FIFO读出(0x61指令); G. 所有数据读取完毕后,可清除STATUS寄存器;NRF24L01可以进入四中主要的模式之一。
2、DS18B20
 DS18B20内部主要包括,64位ROM、2字节温度输出寄存器、1字节上下警报寄存器(TH和TL)和1字节配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同,这样就可以实现一根总线挂接多个DS18B20的目的。
操作方式
a 通过模块配置信号DQ写入(CCH)命令,跳过DS18B20的ROM匹配。因为此单片机上仅挂载了一个DS18B20,不需要进行读取ROM编码以及匹配ROM编码。 b 通过模块配置信号DQ写入(44H)命令,启动温度转换。系统采用DS18B20默认的12位精度,温度转换所需时间最大750ms,因此需等待750ms。 c 通过模块配置信号DQ写入(BEH)命令,读取DS18B20中暂存寄存器内的温度数据。 d 暂存寄存器值送入CRC校验模块,检测CRC校验模块反馈标志,若CRC校验正确,则更新温度数据,否则,不更新温度数据。
四、模块程序
1、NRF24L01程序
nrf24l01.c
#include "24l01.h"
#include "delay.h"
const u8 TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};
const u8 RX_ADDRESS[RX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};
void NRF24L01_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_ResetBits(GPIOC,GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
SPI1_Init();
SPI_Cmd(SPI1, DISABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
NRF24L01_CE=0;
NRF24L01_CSN=1;
}
u8 NRF24L01_Check(void)
{
u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
u8 i;
SPI1_SetSpeed(SPI_BaudRatePrescaler_4);
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,buf,5);
NRF24L01_Read_Buf(TX_ADDR,buf,5);
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;
return 0;
}
u8 NRF24L01_Write_Reg(u8 reg,u8 value)
{
u8 status;
NRF24L01_CSN=0;
status =SPI1_ReadWriteByte(reg);
SPI1_ReadWriteByte(value);
NRF24L01_CSN=1;
return(status);
}
u8 NRF24L01_Read_Reg(u8 reg)
{
u8 reg_val;
NRF24L01_CSN = 0;
SPI1_ReadWriteByte(reg);
reg_val=SPI1_ReadWriteByte(0XFF);
NRF24L01_CSN = 1;
return(reg_val);
}
u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0;
status=SPI1_ReadWriteByte(reg);
for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=SPI1_ReadWriteByte(0XFF);
NRF24L01_CSN=1;
return status;
}
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0;
status = SPI1_ReadWriteByte(reg);
for(u8_ctr=0; u8_ctr<len; u8_ctr++)SPI1_ReadWriteByte(*pBuf++);
NRF24L01_CSN = 1;
return status;
}
u8 NRF24L01_TxPacket(u8 *txbuf)
{
u8 sta;
SPI1_SetSpeed(SPI_BaudRatePrescaler_8);
NRF24L01_CE=0;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
NRF24L01_CE=1;
while(NRF24L01_IRQ!=0);
sta=NRF24L01_Read_Reg(STATUS);
NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
if(sta&MAX_TX)
{
NRF24L01_Write_Reg(FLUSH_TX,0xff);
return MAX_TX;
}
if(sta&TX_OK)
{
return TX_OK;
}
return 0xff;
}
u8 NRF24L01_RxPacket(u8 *rxbuf)
{
u8 sta;
SPI1_SetSpeed(SPI_BaudRatePrescaler_8);
sta=NRF24L01_Read_Reg(STATUS);
NRF24L01_Write_Reg(NRF_WRITE_REG+STATUS,sta);
if(sta&RX_OK)
{
NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);
NRF24L01_Write_Reg(FLUSH_RX,0xff);
return 0;
}
return 1;
}
void NRF24L01_RX_Mode(void)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
NRF24L01_Write_Reg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG, 0x0f);
NRF24L01_CE = 1;
}
void NRF24L01_TX_Mode(void)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);
NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01);
NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x1a);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,40);
NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x0f);
NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x0e);
NRF24L01_CE=1;
}
nrf24l01.h
#ifndef __24L01_H
#define __24L01_H
#include "sys.h"
#define NRF_READ_REG 0x00
#define NRF_WRITE_REG 0x20
#define RD_RX_PLOAD 0x61
#define WR_TX_PLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define MAX_TX 0x10
#define TX_OK 0x20
#define RX_OK 0x40
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define NRF_FIFO_STATUS 0x17
#define NRF24L01_CE PCout(3)
#define NRF24L01_CSN PCout(2)
#define NRF24L01_IRQ PCin(1)
#define TX_ADR_WIDTH 5
#define RX_ADR_WIDTH 5
#define TX_PLOAD_WIDTH 32
#define RX_PLOAD_WIDTH 32
void NRF24L01_Init(void);
void NRF24L01_RX_Mode(void);
void NRF24L01_TX_Mode(void);
u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 u8s);
u8 NRF24L01_Read_Buf(u8 reg, u8 *pBuf, u8 u8s);
u8 NRF24L01_Read_Reg(u8 reg);
u8 NRF24L01_Write_Reg(u8 reg, u8 value);
u8 NRF24L01_Check(void);
u8 NRF24L01_TxPacket(u8 *txbuf);
u8 NRF24L01_RxPacket(u8 *rxbuf);
#endif
2、DS18B20程序
bs18b20.c:
#include "ds18b20.h"
#include "delay.h"
void DS18B20_Rst(void)
{
DS18B20_IO_OUT();
DS18B20_DQ_OUT=0;
delay_us(750);
DS18B20_DQ_OUT=1;
delay_us(15);
}
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN();
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;
}
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT();
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN();
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
u8 DS18B20_Read_Byte(void)
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT();
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0;
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0x44);
}
u8 DS18B20_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_15);
DS18B20_Rst();
return DS18B20_Check();
}
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start ();
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc);
DS18B20_Write_Byte(0xbe);
TL=DS18B20_Read_Byte();
TH=DS18B20_Read_Byte();
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;
}
bs18b20.h:
#ifndef __DS18B20_H
#define __DS18B20_H
#include "sys.h"
#define DS18B20_IO_IN() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOA->CRH&=0XFFFF0FFF;GPIOA->CRH|=3<<12;}
#define DS18B20_DQ_OUT PAout(15)
#define DS18B20_DQ_IN PAin(15)
u8 DS18B20_Init(void);
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);
void DS18B20_Rst(void);
#endif
五、总结
系统利用DS18B20完成温度采集,将单片机与NRF24L01模块结合,克服了传统近距离监测系统中的局限,给出了一种远距离多点温度遥测采集系统的实现方法。该系统结构简单、便于维护、性价比高,在原设计思路基础上,稍加修改,就可应用食品加工、工业检测等领域。
六、详细代码
基于STM32远距离温度监测系统程序
|