Простая велофара под управлением ATtiny13A

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

если я правильно понял стабилизировать ток вы не будете? или все таки будете? по коду вы что то измеряете и от этого зависит яркость. что измеряете?

сам давно собирался сделать драйвер

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

jeka_tm пишет:

если я правильно понял стабилизировать ток вы не будете? или все таки будете? по коду вы что то измеряете и от этого зависит яркость. что измеряете?

сам давно собирался сделать драйвер

Нет, стабилизировать ничего небуду, в моем случае ток будет падать прямо пропорционально что на входе что на выходе.

Есть подстроечник, который задаёт максимальное значение для ШИМ, тоесть изменяет макс. напряжение и следовательно макс. ток, ведь закон Ома никто не отменял, ну и потом от этого значения уже подсчитывает 75/50/25/0% Гг да 0% тоесть потребление около 5мА, может будет кому и полезно. Стробоскоп вырезал, он меня бесит, да и лишние прерывания... да ну. КПД моей реализации контроллера для светодиода зависит только от транзистора, ток который кушает тинька не в счёт ну 0.21 Вт это разве мощность?

Итак, как работает, если быстро нажать и отпустить кнопку то уровень уменьшится, если же зажать то растёт каждых 2 - 3 сек.  ну и само собой запоминание последнего перед выключением питания режима.

Оптимизировал немного код:





#include <EEPROM.h>
byte level = 0, light = 0;

void setup() {
  pinMode(0, OUTPUT); // светодиод
  pinMode(3, INPUT); // кнопка для смены режимов, пока на 3 пине
  delay(200); // на всякий случай
  level = EEPROM.read(0);
  digitalWrite(3, HIGH); // подтяну программно резистор
}

void loop() {
  if (digitalRead(3) == LOW) { // если кнопка нажата
    byte time = 0;
    //delay(50); // защита от случайных нажатий и дребезга
    while(digitalRead(3) == LOW) { // считаем сколько мс нажата
      time +=25;
      delay(25);
      if (time == 250) {
        break; // принудительно выходим из цикла
      }  
    }

    if (time <= 100) { // если меньше секунды то увеличиваем реж.
      level++;
      if(level >= 5){ // нечего записывать то что не используем
        level = 4; // ведь есть 4 режима
      }

    }  
    if (time == 250) { // если держать больше 2.5 секунды то уменьшаем реж.
      level--;
      if(level >= 5){ // если от 0 отнять 1 будет 255
        level = 0; // чтобы не было 255 запишем 0
        delay(500);  
      }
    }
    EEPROM.write(0, level); // запишем режим
  }

  // режыми

  if(level == 0){  // 100%
    light = 4; 
  }

  if(level == 1){ //  75%
    light = 6; 
  }

  if(level == 2){ // 50%
    light = 8; 
  }

  if(level == 3){ // 25%
    light = 16;
  }

  if(level == 4){  // 0%
    analogWrite(0, 0); 
  }
  else{
    analogWrite(0, (analogRead(A2) / light));
  }
}

 

Размер скетча в двоичном коде: 812 байт (из 1 024 байт максимум) пока место есть не буду уходить от отличной наглядности  функций Arduino.

Обнаружил баг, который не могу никак исправить, при повышении мощности(level++) если дождаться момента именно когда только только уровень вырастает на 1 и резко отпустить кнопку то уровень уменьшится(level--) хотя должен бы остаться... Чёт мозги уже не варят или что? Причём целый день.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

понятно. значит это не драйвер а просто регулятор

если есть регулятор для шим зачем кнопка? можно же просто регулятором яркость изменять, хотя регулятор похоже толкьо для подстройки

глянул в инете несколько схем драйверов на тиньке. со стабилизацией тока люди не заморачиваются. такие же регуляторы как у вас. может и действительно забить

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Кнопка для переключения режымов яркости, это же велофара, поставлю около переключателя для удобства.

у меня по сути работает как с токоограничивающим резистором, только с большим КПД.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

HWman пишет:

Кнопка для переключения режымов яркости, это же велофара, поставлю около переключателя для удобства.

у меня по сути работает как с токоограничивающим резистором, только с большим КПД.

ну да. я это и имел в виду

вы кстати не знаете как запусть ацп тиньки на внутреннем опорнике?

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Тут пишут что есть проблемы, говорят что с следующей версией должны исправить.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

автор пишет что работает, но есть проблемы

в wiring_analog есть функция analogReference

/*
**** Core13 ***
Arduino core designed for Attiny13 and similar devices.
NO WARRANTEE OR GUARANTEES!
Written by John "smeezekitty" 
You are free to use, redistribute and modify at will EXCEPT IF MARKED OTHERWISE IN A PARTICULAR SOURCE FILE!
Version 0.18
*/
#include "wiring_private.h"
//#include "pins_arduino.h"
void analogReference(uint8_t mode){
   if(mode==INTERNAL)
      ADMUX |= _BV(REFS0);
   else
      ADMUX &= ~_BV(REFS0);
}

