【蓝桥杯单片机】DS1302时钟芯片+DS18B20单总线温度传感器(官方驱动源码改写)

实验开发板为CT107D蓝桥官方板,编译环境为MDK5

采用蓝桥官方驱动改写

目录

 

一、DS1302时钟芯片

 二、DS18B20温度传感器


一、DS1302时钟芯片

 

  • CE 复位脚
  • I/O 数据输入/输出引脚
  • SCLK 串行时钟
  • SCLK:串行时钟,输入,控制数据的输入与输出;
  • I/O:三线接口时的双向数据线;
  • CE:输入信号,在读、写数据期间,必须为高。

DS1302的使用主要在于看懂和掌握时序图

第一个字节的数据的第一位:1(读)2(写)

下图为各类数据的地址以及传输的格式(输入输出均用BCD码):

注意:年只有后两位,格式为20xx年。

DS1302具有Burst模式可顺序读或写日历和时间数据而跳过写地址步骤

当启用该模式后DS1302会通过数据线按:秒,分,时,日,月,星期,年的顺序输出。

main.h:

#ifndef _MAIN_H
#define _MAIN_H

#include "STC15F2K60S2.h"

typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned long u32;

#endif

ds1302.h:

#ifndef  __DS1302_H__
#define  __DS1302_H__

#include "main.h"
#include<intrins.h>
/********************************************************************/ 
sbit SCK=P1^7;		
sbit SD=P2^3;		
sbit RST=P1^3;
/********************************************************************/ 
/*复位脚*/
#define RST_CLR	RST=0	/*电平置低*/
#define RST_SET	RST=1	/*电平置高*/
/*双向数据*/
#define SDA_CLR	SD=0	/*电平置低*/
#define SDA_SET	SD=1	/*电平置高*/
#define SDA_R	SD	/*电平读取*/	
/*时钟信号*/
#define SCK_CLR	SCK=0	/*时钟信号*/
#define SCK_SET	SCK=1	/*电平置高*/
/********************************************************************/ 
#define ds1302_sec_addr			0x80		//秒数据地址
#define ds1302_min_addr			0x82		//分数据地址
#define ds1302_hr_addr			0x84		//时数据地址
#define ds1302_date_addr		0x86		//日数据地址
#define ds1302_month_addr		0x88		//月数据地址
#define ds1302_day_addr			0x8A		//星期数据地址
#define ds1302_year_addr		0x8C		//年数据地址

#define ds1302_control_addr		0x8E		//写保护命令字单元地址
#define ds1302_charger_addr		0x90 		//涓电流充电命令字地址			 
#define ds1302_clkburst_addr		0xBE		//日历、时钟突发模式命令字地址
/********************************************************************/ 
extern u8 Time[7];

typedef struct time{
	u16 year;
	u8 mon;
	u8 day;
	u8 hour;
	u8 min;
	u8 sec;
	u8 week;
}Stime;
/********************************************************************/ 
/*单字节写入一字节数据*/
extern void Write_Ds1302_Byte(unsigned char dat);
/********************************************************************/ 
/*单字节读出一字节数据*/
extern unsigned char Read_Ds1302_Byte(void);
  
/********************************************************************/ 
/********************************************************************/ 
/*向DS1302单字节写入一字节数据*/
extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);
/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr);

extern void DS1302BurstWrite(unsigned char *dat);

extern void DS1302BurstRead(unsigned char *dat);

extern void Init_DS1302();

//extern void DS1302_TimeIn(Stime *time);

//extern void DS1302_TimeOut(Stime *time);

#endif	 
/********************************************************************/
//		     	END FILE
/********************************************************************/

ds1302.c:

#include "ds1302.h"
#include "main.h"

/********************************************************************/ 
/*单字节写入一字节数据*/
void Write_Ds1302_Byte(unsigned char dat) 
{
	unsigned char i;
	SCK = 0;
	for (i=0;i<8;i++) 
	{ 
		if (dat & 0x01) 	// 等价于if((addr & 0x01) ==1) 
		{
			SDA_SET;		//#define SDA_SET SDA=1 /*电平置高*/
		}
		else 
		{
			SDA_CLR;		//#define SDA_CLR SDA=0 /*电平置低*/
		}		 
		SCK_SET;
		SCK_CLR;		
		dat = dat >> 1; 
	} 
}
/********************************************************************/ 
/*单字节读出一字节数据*/
unsigned char Read_Ds1302_Byte(void) 
{
	unsigned char i, dat=0;	
	for (i=0;i<8;i++)
	{	
		dat = dat >> 1;
		if (SDA_R) 	  //等价于if(SDA_R==1)    #define SDA_R SDA /*电平读取*/	
		{
			dat |= 0x80;
		}
		else 
		{
			dat &= 0x7F;
		}
		SCK_SET;
		SCK_CLR;
	}
	return dat;
}

