zsjin 发表于 2016-4-7 15:43

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

基于ATtiny13的无级调光头灯程序     市面上的头灯一般有强光、弱光、爆闪三个挡位,一个按钮来控制开/关和换挡,顺序是:开(强光)-〉弱光->闪烁->关,每次开/关灯需要按三次,非常不方便。        两年前改造的五挡调光头灯一直用的很好,操作简便又人性化。近来比较空闲,突发DIY一个有无级调光功能的头灯想法。于是在网上搜索合适DIY的头灯,搜索原则是散热性能好、能变焦、尽量是装两节18650电池的灯。本人喜欢变焦灯,因为照射范围可调又均匀。第一次购买的灯完全失败,散热极差,为了节省成本居然灯头的重要部件用的是硬塑料,直接丢掉。第二次买的还好,惊喜的是他的控制芯片用的是CX2812,它的引脚与ATTiny13单片机类似,替换控制芯片,稍微改动电路板的布线就可以利用原配的控制板,避免了从头开始做控制板,省去了最繁琐的印刷电路板的制作了。 通过ATtiny13a单片机的编程实现了一下功能:1、按一次开灯,再按一次就关灯,解决了按三次关灯的不方便的问题。2、开关灯保留了逐步亮和逐步暗的功能,此功能非常人性化,本人很喜欢。具体实现如下:开灯的时候PWM信号的占空比从0开始逐步加到设定的亮度,关灯时候占空比逐步减到0。3、无级调光:在灯亮状态下按住按钮,LED灯亮度增加或减少,亮度达到100%或10%时闪烁三次来提醒亮度已经达到了全亮或最暗,松开按钮就停止调光,一直按住就循环调光。 程序中利用了ATtiny13a的PWM、外部中断(PCINT0)、睡眠、看门狗和EEPROM的读写功能,基本上每一行都加了注释,对于初次接触ATtiny13的人来说应该有帮助。 图片1:头灯                              
图片2:头灯控制板(此控制板网上也有卖的) 图片3:程序调试电路图 图片4:用面包板搭建程序调试电路 图片5:基于ATTiny13A的控制板电路图 图片6:修改后的ATTiny13A控制板 图片7:18650电池下的待机电流为0.26uA。
程序编辑和编译工具用了CodeVisionAVR 2.04.4a,烧写工具用了progisp1.72。
需要工程文件的请本人百度消息联系我(百度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 uintunsigned int#define KEY    PINB.2//tiny13第7脚,PCINT0中断#define LEDDRV PORTB.0//tiny13第5脚#define KEY_DOWN 0      //按下按键#define LED_ON0      //LED 亮#define LED_OFF 1       //LED 灭#define PWM_ON0xc3   //PWM 启动#define PWM_OFF 0x03    //PWM 关闭#define MIN_VAL 0x1a    //最小亮度#define MAX_VAL 0xff    //最大亮度#define LONG_KEY3    //长按键的时间#define ADDRESS 0x01    //保存挡位的地址 uchar pwmVal = 0;   //亮度值uint keytime = 0;   //按键时间bit status = 0;   //0为LED ON,1为LED OFFbit 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 voidtimer0_ovf_isr(void){}*/ /*********************************************************************** 名称 : 外部中断INT0服务程序* 功能 : * 输入 :无* 输出 :无***********************************************************************//*interrupt void int0_isr(void){}*/ /*********************************************************************** 名称 : 中断PC_INT0服务程序* 功能 : * 输入 :无* 输出 :无***********************************************************************/interrupt 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}

whseen 发表于 2016-4-7 18:30

不错的技术贴,以后买单片机带7135驱动,还可以调程序玩玩。还有的调光是无频闪的像东城LD25,无频闪无级调光程序好像是不好做。

xiaozhuxia2010 发表于 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滤波后的可变的基准(用来调光)电压,说错了,是无频闪调光

yqjyy 发表于 2016-4-9 23:28

学习了,谢谢楼主

wuyinglang 发表于 2016-4-10 08:43

最想要无级无频闪驱动……

zsjin 发表于 2016-4-11 16:53

两年前的五档调光程序链接:http://wenku.baidu.com/view/f20903a503d8ce2f01662322
百度文库的无级调光程序链接:http://wenku.baidu.com/view/091dd5d34431b90d6c85c7cf

100cn 发表于 2016-4-20 12:25

zsjin 发表于 2016-4-22 21:09

100cn 发表于 2016-4-20 12:25
能给我一份ATTINY13A+7135的手电HEX文件吗?,谢谢了。

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

lovepcgame 发表于 2016-4-23 19:06

页: [1]
查看完整版本: 【原创】基于ATtiny13的无级调光头灯程序