手电大家谈-手电筒爱好者之家

 找回密码
 注册成为会员,享受更多功能。

QQ登录

只需一步,快速开始

只需一步,快速开始

搜索
查看: 9423|回复: 8

【原创】基于ATtiny13的无级调光头灯程序

[复制链接]

该用户从未签到

发表于 2016-4-7 15:43 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册成为会员,享受更多功能。

x
基于ATtiny13的无级调光头灯程序
    市面上的头灯一般有强光、弱光、爆闪三个挡位,一个按钮来控制开/关和换挡,顺序是:开(强光)-〉弱光->闪烁->关,每次开/关灯需要按三次,非常不方便。
   
    两年前改造的五挡调光头灯一直用的很好,操作简便又人性化。近来比较空闲,突发DIY一个有无级调光功能的头灯想法。于是在网上搜索合适DIY的头灯,搜索原则是散热性能好、能变焦、尽量是装两节18650电池的灯。本人喜欢变焦灯,因为照射范围可调又均匀。第一次购买的灯完全失败,散热极差,为了节省成本居然灯头的重要部件用的是硬塑料,直接丢掉。第二次买的还好,惊喜的是他的控制芯片用的是CX2812,它的引脚与ATTiny13单片机类似,替换控制芯片,稍微改动电路板的布线就可以利用原配的控制板,避免了从头开始做控制板,省去了最繁琐的印刷电路板的制作了。
通过ATtiny13a单片机的编程实现了一下功能:
1、按一次开灯,再按一次就关灯,解决了按三次关灯的不方便的问题。
2、开关灯保留了逐步亮和逐步暗的功能,此功能非常人性化,本人很喜欢。具体实现如下:开灯的时候PWM信号的占空比从0开始逐步加到设定的亮度,关灯时候占空比逐步减到03、无级调光:在灯亮状态下按住按钮,LED灯亮度增加或减少,亮度达到100%10%时闪烁三次来提醒亮度已经达到了全亮或最暗,松开按钮就停止调光,一直按住就循环调光。
程序中利用了ATtiny13aPWM、外部中断(PCINT0)、睡眠、看门狗和EEPROM的读写功能,基本上每一行都加了注释,对于初次接触ATtiny13的人来说应该有帮助。
图片1:头灯

头灯

头灯
                              

图片2:头灯控制板(此控制板网上也有卖的)

头灯控制板

头灯控制板
  
图片3:程序调试电路图

程序调试电路图

程序调试电路图
图片4:用面包板搭建程序调试电路

用面包板搭建用面包板搭建程序调试电路程序调试电路

用面包板搭建用面包板搭建程序调试电路程序调试电路
图片5:基于ATTiny13A的控制板电路图

基于ATTiny13A的控制板电路图

基于ATTiny13A的控制板电路图
图片6:修改后的ATTiny13A控制板

修改后的ATTiny13A控制板

修改后的ATTiny13A控制板
图片718650电池下的待机电流为0.26uA

18650电池下的待机电流为0.26uA

18650电池下的待机电流为0.26uA

程序编辑和编译工具用了CodeVisionAVR 2.04.4a,烧写工具用了progisp1.72
08.jpg

