⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ds1820.c

📁 这是《Keil Cx51 V7.0单片机高级语言编程与uVision2应用实践》教材各章中列出的全部程序例子。
💻 C
字号:
/******本程序是基于DS5000/DS2251T单片机开发的,运行时需要有128K RAM *****/
#include <absacc.h> 
#include <ctype.h> 
#include <math.h> 
#include <stdio.h>
#include <string.h>
#include <reg5000.h>
/*******************************  参数配置  *****************************/
#define XtalFreq (11059490)     // 主晶振频率 
#define CntrFreq (XtalFreq/12)  // 主计数器频率 
#define BaudRate (38400)        // 波特率 
#define CntrTime (8)            // 计数器的周期数 
#define Ft (32768.0)            // 目标晶振频率 

#define FALSE 0
#define TRUE 1

sbit DQ = 0x97;                // 定义DQ引脚为P1.7

/******************************* 全局变量 ********************************/
unsigned char ROM[8];          // ROM 位
unsigned char lastDiscrep = 0; // 上次差值
unsigned char doneFlag = 0;    // 完成标志
unsigned char FoundROM[5][8];  // ROM 代码表
unsigned char numROMs;
unsigned char dowcrc;
unsigned char code dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53};

/*******************************  延时函数 ********************************
*  功能:在11.059MHz的晶振条件下调用本函数需要24μs ,然后每次计数需16μs 
**************************************************************************/
void delay(int useconds) {
int s;
for (s=0; s<useconds;s++);
}

/*******************************  复位函数 *******************************
* 功能:完成单总线的复位操作。
* 复位时间为480μs,因此延时时间为(480-24)/16 = 28.5,取29μs。
* 经过70μs之后检测存在脉冲,因此延时时间为(70-24)/16 = 2.875,取3μs。
**************************************************************************/
unsigned char ow_reset(void) {
unsigned char presence;
DQ = 0;  			// 将 DQ 线拉低
delay(29); 			// 保持 480μs
DQ = 1; 			// DQ返回高电平
delay(3); 			// 等待存在脉冲
presence = DQ; 		// 获得存在信号
delay(25); 			// 等待时间隙结束
return(presence); 	// 返回存在信号,0 = 器件存在, 1 = 无器件
}


/****************************** 位写入函数 *******************************
* 功能:向单总线写入1位值:bitval
*************************************************************************/
void write_bit(char bitval) {
DQ = 0; 				// 将DQ 拉低开始写时间隙
if(bitval==1) DQ =1; 	// 如果写1,DQ 返回高电平
delay(5); 				// 在时间隙内保持电平值,
DQ = 1; 	// Delay函数每次循环延时16μs,因此delay(5) = 104μs
}	


/**************************** 字节写入函数 *******************************
* 功能:向单总线写入一个字节值:val
*************************************************************************/
void write_byte(char val) {
unsigned char i;
unsigned char temp;
for (i=0; i<8; i++) {	// 写入字节, 每次写入一位 
temp = val>>i; 		
temp &= 0x01; 		
write_bit(temp); 
}
delay(5);
}

/**************************** 位读取函数 ********************************
* 功能:从单总线上读取一位信号,所需延时时间为15μs,因此无法调用前面定义
* 的delay()函数,而采用一个for()循环来实现延时。
* ***********************************************************************/
unsigned char read_bit(void) {
unsigned char i;
DQ = 0;     		 //将DQ 拉低开始读时间隙
DQ = 1; 			// then return high
for (i=0; i<3; i++); 	// 延时15μs
return(DQ); 			// 返回 DQ 线上的电平值
}

/**************************** 字节读取函数 *******************************
* 功能:从单总线读取一个字节的值
*************************************************************************/
unsigned char read_byte(void) {
unsigned char i;
unsigned char value = 0;
for (i=0;i<8;i++) {  				// 读取字节,每次读取一个字节
if(read_bit()) value|=0x01<<i; 	// 然后将其左移
delay(6); 					
}
return(value);
}

/***************************** 读取ROM代码函数 ***************************
* 功能:用于读取单总线上单个DS1820器件的ROM代码,对于多个器件需要采用
* 搜索ROM函数。
**************************************************************************/
void Read_ROMCode(void) {
int n;
char dat[9];
printf("\nReading ROM Code\n");
ow_reset();
write_byte(0x33);
for (n=0;n<8;n++){dat[n]=read_byte();}
printf("\nROMCode=%X%X%X%X\n",
dat[7],dat[6],dat[5],dat[4],dat[3],dat[2],dat[1],dat[0]);
}

/*************************** 单总线CRC函数 ******************************
* 功能:完成一次循环冗余校验,进行搜索ROM操作时应包含循环冗余校验
**************************************************************************/
unsigned char ow_crc( unsigned char x) {
dowcrc = dscrc_table[dowcrc^x];
return dowcrc;
}

