基于Proteus的pwm调光人体检测台灯

用几个按键表示手动的调光,其中一个按键代表检测到人体。

一个adc转化模块:

以下为全图  

 代码如下,不是很好用,建议看看就好


#include<reg51.h>
#include<intrins.h>
#define uint unsigned int 
#define uchar unsigned char
#define p1 P1
#define p0 P0
#define p2 P2
#define p3 P3
#define f1(a) (65536-a)/256
#define f2(a) (65536-a)%256
sbit s4=p0^3;
sbit s5=p0^4;
sbit sdo=p1^0;
sbit cs=p1^1;
sbit sclk=p1^2;
sbit pwm1=p1^3;

uchar Auto=0;//控制时候自动;
uchar color=0;//控制颜色
uchar temp=0;//控制亮度
static uint cnt=0;
static bit keyflag=1;//标志位
static uchar keydata=0;//保存按键值

uchar adcresult=0;//记录adc的亮度结果,将adc的函数放置在定时器之中,进行实时记录;
static uint times=0;
void delay10ms();
void delay18us(void);
void delay(); 
void key_read_data(void);
void keyscan(void);
uchar adc(void);
uchar pwm(void);
void main(void)
{
  
	//打开两个中断
	//进行全局初始化
	TMOD=0x11;//打开T1 T0,并且全部使用方式1,为16位定时器
	TH0=(65536-500)/256;//b=125,125us=0.125ms,最大1khz
	TL0=(65536-500)%256;
TH1=(65536-500)/256;//
	TL1=(65536-500)%256;
	
	EA=1;
	ET0=1;//EA=1;总中断允许ET1=1;ET0=1;定时器中断允许;
	ET1=1;
	PT1=0;
	PT0=1;
	//ET0=1;
	TR0=1;//制造pwm波形不一定要在这里就开启;
	TR1=1;
	cs=1;//停止adc采样
	sclk=0;
	sdo=1;
	while(1){
		delay10ms();
		while(s5==0){
		
				if(Auto==0){p2=0xf0;}
				if(Auto==1)
					{
					
						switch(color)//灯色优先
						{
							case 0://黄白
							case 1:
								p2=0;
							
							
								break;
							case 2:
								p2=0x0f;
							
						
							//白
								break;
							case 3:
								p2=0xf0;
							
						
								//黄
						break;
							}
						}
				
					
					keyscan();
						
				}
				
				delay();
				p2=0x11;
				delay10ms();
				p2=0x44;
				delay10ms();
				p2=0x88;
				delay10ms();
				p2=0xaa;
				delay10ms();
				p2=0xcc;
				delay10ms();
				p2=0xff;
	
	//EA=0;
	}
}

void delay10ms(void)//eliminate jitter(抖动)
{
	uchar i,j;
	for(i=0;i<10;i++)
	for(j=0;j<10;j++)
	;
}
void delay18us(void)//延时18us
{
	_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
	_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
}

	void delay()
{
	uchar i,j;
	for(i=0;i<100;i++)
	for(j=0;j<100;j++);
}
//void init()//初始化{}
uchar adc(void)//得到adc数据
{
	//取得adc的值并返回给pwm;
	uchar i,t;
	cs=0;
	delay18us();
	for(i=0;i<8;i++)
	{
		if(sdo==1)
		{
			t=t|0x01;
		}
		if(i<7)
		{
			t=t<<1;
		}
		sclk=1;
		_nop_();_nop_();_nop_();_nop_();
		sclk=0;
		_nop_();_nop_();
	}
	cs=1;
	//temp的值从0-256,0x00-0xff,,天然对应8个二极管,
	//256分为4个段,0<= x<64(25%),64<=x<128(50%),128<=x<192(75%),192<=x<256(100%)
	
	return t;//temp是一个二进制值,也可以直接看作是一个十六进制值
}
void key_read_data()//采集数据
{
	p0=0xff;//检测低四位
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	keydata=p0^0x0f;//如果p0是1110,1111
	//异或后会得到0001,相当于和0x0f与运算后再取反;
	//如果没有按键按下,那么1111全部取值后就是0;
}

