很多现有的台灯都不具备调光的功能,只有一个电源开关,现用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