51单片机实现光敏电阻控制LED灯亮灭

一、概述

1.光敏电阻简介

        光敏电阻(photoresistor or light-dependent resistor,后者缩写为ldr)或光导管photoconductor),常用的制作材料为硫化镉,另外还有硒、硫化铝硫化铅硫化铋等材料。这些制作材料具有在特定波长的光照射下,其阻值迅速减小的特性。这是由于光照产生的载流子都参与导电,在外加电场的作用下作漂移运动,电子奔向电源的正极,空穴奔向电源的负极,从而使光敏电阻器的阻值迅速下降。

        光敏电阻是用硫化镉或硒化镉等半导体材料制成的特殊电阻器,其工作原理是基于内光电效应。光照愈强,阻值就愈低,随着光照强度的升高,电阻值迅速降低,亮电阻值可小至1KΩ以下。光敏电阻对光线十分敏感,其在无光照时,呈高阻状态,暗电阻一般可达1.5MΩ。光敏电阻的特殊性能,随着科技的发展将得到极其广泛应用。 [1]

        光敏电阻器是利用半导体的光电导效应制成的一种电阻值随入射光的强弱而改变的电阻器,又称为光电导探测器;入射光强,电阻减小,入射光弱,电阻增大。还有另一种入射光弱,电阻减小,入射光强,电阻增大。

        光敏电阻器一般用于光的测量、光的控制和光电转换(将光的变化转换为电的变化)。常用的光敏电阻器硫化镉光敏电阻器,它是由半导体材料制成的。光敏电阻器对光的敏感性(即光谱特性)与人眼对可见光(0.4~0.76)μm的响应很接近,只要人眼可感受的光,都会引起它的阻值变化。设计光控电路时,都用白炽灯泡(小电珠)光线或自然光线作控制光源,使设计大为简化。

2.ADC数模转换

        数模转换器,又称D/A转换器,简称DAC,它是把数字量转变成模拟的器件。D/A转换器基本上由4个部分组成,即权电阻网络运算放大器、基准电源和模拟开关模数转换器中一般都要用到数模转换器,模数转换器即A/D转换器,简称ADC,它是把连续的模拟信号转变为离散的数字信号的器件。

        如何检测外部模拟信号,因为我们使用的 STC89C5x 单片机内部不含 ADC 接口,所以需要外接一个 ADC 转换芯片将模拟信号转换成数字信号供单片机 处理。我们开发板上集成了一个ADC 模数转换电路,选用的 ADC 芯片是 12 位的 AD 芯片-XPT2046。这里要实现的功能是:通过ADC 转换电路采集电位器电压值, 将采集转换后的 AD 值通过数码管显示。
        我们知道 51 单片机系统内部运算时用的全部是数字量,即 0 和 1,因此对 单片机系统而言,无法直接操作模拟量,必须将模拟量转换成数字量。所谓数字 量,就是用一系列 0 和 1 组成的二进制代码表示某个信号大小的量。用数字量 表示同一个模拟量时,数字位数可以多也可以少,位数越多则表示的精度越高, 位数越少表示的精度就越低。

3.XPT2046 芯片介绍

        XPT2046 是一款 4 线制电阻式触摸屏控制器,内含 12 位分辨率 125KHz 转换速率逐步逼近型 A/D 转换器。XPT2046 支持从 1.5V 到 5.25V 的低电压 I/O 接口。XPT2046 能通过执行两次 A/D 转换查出被按的屏幕位置,除此之外, 还可以测量加在触摸屏上的压力。内部自带 2.5V 参考电压,可以作为辅助输入、 温度测量和电池监测之用,电池监测的电压范围可以从 0V 到 6V。XPT2046 片 332内集成有一个温度传感器。在 2.7V 的典型工作状态下,关闭参考电压,功耗可 小于 0.75mW。XPT2046 采用微小的封装形式:TSSOP-16,QFN-16 和 VFBGA-48。 工作温度范围为-40℃~+85℃。与 ADS7846、TSC2046、AK4182A 完全兼容。