но все равно ругается

sketch_oct15a.ino: In function 'void setup()':
sketch_oct15a:5: error: 'analogReference' was not declared in this scope

 

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

А данная  функция использует источник опорного напряжения для АЦП для всех портов или же для какого-то конкретного?

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

скорее всего для всех. только на тиньке не работает или я что то неправильно делаю.

придется на си писать

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Было бы неплохо посмотреть, может мне пригодится.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Нашёл неплохую инфрмацию по AnalogReference(), на сколько я понял для того чтобы считать значение АЦП и сравнять его с внутренним источником 1.1 В:



analogReference(INTERNAL);
analogRead(порт); 

analogReference(DEFAULT);

Ну а дальше по старинке сравниваем с напряжением питания... Вроде так.

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

я видел эту статью. может и правда нужно так делать. хотя где логика. если захочу постоянно на внутреем опорнике измерять зачем переключаться. думаю так же ругаться будет на analogReference

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Итак, баг исправлен, код занимает  836 байт, вот он:



#include <EEPROM.h>
byte level = 0, light = 0;

void setup() {
  pinMode(0, OUTPUT); // светодиод
  pinMode(3, INPUT); // кнопка для смены режимов, пока на 3 пине
  delay(200); // на всякий случай
  level = EEPROM.read(0); // считаем значение из EEPROM
  digitalWrite(3, HIGH); // подтяну программно резистор
}

void loop() {
  if (digitalRead(3) == LOW) { // когда нажимаем на кнопку
    unsigned int time = 0; 
    delay(25); // защита от случайных нажатий и дребезга тактовой кнопки
    while(digitalRead(3) == LOW) { // подсчитаем сколько мс нажата
      time +=1;
      delay(1);
      if (time == 2000) { // если больше 2 сек
        break; // принудительно выходим из цикла
      }  
    }

    if (time == 2000 && digitalRead(3) == LOW) { // если больше 2 сек. и ещё нажата то уменьшаем реж.
      level--;
      if(level >= 5){ // если от 0 отнять 1 будет 65535
        level = 0; // чтобы этого не было запишем 0
      }
      //delay(500);
    }

    if (time <= 165 && time >= 50){ // если просто клацнули то увеличиваем реж.
      level++;
      if(level >= 5){ // нечего записывать то что не используем
        level = 4; // ведь есть 4 режима
      }
      //delay(500);
    }  

    EEPROM.write(0, level); // запишем режим в EEPROM
  }

  // режимы

  if(level == 0){  // 100%
    light = 4; 
  }

  if(level == 1){ //  75%
    light = 6; 
  }

  if(level == 2){ // 50%
    light = 8; 
  }

  if(level == 3){ // 25%
    light = 16;
  }

  if(level == 4){  // 0%
    analogWrite(0, 0); 
  }
  else{
    analogWrite(0, (analogRead(A2) / light));
  }
}

Вроде бы как все работает, видео:

http://www.youtube.com/watch?v=Guv-4oeQrrg

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Сделал парочку фоток, расстояние до стены ~ 10 метров:

http://i4.imageban.ru/out/2013/10/30/6ccea299ed8ab78293870cbbf2a19fba.jpg

Режим 100%

http://i2.imageban.ru/out/2013/10/30/469b2095a6cb07e5bd8d0eec635b137b.jpg

Режим 75%

http://i1.imageban.ru/out/2013/10/30/36fd3ac32552390dd521ca8486b8cb74.jpg

Режим 25%
В реале выглядит ярче но увы фотик отстойный,
Фото режима 50% вышло очень размытое, выгружать нету особого смысла, а перефоткать не получится.
Вот парочка видео:

http://www.youtube.com/watch?v=AgNt7LKDlq8

http://www.youtube.com/watch?v=x7sHIU-Nllc

Название их говорит само за себя.
Пока уменьшаю схемку дабы её засунуть в фонарик:

http://i2.imageban.ru/out/2013/10/30/eaa297a0a63b385cef43d9601b7d9cef.jpg

На всё, кстати, потратил меньше 40 грн + 10 грн АКБ от старого ноута, банки оказались вполне исправными и имеют ещё как минимум половину емкости, тоесть как минимум больше 1000 мА/ч на штуку.

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

Добавлю свои 5 капель

Идея драйвера хорошая, но мне хотелось чтобы автоматически поддерживался заданный ток при изменении питания. поэтому сделал по своему

На данный момент протестировал в протеусе. в железе еще не тестировал. пока только заданный ток, без режимов яркости