void keyscan()//重复扫描键盘;
{
	key_read_data();
	if(keyflag==1&&keydata>0x08)
	{
		if(cnt>5)
			{
				switch(keydata)
			{
					case 0x01://1110
						Auto=0;//自动
						break;
					case 0x02://1101
						Auto=0;//自动
						break;
					case 0x03://1100
						Auto=0;//自动
						break;
					case 0x04://1011
						Auto=0;//自动
						break;
					case 0x05://1010
						Auto=0;//自动
						
						break;
					case 0x06://1001
					Auto=0;//自动
					
						break;
					case 0x07://1000
					Auto=0;//自动
						break;
					
					//以上为自动
					//以下为手动
					
				case 0x08://0111,//只有给出手动的指令
				case 0x0e://0001
						Auto=1;//手动
						break;
				
						
				case 0x09://0110
					Auto=1;//手动
					color++;
					if(color>3)color=0;
					
						break;
				case 0x0a://0101,
							Auto=1;//手动
							if(temp==0);
							else if(temp>0)temp--;//越接近0,亮度越高
							break;
					case 0x0b://0100
						Auto=1;//手动
						color++;
						if(color>3)color=0;
						
						 if(temp>0)temp--;//越接近0,亮度越高
					break;
					
					case 0x0c://0011 同时加减亮度,则取0;
							Auto=1;//手动
							temp++;
						if(temp>3)temp=3;
							break;	
					case 0x0d://0010
							Auto=1;//手动
							color++;
							if(color>3)color=0;
							temp++;
							if(temp>3)temp=3;
								break;
					
					case 0x0f://0000
						Auto=1;//手动
						color++;
						if(color>3)color=0;
							break;
				}
			keyflag=0;//禁止再次进入处理
				cnt=0;
			}
			
		}
	
	else if(0<keydata&&keydata<=0x08)
		{
			
			keyflag=1;
			cnt=0;//技术清零,主要针对按键抖动情况
		}
		else if(keydata==0)
		{
			Auto=0;
			keyflag=1;
			cnt=0;//技术清零,主要针对按键抖动情况
		}
	
	
}
//
uchar pwm(void)//返回调节占空比数字n,代表调节了
{
	uint n;
	uchar i;
	i=adc();
		//TH0=(65536/256-1000/256);//得到固定周期,
		//TL0=(65536%256-1000%256);//总周期为0.1ms,100us,
		//应该分为4个等级
		if(i<0x40)
		{
			n=0;
		}
		else if(i<0x80)
		{
			n=1;
		}
		else if(i<0xc0)
		{
			n=2;
		}
		else//0xff
		{
			n=3;
		}
		//输入adc获得的数据,判断pwm所属于的层次,基础分为四个量级,
	//0-25%,25-50,50-75,75-100,共四个光强强度对应对应的脉冲宽度;
	return n;//返回等级
}

void timer0() interrupt 1//定时器T0 
{
	
	//IP决定优先级别
	//IE决定是否允许中断,及中断的形式
	//TCON寄存器,包括了溢出标志
	//TMOD选择定时器和计数器;
	TH0=(65536-500)/256;//b=500,500us=0.5ms,最大1khz
	TL0=(65536-500)%256;
	
	cnt++;
//	keyscan();
	times++;//times越大,频率越高;
	adcresult=pwm();
	if(Auto==0)//自动
	{
		temp=adcresult;//把手动的亮度结果反馈进入其中
			
	}
		if(times==10) //2.5 毫秒的时钟周期 
			{ 
							times=0; //使 tt=0,开始新的 PWM 周期 
							pwm1=0; //使 LED 灯亮 
						} 
		if(temp==times) //按照当前占空比切换输出为高电平 
							pwm1=1; //使 LED 灯灭
		
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值