主要特性:
①工作电压范围为 1.5V~5.25V
②支持 1.5V~5.25V 的数字 I/O 口
③内建 2.5V 参考电压源
④电源电压测量( 0V~6V)
⑤内建结温测量功能
⑥触摸压力测量
⑦采用 3 线制 SPI 通信接口
⑧具有自动省电功能
        XPT2046 是一种典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保 持、模数转换、串口数据 输出等功能。同时芯片集成有一个 2.5V 的内部参考 电压源、温度检测电路,工作时使用外部时钟。XPT2046 可以单电源供电,电源 电压范围为 2.7V~5.5V。参考电压值直接决定 ADC 的输入范围,参考电压可以 使用内部参考电压,也可以从外部直接输入 1V~VCC 范围内的参考电压(要求 外部参考电压源输出阻抗低)。X、Y、Z、VBAT、Temp 和 AUX 模拟信号经过片内 的控制寄存器选择后进入 ADC,ADC 可以配置为单端或差分模式。选择 VBAT、Temp 和 AUX 时应该配置为单端模式;作为触摸屏应用时,应该配置为差分模式,这可 有效消除由于驱动开关的寄生电阻及外部的干扰带来的测量误差,提高转换精 度。单端和差分模式输入配置如下图所示:
        XPT2046 数据接口是串行接口,其典型工作时序如下图所示,图中展示的信 号来自带有基本串行接口的单片机或数据信号处理器。处理器和转换器之间的的 通信需要 8 个时钟周期,可采用 SPI、SSI 和 Microwire 等同步串行接口。一 次完整的转换需要 24 个串行同步时钟(DCLK)来完成。
        前 8 个时钟用来通过 DIN 引脚输入控制字节。当转换器获取有关下一次转 换的足够信息后,接着根据获得的信息设置输入多路选择器和参考源输入,并进 入采样模式,如果需要,将启动触摸面板驱动器。3 个多时钟周期后,控制字节 设置完成,转换器进入转换状态。这时,输入采样-保持器进入保持状态,触摸 面板驱动器停止工作(单端工作模式)。接着的 12 个时钟周期将完成真正的模 数转换。如果是度量比率转换方式(SER/DFR=0),驱动器在转换过程中将一直 工作,第 13 个时钟将输出转换结果的最后一位。剩下的 3 个多时钟周期将用 来完成被转换器忽略的最后字节(DOUT 置低)。
在对 XPT2046 进行控制时,控制字节由 DIN 输入的控制字命令格式如下图所示:

二、工作原理

1.光敏电阻工作原理

        光敏电阻的工作原理是基于内光电效应。在半导体光敏材料两端装上电极引线,将其封装在带有透明窗的管壳里就构成光敏电阻,为了增加灵敏度,两电极常做成梳状。用于制造光敏电阻的材料主要是金属的硫化物硒化物碲化物等半导体。通常采用涂敷、喷涂、烧结等方法在绝缘衬底上制作很薄的光敏电阻体及梳状欧姆电极,接出引线,封装在具有透光镜的密封壳体内,以免受潮影响其灵敏度。入射光消失后,由光子激发产生的电子—空穴对将复合,光敏电阻的阻值也就恢复原值。在光敏电阻两端的金属电极加上电压,其中便有电流通过,受到一定波长的光线照射时,电流就会随光强的增大而变大,从而实现光电转换。光敏电阻没有极性,纯粹是一个电阻器件,使用时既可加直流电压,也加交流电压。半导体的导电能力取决于半导体导带载流子数目的多少。

2.ADC转换原理

        AD 转换器(ADC)将模拟量转换为数字量通常要经过 4 个步骤:采样、保持、 量化和编码。所谓采样即是将一个时间上连续变化的模拟量转换为时间上离散变化的模拟量。如下图所示: 将采样结果存储起来,直到下次采样,这个过程叫做保持。一般采样器和保 持电路一起总称为采样保持电路。
        将采样电平归化为与之接近的离散数字电平, 这个过程叫做量化。将量化后的结果按照一定数制形式表示就是编码。将采样电 平(模拟值)转换为数字值时,主要有两类方法:直接比较型与间接比较型。 --直接比较型:就是将输入模拟信号直接与标准的参考电压比较,从而得到 数字量。常见的有并行 ADC 和逐次比较型 ADC。 --间接比较型:输入模拟量不是直接与参考电压比较,而是将二者变为中间 的某种物理量在进行比较,然后将比较所得的结果进行数字编码。常见的有双积分型 ADC。

三、实验程序

1.参考代码

main.c

#include "regx52.h"
#include "LCD1602.h"
#include "stdio.h"
#include "xpt2046.h"
#include "delay.h"


sbit LED1 = P2^0;

unsigned int light_value = 0;

void main()
{
	lcd1602_init();
	while(1)
	{                                                                                                                 
		char buf[20] = {0};
		light_value = xpt2046_read_adc_value(0xA4);
		sprintf(buf,"value=%4d",light_value);
		lcd1602_show_string(1,0,buf);
		Delay1_ms(100);
		
			if(light_value < 100)
				LED1 = 0;
			else
				LED1 = 1;
	}
}