需要工程文件的请本人百度消息联系我(百度ID: zs_jin)。
程序源码:
/**********************************************************************
* 名称 LED控制程序
* 描述 :无级调光功能,单击开/关,长按无级调光
* MCU ATTiny13A
* 晶振 RC 9.6MHz
* 编译环境 CodeVisionAVR2.04.4a
* 版本 4.0 KEY用外部中断方式、增加睡眠功能、看门狗,8分频(4.6875KHz
*       外部中断服务程序=>PCINT0, 无级调光
***********************************************************************/
#include <tiny13a.h>
#include <delay.h>
#define uchar unsigned char
#define uint  unsigned int
#define KEY    PINB.2  //tiny137脚,PCINT0中断
#define LEDDRV PORTB.0  //tiny135
#define KEY_DOWN 0      //按下按键
#define LED_ON  0      //LED
#define LED_OFF 1       //LED
#define PWM_ON  0xc3   //PWM 启动
#define PWM_OFF 0x03    //PWM 关闭
#define MIN_VAL 0x1a    //最小亮度
#define MAX_VAL 0xff    //最大亮度
#define LONG_KEY  3    //长按键的时间
#define ADDRESS 0x01    //保存挡位的地址
uchar pwmVal = 0;   //亮度值
uint keytime = 0;   //按键时间
bit status = 0;     //0LED ON1LED OFF
bit fangxiang = 0;  //亮度增减方向
/**********************************************************************
* 描述:eeprom写一个字节数据
* 参数:address--地址    data--数据
***********************************************************************/
void eeprom_write(uchar address,uchar data)
{
   //等待上一次写操作结束
   while(EECR&(1<<EEPE));
   //设置编程模式
   EECR=(0<<EEPM1)|(0>>EEPM0);
   //设置地址和数据寄存器
   EEAR = address;
   EEDR  = data;
   //置位EEMPE
   EECR |= (1<<EEMPE);
   //置位EEWE,启动写操作
   EECR |= (1<<EEPE);
}
/***********************************************************************
* 描述:eeprom读一个字节数据
* 参数:address--地址
************************************************************************/
uchar eeprom_read(uchar address)
{
   //等待上一次写操作结束
   while(EECR&(1<<EEPE));
   //设置地址寄存器
   EEAR=address;
   //设置EERE以启动读操作
   EECR |= (1<<EERE);
   //自数据寄存器返回数据
   return(EEDR);
}
/***********************************************************************
* 描述:开启看门狗
* 参数:无
************************************************************************/
void WDT_on(void)
{
   // 看门狗设置
   //#asm("cli") // 关闭全局中断
   #asm("WDR") // 看门狗复位指令WDR用来复位看门狗定时器
   WDTCR=0x18; // 启动时序 WDTCR |= (1<<WDCE) | (1<<WDE);
   //WDTCR=0x28; // 看门狗定时4s WDTCR = (1<<WDP3) | (1<<WDE);
   WDTCR = (1<<WDP3) | (1<<WDE);   // 看门狗定时4s
   //#asm("sei") // 开启全局中断
}
/***********************************************************************
* 描述:关闭看门狗
* 参数:无
************************************************************************/
void WDT_off(void)
{
   // 看门狗设置
   //#asm("cli") // 关闭全局中断
   #asm("WDR") // 看门狗复位指令WDR用来复位看门狗定时器
   MCUSR &= ~(1<<WDRF);   // 清除MCUSR 寄存器中WDRF
   // WDCE WDE 中写逻辑1,保持旧预分频器设置防止无意暂停
   WDTCR |= (1<<WDCE) | (1<<WDE);
   WDTCR = 0x00;    // 关闭WDT
   //#asm("sei") // 开启全局中断
}
/***********************************************************************
* 描述:LED Flicker 闪烁
* 参数:无
************************************************************************/
void led_flicker(uchar data)
{
   uchar i;
   for(i=0; i<data; i++){
       OCR0A = 0x00;
       delay_ms(20);
       OCR0A = pwmVal;
       delay_ms(20);
    }
}
/***********************************************************************
* 描述:LED ON 开灯
* 参数:无
***********************************************************************/
void led_on(void)
{
   uchar i;
   
   TCCR0A = PWM_ON; //开启PWM
   for (i=0; i<pwmVal; i++)
    {
       OCR0A = i; //更改占空比
       delay_us(500);
    }
   
   //全亮时候 PWM Off
   if (pwmVal >= MAX_VAL)
    {
       TCCR0A = PWM_OFF;
       LEDDRV = LED_ON;
    }
   WDT_on();  //启动看门狗
}
/***********************************************************************
* 描述:LED OFF 关灯
* 参数:无
************************************************************************/
void led_off(void)
{
   uchar i;
   
   TCCR0A = PWM_ON; //开启PWM
   for (i=pwmVal; i>0; i--)
    {
       OCR0A = i; //更改占空比
       delay_us(500);
    }
   TCCR0A = PWM_OFF; //关闭PWM
   LEDDRV = LED_OFF;
}
/***********************************************************************
* 描述:LED 亮度增加
* 参数:无
***********************************************************************/
void led_zeng(void)
{
   TCCR0A = PWM_ON; //开启PWM
   for (; pwmVal<MAX_VAL && KEY==KEY_DOWN; pwmVal++)
    {
       OCR0A = pwmVal; //更改占空比
       delay_ms(2);
    }
   if(pwmVal>=MAX_VAL)
       led_flicker(3);
}
/***********************************************************************
* 描述:LED 亮度减少
* 参数:无
************************************************************************/
void led_jian(void)
{
   TCCR0A = PWM_ON; //开启PWM
   for (; pwmVal>MIN_VAL && KEY==KEY_DOWN; pwmVal--)
    {
       OCR0A = pwmVal; //更改占空比
       delay_ms(2);
    }
   if(pwmVal <= MIN_VAL)
       led_flicker(3);
}
/**********************************************************************
* 描述 :定时器中断服务函数
* 输入 :无
***********************************************************************/
/*interrupt[TIM0_OVF] voidtimer0_ovf_isr(void)
{
}*/
/**********************************************************************
* 名称 : 外部中断INT0服务程序
* 功能 :
* 输入 :无
* 输出 :无
***********************************************************************/
/*interrupt [EXT_INT0] void int0_isr(void)
{
}*/
/**********************************************************************
* 名称 : 中断PC_INT0服务程序
* 功能 :
* 输入 :无
* 输出 :无
***********************************************************************/
interrupt [PC_INT0] void pc_int0_isr(void)
{
   if (KEY==KEY_DOWN)      //判断是否按下键,KEY接地
       {
           delay_ms(5);    //防抖延时
           for (keytime=0; (KEY==KEY_DOWN) && keytime<LONG_KEY;keytime++)
           {
                keytime++;
                delay_ms(50);   // 50ms
           }
           
           //长按逻辑处理
           while (keytime > LONG_KEY && KEY==KEY_DOWN && status== 1)  //长按逻辑处理
           {
                //#asm("WDR")     //喂狗
                if (pwmVal >= MAX_VAL)
                    fangxiang = 1;
                if (pwmVal <= MIN_VAL)
                    fangxiang = 0;
                    
                if (fangxiang == 0)
                    led_zeng();
                else
                    led_jian();
                fangxiang = ~fangxiang;
               
                delay_us(10);
                eeprom_write(ADDRESS,pwmVal);      //eeprom里的数据
                delay_us(100);
               
                //全亮时候 PWM Off
                if (pwmVal >= MAX_VAL)
                {
                    TCCR0A = PWM_OFF;
                    LEDDRV = LED_ON;
                }
           }
           
           //短按逻辑处理
           if (keytime > 0 &&keytime <= LONG_KEY) //短按逻辑处理
           {
                if (status == 0)    // LED NO
                    led_on();       //开灯
                else if (status == 1)   // LED OFF
                    led_off();          //关灯
               status = ~status;
           }
       }
}
/**********************************************************************
* 名称 : Main()
* 功能 : 主函数
* 输入 :无
* 输出 :无
***********************************************************************/
void main(void)
{
   // Crystal Oscillator division factor: 8
   #pragma optsize-
   CLKPR=0x80;
   CLKPR=0x03;
   #ifdef _OPTIMIZE_SIZE_
   #pragma optsize+
   #endif
   
   // I/O端口的初始化
   DDRB = 0x01;    // PB.1输入,PB.0输出
   PORTB = 0x05;   // PB.1上拉电阻,PB.0高电平
   //PWM 初始化(TCCR0A=0xC3; 占空比相反时TCCR0A = 0x83 0<<COM0A0
   //TCCR0A |=(1<<COM0A1)|(0<<COM0A0)|(1<<WGM01)|(1<<WGM00);
   TCCR0A = PWM_ON;    //开启PWM
   TCCR0B |=(0<<WGM02)|(0<<CS02)|(1<<CS01)|(0<<CS00);         //8分频(4.6875KHz
   OCR0A = 0x00;
    TCNT0 = 0x00;       // T/C0计数寄存器初值
   TCCR0A = PWM_OFF;   // 关闭PWM
   
   // 外部中断初始化设置
   //MCUCR |= (1<<ISC01) | (0<<ISC00);    // INT0 为下降沿时产生中断请求
   //GIMSK |= (1<<INT0);   // 允许 INT0 产生中断
   GIMSK |= (1<<PCIE);     // 允许 PCINT0 产生中断
   PCMSK |= (1<<PCINT2);   //引脚变化使能 -PB.2(7引脚)
   
   // 读取eeprom中的亮度档位数据
   pwmVal = eeprom_read(ADDRESS);     //读取eeprom里的数据
   delay_us(100);   //延时10us
   if (pwmVal<MIN_VAL || pwmVal >=MAX_VAL) //eeprom无数据的话设为最高档位
       pwmVal = MAX_VAL;
    if (pwmVal >= MAX_VAL)
       fangxiang = 1;      //亮度减
   else
       fangxiang = 0;      //亮度增
   // 睡眠模式初始化
   MCUCR|=(1<<SM1)|(0<<SM0);       // 掉电模式
   MCUCR|=(1<<SE);                // 休眠使能
   #asm("sei")                    // 打开全局中断
   
   #asm ("sleep")  //睡眠
   #asm("NOP");
         
   while(1)
    {
       #asm("WDR")     //喂狗
      
       if (status == 0)    //关机的话睡眠
       {
           TCCR0A = PWM_OFF;   //关闭PWM
           WDT_off();          // 关闭WDT(关闭看门狗)
           #asm ("sleep")
           #asm("NOP");
       }
       delay_ms(10);
   }//while
}

