1led.c不需要时序保护

idata  unsigned char temp_1 = 0x00;
 idata  unsigned char temp_old_1 = 0xff;

void Led_Disp(unsigned char *ucLed)
{
   unsigned char temp;
   temp_1=0x00;
   temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
         (ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
  if (temp_1 != temp_old_1)
  {
    P0 = ~temp_1;
    
    // 操作P2锁存器
    temp = P2 & 0x1f;    // 保留P2的低5位
    temp = temp | 0x80;  // 与0x80进行或操作
    P2 = temp;           // 写入P2
    temp = P2 & 0x1f;    // 保留P2的低5位
    P2 = temp;           // 写入P2,关闭锁存器
    
    temp_old_1 = temp_1;
  }
}

判断一个函数要不要加 EA=0/1 时序保护,唯一的标准是:这个函数是在哪里被调用的?

  1. Led_Disp 是在定时器中断 T1service() 里面调用的。

  2.  单片机有一个硬件机制:当程序进入中断服务函数时,硬件会自动屏蔽掉同级中断。 也就是说,当代码正在执行中断里的 Led_Disp 操作 P0 和 P2 时,绝对不可能有另一个定时器中断跑出来打断它。它本身就是“最高优先级”的,所以天生自带保护光环!

  3. 谁才需要加 EA=0/1 保护? 是在主循环 while(1) 里面调用的那些操作了 P0 和 P2 的函数! 比如你之前写的 Relay()。因为主循环运行级别最低,随时可能被定时器中断(也就是 Led_Disp 和 seg_disp)打断。所以主循环里的 Relay 必须自己加 EA=0; Relay(); EA=1; 来防身。

2温度读取/AD转换

算温度 (DS18B20):用 读取值 / 16.0

算电压 (PCF8591):用 读取值 / 51.0 

3iic导致数码管闪烁

  1. DELAY_TIME 根本不是用来防抖或稳定的! 它是用来控制 I2C 总线通讯速度(SCL 时钟频率)的。

  2. 当你把 DELAY_TIME 设为 10 时,执行一次完整的 ad_zhuanhuan,CPU 需要在里面空转等待将近 2 毫秒!

  3. 你在 ad_zhuanhuan 里用了 EA = 0; 和 EA = 1;。这意味着全局中断被死死关了近 2 毫秒!

  4. 你的数码管是靠定时器每 1 毫秒刷新一次的。中断被关了 2 毫秒,数码管错过了刷新时机,绝对会严重闪烁、卡顿!


解决办法

将你的 DELAY_TIME 改成官方推荐的极小值。单片机跑到 12MHz 时,延时 1 到 2 就足够满足 PCF8591 的通讯要求了。

把这句:

#define DELAY_TIME  10  // 删掉这个习惯!

改成:

#define DELAY_TIME  1   // 提高I2C速度,解放CPU

改完这一步,I2C 整体耗时会降到两三百微秒,远小于 1ms 的数码管刷新周期,数码管立刻就不闪了!

4硬件冲突引脚共用

在蓝桥杯 CT107D 开发板上:

  1. NE555 频率发生器的信号:是通过 J3 跳线帽直接连接到单片机的 P34 引脚上的(因为 P34 是单片机 Timer 0 的外部脉冲输入脚 T0

你看一下你的 key_read() 函数里的这一段:

    P44=1;P42=1;P35=1;P34=0;  // <--- 罪魁祸首在这里!!!
    if(P30==0)temp=19;
    if(P31==0)temp=18;
    // ...

NE555 正在辛辛苦苦地往 P34 引脚发送高低电平的频率脉冲,但你的 key_read() 却在 while(1) 的主循环里疯狂地执行 P34=0;,强行把 P34 拉低到地 (GND)!

这直接导致单片机和 NE555 发生了“信号打架”,你的程序把 NE555 的脉冲给“捂死”了,定时器 0 自然一个脉冲都数不到,频率永远显示 0!

既然这道题要测频率,就绝对不能让程序主动把 P34 拉低。

所以解决办法极其简单:直接把扫描 P34 列的代码删掉(或注释掉),并保证 P34 始终处于高电平接收输入状态即可!

如果写 0:相当于单片机把引脚接地,NE555发出的信号全被吃掉,测不到频率。

如果写 1:STC15单片机在输出 1 的瞬间,会开启“强推挽”模式(强行拉高电压),这会和NE555输出的低电平发生“短路打架”,直接把波形冲烂,导致测不准。结论:既然用来测频率,P34就只能作为“输入引脚”,我们干脆在按键扫描里假装它不存在。

6ERROR L107: ADDRESS SPACE OVERFLOW 

“内存溢出(RAM不够用了)”!

在默认情况下,51单片机的变量都会被存放在一个叫 data 的内存区。这个区只有可怜的 128 个字节!

由于这道题你需要算平均值、历史数据、还有一堆计时器,你定义了:

  • 11 个 float 浮点数(每个占 4 字节,共 44 字节)

  • 1 个 long int 长整型(占 4 字节)

  • 变量总大小直接撑爆了这 128 个字节! 编译器装不下去了,就给你报了 ADDRESS SPACE OVERFLOW(地址空间溢出),并且后面跟了一连串的 IGNORED SEGMENT(因为装不下,编译器直接罢工,后面的变量全都忽略了)。


🛠️ 终极解法

STC15 单片机其实并不缺内存(它有额外的 256 字节 idata 区,甚至还有 2048 字节的 xdata 区)。

第一次提交18分

把进入seg_proc()的时间从500ms,变成20ms,就从18分变成85分了

main.c

#include <STC15F2K60S2.H>
#include <seg.h>
#include <key.h>
#include <pcf8591.h>
#include <init.h>
#include <led.h>
#include <ds18b20.h>
#include <ds1302.h>
unsigned char seg_pos;
idata unsigned char seg_buf[8]={10,10,10,10,10,10,10,10};
idata unsigned char seg_point[8]={0,0,0,0,0,0,0,0};
idata unsigned char ucled[8]={0,0,0,0,0,0,0,0};
unsigned int seg_slow_down;
unsigned char segmode;
unsigned char key_slow_down;
unsigned char key_val,key_down,key_old,key_up;
float tem;//温度
float tem_m;
idata unsigned char time[7]={1,0,0};//teme[0]--秒,time[1]--分
idata unsigned char time_chu[3]={0};
unsigned int t1000ms;
idata long int freq;
unsigned char wcan_seg=30;//0-99
unsigned char mode;
bit wuxiao;//wuxiao=1,表示频率不在200-2000hz范围内,是无效数据
float shi;
float shi_m;
unsigned char chu;
float v_zhen;
unsigned char ad_slow_down;
unsigned int t3000ms;
bit dangg,dangg_old,cai,f3s;
//dangg=1,表示暗
idata float tem_sum = 0;      // 记录所有采集过的温度总和
idata float tem_ave = 0; 
idata float tem_old;
idata float shi_sum=0;
idata float shi_ave=0;
idata float shi_old;
bit seg_t;
unsigned int t2000ms;
bit f2s;
//bit first_ad = 1; // 用于标记是否是上电第一次读取AD
unsigned char t100ms;
bit f100ms;


void key_proc()
{
	if(key_slow_down<10)return ;
	key_slow_down=0;

	key_val=key_read();
	key_down=key_val&(key_old^key_val);
	key_up=~key_val&(key_old^key_val);
	key_old=key_val;
	
	if(seg_t==0)//不是特殊界面
	{
					if(segmode==1&&mode==2)//时间回显子界面下
					{
						if(key_down==9)
						{
						
							f2s=1;
						}
						if(key_up==9)
						{
							f2s=0;
							if(t2000ms>2000)//长按s9超过2s
							{
								tem_sum=0;
								tem_ave=0;
								shi_sum=0;
								shi_ave=0;
								tem_m=0;
								shi_m=0;
								chu=0;
							}
						
						}
				
				
				}
				
				
				
				switch(key_down)
				{
					case 4://界面按键
							if(++segmode==3)segmode=0;
							if(segmode==1)//进入回显界面
							{
								mode=0;//温度回显界面
							}
										
					
									
					break;
					case 5://回显按键
						if(segmode==1)//回显界面
						{
							if(++mode==3)mode=0;
						}
									
						
						
					break;
					case 8://++
						if(segmode==2)
						{
							wcan_seg++;
							if(wcan_seg>=100)wcan_seg=0;
						}
					break;
					case 9://--
						if(segmode==2)//参数界面
						{
							wcan_seg--;
							if(wcan_seg>200)wcan_seg=99;
						
						}
						
					break;
					
				
				}
	
	
	}
	
}





void T1service() interrupt 3
{
	seg_slow_down++;
	key_slow_down++;
	ad_slow_down++;
	
	if(++seg_pos==8)seg_pos=0;
	seg_disp(seg_pos,seg_buf[seg_pos],seg_point[seg_pos]);
	 Led_Disp(ucled);
	if(++t100ms==100)
	{
		t100ms=0;
		f100ms^=1;
	}
	if(f3s==1)
	{
	
		if(++t3000ms==3000)
		{
			t3000ms=0;
			f3s=0;//已经3s,可以再次触发
			seg_t=0;//返回“原状态”
		}
	}
	if(f2s==1)
	{
		if(t2000ms<4000)
		{
			t2000ms++;
			//这样最大不会超过4000
		}
	
	}
	
	
	if(++t1000ms==1000)
	{
		t1000ms=0;
		
		TR0=0;
		freq=(TH0<<8)|TL0;
		TH0=0;
		TL0=0;
		
		TR0=1;
	}
	
	
	
	

}

void seg_proc()
{
	if(seg_slow_down<20)return;
		seg_slow_down=0;
	
	if(cai==1)//触发一次温度、湿度数据采集功能
	{
			cai=0;//等待下一次触发
			seg_t=1;//采集功能触发后,数码管立刻切换到温湿度界面
			f3s=1;//计时3s,防止3s内重复触发
			t3000ms=0;
			
					//湿度采集
					shi_old=shi;
					if(freq>=2000)
					{
						shi=90;
						wuxiao=1;//无效数据
					}
					else if(freq<=200)
					{
						shi=10;
						wuxiao=1;//无效数据
					}
					else
					{
						shi=(80.0/1800)*freq +10 -160.0/18;
						wuxiao=0;//有效数据
					}
					tem_old=tem;
					tem=rd_temperature();//采集温度,还要在温湿度界面显示
					
					
					
		if(wuxiao==0)//采集到的湿度数据有效
		{
											//触发次数
				chu++;//放在前面,以免使得除数为0
				
				
				shi_sum+=shi;
				shi_ave=shi_sum/(chu*1.0);   			 //平均湿度
				if(shi>shi_m)
				{
					shi_m=shi;					//最高湿度
				}
				
				
				
				tem_sum+=tem;
				tem_ave=tem_sum/(chu*1.0);			//平均温度
				if(tem>tem_m)
				{
					tem_m=tem;
				}							//最高温度
				
				
				
											//触发时间
				time_chu[0]=time[0];
				time_chu[1]=time[1];
				time_chu[2]=time[2];
		
		}
					
				
			
					
					
			
			
			
			
	
	}
	
	
	
	
	read_rtc(time);
	
	
	if(seg_t==0)//不是特殊界面
	{
				
						switch(segmode)
						{
						case 0://时间界面
							//时
							seg_buf[0]=time[2]/16;
							seg_buf[1]=time[2]%16;
							seg_buf[2]=15;
							//分
							seg_buf[3]=time[1]/16;
							seg_buf[4]=time[1]%16;
							seg_buf[5]=15;
							//秒
							seg_buf[6]=time[0]/16;
							seg_buf[7]=time[0]%16;
							seg_point[6]=0;
							
						break;
						case 1://回显界面
							if(mode==0)//温度回显
							{
								
									seg_buf[0]=16;//C
									seg_buf[1]=10;
									//最大温度
									seg_buf[2]=(chu==0)?10:(unsigned char )tem_m/10;
									seg_buf[3]=(chu==0)?10:(unsigned char )tem_m%10;
									
									seg_buf[4]=(chu==0)?10:15;
									//平均温度
									seg_buf[5]=(chu==0)?10:(unsigned char )tem_ave/10;
									seg_buf[6]=(chu==0)?10:(unsigned char )tem_ave%10;
									seg_buf[7]=(chu==0)?10:(unsigned int)(tem_ave*10)%10;
								
									seg_point[6]=(chu==0)?0:1;
								
								
								
							}
							else if(mode==1)//湿度回显
							{
									seg_buf[0]=17;//H
									seg_buf[1]=10;
									//最大湿度
									seg_buf[2]=(chu==0)?10:(unsigned char )shi_m/10;
									seg_buf[3]=(chu==0)?10:(unsigned char )shi_m%10;
									
									seg_buf[4]=(chu==0)?10:15;
									//平均湿度
									seg_buf[5]=(chu==0)?10:(unsigned char )shi_ave/10;
									seg_buf[6]=(chu==0)?10:(unsigned char )shi_ave%10;
									seg_buf[7]=(chu==0)?10:(unsigned int)(shi_ave*10)%10;
									seg_point[6]=(chu==0)?0:1;
							}
							else if(mode==2)//时间回显
							{
								
									seg_buf[0]=14;//F
									//触发次数,长度不足2位时左侧补0
									seg_buf[1]=chu/10;
									seg_buf[2]=chu%10;
									//时
									seg_buf[3]=(chu==0)?10:time_chu[2]/16;
									seg_buf[4]=(chu==0)?10:time_chu[2]%16;
									
									seg_buf[5]=(chu==0)?10:15;
									//分
									seg_buf[6]=(chu==0)?10:time_chu[1]/16;
									seg_buf[7]=(chu==0)?10:time_chu[1]%16;
									
									seg_point[6]=0;	
							}
							
							
						
						break;
						case 2://参数界面
									seg_buf[0]=12;//P
									seg_buf[1]=10;
									seg_buf[2]=10;
									seg_buf[3]=10;
									seg_buf[4]=10;
									seg_buf[5]=10;
									seg_buf[6]=wcan_seg/10;
									seg_buf[7]=wcan_seg%10;
									seg_point[6]=0;
						break;
//						case 3://棰戠巼鏄剧ず鐣岄潰
//							seg_buf[0]=6;
//							seg_point[5]=0;
//							seg_buf[1]=(freq>=1000000)?freq/1000000:10;
//							seg_buf[2]=(freq>=100000)? freq/100000%10:10;
//							seg_buf[3]=(freq>=10000)?freq/10000%10:10;
//								
//							seg_buf[4]=(freq>=1000)?freq/1000%10:10;
//							seg_buf[5]=(freq>=100)?freq/100%10:10;
//							seg_buf[6]=(freq>=10)?freq/10%10:10;
//							seg_buf[7]=(freq>=1)?freq%10:0;
					
				break;
					}
					
			
			}
			if(seg_t==1)//显示温湿度界面
			{
									seg_buf[0]=18;//E
									seg_buf[1]=10;
									seg_buf[2]=10;
									seg_buf[3]=(unsigned char )tem/10;
									seg_buf[4]=(unsigned char )tem%10;
									seg_buf[5]=15;
									seg_buf[6]=(wuxiao==1)?19:(unsigned char )shi/10;
									seg_buf[7]=(wuxiao==1)?19:(unsigned char )shi%10;
									seg_point[6]=0;
			}
			
}
void Delay750ms(void)	//@12.000MHz
{
	unsigned char data i, j, k;

	_nop_();
	_nop_();
	i = 35;
	j = 51;
	k = 182;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void led_proc()
{
	//界面指示灯
	ucled[0]=(segmode==0&&seg_t==0)?1:0;
	ucled[1]=(segmode==1&&seg_t==0)?1:0;
      ucled[2]=(seg_t==1)?1:0;

	//报警指示灯
	ucled[3]=(tem>(wcan_seg))?f100ms:0;
	ucled[4]=(wuxiao==1)?1:0;
	if(chu>=2)
	{
		if(tem_old<tem&&shi_old<shi)
		{
			ucled[5]=1;
		}
		else ucled[5]=0;
	
	}
	
	



}
void ad_proc()//亮暗状态变化感知时间
{
	if(ad_slow_down<70)return ;
	ad_slow_down=0;
	
	if(f3s==0)//过了3s,才能再次触发
	{
		dangg_old=dangg;//保存上一次的状态
		v_zhen=ad_zhuanhuan(0x41)/51.0;
		
		if(v_zhen<2.50)//光敏电阻在“挡光”条件下
		{
			dangg=1;//光敏电阻在挡光条件下,“暗状态”
		}
		else
		{
			dangg=0;//"亮"状态
		}
		
		
		
		if(dangg_old==0&&dangg==1)
		{
			cai=1;//触发一次温度、湿度数据采集功能
		}
	}
}
void main()
{
	
		Delay750ms();
		rd_temperature();//延时一下再解决上电85
		sys_init();
		Timer1_Init();
		Timer0_Init();
	      set_rtc(time);
		
		
		
			while(1)
			{ 
				led_proc();
				key_proc();
				seg_proc();
				led_proc();
				ad_proc();
			}
}

seg.c

#include <seg.h>
unsigned char code seg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
unsigned char code seg_duan[]={0xC0,0xF9,0xA4,0xB0,0x99,
                               0x92,0x82,0xF8,0x80,0x90,
                               0xff,0xc1,0x8c,0xc8,0x8e,0xbf,0xc6,0x89,0x86,0X88};
//11-u锛?2-P锛?3-N锛?4-F,15--,16-C,17-H,18-E,19-A

void seg_disp(unsigned char wei,duan,point)
{
	P0=0xff;
	P2=P2&0x1f|0xe0;//娈甸€?
	P2&=0x1f;
	
	P0=seg_wei[wei];
	P2=P2&0x1f|0xc0;//浣嶉€?
	P2&=0x1f;
	
	P0=seg_duan[duan];
	if(point==1)P0&=0x7f;
	P2=P2&0x1f|0xe0;//娈甸€?
	P2&=0x1f;
}

key.c

#include <key.h>

unsigned char key_read(void)
{
	unsigned char temp=0;
	
	AUXR &=~0X10;//关闭定时器2
	P44=0;P42=1;P35=1;
	//P34=1;
	if(P30==0)temp=7;
	if(P31==0)temp=6;
	if(P32==0)temp=5;
	if(P33==0)temp=4;
	
	P44=1;P42=0;P35=1;
	//P34=1;
	if(P30==0)temp=11;
	if(P31==0)temp=10;
	if(P32==0)temp=9;
	if(P33==0)temp=8;
	
	P44=1;P42=1;P35=0;
	//P34=1;
	if(P30==0)temp=15;
	if(P31==0)temp=14;
	if(P32==0)temp=13;
	if(P33==0)temp=12;
	
	P44=1;P42=1;P35=1;
	//P34=0;
//	if(P30==0)temp=19;
//	if(P31==0)temp=18;
//	if(P32==0)temp=17;
//	if(P33==0)temp=16;
	AUXR|=0X10;//开启定时器2
	return temp;
}

init.c

#include <init.h>


void sys_init()
{
	P0=0xff;//led
	P2=(P2&0x1f)|0x80;
	P2&=0x1f;
	
	P0=0x00;//蜂鸣器
	P2=(P2&0x1f)|0xa0;
	P2&=0x1f;
}


void Timer1_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;			//定时器时钟12T模式
	TMOD &= 0x0F;			//设置定时器模式
	TL1 = 0x18;				//设置定时初始值
	TH1 = 0xFC;				//设置定时初始值
	TF1 = 0;				//清除TF1标志
	TR1 = 1;				//定时器1开始计时
	ET1=1;
	EA=1;
}


void Timer0_Init(void)		//100微秒@12.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TMOD|=0X05;
	TL0 = 0;				//设置定时初始值
	TH0 = 0;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
}

led.c

#include <led.h>
idata  unsigned char temp_1 = 0x00;
idata  unsigned char temp_old_1 = 0xff;

void Led_Disp(unsigned char *ucLed)
{
   unsigned char temp;
   temp_1=0x00;
   temp_1 = (ucLed[0] << 0) | (ucLed[1] << 1) | (ucLed[2] << 2) | (ucLed[3] << 3) |
         (ucLed[4] << 4) | (ucLed[5] << 5) | (ucLed[6] << 6) | (ucLed[7] << 7);
  if (temp_1 != temp_old_1)
  {
    P0 = ~temp_1;
    
    // 操作P2锁存器
    temp = P2 & 0x1f;    // 保留P2的低5位
    temp = temp | 0x80;  // 与0x80进行或操作
    P2 = temp;           // 写入P2
    temp = P2 & 0x1f;    // 保留P2的低5位
    P2 = temp;           // 写入P2,关闭锁存器
    
    temp_old_1 = temp_1;
  }
}





idata unsigned char temp_0 = 0x00;
idata unsigned char temp_old_0 = 0xff;
///  蜂鸣器控制

//void Beep(bit enable)
//{
//  unsigned char temp;
//  EA=0;



//  if (enable)
//    temp_0 |= 0x40;
//  else
//    temp_0 &= ~(0x40);
//  if (temp_0 != temp_old_0)
//  {
//    P0 = temp_0;
//    
//    // 操作P2锁存器
//    temp = P2 & 0x1f;    // 保留P2的低5位
//    temp = temp | 0xa0;  // 与0xa0进行或操作
//    P2 = temp;           // 写入P2
//    temp = P2 & 0x1f;    // 保留P2的低5位
//    P2 = temp;           // 写入P2,关闭锁存器
//    
//    temp_old_0 = temp_0;
//  }



//	EA=1;

//}
///// 继电器控制
///
//void Relay(bit enable)
//{
//  unsigned char temp;
//  EA=0;//防止总线冲突



//  if (enable)
//    temp_0 |= 0x10;
//  else
//    temp_0 &= ~(0x10);
//  if (temp_0 != temp_old_0)
//  {
//    P0 = temp_0;
//    
//    // 操作P2锁存器
//    temp = P2 & 0x1f;    // 保留P2的低5位
//    temp = temp | 0xa0;  // 与0xa0进行或操作
//    P2 = temp;           // 写入P2
//    temp = P2 & 0x1f;    // 保留P2的低5位
//    P2 = temp;           // 写入P2,关闭锁存器
//    
//    temp_old_0 = temp_0;
//  }




//  EA=1;
//}

ds18b20.c

#include <ds18b20.h>

sbit DQ=P1^4;
void Delay_OneWire(unsigned int t)  
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//
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;
}







