18b20,很常见的传感器了,软件编写重点主要就是在one-wire总线的时序上,相关的时序可以参考ds18b20不多做赘述;
本次依然采用作者最熟悉的TinyOS平台+CC2538CB实现,由于ds18b20.c驱动文件直接采用c语言编程,contiki和RIOT也可直接使用,这里我就不移植过去测试了;源码在我的百度网盘;
硬件连接:DQ使用PA5,(上拉)
首先TinyOS部分编写APP;代码如下:
/*******************************************************************
*附加实验3:DS18B20测温实验
*节点需求数1
*编译命令make cc2538cb
********************************************************************/
#include "printf.h"
#include "ds18b20.h"
module TestDS18B20C{
uses interface Boot;
uses interface Timer<TMilli> as Timer;
}
implementation
{
unsigned long testdata=0;
task void ds18b20_Task();
void print_ds18b20(){
unsigned short result;
double temp_data;
result = ds18b20_read();
printf("ds18b20:");
printf(" %x ", result);
if( result < 0x800 ){
temp_data = result;
}
else{
printf("-");
temp_data =(~result + 1) & 0x7ff;
}
temp_data = temp_data * 0.625 + 0.5;
result = (unsigned short)(temp_data );
printf(" %d", result/10);
printf(".%d", result%10);
printf("℃\n");
}
/***************************************************
*启动事件
****************************************************/
event void Boot.booted(){
print_ds18b20();
call Timer.startPeriodic( 5000 );
}
/***************************************************
*任务time1_Task
****************************************************/
task void ds18b20_Task(){
print_ds18b20();
}
/***************************************************
*Timer1定时时间到事件
****************************************************/
event void Timer.fired()
{
/****提交time_Task任务***/
post ds18b20_Task();
}
}
代码逻辑简单,每5秒读取一次ds18b20的数据;计算后通过串口打印 出来
其中ds18b20_read在ds18b20.c中,代码如下:
#include "hw_memmap.h"
#include "gpio.h"
#include "hw_gpio.h"
#include "ds18b20.h"
#define ReSet_18b20_DQ() do{GPIOPinTypeGPIOOutput(GPIO_A_BASE, GPIO_PIN_5); \
HWREG(GPIO_A_BASE + (GPIO_O_DATA + (GPIO_PIN_5 << 2))) &= (~(GPIO_PIN_5));}while(0)
#define Set_18b20_DQ() do{GPIOPinTypeGPIOOutput(GPIO_A_BASE, GPIO_PIN_5); \
HWREG(GPIO_A_BASE + (GPIO_O_DATA + (GPIO_PIN_5 << 2))) |= GPIO_PIN_5;}while(0)
/*******************************************************************************
读取DS18B20 总线状态
*******************************************************************************/
unsigned char GetDQ(void){
GPIOPinTypeGPIOInput(GPIO_A_BASE, GPIO_PIN_5);
return HWREG(GPIO_A_BASE + (GPIO_O_DATA + (GPIO_PIN_5 << 2)));
}
/*******************************************************************************
复位DS18B20
*******************************************************************************/
unsigned long ResetDS18B20(void) {
unsigned char is_exsist;
unsigned short delay;
ReSet_18b20_DQ();
delay = 1250;
while(--delay); //500us (该时间的时间范围可以从480到960微秒)
Set_18b20_DQ();
delay = 150;
while(--delay);
is_exsist = 0;
if(0 == GetDQ())
is_exsist |= 1;
delay = 300;
while(--delay);
Set_18b20_DQ();
return is_exsist;
}
/*******************************************************************************
写一个字节到DS18B20
*******************************************************************************/
void DS18B20WriteByte(unsigned char Dat) {
unsigned char i;
unsigned short delay;
for(i = 8; i > 0; i--) {
ReSet_18b20_DQ();
delay = 5;
while(--delay);
if(Dat & 0x01)
Set_18b20_DQ();
else
ReSet_18b20_DQ();
delay = 130;
while(--delay);
Set_18b20_DQ();
delay = 5;
while(--delay);
Dat >>= 1;
}
}
/*******************************************************************************
从DS18B20读取一个字节
*******************************************************************************/
unsigned char DS18B20ReadByte( ) {
unsigned char i,Dat = 0;
unsigned short delay;
for(i = 8; i > 0; i--) {
Dat >>= 1;
ReSet_18b20_DQ();
delay = 5;
while(--delay);
Set_18b20_DQ();
delay = 5;
while(--delay);
if(GetDQ())
Dat |= 0x80;
delay = 130;
while(--delay);
Set_18b20_DQ();
}
return Dat;
}
/*******************************************************************************
读取DS18B20温度值,读取为两个字节,温度值为0XXXXX *0.0625°C
*******************************************************************************/
unsigned short ds18b20_read(void){
unsigned char Temperature1L, Temperature1H;
unsigned short Temperature;
unsigned long delay;
if(0 == ResetDS18B20()){
return 0x88; //可以 自定义返回 未检测到ds18b20的接入
}
DS18B20WriteByte(SkipROM);
DS18B20WriteByte(StartConvert);
delay = 1800000;
while(--delay);
ResetDS18B20();
DS18B20WriteByte(SkipROM);
DS18B20WriteByte(ReadScratchpad);
Temperature1L= DS18B20ReadByte();
Temperature1H= DS18B20ReadByte();
ResetDS18B20();
Temperature = 0;
Temperature = Temperature1H;
Temperature <<= 8;
Temperature |= Temperature1L;
return Temperature;
}
编译后下载到cc2538cb节点运行效果如下图:
需要注意的是可以去看cc2538的手册;IO口的读取真实电平必须先配置该IO口为输入,因为2538的IO口在输出状态下,不管实际电平是否变化,始终读取上一次软件output IO口的值;