/********************************************************************/ 
/*向DS1302 单字节写入一字节数据*/
void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat)
{ 
	RST_SET;			/*启动DS1302总线,RST=1电平置高 */
	addr = addr & 0xFE;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/	
	Write_Ds1302_Byte(dat);	 /*写入数据:dat*/
	RST_CLR;				 /*停止DS1302总线*/
}

/********************************************************************/ 
/*从DS1302单字节读出一字节数据*/
unsigned char Ds1302_Single_Byte_Read(unsigned char addr) 
{ 
	unsigned char temp;
	RST_CLR;			/*RST脚置低,实现DS1302的初始化*/
	SCK_CLR;			/*SCK脚置低,实现DS1302的初始化*/

	RST_SET;	/*启动DS1302总线,RST=1电平置高 */	
	addr = addr | 0x01;	 
	Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/
	temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/		
	RST_CLR;	/*停止DS1302总线*/
	return temp;
}

void DS1302BurstWrite(u8 *dat)
{
	u8 i;
	RST_SET;
	Write_Ds1302_Byte(ds1302_clkburst_addr);	//写入Burst模式启动指令
	for(i = 0; i < 8; i ++)
	{
		Write_Ds1302_Byte(*dat ++);
	}
	RST_CLR;
}

void DS1302BurstRead(u8 *dat)
{
	u8 i;
	RST_SET;
	Write_Ds1302_Byte(0XBF);
	for(i = 0; i < 8; i ++)
	{
		dat[i] = Read_Ds1302_Byte();
	}
	RST_CLR;
}

void Init_DS1302()
{
	u8 Init_Time[] = {
		0x50 , 0x59 , 0x23 , 0x16 , 0x03 , 0x06 , 0x19 
	};
	RST_CLR;
	SDA_CLR;
	Ds1302_Single_Byte_Write(ds1302_control_addr,0x00);
	DS1302BurstWrite(Init_Time);
}

新版官方驱动改写(DS1302):

DS1302.h:

#ifndef __DS1302_H
#define __DS1302_H

sbit SCK = P1^7;		
sbit SDA_D = P2^3;		
sbit RST = P1^3;   // DS1302复位	

void Write_Ds1302(unsigned char temp);
u8 Read_Ds1302();
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void DS1302BurstWrite(u8 *Dat);
void DS1302BurstRead(u8 *Dat);
void DS1302Init();
void TimeTranslate();
void TimeDisplay();
u8 HexToBCD(u8 Hex);
u8 BCDToHex(u8 BCD);

#endif

DS1302.c:

#include "Sys.h"											

void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK=0;
		SDA_D=temp&0x01;
		temp>>=1; 
		SCK=1;
	}
	SCK = 0;//记得加上
}   
/*******************************/
u8 Read_Ds1302(){
	u8 i = 0, temp = 0x00;
	for (i=0;i<8;i++) 											//这段来自于第47行
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA_D)
 		temp|=0x80;	
 		SCK=1;
	} 
	SCK = 0;//记得加上
	return (temp);		
}
/*******************************/
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_(); 
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

unsigned char Read_Ds1302_Byte ( unsigned char address )//未使用
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA_D)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA_D=0;	_nop_();
	SDA_D=1;	_nop_();
	return (temp);			
}/*******************************/

