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

📄 multi-points.c

📁 单总线多点温度测量系统(DS18B20)
💻 C
📖 第 1 页 / 共 2 页
字号:
     write_byte(0xf0);  //单片机发布搜索命令
     for(m=0;m<8;m++)
       {
         uchar s=0; //s用来记录本次循环得到的1个字节(8位)序列号
         for(n=0;n<8;n++)
            {
             k=read_2bit();  //读第m*8+n位的原码和反码,保存在k中
             k=k&0x03;		 //屏蔽掉k中其它位的干扰,为下一步判断作准备
             s>>=1;			 //s右移一位,即把上一次循环得到的位值右移一位,
			 				 //这样执行完一次n为变量的循环,便可得到一个字节的ROM号
             if(k==0x01)     //k为01,表明读到的数据为0,即所有器件在这一位都为0,所以向总线上写0
			 				 //同时对s的值不进行操作,即这位的序列号记为0
                {     
                 write_bit (0);
                }
             else if(k==0x02)//k为02,表明读到的数据为1,即所有器件在这一位都为1,所以向总线上写1
                {
                 s=s|0x80;  //记录下此位的值,即s的最高位置1
                 write_bit (1);
                }
             else if(k==0x00)
                {
                 chongtuwei=m*8+n+1;   //记录下这个冲突位发生的位置;之所以加1是为了让_00web数组中的第一位保持0不变,
 				 					   //便于判断搜索循环是否结束;
                 if(chongtuwei>_00web[l])//如果冲突位比标志00位的位高,即发现了新的冲突位,那么这位写0
                    {      
                     write_bit (0);
                     _00web[++l]=chongtuwei;    //依次记录位比冲突标志位高的冲突位在_00web数组中  
                    }
                 else if(chongtuwei<_00web[l]) //如果冲突位比标志00位的位低,那么把ID中这位所在的字节右移n位,
                    {						 //从而得到这位先前已经写过的值,如果为0,说明这位先前写的是0,那么继续写0,
				 						    // 如果这位先前写的是1,那么继续写1
					 a=(ID[num-1][m]>>n)&0x01;
                     s=s|(a<<7);			//记录下此位的值
                     write_bit(a);
                    }
                 else if(chongtuwei==_00web[l])//如果冲突位就是标志00位,那么s的最高位置1,即这位记为1,同时向总线上写1;
				 							 //之所以不写0,是因为前面已经写过0,再写0,就得不到遍历的效果.
                    {
                     s=s|0x80;
                     write_bit (1);
                     l=l-1;				//改变标志00位的位置,即向前推一个00位,并且是往低位方向推
                    }
                }
			 else if(k==0x03)  //k为03,表明总线上没有DS18B20,函数结束,同时返回零值
			    {return(0);}
            }    
         ID[num][m]=s;  
       }
     num++;			//DS18B20的个数加1
   }while((_00web[l]!=0)&&(num<MAXNUM));//如果冲突位记录数组已经前推到0值或是DS18B20的数目已经超过最大允许数目,
   									  //就退出循环
  return(1);  //搜索完毕,返回1值
}


void Read_Temperature_rom(void) //读取温度函数
{	uchar i;
	DS_init();
	write_byte(0x55);		//匹配ROM
	for(i=0;i<8;i++)		//发出64位ROM编码
			write_byte(RomID_temp[i]);
	write_byte(0x44);		//开始转换
	DS_init();
	write_byte(0x55);		//匹配ROM
	for(i=0;i<8;i++)		//发出64位ROM编码
			write_byte(RomID_temp[i]);
	write_byte(0xBE);		//发读温度命令
	temp.c[1]=read_byte();  //读低字节,之所以c[1]中放低字节,是因为C51采用的是大端格式,具体详见共用体定义的说明
	temp.c[0]=read_byte();	//读高字节,之所以c[0]中放低字节,是因为C51采用的是大端格式,具体详见共用体定义的说明
}


void Temperature_cov(void)	//温度转换
{
	if (temp.c[0]>0xf8) {flag=1;temp.x=~temp.x+1;}
							//如果为负,则符号标志置1,计算温度值,注意c[0]中放的是读取温度值的高字节
							//还要注意读出的数值一共是12位
	
	cc=temp.x/16;			//计算出温度值的整数部分,这个语句相当于数值乘0.0625再取整数部分
	xs=temp.x&0x0f;			//取温度值小数部分的第一位
	xs=xs*10;				//这两条语句相当于乘0.625,得小数位的第一位,注意不是乘0.0625
	xs=xs/16;
}