xtp2046.c

#include "xpt2046.h"
#include "intrins.h"

/*******************************************************************************
* 函 数 名       : xpt2046_wirte_data
* 函数功能		 : XPT2046写数据
* 输    入       : dat:写入的数据
* 输    出    	 : 无
*******************************************************************************/
void xpt2046_wirte_data(u8 dat)
{
	u8 i;

	CLK = 0;
	_nop_();
	for(i=0;i<8;i++)//循环8次,每次传输一位,共一个字节
	{
		DIN = dat >> 7;//先传高位再传低位
		dat <<= 1;//将低位移到高位
		CLK = 0;//CLK由低到高产生一个上升沿,从而写入数据
		_nop_();	
		CLK = 1;
		_nop_();
	}
}

/*******************************************************************************
* 函 数 名       : xpt2046_read_data
* 函数功能		 : XPT2046读数据
* 输    入       : 无
* 输    出    	 : XPT2046返回12位数据
*******************************************************************************/
u16	xpt2046_read_data(void)
{
	u8 i;
	u16 dat=0;

	CLK = 0;
	_nop_();
	for(i=0;i<12;i++)//循环12次,每次读取一位,大于一个字节数,所以返回值类型是u16
	{
		dat <<= 1;
		CLK = 1;
		_nop_();
		CLK = 0; //CLK由高到低产生一个下降沿,从而读取数据
		_nop_();
		dat |= DOUT;//先读取高位,再读取低位。	
	}
	return dat;	
}

/*******************************************************************************
* 函 数 名       : xpt2046_read_adc_value
* 函数功能		 : XPT2046读AD数据
* 输    入       : cmd:指令
* 输    出    	 : XPT2046返回AD值
*******************************************************************************/
u16 xpt2046_read_adc_value(u8 cmd)
{
	u8 i;
	u16 adc_value=0;

	CLK = 0;//先拉低时钟
	CS  = 0;//使能XPT2046
	xpt2046_wirte_data(cmd);//发送命令字
	for(i=6; i>0; i--);//延时等待转换结果
	CLK = 1;
	_nop_();
	CLK = 0;//发送一个时钟,清除BUSY
	_nop_();
	adc_value=xpt2046_read_data();
	CS = 1;//关闭XPT2046
	return adc_value;
}
#ifndef _xpt2046_H
#define _xpt2046_H

#include "regx52.h"

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

//管脚定义
sbit DOUT = P3^7;	  //输出
sbit CLK  = P3^6;	  //时钟
sbit DIN  = P3^4;	  //输入
sbit CS   = P3^5;	  //片选

//函数声明
u16 xpt2046_read_adc_value(u8 cmd);

#endif

LCD1602.c

#include "LCD1602.h"
#include "regx52.h"
#include "delay.h"

void lcd1602_write_cmd(unsigned char cmd)
{
	LCD1602_RS=0;
	LCD1602_RW=0;
	LCD1602_EN=0;
	
	LCD1602_DATAPORT=cmd;
	
	LCD1602_EN=1;
	Delay1_ms(1);
	LCD1602_EN=0;
	Delay1_ms(1);
	
}

void lcd1602_write_data(unsigned char dat)
{
	LCD1602_RS=1;
	LCD1602_RW=0;
	LCD1602_EN=0;
	
	LCD1602_DATAPORT=dat;
	
	LCD1602_EN=1;
	Delay1_ms(1);
	LCD1602_EN=0;
	Delay1_ms(1);

}

void lcd1602_init()
{
	lcd1602_write_cmd(0x38);//数据长度为8、2行显示、5*7点阵
	//显示功能打开、无光标、光标不闪烁
	lcd1602_write_cmd(0x0c);
	//写入新数据后光标右移、文字保持不动
	lcd1602_write_cmd(0x06);
	
	lcd1602_write_cmd(0x01);
}

void lcd1602_show_string(unsigned char x,unsigned char y,unsigned char*str)
{
	if(y==0)
		lcd1602_write_cmd(0x80+0x00+x);
	if(y==1)
		lcd1602_write_cmd(0x80+0x40+x);
	
	while(*str != '\0')
	{
		lcd1602_write_data(*str);
		str++;
	}
}
#include "regx52.h"
#ifndef _LCD1602_H_
#define _LCD1602_H_

sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_EN = P2^7;

#define LCD1602_DATAPORT P0