/**************************************************************************
函数功能:DS1302Burst写
入口参数:待写入数组地址
返回值  :无
**************************************************************************/
void DS1302BurstWrite(u8 *Dat){
	u8 index = 0;
	RST = 1;
	Write_Ds1302(0xBE);											//写Burst写指令
	for(index = 0 ; index < 8; index ++){
																					//读数据
		Write_Ds1302(Dat[index]);
	}
	RST = 0;
}
/**************************************************************************
函数功能:DS1302Burst读
入口参数:时间存储数组地址
返回值  :无
**************************************************************************/
void DS1302BurstRead(u8 *Dat){
	u8 index = 0;
	RST = 1;
	Write_Ds1302(0xBF);											//写Burst读指令
	for(index = 0 ; index < 8; index ++){
																					//读数据
		Dat[index] = Read_Ds1302();
	}
	RST = 0;
}
/**************************************************************************
函数功能:DS1302时间初始化
入口参数:无
返回值  :无
**************************************************************************/
void DS1302Init(){
	u8 InitTime[] = {  											//2019年12月12日 星期四 10:00:00
        0x00,0x00,0x10, 0x12, 0x12, 0x04, 0x19
    };//秒   分   时    日    月    周    年
	RST = 0;
	SDA_D = 0;
	Write_Ds1302_Byte(0x8E,0x00);						//撤销写保护
	DS1302BurstWrite(InitTime);
}
/**************************************************************************
函数功能:时间读取
入口参数:无
返回值  :无
**************************************************************************/
void TimeTranslate(){
	u8 Time[7] = {
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
	};
	DS1302BurstRead(Time);
	
	LocalTime.Sec   = Time[0];
	LocalTime.Minu  = Time[1];
	LocalTime.Hour  = Time[2];
	LocalTime.Day   = Time[3];
	LocalTime.Month = Time[4];
	LocalTime.Week  = Time[5];
	LocalTime.Year  = Time[6];
}
/**************************************************************************
函数功能:将实时时间加载到数码管缓冲区
入口参数:无
返回值  :无
**************************************************************************/
void TimeDisplay(){
	
	TimeTranslate();
	
	SMG_Buff[0] = SMG[LocalTime.Hour >> 4];
	SMG_Buff[1] = SMG[LocalTime.Hour & 0x0F];
	SMG_Buff[2] = 0xBF;//-
	SMG_Buff[3] = SMG[LocalTime.Minu >> 4];
	SMG_Buff[4] = SMG[LocalTime.Minu & 0x0F];
	SMG_Buff[5] = 0xBF;
	SMG_Buff[6] = SMG[LocalTime.Sec >> 4];
	SMG_Buff[7] = SMG[LocalTime.Sec & 0x0F];
}
/**************************************************************************
函数功能:十六进制数转BCD码
入口参数:十六进制数
返回值  :BCD码
**************************************************************************/
//u8 HexToBCD(u8 Hex){
//	u8 BCD;
//	BCD = Hex/10;
//	BCD <<= 4;
//	BCD |= Hex % 10;
//	
//	return BCD;
//}
/**************************************************************************
函数功能:BCD码转十六进制数
入口参数:BCD码
返回值  :十六进制数
**************************************************************************/
//u8 BCDToHex(u8 BCD){
//	u8 Hex;
//	Hex = (BCD >> 4)*10 + (BCD & 0x0F);
//	
//	return Hex;
//}
/*******************************/

 

————————————————————————————————————————————————— 

 二、DS18B20温度传感器

由于DS18B20只有一条总线,数据和指令都从这条总线上传输,所以对时间有及其严格的要求

对应于ds18B20.c中的“Start_DS18B20”函数

数据读写时序:

ds18b20.h:

#ifndef _ONEWIRE_H
#define _ONEWIRE_H

#include "main.h"

#define OW_SKIP_ROM 0xcc			//每次使用都需要写入
#define DS18B20_CONVERT 0x44	//启动温度转换
#define DS18B20_READ 0xbe			//读取指令

//IC引脚定义
sbit DQ = P1^4;

//函数声明
void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
bit Init_DS18B20(void);
unsigned char Read_DS18B20(void);
extern bit Start_DS18B20();

#endif

ds18b20.c:

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台
  日    期: 2011-8-9
*/

#include "onewire.h"
#include "main.h"
#include "intrins.h"
//单总线延时函数
u8 i;
void Delay_OneWire(unsigned int t)    //约等于延时1us
{
	do{
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
	}while(-- t);
}