void display(void)			//定义温度底层显示函数
{
	uchar codevalue[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff,0xbf};
							//共阳极的字段码
	uchar chocode[]={0xf7,0xfb,0xfd,0xfe,0x7f,0xbf,0xdf,0xef};
							//位选码表
	uchar i=0,p,t;
	disbuffer[4]=0x10;   //让LCD的第5位全灭,即什么也不显示,注意是16进制表示
	disbuffer[5]=0x0a+m; //LCD的第6位显示DS18B20序列号,以字母A,B,C,D,E,F来给示,所以加上0x0a
	if (flag==1)disbuffer[3]=0x11;//判断是否显示负号
     	 else disbuffer[3]=0x10;
	disbuffer[0]=xs;   //放入小数位显示的数值
	disbuffer[1]=(cc%10);//放入个数要显示的数值
	disbuffer[2]=(cc/10);//放入十位要显示的数值
	for (i=0;i<6;i++)
	{
  		t=chocode[i];		//取当前的位选码
  		P2=t;				//送出位选码
  		p=disbuffer[i];		//取当前显示的字符
  		t=codevalue[p];		//查得显示字符的字段码
 		if (i==1) t=t+0x80;	//个位比较特殊,因为有小数点,所以要加上0x80
 		P0=t;				//送出字段码
		delay(40);			
	}
}


void diplay_final(void)  //定义温度上层显示函数
{		uint q,r;
		z=0;
		for(q=0;q<8;q++)  //将要显示DS18B20的温度值的序列号放入数组RomID_temp中
			{
				RomID_temp[q]=ID[m][q];
			 }

		P2=0xFF;

		if(a==0)		//如果按键0的标志变量a=0,即进行闪烁显示
		{
			for(q=0;q<3;q++)    //闪烁空隙仍在读取温度
			{	
				if(z==1)		//如果z为1,有按键按下,表明要显示不同的内容,此时从这个循环中跳出
				break;
				flag=0;
				Read_Temperature_rom();     // 读取双字节温度 
				Temperature_cov();      	//温度转换		
				for(r=0;r<15;r++)
				delay(1000);
	
		 	}
		}


		for(q=0;q<5;q++)			//读取温度并显示
		{	if(z==1)				//如果z为1,有按键按下,表明要显示不同的内容,此时从这个显示循环中跳出
			break;
			flag=0;
			Read_Temperature_rom();  // 读取双字节温度 
			Temperature_cov();      //温度转换
			for(r=0;r<100;r++)
			display();             //显示温度
		}
}



void key_0() interrupt 0    //外部中断0的中断处理函数
{
	delay(1200); //延时消抖
	if(Key0==0)
	{
	if(a==0)	//a只可能取0值或1值
    	a=1;
	else a=0;
	b=0;		//同时一旦0键按下就将b归零
	z=1;		//将有按键按下标志位z置位
	}
 }

 
void key_1() interrupt 2	//外部中断1的中断处理函数
{
	delay(1200); //延时消抖
	if(Key1==0)
	{ 	if(a==0)	//只有a等于0时才让b的值在0或1之间转变
		{
		if(b==0)
    		b=1;
		else b=0;
		}
		z=1;		//将有按键按下标志位z置位
		if(a==1)	//当a=1时进入固定显示一个DS18B20的温度值的状态
		{	
			m++;	//按一次1键m值加1,即在不同的DS18B20切换显示
			if(m>=num) //当然,m的值不能超过或等于总线上挂接的DS18B20的数目
			m=0;
		}
	}
 }

void main()					//主函数
{	uchar p,i;
	delay(10);
	p=search_rom();  //执行搜索DS18B20算法,同时返回搜索情况,p值为0,表明总线上没有DS18B20,p值为1表明搜索到DS18B20; 
	if(p==0) 		//如果总线上没有DS18B20,显示"OFF 1820"
	while(1)
	display_error();
	EA=1;  	//开中断
	EX0=1;	//允许外部中断0
	IT0=1;  //外部中断0为边沿触发方式
	EX1=1;	//允许外部中断1
	IT1=1;	//外部中断1为边沿触发方式
	while(1)
	{   
		if(a==0&&b==0)	//按键0和1的状态变量值都为0,此时轮换显示各DS18B20的温度值
		{
			diplay_final(); //显示DS18B20的温度值
		 	if(m<num-1)	//为了实现轮换显示,要改变m的值
			m++;
			else m=0;
			if(z==1)	//如果有按键按下,将m清零
			{
				m=0;
			}
		}
		
		else if(a==0&&b==1) //按键0和按键1的状态变量值分别为0和1,此时轮换显示各DS18B20的序列号
		{   
		    
			display_ROMID(); //显示DS18B20的序列号
			if(m<num-1)		//为了实现轮换显示,要改变m的值
			m++;
			else m=0;
			if(z==1)	//如果有按键按下,将m清零
			{
				m=0;
			}
		 }
		else	//按键0的状态变量值为1,此时固定显示各DS18B20的温度值,按键1用于不同DS18B20间的切换
		{  
		   diplay_final(); //显示DS18B20的温度值

 		}
	}
}

⌨️ 快捷键说明

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