/********************************* NEXT函数 ******************************
* 功能:搜索单总线上的下一个器件,如果单总线上没有其它器件则返回“假”
**************************************************************************/
unsigned char Next(void) {
unsigned char m = 1; 	// ROM 位索引
unsigned char n = 0;   	// ROM 字节索引
unsigned char k = 1;    
unsigned char x = 0;
unsigned char discrepMarker = 0; 
unsigned char g; 		// 输出位
unsigned char nxt; 		// 返回值
int flag;
nxt = FALSE; 			
dowcrc = 0; 
flag = ow_reset(); 		// 复位单总线
if(flag||doneFlag) {	// 如果没有其它器件则返回“假”
lastDiscrep = 0; 	
return FALSE;
}
write_byte(0xF0); 		// 发送搜索ROM 命令
do {					
x = 0;
if(read_bit()==1) x = 2;
delay(6);
if(read_bit()==1) x |= 1; 	
if(x ==3) break;
else {
if(x>0) 				
g = x>>1; 			
else {					
if(m<lastDiscrep) g = ((ROM[n]&k)>0);
else g = (m==lastDiscrep); 
if (g==0) discrepMarker = m;
}
if(g==1) ROM[n] |= k;
else ROM[n] &= ~k;
write_bit(g); 
m++; 
k = k<<1; 
if(k==0) { 
ow_crc(ROM[n]); 
n++; k++;
}
}
}	while(n<8); 		// 循环,直到全部ROM字节0~7都完成
if(m<65||dowcrc)  lastDiscrep=0; 
else {					// 搜索成功,置位lastDiscrep, lastOne和nxt
lastDiscrep = discrepMarker;
doneFlag = (lastDiscrep==0);
nxt = TRUE; 		// 表示搜索还未结束,单总线上还有其它器件
}
return nxt;
}

/********************************* FIRST函数 ******************************
* 功能: 复位当前ROM搜索状态并调用NEXT函数搜索单总线的第一个器件
**************************************************************************/
unsigned char First(void) {
lastDiscrep = 0; 
doneFlag = FALSE;
return Next(); 
}


/********************************* 读暂存器 *******************************
* 功能:读取暂存器中9个字节的数据
**************************************************************************/
void Read_ScratchPad(void) {
int j;
char pad[10];
printf("\nReading ScratchPad Data\n");
write_byte(0xBE);
for (j=0;j<9;j++){pad[j]=read_byte();}
printf("\n ScratchPAD DATA =%X%X%X%X%X%X\n",
pad[8],pad[7],pad[6],pad[5],pad[4],pad[3],pad[2],pad[1],pad[0]);
}

// 
/****************************** FIND DEVICES *****************************
* 功能:首先复位单总线以确定是否存在任何器件,如果存在则将其唤醒。然后调用
* FIRST函数跟踪冲突位,并返回到NEXT函数。NEXT函数完成鉴别单总线上每个器件
* 唯一ROM代码的大部分工作。
**************************************************************************/
void FindDevices(void) {
unsigned char m;
  if(!ow_reset()) { 	// 如果单总线上存在器件则开始处理
	if(First()) { 		// 至少发现一个器件才开始
		numROMs=0;
		do {
			numROMs++;
			for(m=0;m<8;m++) {
				FoundROM[numROMs][m]=ROM[m]; // 对发现的器件鉴别其ROM代码
			}
		 printf("\nROM CODE =%02X%02X%02X%02X\n",
		 FoundROM[5][7],FoundROM[5][6],FoundROM[5][5],FoundROM[5][4],
		 FoundROM[5][3],FoundROM[5][2],FoundROM[5][1],FoundROM[5][0]);
		 }while (Next()&&(numROMs<10)); // 一直持续到没有发现其它器件
  	}
  }
}


/******************************** Match ROM 函数 **************************
* 功能: 选中某一特定的DS1820进行操作。
**************************************************************************/
unsigned char Send_MatchRom(void) {
unsigned char i;
if(ow_reset()) return FALSE;
write_byte(0x55);         			  // 发送匹配ROM命令
for(i=0;i<8;i++) {
write_byte(FoundROM[numROMs][i]); // 发送 ROM 代码
}
return TRUE;
}