в левом верхнем углу стоит кнопка. при нажатии сопротивление нагрузки падает в 2 раза, соответтсвенно напряжение должно тоже упасть в 2 раза для сохранения заданного того. для этого стоит вольтметр

обращать внимание на кнопку, вольтметр слева и вольтметр внизу ну и конечно осциллограф (ширину шим, сигналы инвертированы)

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

А меряешь напряжение обычно или при помощи источника опорного напряжения? Для 8-й меги оно вроде 2.5 В.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Вот кстати всё что насобиралось со временем, код, прошивка, фюзы, ещё что-то...

http://hwman.ho.ua/files/Bicycle_lights/

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

HWman пишет:

А меряешь напряжение обычно или при помощи источника опорного напряжения? Для 8-й меги оно вроде 2.5 В.

и питание в качестве опорника, и внутренний. в конце использовал внутренний. мегу применл для теста, чтобы не было проблем с памяться на этапе програмирования

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Добавил измерение напряжения питания:

Пока только в протеусе, пока стабилитрона нет, да и код ещё не писал, может вообще места не хватит.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Так тааак, пробую измерять напряжение от опорника 1.1 В, это исключит стабилитрон из схемы, будет достаточно простого резистивного делителя напряжения.

И ещё открыл для себя BODLEVEL фюзы, ну и собственно калькулятор фюзов, их применение мне позволит сделать защиту от глубокого разряда не увеличивая размер кода.

Кстати, давно хотел спросить, а что будет если измерять по опорнику и подать на порт больше 1.1 В ? если дать 5 В то будет кирдык?

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а фиг его знает. может и кирдык, а может будет не то значение, например так 5В-1,1В*4=0,6В, его уже измеряет. трудно сказать надо проверять или искать инфу

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Выставил фюзы чтобы тинька отключалась при напряжении в 2.7 В в файлике boards.txt, зашил и.... при напряжении 2.6 ещё работает, да и ниже тоже, что же не так?







attiny13.name=ATtiny13 @ 9.6MHz 2.7 off
attiny13.upload.using=arduino:arduinoisp
attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xfb
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=1200000
attiny13.build.core=core13

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

а что у вас за фигня с фьюзами? у вас стоит 7A что значит 9,6мгц без делителя и частота соответственно 9,6мгц, а в параметрах платы стоит 1,2мгц как будто делитель включен. поменяйте на 9600000 или low смените на 6A

и тогда уже проверяйте. хотя не должно быть связано. я не проверял честно сказать. по разным данным программа при напряжении ниже Bodlevel перезапустится и будет так постоянно перезапускаться, по другим она как бы встает на паузу. так что точно должно произойти я не понял

 

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Вот нашёл кое что об BODе.

Все файлы которые использую взяты отсюда, шю дуинкой..

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

это файлы на ядро, в них не нашел строки которые нужно прописать в boards.txt

вот на их сайте для 7A

attiny13.name=ATtiny13 (internal 9.6 MHz clock)
attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=9600000L
attiny13.build.core=arduino:arduino
attiny13.build.variant=tiny8

о чем я и говорил

а если 1.2 Мгц как у вас написано должно быть

attiny13.name=ATtiny13 (internal 9.6 MHz clock)
attiny13.bootloader.low_fuses=0x6a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=1200000L
attiny13.build.core=arduino:arduino
attiny13.build.variant=tiny8

вот фьюзы для разных частот

0x69 = 4.8MHz / 8 = 0.6MHz
0x6a = 9.6MHz / 8 = 1.2MHz
0x79 = 4.8MHz
0x7a = 9.6MHz

 

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Пробовал играться со фюзами и сложилось такое впечатление что при изменении фьюзов ничего не меняется, на разных скоростях камня ШИМ работает на частоте 4 кГц.

Ядро лежит C:\Users\Администратор\Documents\Arduino\hardware\attiny13

Вот содержымое файла boards.txt:




###########################################################################
attiny13int.name=Attiny13 @ 128 KHz (internal watchdog oscillator)
attiny13int.upload.using=arduino:arduinoisp
attiny13int.upload.maximum_size=1024
attiny13int.upload.speed=250 # important for not losing connection to a slow processor
attiny13int.bootloader.low_fuses=0x7B
attiny13int.bootloader.high_fuses=0xFF
attiny13int.bootloader.unlock_bits=0x3F
attiny13int.bootloader.lock_bits=0x3F
attiny13int.build.mcu=attiny13
attiny13int.build.f_cpu=128000
attiny13int.build.core=core13

###############################################################