//float rd_temperature()
//{
//	unsigned char low,high;//低八位,高八位
//	
//	EA=0; init_ds18b20();  EA=1;//初始化
//	EA=0; Write_DS18B20(0xcc);  EA=1;//跳过ROM
//	EA=0; Write_DS18B20(0x44);  EA=1;//温度转换
//	Delay_OneWire(200);
//	EA=0; init_ds18b20();  EA=1;
//	EA=0; Write_DS18B20(0xcc);  EA=1;//跳过ROM
//	EA=0; Write_DS18B20(0xbe);  EA=1;//读取温度,而且这种写法其实读到的是上一次转换的温度
//	EA=0; low=Read_DS18B20();  EA=1;
//	EA=0; high=Read_DS18B20();  EA=1;
//	return (float)(high<<8|low)*0.0625;	
//	//先将数据变成八位二进制数,然后转换成float型,再乘精度
//}


1+2+2
1+2

float rd_temperature()
{
	unsigned char low,high;//低八位,高八位
	
	// 1. 先读取【上一次】已经转换好的温度(完全不需要 Delay)
	EA=0; init_ds18b20();  EA=1;
	EA=0; Write_DS18B20(0xcc);  EA=1;//跳过ROM
	EA=0; Write_DS18B20(0xbe);  EA=1;//读取温度,
	EA=0; low=Read_DS18B20();   EA=1;
	EA=0; high=Read_DS18B20();  EA=1;
	
	// 2. 紧接着发送【下一次】温度转换命令(发完直接走人,让它自己慢慢转)
	EA=0; init_ds18b20();  EA=1;
	EA=0; Write_DS18B20(0xcc);  EA=1;//跳过ROM
	EA=0; Write_DS18B20(0x44);  EA=1;//温度转换
	
	// 3. 计算并返回刚才读到的数据
	return ((float)(high<<8|low))*0.0625;	
}











