Драйвер для кемпингового фонаря на ATTiny13A
|
|
| Сообщение # 1
|
34kilowatt
Постов: 75
ОК |
Всем доброго времени! Прошу помощи или направления для решения проблемы. Ситуfция такая - решил заменить драйвер светодиодного фонаря на неизвестном китайском МК, который ушел в мир иной на Тини13а. Набросал программку. На порту 0 и 1 сделал шим, 3 порт хочу сделать, как выход у управлять им полевиком, чтобы включать делитель напряжения в цепь АКБ и не жрать через него аккумулятор, когда фонарь не работает. На 4ом кнопка с внутренней подтяжкой. Порты нагружены светодиодами через резисторы 4.7к. Но столкнулся с проблемой - если включаю 3й порт, то все начинает глючить... Диоды на 0 и 3 порте или на 1 и 3м (если переключить кнопкой) начинают мигать с частотой герц 15-20 в пол накала. В протеусе тоже ситуация странная на выводах шим амплитуда всего чуть больше вольта, как закомментирую выделенные строки, все начинает работать нормально. Листинг АтмельСтудио:
Код #define F_CPU 9600000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> //#include <avr/sleep.h> // здесь описаны режимы сна
#define true 1 // логическое состояние правда #define false 0 // логическое состояние ложь
volatile uint16_t voltVal = 0; // переменная для накопления значений АЦП volatile uint8_t sss1 = 0; // счетчик значений АЦП volatile uint8_t sleep_MODE = true; // режим сна
uint8_t PWM_MODE[4] = {255, 0, 86, 172}; // режимы PWM (100%, 67%, 33%) uint8_t LedMode = false; // переключатель светодиодов
uint8_t butCount = 0; // счетчик времени нажатия uint8_t flgPress = false; // признак кнопка в нажатом состоянии uint8_t flgClick = false; // признак отпускания кнопки uint8_t switchLED = false; // признак переключения диодов uint8_t flgLngPress = false; // признак удержания кнопки uint8_t i = 0; // счетчик
void Set_PWM (void) {
switch (LedMode) { case 0: DDRB &= (0 << PINB1); DDRB |= (1 << PINB0); OCR0A = PWM_MODE[i]; OCR0B = PWM_MODE[0]; break;
case 1: DDRB &= (0 << PINB0); DDRB |= (1 << PINB1); OCR0A = PWM_MODE[0]; OCR0B = PWM_MODE[i]; break; }// end switch
}// end Set_PWM()
/* ISR(PCINT0_vect){
GIMSK=0x00; // Pin Change Interrupt выкл. PCMSK=0x00; // PCINT4 откл. if (sleep_MODE) sleep_MODE = false; DDRB |= (1 << PINB3); // порт 3 на выход (для подключения делителя) PORTB |= (1 << PINB3); // порт 3 высокий уровень
}// ISR(PCINT0_vect) */ /* ISR (ADC_vect){
voltVal += ADCW; sss1++;
if (sss1 > 10) { voltVal = voltVal / sss1; sss1 = 0; }// end if
if (voltVal < 690){ sleep_MODE = true; }// end if
}// end ISR (ADC_vect) */
int main(void){ /* ADMUX |= (1 << REFS0) | (0 << ADLAR) | (1 << MUX0); // внутреннее опорное напряжение, // левое ориентирование данных, выбран вход ADC1 ADCSRA = 0xEF; // АЦП включен, запуск преобразования, режим автоизмерения, // прерывание по окончанию преобразования, частота CLK/128 ADCSRB = 0x00; // режим автоизмерения: постоянно запущено DIDR0 |= (1 << PINB2); // запрещаем цифровой вход на ноге аналогового входа */
PORTB |= (1 << PINB4); // подтяжка кнопки порт 4, высокий на порт 3 (для включения делителя в цепь) //DDRB |= (1 << PINB3); // порт 3 на выход (для подключения делителя)
// Режим Fast PWM, частота сигнала=F_CPU / делитель*256 TCCR0A |= (1<<WGM00) | (1<<WGM01); // Режим Fast PWM, таймер считает до 255 и сбрасывается в 0 TCCR0A |= (1<<COM0A1) | (1<<COM0A0); // 0 при равенстве регистров TCNT0 и OCROA. 1 при переполнении (инвертированный ШИМ-сигнал) TCCR0A |= (1<<COM0B1) | (1<<COM0B0); // 1 при равенстве регистров TCNT0 и OCROB. 0 при переполнении (неинвертированный ШИМ-сигнал) TCCR0B |= (1<<CS01); // делитель 8 OCR0A = 255; // регистр сравнения (инвертированный сигнал ШИМ 255) OCR0B = 255; // регистр сравнения (инвертированный сигнал ШИМ 0)
//_delay_ms(50);
//asm("sei"); //разрешаем глобально прерывания
//set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную
while(1) {
if ((PINB & (1 << PINB4)) == 0 && !flgLngPress) { _delay_ms(10); // задержка (защита от дребезга) if ((PINB & (1 << PINB4)) == 0) { flgPress = true; // кнопка нажата (устанавливаем флаг в 1) butCount++; // начало отсчета нажатия кнопки if (butCount > 100){ flgLngPress = true; flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if }// end if }// end if
if ((PINB & (1 << PINB4)) && flgLngPress){ // если отпустили после длительного нажатия switchLED = false; flgLngPress = false; flgPress = false; // сбрасываем флаг нажатия flgClick = false; }// end if
if (flgPress && (PINB & (1 << PINB4))){ // отпустили кнопку flgClick = true; // устанавливаем флаг клика flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if
if (flgLngPress && !switchLED){ // было удержание кнопки LedMode++; // переключаем на другой светодиод if (LedMode > 1) LedMode = 0; i = 1; Set_PWM(); // устанавливаем режим светодиода switchLED = true; }// end if
if (flgClick){ // был клик flgClick = false; // сбрасываем флаг клика i++; // инкрементируем режим PWM if (i > 3) i = 0; // обнуляем счетчик Set_PWM(); // устанавливаем режим светодиода [b] if (i == 0){ sleep_MODE = true; // отладка //DDRB |= (1 << PINB3); // порт 3 на выход //PORTB |= (1 << PINB3); // высокий уровень }// end if else{ // отладка sleep_MODE = false; //PORTB &= (0 << PINB3); // низкий уровень //DDRB &= (0 << PINB3); // порт 3 на вход }// end else }// end if[/b]
/*if (sleep_MODE){
GIMSK=0x20; // Pin Change Interrupt Enable PCMSK=0x10; // PCINT4 set для возращения в нормальный режим из сна DDRB &= (0 << PINB3) | (0 << PINB1) | (0 << PINB0); // выключаем светодиоды, делитель PORTB = 0x00; // отключаем подтяжку и высокий уровень на всех портах sleep_enable(); // разрешаем сон sleep_cpu(); // спать!
}// end if*/
}// end while(1) }// end main
Схема Протеуса:
|
|
| Сообщение # 2
|
DarkRus66
Постов: 750
Друзья |
|
|
| Сообщение # 3
|
msmmmm
Постов: 891
Друзья |
34kilowatt, у тебя сброс правильно подключен?
|
|
| Сообщение # 4
|
34kilowatt
Постов: 75
ОК |
В том фонаре, в который пытаюсь сделать драйвер, установлены 2 светодиода, 3 Вт и COB (кемпинговый режим). Для первого светодиода 2 режима яркости + стробоскоп, у второго - только 1 режим, затем фонарь выключается. При этом потребляет 3мА - что, как мне кажется, много. Ко всему этому отсутствует контроль разряда - фонарь будет высаживать АКБ вплоть до 1.5В, пока не отключится МК (по распиновке похож на 12F679, но китайцы затерли название). Меня не устраивали режимы работы (сторобоскоп), и то что еще нужно заряжать каждые 1-1.5 месяца, чтобы АКБ не умерли. Плюс ко всему драйвер стал глючить, то не включается, то не выключается. Вот и решил сделать на тиньке, т.к. ее функционала, по идее, должно хватить: 2 канала шим, 1 АЦП - отслеживание напряжения, 1 кнопка на несколько режимов, плюс при переключении переход в режим Power Down (для экономии АКБ). Выход из него по нажатию кнопки. Но сейчас стоит вопрос, не в схеме фонаря, а в правильной работе самой тинки (прошивки). Если у меня включены только 2 канада шим, кнопка, а остальные выходы на вход - то все работает как нужно. Но если устанавливаю 3-й порт на выход и включаю высокий уровень, начинает все глючить - диод на канале ШИМ мигает по переменно с диодом на 3 порте, переключая на другой канал ШИМ, тоже самое, только начинает мигать другой диод канала ШИМ. Резет подключен на питание через резистор 10к, светодиоды через 4.7к, кнопка подтянута внутренним резистором.
|
|
| Сообщение # 5
|
msmmmm
Постов: 891
Друзья |
Тщательно не смотрел, но что-то мне подсказывает, что эти команды делают совсем не то, что задумывалось :
PORTB &= (0 << PINB3); // низкий уровень DDRB &= (0 << PINB3); // порт 3 на вход
|
|
| Сообщение # 6
|
34kilowatt
Постов: 75
ОК |
Здесь все нормально - сброс битов порта регистра в 0. Ошибку нашел "дело было не в бобине" (не включил порты 0 и 1 после выключения), в протеусе заработало. Но в железе все равно нормально не работает. Разбираюсь дальше. Видимо еще кнопку к минусу подтягивать придется...
|
|
| Сообщение # 7
|
msmmmm
Постов: 891
Друзья |
Цитата 34kilowatt ( ) Здесь все нормально Ну, пусть будет "нормально" , в описании функции Set_PWM тот же косяк. Если нужно сбросить весь регистр, достаточно написать PORTB = 0 ; А если нужно сбросить 1 бит, то: DDRB &=~ (1 << PINB3); // порт 3 на вход,
|
|
| Сообщение # 8
|
34kilowatt
Постов: 75
ОК |
Да, все верно, написание сброса бита(ов) именно так и должно выглядеть. После ардуины (хотя и она в процессе изучения), бывает... Да прошивки не так часто пишу, забывается... Поправил, теперь пытаюсь в сон загнать, в протеусе работает, в железе не просыпается.
|
|
| Сообщение # 9
|
msmmmm
Постов: 891
Друзья |
34kilowatt, могу посмотреть, но нужна последняя версия исходника. С месяц назад делал жене измеритель влажности для цветов на тини13 с питанием от литиевого элемента - потребление в режиме сна - меньше 0,1мкА. Пока не забыл, может подскажу чего-нибудь. Хотя ковыряться в чужой программе - быстрее и проще свою написать .
|
|
| Сообщение # 10
|
nolpofaze
Постов: 442
Друзья |
34kilowatt, из сна, в железе и не должен выходить мк, в шпроте может выйти, у Вас подтяжка на инт4, там где кнопка, выключена в режиме сна. Вопрос, как мк отследить изменение уровня сигнала, при нажатии кнопки? Только, когда словит помеху.
|
|