attiny13at4.name=ATtiny13 @ 4.8MHz (internal 4.8 MHz clock)
attiny13at4.upload.using=arduino:arduinoisp
attiny13at4.bootloader.low_fuses=0x69
attiny13at4.bootloader.high_fuses=0xff
attiny13at4.upload.maximum_size=1024
attiny13at4.build.mcu=attiny13
attiny13at4.build.f_cpu=600000
attiny13at4.build.core=core13
###############################################################

attiny13.name=ATtiny13 @ 9.6MHz (interne 9.6 MHz clock)
attiny13.upload.using=arduino:arduinoisp
attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=1200000
attiny13.build.core=core13

###############################################################

 

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

у вас последняя неправильная

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

если прописать



attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=9600000L

то всё очень медлено

jeka_tm
jeka_tm аватар
Offline
Зарегистрирован: 19.05.2013

что медленно?

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

делей 1000 будет где-то 5 сек.

Кстати, МК при выставлении соответствующих фьюзов  напрочь отказывается отрубаться при напряжении 2.7 В. выжрал АКБ до 1.9 В. Как будто просто игнорирует их.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Разобрался с фюьзами, как выяснилось нужно было сначала записать загрузчик, кстати я перезалил файлы ядра тини13 при выборе 128 кГц тиньки "по уходили в себя"

Настроил BODLEVEL(9.6 MHz, BOD 2.7 V) теперь есть защита от глубокого разряда, так как перед тинькой, для защиты, стоит диод, то на нём падает  падает пару десятых вольта.

Видео работы:

https://www.youtube.com/watch?v=RB1OCoUqFeo

Код:

/*
ATtiny13 9.6  9.6 MHz, BOD 2.7 V
 Ядро для ардуино: http://hwman.ho.ua/files/ATtiny13A101/
 low_fuses=0x7A
 high_fuses=0xFB 
 */

#include <EEPROM.h>
byte level = 0, light = 0;

void setup() {
  pinMode(0, OUTPUT); // светодиод
  pinMode(3, INPUT); // кнопка для смены режимов, пока на 3 пине
  delay(500); // на всякий случай
  level = EEPROM.read(0); // считаем значение из еепром
  digitalWrite(3, HIGH); // подтяну программно резистор
}

void loop() {
  if (digitalRead(3) == LOW) { // когда нажимаем на кнопку
    unsigned int time = 0; 
    delay(25); // защита от случайных нажатий и дребезга тактовой кнопки
    while(digitalRead(3) == LOW) { // подсчитаем сколько мс нажата
      time +=1;
      delay(1);
      if (time == 2000) { // если больше 2 сек
        break; // принудительно выходим из цикла
      }  
    }

    if (time == 2000 && digitalRead(3) == LOW) { // если больше 2 сек. и ещё нажата то уменьшаем реж.
      level--;
      if(level >= 5){ // если от 0 отнять 1 будет 65535
        level = 0; // чтобы этого не было запишем 0
      }
      //delay(500);
    }

    if (time <= 165 && time >= 50){ // если просто клацнули то увеличиваем реж.
      level++;
      if(level >= 5){ // нечего записывать то что не используем
        level = 4; // ведь есть 4 режима
      }
      //delay(500);
    }  

    EEPROM.write(0, level); // запишем режим в еепром
  }

  // режимы

  if(level == 0){  // 100%
    light = 4; 
  }

  if(level == 1){ //  75%
    light = 6; 
  }

  if(level == 2){ // 50%
    light = 8; 
  }

  if(level == 3){ // 25%
    light = 16;
  }

  if(level == 4){  // 0%
    analogWrite1(0, 0);
  }
  else{
    analogWrite1(0, (analogRead(A2) / light));
  }
}

void analogWrite1(uint8_t pin, uint8_t val){ 
  pinMode(pin, OUTPUT); //For compatibility - STUPID! 
  if(val==0){ //Handle Off condition
    digitalWrite(pin,0);
  } 
  else if(val == 255){ //Handle On condition
    digitalWrite(pin, HIGH);
  } 
  else { //Otherwise setup the appropriate timer compare
    if(pin == 1){
      TCCR0A = 0x83; // рулим ШИМом
      TCCR0B = 0x02; // делитель N = 256

      /*
       TCCR0B = 0x05 (N = 1024), 9600000(9.6 МГц) / 1024 / 256 = 36.6 Гц
       TCCR0B = 0x04; (N = 256), 9600000 / 256 / 256 = 146 Гц
       TCCR0B = 0x03 (N = 64), 9600000 / 64 / 256 = 586 Гц
       TCCR0B = 0x02 (N = 8), 9600000 / 8 / 256 = 4688 Гц 
       TCCR0B = 0x01 (N = 1), 9600000 / 1 / 256 = 37500 Гц 
       */

      OCR0B = val;
    }
    if(pin == 0){
      TCCR0A = 0x83;
      TCCR0B = 0x02; // то же самое
      OCR0A = val;
    }
  }
}