void lcd1602_init();
void lcd1602_show_string(unsigned char x,unsigned char y,unsigned char*str);



#endif

另外还有delay函数的模块

#include "delay.h"
#include "intrins.h" 

//延时函数
void Delay1_ms(unsigned int a)		//@11.0592MHz
{
	unsigned char i, j;
	for(a;a>0;a--)
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
	}
}

四、实验现象

编译成功后将程序烧录到开发板上,插上LCD1602模块

如果亮度value值大于100,LED1灭

覆盖住光敏电阻,亮度value值小于100,LED1亮

(文章内容取自51单片机开发板资料)

  • 27
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据提供的引用内容,可以得知51单片机光敏电阻调节LED亮度的具体实现方法如下: 1. 首先需要连接STC89C52单片机电路、光照检测电路(光敏电阻)、AD0832转换电路、4位高亮LED灯电路、按键电路和电源电路。 2. 系统具有自动模式和手动模式,按模式键可以进行切换。在手动模式下,按加、减键可以手动调节台灯的亮度。 3. 在自动模式下,需要实时监测当前亮度,比预设值小,就点亮一个LED,再检测,再点亮,以此类推,直到达到预设亮度。 4. 在手动模式下,需要通过光敏电阻检测当前亮度,并将其转换为电压信号,然后通过AD0832转换电路将其转换为数字信号,最后通过单片机控制4位高亮LED灯电路的亮度。 代码实现如下: ```c #include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit led1 = P1^0; // 定义LED1引脚 sbit led2 = P1^1; // 定义LED2引脚 sbit led3 = P1^2; // 定义LED3引脚 sbit led4 = P1^3; // 定义LED4引脚 sbit key1 = P3^0; // 定义按键1引脚 sbit key2 = P3^1; // 定义按键2引脚 sbit key3 = P3^2; // 定义按键3引脚 sbit key4 = P3^3; // 定义按键4引脚 sbit light = P2^0; // 定义光敏电阻引脚 uchar code led_table[] = { // 定义数码管显示表 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 }; void delay(uint i) { // 延时函数 while(i--); } void display(uchar num) { // 数码管显示函数 P0 = led_table[num]; } uchar read_AD0832(uchar channel) { // 读取AD0832转换电路函数 uchar i, dat = 0; CS = 0; CLK = 0; DIN = 1; delay(1); CS = 1; delay(1); CS = 0; delay(1); DIN = 0; delay(1); CLK = 1; delay(1); CLK = 0; delay(1); DIN = 1; delay(1); CS = 1; delay(1); CS = 0; delay(1); DIN = 1; delay(1); CLK = 1; delay(1); CLK = 0; delay(1); DIN = channel; delay(1); for(i = 0; i < 8; i++) { CLK = 1; delay(1); CLK = 0; delay(1); dat <<= 1; dat |= DOUT; } CS = 1; return dat; } void main() { uchar mode = 0, light_value = 0, led_value = 0; while(1) { if(key1 == 0) { // 切换模式 delay(10); if(key1 == 0) { mode = !mode; while(!key1); } } if(key2 == 0 && mode == 0) { // 手动调节亮度 delay(10); if(key2 == 0) { led_value++; if(led_value > 15) { led_value = 0; } while(!key2); } } if(mode == 0) { // 手动模式 display(led_value); if(led_value == 0) { led1 = 0; led2 = 0; led3 = 0; led4 = 0; } else if(led_value == 1) { led1 = 1; led2 = 0; led3 = 0; led4 = 0; } else if(led_value == 2) { led1 = 1; led2 = 1; led3 = 0; led4 = 0; } else if(led_value == 3) { led1 = 1; led2 = 1; led3 = 1; led4 = 0; } else { led1 = 1; led2 = 1; led3 = 1; led4 = 1; } } else { // 自动模式 light_value = read_AD0832(0); // 读取光敏电阻的值 if(light_value < 100) { // 如果亮度小于100,点亮LED1 led1 = 1; led2 = 0; led3 = 0; led4 = 0; } else if(light_value < 200) { // 如果亮度小于200,点亮LED1和LED2 led1 = 1; led2 = 1; led3 = 0; led4 = 0; } else if(light_value < 300) { // 如果亮度小于300,点亮LED1、LED2和LED3 led1 = 1; led2 = 1; led3 = 1; led4 = 0; } else { // 如果亮度大于等于300,点亮LED1、LED2、LED3和LED4 led1 = 1; led2 = 1; led3 = 1; led4 = 1; } } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值