STC学习:温度与光照传感器

本文详细介绍了如何使用STC15F2K60S2单片机进行AD转换,采集光敏和热敏电阻的值,并在数码管上显示。程序设计目标包括测量光照和温度,通过多次测量取平均值减少误差。文章还提供了温度值与AD值的对应表,以及完整的C语言程序代码,包括延时函数、数码管显示和中断服务程序等。
摘要由CSDN通过智能技术生成

该文需用到A/D转换,已做该内容总结
STC学习:ADC
程序设计目标及程序运行效果说明
程序设计目标:学会使用AD采集光敏电阻和热敏电阻的值,并显示在数码管上。
程序运行效果说明:用ISP下载hex文件后,单片机根据测量地、时间等不同因素,相应的温度信息(包含零下温度值)将显示在数码管左边三位,相应光数据显示在右侧三位。

程序相关电路及工作原理说明
1.LED数码管电路
在这里插入图片描述
2.光敏和热敏电阻电路
在这里插入图片描述
3.工作原理
热敏电阻随温度呈直线变化,光敏电阻岁光强线性变化。通过AD采集光敏电阻和热敏电阻的输出值,输出对应的AD值,光照值直接为AD,而采集的温度AD值,首先10位转换为8位AD值,再通过查找对应的表来获取温度。

Ro引脚:P1.4
Rt引脚:P1.3
当环境中的光照/温度变化时,Rop和Rt对应的电阻值会发生变化,V端的电压值将随着变化。

4.实现思路
测量光照:使用A/D转换,将每一次的A/D转换的结果累加,多次测量后取平均值。
测量温度:使用A/D转换测量每一次10位结果转换成8位AD值,再通过查找对应的表来获取温度,多次测量后取平均值。
结果显示:通过整除求余计算每一位的数值;温度显示在数码管前三位,需要判断正负;光照显示在数码管后3位。

代码如下:

#include "STC15F2K60S2.H"
sbit SEL0=P2^0;			//定义引脚
sbit SEL1=P2^1;
sbit SEL2=P2^2;
sbit SEL3=P2^3;
#define uint unsigned int
#define ulint unsigned long
uint time=0;				//延时
uint flag=1;				//标志位,区分光和温度
uint l=0;						//执行光的次数
uint t=0;						//执行温度的次数
ulint suml=0;				//光AD值的总和
ulint sumt=0;				//温度AD值的总和
uint date_temp;
int temp=0;					//温度值
uint abs_temp;			//温度绝对值
uint light=0;				//光
//设置用于显示温度的三个变量
uint temp_bai=0;		//百位
uint temp_shi=0;		//十位
uint temp_ge =0;		//个位
//设置用于显示光的三个变量
uint light_bai=0;		//百位
uint light_shi=0;		//十位
uint light_ge =0;		//个位
//数码管上显示0-F
char segtable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
								 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//温度值对应表
int code tempdata[]={239,197,175,160,150,142,135,129,124,120,116,113,109,107,104,101, 
				     99, 97, 95, 93, 91, 90, 88, 86, 85, 84, 82, 81, 80, 78, 77, 76, 
					 75, 74, 73, 72, 71, 70, 69, 68, 67, 67, 66, 65, 64, 63, 63, 62, 
					 61, 61, 60, 59, 58, 58, 57, 57, 56, 55, 55, 54, 54, 53, 52, 52, 
					 51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44, 44, 
					 43, 43, 42, 42, 41, 41, 41, 40, 40, 39, 39, 38, 38, 38, 37, 37, 
					 36, 36, 36, 35, 35, 34, 34, 34, 33, 33, 32, 32, 32, 31, 31, 31, 
					 30, 30, 29, 29, 29, 28, 28, 28, 27, 27, 27, 26, 26, 26, 25, 25,
					 24, 24, 24, 23, 23, 23, 22, 22, 22, 21, 21, 21, 20, 20, 20, 19, 
					 19, 19, 18, 18, 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 
					 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, 9, 9, 9, 8, 8, 8, 7, 
					 7, 7, 6, 6,5, 5, 54,4, 3, 3,3, 2, 2, 1, 1, 1, 0, 0, -1, -1, -1, 
					 -2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, 
					 -10, -10, -11, -11, -12, -13, -13, -14, -14, -15, -16, -16, -17, 
					 -18, -19, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 
					 -30, -32, -33, -35, -36, -38, -40, -43, -46, -50, -55, -63, 361};
