【原创】基于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}
不错的技术贴,以后买单片机带7135驱动,还可以调程序玩玩。还有的调光是无频闪的像东城LD25,无频闪无级调光程序好像是不好做。 本帖最后由 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滤波后的可变的基准(用来调光)电压,说错了,是无频闪调光
学习了,谢谢楼主
最想要无级无频闪驱动…… 两年前的五档调光程序链接:http://wenku.baidu.com/view/f20903a503d8ce2f01662322
百度文库的无级调光程序链接:http://wenku.baidu.com/view/091dd5d34431b90d6c85c7cf 100cn 发表于 2016-4-20 12:25
能给我一份ATTINY13A+7135的手电HEX文件吗?,谢谢了。
发邮件了, 注意该7135电路是按钮接在第二脚和VCC之间。
测试电路也发过去了。
页:
[1]