评分

4

查看全部评分

回复 dsu_marcocopyright:copyright

使用道具 举报

  • TA的每日心情
    开心
    2014-9-10 09:45
  • 签到天数: 146 天

    [LV.7]常住居民III

    发表于 2016-4-7 18:30 | 显示全部楼层
    不错的技术贴,以后买单片机带7135驱动,还可以调程序玩玩。还有的调光是无频闪的像东城LD25,无频闪无级调光程序好像是不好做。

    点评

    无极调光原理是很简单的,参考某些电脑主板的2.5V转1.2V供电电路,某些pc电源的3.3V产出也是类似电路(不是有电感的那些dc-dc),其实电路结构就是运放输出控制MOS,运放的反向输入是接输出反馈,同向输入是单片机PW  详情 回复 发表于 2016-4-8 19:29
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2014-5-15 21:40
  • 签到天数: 10 天

    [LV.3]偶尔看看II

    发表于 2016-4-8 19:29 | 显示全部楼层
    本帖最后由 xiaozhuxia2010 于 2016-4-9 08:55 编辑
    whseen 发表于 2016-4-7 18:30
    不错的技术贴,以后买单片机带7135驱动,还可以调程序玩玩。还有的调光是无频闪的像东城LD25,无频闪无级调 ...

    无极调光原理是很简单的,参考某些电脑主板的2.5V转1.2V供电电路,某些pc电源的3.3V产出也是类似电路(不是有电感的那些dc-dc),其实电路结构就是运放输出控制MOS,运放的反向输入是接输出反馈,同向输入是单片机PWM滤波后的可变的基准(用来调光)电压,说错了,是无频闪调光
    无标题.jpg
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2018-4-29 14:15
  • 签到天数: 47 天

    [LV.5]常住居民I

    发表于 2016-4-9 23:28 | 显示全部楼层
    学习了,谢谢楼主
    来自苹果客户端来自苹果客户端
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2023-1-31 01:04
  • 签到天数: 1027 天

    [LV.10]以坛为家III

    发表于 2016-4-10 08:43 | 显示全部楼层
    最想要无级无频闪驱动……
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2016-4-11 16:53 | 显示全部楼层
    两年前的五档调光程序链接:http://wenku.baidu.com/view/f20903a503d8ce2f01662322
    百度文库的无级调光程序链接:http://wenku.baidu.com/view/091dd5d34431b90d6c85c7cf
    回复

    使用道具 举报

    头像被屏蔽

    该用户从未签到

    发表于 2016-4-20 12:25 | 显示全部楼层
    提示: 作者被禁止或删除 内容自动屏蔽
    回复

    使用道具 举报

    该用户从未签到

     楼主| 发表于 2016-4-22 21:09 | 显示全部楼层
    100cn 发表于 2016-4-20 12:25
    能给我一份ATTINY13A+7135的手电HEX文件吗?,谢谢了。

    发邮件了, 注意该7135电路是按钮接在第二脚和VCC之间。
    测试电路也发过去了。
    回复

    使用道具 举报

    头像被屏蔽
  • TA的每日心情
    开心
    2014-11-27 09:43
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2016-4-23 19:06 | 显示全部楼层
    提示: 作者被禁止或删除 内容自动屏蔽
    回复

    使用道具 举报

    本版积分规则

    小黑屋|手机版|Archiver|论坛自带搜索|下载论坛app|手电大家谈-手电筒爱好者之家 ( 备案序号:鲁ICP备05002565号 )
    以上言论纯属个人观点,与手电大家谈立场无关。
    最佳浏览模式:1920*1080


    GMT+8, 2024-10-8 20:36 , Processed in 0.225471 second(s), 45 queries , Gzip On.

    Powered by Discuz! X3.4

    © 2001-2023 Discuz! Team.

    快速回复 返回顶部 返回列表