void Delay(int n);     //延时函数
void weixuan(char i);  //数码管位的选择
void SEG_Display();    //显示温度,光度
void InitADC_temp();   //初始化温度ADC
void InitADC_light();  //初始化光ADC
void date_processtemp();
void date_processlight();
void Delay(int n)			//延时函数
{
	int x;
	while(n--)
	{
		x=60;
		while(x--);
	}
}
void weixuan(char i)	//数码管位的选择
{
	SEL2=i/4;
	SEL1=i%4/2;
	SEL0=i%2;
}
void SEG_Display()   //显示温度,光度
{
  //用于设置温度的位数
	if(temp<0)
	{
		P0=0;
		weixuan(0);				//若温度为负,则首位显示‘-’
		P0=0x40;
		Delay(10);
	}
	else
	{
		P0=0;
		weixuan(0);
		P0=segtable[temp_bai];
		Delay(10);
	}
	
	P0=0;
	weixuan(1);
	P0=segtable[temp_shi];
	Delay(10);
	
	P0=0;
	weixuan(2);
	P0=segtable[temp_ge];
	Delay(10);

	//用于设置光的位数
	P0=0;
	weixuan(5);
	P0=segtable[light_bai];
	Delay(10);
	
	P0=0;
	weixuan(6);
	P0=segtable[light_shi];
	Delay(10);
	
	P0=0;
	weixuan(7);
	P0=segtable[light_ge];
	Delay(10);
}

void T_L()
{
	P0M1=0x00;						//设置P0为推挽模式,点亮数码管
	P0M0=0xff;
	P2M1=0x00;
	P2M0=0x08;						//设置P2^3为推挽模式,其余为准双向口模式
	SEL3=0;								//熄灭LED灯
	IE=0xa8;					//EA=1打开总中断,EADC=1允许A/D转化中断,ET1=1允许T1中断	
	TMOD=0x10;					//使用定时器1,16位不可装载模式,TH1,TL1全用
	TH1=(65535-40000)/256;//高8位赋初值,定时40000周期
	TL1=(65535-40000)%256;//低8位赋初值
	TR1=1;								//启动定时器1
	while(1)
	{
		SEG_Display();
	}
}

void InitADC_temp()			//初始化温度ADC
{
	P1ASF=0xff;						//将P1口作为模拟功能AD使用
	ADC_RES=0;						//寄存器ADC_RES和ADC_RESL保存A/D转化结果
	ADC_RESL=0;						//初始赋值0
	ADC_CONTR=0x8b;	//ADC_POWER=1打开A/D转换器电源;ADC_START=1启动模拟转换器ADC;CHS=011选择P1^3作为A/D输入使用
	CLK_DIV=0x20;//ADRJ=1:ADC_RES[1:0]存放高2位ADC结果,ADC_RESL[7:0]存放低8位ADC结果
}
void InitADC_light()		//初始化光ADC
{
	P1ASF=0xff;
	ADC_RES=0;
	ADC_RESL=0;
	ADC_CONTR=0x8c;				//CHS=100选择P1^4作为A/D输入使用
	CLK_DIV=0x20;
}
//分别取出温度和光照的百位、十位、个位
void date_processtemp()
{
	if(temp<0)
		abs_temp=-temp;
	else
		abs_temp=temp;
	temp_bai=abs_temp%1000/100;
	temp_shi=abs_temp%100/10;
	temp_ge =abs_temp%10;
}
void date_processlight()
{
	light_bai=light%1000/100;
	light_shi=light%100/10;
	light_ge =light%10;
}
void Timer1_Routine() interrupt 3	//3为定时器1中断编号
{
	IE=0x00;							//关闭总中断
	TR1=0;								//定时器1停止
	TH1=(65535-40000)/256;//重新赋值
	TL1=(65535-40000)%256;
	if(flag==1)
	{
		InitADC_light();		//初始化光
	}
	else
	{
		InitADC_temp();			//初始化温度
	}
	flag=-flag;

	IE=0xa8;							//打开总中断
	TR1=1;								//启动定时器1
}

//AD中断
void adc_isr() interrupt 5 using 1
{
  time++;
	IE=0x00;							//关闭中断
	
	if(time>2000)      //取多次值求平均值减小误差
	{
		if(flag==1)										//此时flag=1执行温度部分
		{	
			date_temp=(sumt+t/2)/t;			//四舍五入
			temp=tempdata[date_temp-1]; //查找对应ADC值
			sumt=0;
			t=0;
			time=0;
			date_processtemp();	
		}
		if(flag==-1)									//此时flag=-1执行光部分
		{
			light=(suml+l/2)/l;					//四舍五入
			suml=0;
			l=0;
			time=0;
	   	date_processlight();
		}    
	}

	if(flag==1)
	{
		//对应温度的数据处理
		t++;
		date_temp=(ADC_RES*256+ADC_RESL)/4;//由10位AD值转化为8位AD值
		sumt+=date_temp;						//求t次AD值的和

	}
	if(flag==-1)
	{
		//对应光部分的数据处理
		l++;
		suml+=ADC_RES*256+ADC_RESL;//求l次AD的值
	}

	ADC_CONTR&=~0X10;  					 //转换完成后,ADC_FLAG清零
	ADC_CONTR|=0X08;	 					 //转换完成后,ADC_START赋1
	IE=0xa8;					 					 //打开中断
}
void main()
{
	T_L();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布布要成为最负责的男人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值