//DS18B20芯片初始化
bit Init_DS18B20(void) //每次获取温度都需要初始化
{
	bit initflag = 0;
	EA = 0;
	
	//DQ = 1;
	//Delay_OneWire(12);
	DQ = 0;
	Delay_OneWire(500); 
	DQ = 1;
	Delay_OneWire(60); 
	initflag = DQ;    
	//Delay_OneWire(5);
	while(!DQ);
	
  EA = 1;
	
	return initflag;
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	EA = 0;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		Delay_OneWire(2);		//*
		DQ = dat&0x01;			//如果写1就拉高,0则拉低
		Delay_OneWire(60);
		DQ = 1;
		dat >>= 1;
	}
	//Delay_OneWire(5);
	EA = 1;
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
	
	EA = 0;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
//		Delay_OneWire(2);		//*
		dat >>= 1;		//使第一位置0
		DQ = 1;
		if(DQ)				//读取第一位
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(60);	//一位数据的读写要超过60us
	}
	EA = 1;
	return dat;
}

bit Start_DS18B20()
{
	bit ack;
	ack = Init_DS18B20();
	if(ack == 0)
	{	
		Write_DS18B20(OW_SKIP_ROM);
		Write_DS18B20(DS18B20_CONVERT);
	}
	
	return ~ack;
}


//另外插入温度的数据处理函数(零下温度未处理)

void Temp_Get()	//温度获取
{
	bit Ack;
	u8 LSB , MSB, index;	
	u16 temp;
	Ack = Init_DS18B20();
	if(Ack == 0)
	{
		Write_DS18B20(OW_SKIP_ROM);			//跳过器件选取(ds18b20是可以挂载多个的,由于只用一个所以跳过器件的选取)
		Write_DS18B20(DS18B20_READ);	//温度读取指令
		LSB = Read_DS18B20();						//
		MSB = Read_DS18B20();
		temp = ((int)MSB << 8) + LSB;
		
		temp >>= 4; //舍弃小数
		for(index = 7; index >= 3; index --)
			Led_DataBuff[index] = 0xFF;	//格式转换
		
		Led_DataBuff[2] = SMG[temp / 10];
		Led_DataBuff[1] = SMG[temp % 10];
		Led_DataBuff[0] = 0xC6;
	}
	Start_DS18B20();	//再次启动温度转换模式

}

新版官方驱动改写(One-Wire):

//*************************ONEWIRE**********************//
#ifndef __ONEWIRE_H
#define __ONEWIRE_H

#include "config.h"

void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
unsigned char Read_DS18B20(void);

bit Start_DS18B20();
bit init_ds18b20(void);
void Temp_Get();
#endif
--------------------------------------------------------
sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //IAP15F2K61S2
{
	t = t * 7;
	while(t--);
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	EA = 0;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
	EA = 1;
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
        EA = 0;
	
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	EA = 1;
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
        initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

bit Start_DS18B20()
{
	bit ack;
	ack = init_ds18b20();
	if(!ack)
	{
		Write_DS18B20(0xCC);
		Write_DS18B20(0x44);
	}
	return ~ack;
}

bit Config_DS18B20()
{
	bit ack;
	ack = Start_DS18B20();
	if(ack == 0)
	{
		Write_DS18B20(0xCC);
		
		Write_DS18B20(0x4E);//写暂存器指令4E
		Write_DS18B20(0x4B);//写高速缓存器TH高温限值75度
		Write_DS18B20(0x00);//写高速缓存器TL低温限值0度
		Write_DS18B20(0x1F);//写配置寄存器4
												//0x1f : 0.5000°C  转换时间93.75ms
												//0x3f : 0.2000°C  转换时间187.5ms
												//0x5f : 0.1250°C  转换时间375ms
												//0x7f : 0.0625°C  转换时间750ms
	}
	return ~ack;
}

/************FOR_DATA***********/

void Temp_Get()
{
	bit ack;
	u8 LSB , MSB;
	u8 index;
	int temp;
	ack = init_ds18b20();
	if(!ack)
	{
		Write_DS18B20(0xCC);
		Write_DS18B20(0xBE);
		LSB = Read_DS18B20();
		MSB = Read_DS18B20();
		temp = ((int)MSB << 8) + LSB;
		
		temp >>= 4;
		for(index = 0; index < 5; index ++)
		{
			SMG_Buff[index] = 0xFF;
		}
		SMG_Buff[5] = SMG_Data[temp / 10];
		SMG_Buff[6] =	SMG_Data[temp % 10];
		SMG_Buff[7] = 0xC6;	
	}
	Start_DS18B20();
}

 

  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值