//float rd_temperature(void)
//{
//	unsigned char high;
//	unsigned char low;
//	init_ds18b20();
//	Write_DS18B20(0xcc);
//	Write_DS18B20(0x44);
//	
//	init_ds18b20();
//	Write_DS18B20(0xcc);
//	Write_DS18B20(0xbe);
//	low=Read_DS18B20();
//	high=Read_DS18B20();
//	return ((high<<8)|low)/16.0;
//}

ds1302.c

#include <ds1302.h>
#include <intrins.h>

sbit SDA=P2^3;
sbit RST=P1^3;
sbit SCK=P1^7;

unsigned char code write_rtc_addr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
unsigned char code read_rtc_addr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};

							

//
void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK = 0;
		SDA = temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

//
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)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}

void set_rtc(unsigned char *time)
{
	unsigned char i;
	EA = 0;//开始通信,关闭中断保护时序和P2口
	Write_Ds1302_Byte(0x8e,0x00);
	
	for(i=0;i<7;i++)
	{
		Write_Ds1302_Byte(write_rtc_addr[i],time[i]);
	}
	
	Write_Ds1302_Byte(0x8e,0x80);
	EA = 1; // 通信结束,立刻恢复中断
}

void read_rtc(unsigned char *time)
{
	unsigned char i;

	EA = 0; // 开始通信,关闭中断保护时序和P2口
	for(i=0;i<7;i++)
	{
		time[i]=Read_Ds1302_Byte (read_rtc_addr[i]);
		
	}
	EA = 1; // 通信结束,立刻恢复中断
}
//完全不需要操心时序会不会被数码管定时器打断的问题