/******************************* 读取温度函数 *****************************
* 功能:如果单总线节点上只有一个器件则可以直接掉用本函数。如果节点上有多个器
*      件,为了避免数据冲突,应使用Match ROM函数来选中特定器件。
* 注: 本函数是根据DS1820的温度数据格式编写的,若用于DS18B20,必须根据
*      DS18B20的温度数据格式作适当修改。
**************************************************************************/
void Read_Temperature(void) {
char get[10];
char temp_lsb,temp_msb;
int k;
char temp_f,temp_c;
ow_reset();
write_byte(0xCC); 					// 跳过 ROM
write_byte(0x44); 					// 启动温度转换
delay(5);
ow_reset();
write_byte(0xCC); 					// 跳过 ROM
write_byte(0xBE); 					// 读暂存器
for (k=0;k<9;k++){get[k]=read_byte();}
printf("\n ScratchPAD DATA = %X%X%X%X%X\n",
get[8],get[7],get[6],get[5],get[4],get[3],get[2],get[1],get[0]);
temp_msb = get[1]; // Sign byte + lsbit
temp_lsb = get[0]; // Temp data plus lsb
if (temp_msb <= 0x80){         
temp_lsb = (temp_lsb/2);    // 移位得到完整的温度值
} 								
temp_msb = temp_msb & 0x80;     // 屏蔽除符号位之外的所有位
if (temp_msb >= 0x80) {
temp_lsb = (~temp_lsb)+1; 	// 取补
} 
if (temp_msb >= 0x80) {
temp_lsb = (temp_lsb/2);	// 移位得到完整的温度值
}
if (temp_msb >= 0x80) {
temp_lsb = ((-1)*temp_lsb); // 加入符号位
} 
printf( "\nTempC= %d degrees C\n", 
(int)temp_lsb ); 	// 输出摄氏温度值
temp_c = temp_lsb; 				// 华氏温度转换
temp_f = (((int)temp_c)* 9)/5 + 32;
printf( "\nTempF= %d degrees F\n", 
(int)temp_f );		 // 输出华氏温度值
}

/***************************** main函数 ********************************/
main() {
unsigned char Select_Type; 
  TA = 0xAA; 		// 设置DS5000T存储器为同步访问(timed access)
  TA = 0x55;
  PCON = 0x00; 		// 禁止看门狗

  SCON = 0x50; 		// 设置串行口:方式1, 8-bit UART, 允许接收
  TMOD = 0x21; 		// 设置定时器T1:方式2, 8-bit 自动重装
// 设置定时器T0:方式1, 16-bit 
  PCON |= 0x80; 	// SMOD = 1 波特率加倍
  TH0=TL0 = 0;
  TH1=TL0 = (unsigned int)(256 - ( (XtalFreq / BaudRate) / 192));
  TR0 = 1; 			// 启动T0
  TR1 = 1;       	// 启动T1
  TI = 1; 			// 启动发送 UART 中的第一个字符

  printf (" Source for DS1820 Temperature Reading and\n");
  printf (" Search ROM code.\n");
  printf (" [C51 Program for DS5000 or 8051 Compatible Microcontroller]");
  printf("\n*********************************************************\n");
  printf (" Select Menu Option\n");
  printf (" 1. One-Wire Reset\n");
  printf (" 2. Read ROM Code of Single Device On Net\n");
  printf (" 3. Perform Search ROM\n");
  printf (" 4. Read Scratch PAD\n");
  printf (" 5. Read Temperature\n");
  printf (" 6. Find All Devices\n");
  do { 						
	EA = 0; 					// 关中断
	TA = 0xAA; 					// 同步访问(timed access)
	TA = 0x55;
	MCON = MCON |= 0x04; 		// 允许CE2
	TA = 0xAA; 					// 同步访问(timed access)
	TA = 0x55;
	MCON = 0xC8; 				// 禁止CE2
	EA = 1; 					// 开中断
	Select_Type = _getkey(); 	// 从键盘输入选择数字
	switch(Select_Type){
		case '1': printf ("\n 1. Sent 1-Wire Reset\n");
			ow_reset();
			break;
		case '2': printf ("\n 2. Read ROM Code of Single Device On Net\n");
			ow_reset();
			Read_ROMCode();
			break;
		case '3': printf("\n 3. Performing Search ROM\n");
			ow_reset();
			First();
			printf("\nROM CODE =%02X%02X%02X%02X\n",
			  FoundROM[5][7],FoundROM[5][6],FoundROM[5][5],FoundROM[5][4],
			  FoundROM[5][3],FoundROM[5][2],FoundROM[5][1],FoundROM[5][0]);
			break;
		case '4': printf ("\n 4. Read Scratch PAD\n");
			ow_reset();
			write_byte(0xCC); 			// 跳过 ROM
			Read_ScratchPad();
			break;
		case '5': printf ("\n 5. Read Temperature\n");
			Read_Temperature(); 		// 读取温度值
			break;
		case '6': printf ("\n 6. Find All Devices\n");
			ow_reset();
			FindDevices();
			break;
		default: printf ("\n Typo: Select Another Menu Option\n");
			break;
		}; 
  }while(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -