stc单片机pwm怎么调光 (单片机调光灯程序视频)

很多现有的台灯都不具备调光的功能,只有一个电源开关,现用STC15F104E/STC15F104W等8脚芯片进行改造。利用单片机内部的EEPROM功能进行数据的掉电保存。

项目设计要求:

1.通过台灯适配器上的电源开关来进行调光切换。

2.调光分成4个档位,分别对应pwm占空比的:25%,50%,75%,100%

3.程序带记忆功能,上电时间超过6秒钟单片机将记住此时的亮度数据(及占空比),关灯后下次打开依旧为上次的亮度

4.调光切换,上电后在6秒钟以内,每开关一次,亮度将向后变化一次,如果当前为100%,下次切换后为25%的亮度

有了以上的设计要求后就可以自己写代码和搭硬件电路了。

台灯适配器图片:

基于单片机的自动调光台灯,单片机调光灯程序视频

台灯开关,增加的电路会装在这个开关中

基于单片机的自动调光台灯,单片机调光灯程序视频

最暗时候的灯珠亮度

基于单片机的自动调光台灯,单片机调光灯程序视频

最暗时候的PWM波形

基于单片机的自动调光台灯,单片机调光灯程序视频

实际调试的电路

基于单片机的自动调光台灯,单片机调光灯程序视频

一下是原理图,方块内部的部分电路最后全部装到适配器上的开关里

基于单片机的自动调光台灯,单片机调光灯程序视频

以下是程序代码!C程序调试

#include "reg51.h"
#include "intrins.h"

typedef bit BOOL;
typedef unsigned char BYTE;
typedef unsigned int WORD;

#define T1MS (65536-500) //12T模式

sfr AUXR = 0x8e;                    //Auxiliary register

/*---------------------------------------------------------------------*/
/*--   端口定义                 ---------------------------------------*/
/*---------------------------------------------------------------------*/
#define PORT_3 P3
#define HIGH 1
#define LOW	 0

sbit PWM_OUT_PORT   = P3^2;		   //	LED_RED	 LED_GREEN
sbit LED   = P3^3;
/*---------------------------------------------------------------------*/
/*--   变量定义                 ---------------------------------------*/
/*---------------------------------------------------------------------*/
BYTE i,j;
BYTE test_num;
BYTE POWER_ON_TEMP_f;
BYTE POWER_ON_TIME;
BYTE READ_POWER_ON_TIME;
BOOL ON_OFF_Flag;

unsigned long POWER_ON_TEMP;

//-----------------------------------------------
sfr IAP_DATA    =   0xC2;               //IAP数据寄存器
sfr IAP_ADDRH   =   0xC3;               //IAP地址寄存器高字节
sfr IAP_ADDRL   =   0xC4;               //IAP地址寄存器低字节
sfr IAP_CMD     =   0xC5;               //IAP命令寄存器
sfr IAP_TRIG    =   0xC6;               //IAP命令触发寄存器
sfr IAP_CONTR   =   0xC7;               //IAP控制寄存器

sfr WDT_CONTR   =   0xC1;               //0000,0000 看门狗控制寄存器

sfr P3M0        =   0xB2;   //0000,0000 端口3模式寄存器0
sfr P3M1        =   0xB1;   //0000,0000 端口3模式寄存器1

#define CMD_IDLE    0                   //空闲模式
#define CMD_READ    1                   //IAP字节读命令
#define CMD_PROGRAM 2                   //IAP字节编程命令
#define CMD_ERASE   3                   //IAP扇区擦除命令
#define ENABLE_IAP 0x83                 //if SYSCLK<12MHz

#define IAP_ADDRESS  0x0100		        //测试地址
#define OFF_TIME_ADD 0x0300		        //测试地址
/*----------------------------
关闭IAP
----------------------------*/
void IapIdle()
{
    IAP_CONTR = 0;                  //关闭IAP功能
    IAP_CMD = 0;                    //清除命令寄存器
    IAP_TRIG = 0;                   //清除触发寄存器
    IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}

/*----------------------------
从ISP/IAP/EEPROM区域读取一字节
----------------------------*/
BYTE IapReadByte(WORD addr)
{
    BYTE dat;                       //数据缓冲区
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_READ;             //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
    IapIdle();                      //关闭IAP功能
    return dat;                     //返回
}

/*----------------------------
写一字节数据到ISP/IAP/EEPROM区域
----------------------------*/
void IapProgramByte(WORD addr, BYTE dat)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_PROGRAM;          //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}

/*----------------------------
扇区擦除
----------------------------*/
void IapEraseSector(WORD addr)
{
    IAP_CONTR = ENABLE_IAP;         //使能IAP
    IAP_CMD = CMD_ERASE;            //设置IAP命令
    IAP_ADDRL = addr;               //设置IAP低地址
    IAP_ADDRH = addr >> 8;          //设置IAP高地址
    IAP_TRIG = 0x5a;                //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                //写触发命令(0xa5)
    _nop_();                        //等待ISP/IAP/EEPROM操作完成
    IapIdle();
}

/*---------------------------------------------------------------------*/
/*--   延时子程序               ---------------------------------------*/
/*---------------------------------------------------------------------*/
void DELAY_1MS(unsigned int z)
{
	unsigned int x,y;
	for(x=z;x>0;x--)
		for(y=123;y>0;y--); 
}
/*---------------------------------------------------------------------*/
/*--   主程序                   ---------------------------------------*/
/*---------------------------------------------------------------------*/

void main()
{
	PORT_3=0X00;
	P3M0=0xFF;
	P3M1=0x00;
	ON_OFF_Flag=0;
	POWER_ON_TIME=0;
	READ_POWER_ON_TIME=0;

    AUXR |= 0x80;                   //定时器0为1T模式
//    AUXR &= 0x7f;                   //定时器0为12T模式
    TMOD = 0x00;                    //设置定时器为模式0(16位自动重装载)
    TL0 = T1MS;                     //初始化计时值
    TH0 = T1MS >> 8;
    TR0 = 1;                        //定时器0开始计时
    ET0 = 1;                        //使能定时器0中断
    EA = 0;
	POWER_ON_TEMP=0;
	POWER_ON_TEMP_f=0;
	j=0;
	i=100;

	DELAY_1MS(100);

	WDT_CONTR = 0x35;	   //启动看门狗
	while (1)
	{
		WDT_CONTR = 0x35;	   //启动看门狗	    
		if(ON_OFF_Flag==0)	   //上电标志,上电只执行一次
		{
			ON_OFF_Flag=1;
			READ_POWER_ON_TIME=IapReadByte(OFF_TIME_ADD);	  //////////////////////////////

			if(READ_POWER_ON_TIME!=4)   //上电时间监测,小于4切换模式
			{
				test_num=IapReadByte(IAP_ADDRESS);			  //////////////////////////////
				if(test_num<3)		 //	LED_RED	 LED_GREEN
				{
				   	test_num++;
					IapEraseSector(IAP_ADDRESS);
					IapProgramByte(IAP_ADDRESS,test_num);					
				}
				else 
				{
					test_num=0;
					IapEraseSector(IAP_ADDRESS);
					IapProgramByte(IAP_ADDRESS,test_num);
				}
			}

			else					  //上电时间监测,大于4模式记忆
			{
				test_num=IapReadByte(IAP_ADDRESS);		  /////////////////////////////////
				if(test_num>3)		 //	LED_RED	 LED_GREEN 
				{
				   	test_num=0;
					IapEraseSector(IAP_ADDRESS);
					IapProgramByte(IAP_ADDRESS,test_num);
				}	
			}
			IapEraseSector(OFF_TIME_ADD);
		}
		/*---------------------------------------------------------------------*/
		EA = 1;
		if(test_num==0)
		{
			j=4;
		}
		else if(test_num==1)
		{
			j=20;			
		}
		else if(test_num==2)
		{
			j=50;			
		}
		else if(test_num==3)
		{
			j=99;			
		}	
	}
}

//-----------------------------------------------

/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
	if(i>0)
	{
		i--;
		if(j