pcf8591.c

#include <pcf8591.h>

/*	#   I2C浠g爜鐗囨璇存槑
	1. 	鏈枃浠跺す涓彁渚涚殑椹卞姩浠g爜渚涘弬璧涢€夋墜瀹屾垚绋嬪簭璁捐鍙傝€冦€?
	2. 	鍙傝禌閫夋墜鍙互鑷缂栧啓鐩稿叧浠g爜鎴栦互璇ヤ唬鐮佷负鍩虹锛屾牴鎹墍閫夊崟鐗囨満绫诲瀷銆佽繍琛岄€熷害鍜岃瘯棰?
		涓鍗曠墖鏈烘椂閽熼鐜囩殑瑕佹眰锛岃繘琛屼唬鐮佽皟璇曞拰淇敼銆?
*/

#define DELAY_TIME	1
sbit scl=P2^0;
sbit sda=P2^1;

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}



//1+2+2
//1+2+4
unsigned char ad_zhuanhuan(unsigned char addr)
{
	unsigned char temp=0;
	
	EA=0;
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();

	I2CStart();
	I2CSendByte(0x91);
	I2CWaitAck();

	temp=I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	
	EA=1;
	return temp;
}




//1+2+2+2+1
//void da_zhuanhuan(unsigned char dat)
//{
    //EA=0;
