/*
初始化DS18B20对应GPIO端口
配置端口的输入输出宏定义
初始化
复位+响应(reset+response)
启动转换
start
跳过Rom
获得数值
读位读字节,写位写字节
*/
/*配套原子mini-stm32开发板*/
/*
short DS18B20_Get_Temperature(void)函数中
u8 TL=0;
u8 TH=0;
不初始化为0,读取的温度数据有乱码
*/
#include <led.h>
#include <delay.h>
#include <sys.h>
#include <usart.h>
#include <lcd.h>
#include <ds18b20.h>
static u8 mark;//串口调试计数值
/*DS18B20端口及端口位还没有实现宏定义的完全可移植*/
#define DS18B20_GPIO GPIOA //端口宏定义
#define DS18B20_DQ GPIO_Pin_0//端口位宏定义
#define DS18B20_IO_IN() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=8<<0;}//GPIO方向设置:输入
#define DS18B20_IO_OUT() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=3<<0;}//GPIO方向设置:输出
/*DS18B20_DQ对应GPIO端口的输入输出数据操作方式:调用位带操作方式(sys.c实现)*/
#define DS18B20_DQ_IN PAin(0) //IO操作函数:读取端口(输入)
#define DS18B20_DQ_OUT PAout(0) //IO操作函数:写入端口(输出)
#define DS18B20_DQ_H GPIO_SetBits(DS18B20_GPIO,DS18B20_DQ); //输出1
#define DS18B20_DQ_L GPIO_ResetBits(DS18B20_GPIO,DS18B20_DQ);//输出0
void main1(void);
/*
复位函数
*/
void Reset(void)//主机将总线拉低至少480us,取750us
{
DS18B20_IO_OUT();//设置PA0为输出
DS18B20_DQ_H; //拉高总线
delay_us(5); //延时
DS18B20_DQ_L; //拉低总线
delay_us(750); //延时
DS18B20_DQ_H; //释放总线
delay_us(15); //延时
}
/*
检测从机DS18B20响应
*/
u8 Response(void)//主机释放总线后,DS18B20等待15-60us后,将总线拉低60-240us低电平,然后释放,主机检测到低电平后确认协议完成,开始通信
{
u8 Test_count;
// delay_us(15); //延时,可有可无
DS18B20_IO_IN(); //配置为输入模式
//两个while,完成主机校验从机响应的两个必要条件:15-60us后有低电平,且低电平持续时间为60-240us
//判断从机有没有等待15-60us后输出低电平
while(DS18B20_DQ_IN&&Test_count<100)
{
Test_count++;
delay_us(1);
}
if(Test_count>100) return 1;
else Test_count=0;
while(!DS18B20_DQ_IN&&Test_count<200)
{
Test_count++;
delay_us(1);
}
if(Test_count>200) return 1;
else return 0;
}
/*
DS18B20端口配置
*/
void DS18B20_GPIO_Config(void)//
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启DS18B20_PORT的外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/*选择要控制的DS18B20_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DS18B20_PORT*/
GPIO_Init(GPIOA, &GPIO_InitStructure);
/*置位输出*/
GPIO_SetBits(GPIOA, GPIO_Pin_0);
}
u8 DS18B20_init(void)//主机将总线拉低至少480us,取750us
{
DS18B20_GPIO_Config();//
Reset();
return Response();
}
/*
读1字位
*/
u8 Read_bit(void)//主机拉低总线至少1us开始时隙,从机在时隙开始后输出到总线高电平|低电平,主机应在15us内完成读取
{
u8 Data_bit=0;
//配置为输出模式
DS18B20_IO_OUT();//设置PA0为输出
DS18B20_DQ_L; //拉高总线
delay_us(2); //延时
DS18B20_DQ_H; //拉低总线
DS18B20_IO_IN();//设置PA0为输出
delay_us(10); //延时
if(DS18B20_DQ_IN)
{
Data_bit=1;
}
else Data_bit=0;
delay_us(45); //延时
return Data_bit;
}
/*
读1字节
*/
u8 Read_byte(void)
{
u8 Time_count=0;
u8 Data_bit;
u8 Data_byte=0;
for(Time_count=0;Time_count<8;Time_count++)
{
Data_bit=Read_bit();
Data_byte|=(Data_bit<<Time_count);
}
return Data_byte;
}
/*
读1字节:另一种方式
*/
/*
u8 Read_byte(void)
{
u8 i=0;
u8 Data_bit=0;
u8 Data_byte=0;
for (i=1;i<=8;i++)
{
Data_bit=Read_bit();
Data_byte=(Data_bit<<7)|(Data_byte>>1);//每读取1位,将其存放于当前字节的最高位(第7位):先存低位后存高位
}
return Data_byte;
}
*/
/*
写1位
*/
void Write_bit(u8 Data_bit)//
{
//配置为输出模式
DS18B20_IO_OUT();//设置PA0为输出
if(Data_bit)
{
DS18B20_DQ_L; //拉高低线
delay_us(2); //延时
DS18B20_DQ_H; //拉高低线
delay_us(80); //延时
}
else
{
DS18B20_DQ_L; //拉高低线
delay_us(70); //延时
DS18B20_DQ_H; //拉高低线
delay_us(2); //延时
}
}
/*
写1字节
*/
void Write_byte(u8 Data_byte)//
{
u8 Time_count;
for(Time_count=0;Time_count<8;Time_count++)
{
Write_bit(Data_byte&(0x01<<Time_count));
delay_us(2); //延时
}
}
/*
写1字节:另一种方式
*/
/*
void Write_byte(u8 Data_byte)//
{
u8 Time_count=0;
u8 Data_bit=0;
for(Time_count=0;Time_count<8;Time_count++)
{
Data_bit=Data_byte&0x01;//要写入字节的最低位
Data_byte=Data_byte>>1;//写入字节右移1位,上次赋值给testb的最低位被移出
Write_bit(Data_bit);
delay_us(2); //延时
}
}
*/
/*
从ds18b20得到温度值
精度:0.1C
返回值:温度值 (-550~1250)
*/
short DS18B20_Get_Temperature(void)
{
u8 TL=0;
u8 TH=0;//存放两字节温度数据的,高低字节
short Data_Temp_HEX;//存放二进制温度数据
short Data_Temp_DEC;//存放十进制温度数据
printf("---TL:%d\r\n",TL);
printf("---TH:%d\r\n",TH);
mark++;
printf("---%d---\r\n",mark);
Reset();//复位
Response();//响应
Write_byte(0xcc);//跳过ROM
Write_byte(0x44);//启动温度转换
Reset();//复位
Response();//响应
Write_byte(0xcc);//跳过ROM
Write_byte(0xbe);//读取温度数据
TL=Read_byte();//温度低字节
TH=Read_byte();//温度高字节
printf("TL:%d\r\n",TL);
printf("TH:%d\r\n",TH);
if(TH>7)//当TH数据为1111****时,标识温度为负,当TH数据为0000****时,标识温度为正。显然温度为正时TH<7,温度为负时TH>7
{
TH=~TH;
TL=~TL;
Data_Temp_HEX=TH;
Data_Temp_HEX=(Data_Temp_HEX<<8)+TL;//合并高低字节
Data_Temp_DEC=(float)((~Data_Temp_HEX+1)*0.625);//二进制--->十进制
printf("123\r\n");
printf("%d\r\n",Data_Temp_DEC);
return -Data_Temp_DEC;
}
else if(TH<7)
{
Data_Temp_HEX=TH;
Data_Temp_HEX=(Data_Temp_HEX<<8)+TL;
Data_Temp_DEC=(float)(Data_Temp_HEX*0.625);
printf("321\r\n");
printf("%d\r\n",Data_Temp_DEC);
return Data_Temp_DEC;
}
}
/*
主函数:调用测试函数
*/
int main(void)
{
main1();
}
/*
测试函数:通过串口及LCD显示检测温度
*/
void main1(void)
{
u8 t=0;//时间计数值
short temperature;//温度数据
delay_init(); //延时函数初始化
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); //初始化与LCD连接的硬件接口
POINT_COLOR=RED; //设置字体为红色
LCD_ShowString(60,50,200,16,16,"NZX---STM32");
LCD_ShowString(60,70,200,16,16,"DS18B20 TEST");
LCD_ShowString(60,90,200,16,16,"stay hungry,stay foolish");
LCD_ShowString(60,110,200,16,16,"2015/01/21");
LCD_ShowString(60,130,200,16,16,"DS18B20 is OK");
while(DS18B20_init()) //DS18B20安装|初始化成功?
{
LCD_ShowString(60,130,200,16,16,"DS18B20 Error");
delay_ms(200);
LCD_Fill(60,130,239,130+16,WHITE);
delay_ms(200);
}
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,150,200,16,16,"Temp: . C");
while(1)//循环显示温度采集值
{
if(t%10==0)//每100ms读取一次
{
temperature=DS18B20_Get_Temperature ();//获取温度值
if(temperature>0)
{
LCD_ShowChar(60+40,150,'+',16,0); //显示正号
}
else
{
LCD_ShowChar(60+40,150,'-',16,0); //显示负号
temperature=-temperature; //转为正数
}
LCD_ShowNum(60+40+8,150,temperature/10,2,16); //显示正数部分
LCD_ShowNum(60+40+32,150,temperature%10,1,16); //显示小数部分
if(t==100)//板载led闪烁
{
t=0;//计数清零
LED0=!LED0;
}
}
t++;//计时计数
delay_ms(10);//延时10ms
}
}
/*
1, 复位:首先我们必须对DS18B20芯片进行复位,复位就是由控制器(单片机)给DS18B20单总线至少480uS的低电平信号。
当18B20接到此复位信号后则会在15~60uS后回发一个芯片的存在脉冲。
2, 存在脉冲:在复位电平结束之后,控制器应该将数据单总线拉高,以便于在15~60uS后接收存在脉冲,存在脉冲为一个60~240uS的低电平信号。
至此,通信双方已经达成了基本的协议,接下来将会是控制器与18B20间的数据通信。
如果复位低电平的时间不足或是单总线的电路断路都不会接到存在脉冲,在设计时要注意意外情况的处理。
3, 控制器发送ROM指令:双方打完了招呼之后最要将进行交流了,ROM指令共有5条,每一个工作周期只能发一条,
ROM指令分别是读ROM数据、指定匹配芯片、跳跃ROM、芯片搜索、报警芯片搜索。ROM指令为8位长度,功能是对片内的64位光刻ROM进行操作。
其主要目的是为了分辨一条总线上挂接的多个器件并作处理。诚然,单总线上可以同时挂接多个器件,并通过每个器件上所独有的ID号来区别,
一般只挂接单个18B20芯片时可以跳过ROM指令(注意:此处指的跳过ROM指令并非不发送ROM指令,而是用特有的一条“跳过指令”)。ROM指令在下文有详细的介绍。
4, 控制器发送存储器操作指令:在ROM指令发送给18B20之后,紧接着(不间断)就是发送存储器操作指令了。
操作指令同样为8位,共6条,存储器操作指令分别是写RAM数据、读RAM数据、将RAM数据复制到EEPROM、温度转换、将EEPROM中的报警值复制到RAM、工作方式切换。
存储器操作指令的功能是命令18B20作什么样的工作,是芯片控制的关键。
5, 执行或数据读写:一个存储器操作指令结束后则将进行指令执行或数据的读写,这个操作要视存储器操作指令而定。
如执行温度转换指令则控制器(单片机)必须等待18B20执行其指令,一般转换时间为500uS。
如执行数据读写指令则需要严格遵循18B20的读写时序来操作。数据的读写方法将有下文有详细介绍。
若要读出当前的温度数据我们需要执行两次工作周期,第一个周期为复位、跳过ROM指令、执行温度转换存储器操作指令、等待500uS温度转换时间。
紧接着执行第二个周期为复位、跳过ROM指令、执行读RAM的存储器操作指令、读数据(最多为9个字节,中途可停止,只读简单温度值则读前2个字节即可)。
*/
///***********************延时函数********************************/
//void delays(u8 i) // 延时1ms函数
//{
// u8 j;
// while(i--)
// {
// for(j=0;j<119;j++);
// }
//}
//void delay(int us) // 延时函数
//{
// int s;
// for (s = 0; s < us; s++);
//}
///***********************温度模块********************************/
//void init(void) //初始化,复位,应答
//{
// u8 n;
//
// GPIO_InitTypeDef GPIO_InitStructure;
//
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA口时钟
//
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PORTA0 推挽输出
// 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_0); //输出1
//
// DS18B20_IO_OUT(); //SET PA0 OUTPUT
// DS18B20_DQ_H; delay_us(8);
// DS18B20_DQ_L; delay_us(750);
// DS18B20_DQ_H; delay_us(15);
//}
//
//u8 read_bit(void) //读0,1
//{
// 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;
//}
//u8 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 write_bit(char bitval) //写0,1
//{
// DS18B20_IO_OUT(); //SET PA0 OUTPUT
// DS18B20_DQ_L; // 拉低
// if(bitval==1) DS18B20_DQ_H; // 若写1,拉高
// delay(5); // 足够转换时间
// DS18B20_DQ_H;
//}
//void write_byte(char val) //写字节
//{
// u8 i,temp;
// for (i = 0; i < 8; i++)
// {
// temp = val>>i;
// temp &= 0x01;
// write_bit(temp);
// }
// delay(5);
//}
//int getTem() //获得温度数据
//{
// int value; //存放温度数值
// double t;
// u32 tmpvalue;
// u8 low, high;
// DS18B20_Start ();// ds1820开始温度转换
// DS18B20_Rst();//复位
// DS18B20_Check();//校验ds18b20
//
// write_byte(0xcc);
// write_byte(0xbe);
// low=read_byte();
// high=read_byte(); //将高低两个字节合成一个整形变量
// tmpvalue=high; //计算机中对于负数是利用补码来表示的
// tmpvalue<<=8; //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的value
// tmpvalue|=low;
// value=tmpvalue;
// t=value*0.0625;
// value=t*100+(value>0?0.5:-0.5); //大于0加0.5, 小于0减0.5
// return value;
//}