//	I2CStart();
//	I2CSendByte(0x90);
//	I2CWaitAck();
//	
//	I2CSendByte(0x41);
//	I2CWaitAck();
//	
//	I2CSendByte(dat);
//	I2CWaitAck();

//	I2CStop();
    //EA=1;
//}




//1+2+2
//1+2
//while+1
//void ee_read(unsigned char *str,unsigned char addr,unsigned char num)
//{
//	EA=0;
//	
//	I2CStart();
//	I2CSendByte(0xa0);
//	I2CWaitAck();
//	
//	I2CSendByte(addr);
//	I2CWaitAck();
//	
//	I2CStart();
//	I2CSendByte(0xa1);
//	I2CWaitAck();
//		
//	while(num--)
//	{
//		*str++=I2CReceiveByte();
//		if(num)I2CSendAck(0);
//		else I2CSendAck(1);
//	}
//		I2CStop();
//	
//	EA=1;
//}



//1+2+2
////while+5
//void ee_write(unsigned char *str,unsigned char addr,unsigned char num)
//{
//	EA=0;
//	I2CStart();
//	I2CSendByte(0xa0);
//	I2CWaitAck();
//	
//	I2CSendByte(addr);
//	I2CWaitAck();
//	
//	while(num--)
//	{
//		I2CSendByte(*str++);
//		I2CWaitAck();
//		I2C_Delay(200);
//	}
//	I2CStop();
//	
//	EA=1;
//	I2C_Delay(255);
//	I2C_Delay(255);
//	I2C_Delay(255);
//	I2C_Delay(255);
//}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