Драйвер для кемпингового фонаря на ATTiny13A
|
|
| Сообщение # 21
|
msmmmm
Постов: 891
Друзья |
Вы прикалываетесь, какой ISC01- это же настройка INT0, у него вход на РВ1 (6 нога). Настраивай Цитата 34kilowatt ( ) GIMSK |= (1 << INT0); // Включаем прерывания по по кнопке GIMSK |= (1 << PCIE);
|
|
| Сообщение # 22
|
34kilowatt
Постов: 75
ОК |
Да, вроде даташит еще раз почитал, стало понятнее немного, INT0 вообще не нужен. Тогда какой вектор использовать в обработчике? P.S. PCINT0_vect - все заработало, правда пока в протеусе... Еще раз спасибо всем за помощь!
Код #define F_CPU 9600000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h>
#define true 1 // логическое состояние правда #define false 0 // логическое состояние ложь
volatile uint16_t voltVal = 0; // переменная для накопления значений АЦП volatile uint8_t sss1 = 0; // счетчик значений АЦП volatile uint8_t sleep_MODE = true; // режим сна volatile uint8_t flgClick = false; // признак клика
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 switchLED = false; // признак переключения диодов uint8_t flgLngPress = false; // признак удержания кнопки uint8_t i = 0; // счетчик
void Set_PWM (void) { switch (LedMode) { case 0: DDRB &= ~(1 << PB1); DDRB |= (1 << PB0); OCR0A = PWM_MODE[i]; OCR0B = PWM_MODE[0]; break; case 1: DDRB &= ~(1 << PB0); DDRB |= (1 << PB1); OCR0A = PWM_MODE[0]; OCR0B = PWM_MODE[i]; break; }// end switch }// end Set_PWM()
ISR(PCINT0_vect){ GIMSK &= ~(1 << PCIE); // включаем прерывания по кнопке PCMSK = 0x00; // PCINT4 откл. if (sleep_MODE) sleep_MODE = false; // отключаем флаг перехода в спящий режим DDRB |= (1 << PB3) | (1 << PB1) | (1 << PB0); // порты на выход PORTB |= (1 << PB3); // порт 3 высокий уровень }// ISR(INT0_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){ DDRB |= (1 << PB3) | (1 << PB1) | (1 << PB0); // порты 0, 1, 3 на выход PORTB |= (1 << PB3); _delay_ms(300); // отладка /* ADMUX |= (1 << REFS0) | (0 << ADLAR) | (1 << MUX0); // внутреннее опорное напряжение, // левое ориентирование данных, выбран вход ADC1 ADCSRA = 0xEF; // АЦП включен, запуск преобразования, режим автоизмерения, // прерывание по окончанию преобразования, частота CLK/128 ADCSRB = 0x00; // режим автоизмерения: постоянно запущено DIDR0 |= (1 << PINB2); // запрещаем цифровой вход на ноге аналогового входа */ // Режим 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; // регистр сравнения (инвертированный сигнал ШИМ 0) OCR0B = 255; // регистр сравнения (инвертированный сигнал ШИМ 0) // настройка режима сна (sleep.h) //set_sleep_mode(SLEEP_MODE_PWR_DOWN); // если спать - то на полную // настройка режима сна MCUCR |= (1 << SM1) | (1 << ISC01); // power-down mode, прерывание по изменению MCUCR &= ~(1 << SM0); // power-down mode //MCUCR |= (1 << SE); // режим сна включен sei(); //разрешаем глобально прерывания while(1) { if ((PINB & (1 << PB4)) && !flgLngPress) { sleep_MODE = false; _delay_ms(10); // задержка (защита от дребезга) while (PINB & (1 << PB4)) { butCount++; // начало отсчета нажатия кнопки _delay_ms(10); if (butCount > 200) break; // выходим после 2 сек в любом случае (время повтора) }// end while if (butCount >= 50){ // ~1 сек flgLngPress = true; flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if else flgPress = true; // клик }// end if if (flgLngPress && (PINB & (1 << PB4)) == 0){ // если отпустили после длительного нажатия switchLED = false; flgLngPress = false; flgPress = false; // сбрасываем флаг нажатия flgClick = false; }// end if if (flgPress && (PINB & (1 << PB4)) == 0){ // отпустили кнопку flgClick = true; // устанавливаем флаг клика flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if if (flgLngPress && !switchLED){ // было удержание кнопки LedMode = !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(); // устанавливаем режим светодиода if (i == 0){sleep_MODE = true;}// end if else{sleep_MODE = false;}// end else }// end if if (sleep_MODE){ PORTB &= ~(1 << PB3); _delay_ms(50); // отладка PORTB |= (1 << PB3); _delay_ms(50); // отладка PORTB &= ~(1 << PB3); _delay_ms(50); // отладка PORTB |= (1 << PB3); _delay_ms(50); // отладка PORTB &= ~(1 << PB3); GIMSK |= (1 << PCIE); // включаем прерывания по кнопке PCMSK |= (1 << PCINT4); // PCINT4 для возращения в нормальный режим из сна DDRB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0)); // выключаем светодиоды PORTB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0)); // отключаем высокий уровень на портах _delay_ms(100); // отладка MCUCR |= (1 << SE); // режим сна включен asm("sleep"); }// end if }// end while(1) }// end main
Дальше буду крутить АЦП для контроля напряжения на АКБ.
|
|
| Сообщение # 23
|
msmmmm
Постов: 891
Друзья |
Вектор как раз выбран правильно - PCINT0_vect. И обработчик для него написан.
|
|
| Сообщение # 24
|
nolpofaze
Постов: 442
Друзья |
34kilowatt, вектор выбран верный (PCINT0_vect)
|
|
| Сообщение # 25
|
msmmmm
Постов: 891
Друзья |
Цитата 34kilowatt ( ) Дальше буду крутить АЦП для контроля напряжения на АКБ. АЦП перед входом в сон нужно отключать, иначе будет немного отъедать лишнего. И нужно проследить отключен ли компаратор. Если нет, отключить.
|
|
| Сообщение # 26
|
34kilowatt
Постов: 75
ОК |
Вроде все работает в протеусе, буду в железе проверять. Всем спасибо!
Код #define F_CPU 9600000UL #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h>
#define true 1 // логическое состояние правда #define false 0 // логическое состояние ложь
volatile uint16_t voltVal = 0; // переменная для накопления значений АЦП volatile uint8_t sss1 = 0; // счетчик значений АЦП
volatile uint8_t sleep_MODE = true; // режим сна volatile uint8_t lowBat = false; // батарея разряжена volatile uint8_t flgClick = false; // признак клика
uint8_t PWM_MODE[4] = {255, 0, 86, 172}; // режимы PWM (100%, 67%, 33%) uint8_t butCount = 0; // счетчик времени нажатия uint8_t i = 0; // счетчик
uint8_t flgPress = false; // признак кнопка в нажатом состоянии uint8_t LedMode = false; // переключатель светодиодов uint8_t switchLED = false; // признак переключения диодов uint8_t flgLngPress = false; // признак удержания кнопки
void BlinkLed(){ PORTB &= ~(1 << PB3); _delay_ms(50); // отладка PORTB |= (1 << PB3); _delay_ms(50); // отладка PORTB &= ~(1 << PB3); _delay_ms(50); // отладка }// end BlinkLed()
void RunSleep(){ PRR |= (1 << PRADC); // выключаем АЦП GIMSK |= (1 << PCIE); // включаем прерывания по кнопке PCMSK |= (1 << PCINT4); // PCINT4 для возращения в нормальный режим из сна DDRB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0)); // выключаем светодиоды PORTB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0)); // отключаем высокий уровень на портах _delay_ms(10); MCUCR |= (1 << SE); // режим сна включен asm("sleep"); }// end RunSleep()
void Set_PWM (void) { switch (LedMode) { case 0: DDRB &= ~(1 << PB1); DDRB |= (1 << PB0); OCR0A = PWM_MODE[i]; OCR0B = PWM_MODE[0]; break; case 1: DDRB &= ~(1 << PB0); DDRB |= (1 << PB1); OCR0A = PWM_MODE[0]; OCR0B = PWM_MODE[i]; break; }// end switch }// end Set_PWM()
ISR(PCINT0_vect){ PRR &= ~(1 << PRADC); // включаем АЦП GIMSK &= ~(1 << PCIE); // включаем прерывания по кнопке PCMSK = 0x00; // PCINT4 откл. if (sleep_MODE) sleep_MODE = false; // отключаем флаг перехода в спящий режим DDRB |= (1 << PB3) | (1 << PB1) | (1 << PB0); // порты на выход PORTB |= (1 << PB3); // порт 3 высокий уровень lowBat = false; }// ISR(INT0_vect)
ISR (ADC_vect){ uint16_t voltValTmp = 1024; voltVal += ADCW; sss1++; if (sss1 > 9) { voltValTmp = voltVal / (sss1); voltVal = 0; sss1 = 0; }// end if if (voltValTmp < 690) lowBat = true; // ~3V }// end ISR (ADC_vect)
int main(void){ DDRB |= (1 << PB3) | (1 << PB1) | (1 << PB0); // порты 0, 1, 3 на выход PORTB |= (1 << PB3); _delay_ms(300); // отладка ADMUX |= (1 << REFS0) | (1 << MUX0); // внутреннее опорное напряжение, выбран вход ADC1 ADCSRA |= (1 << ADEN) | (1 << ADSC) | (1 << ADATE) // АЦП включен, запуск преобразования, режим автоизмерения, | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) // прерывание по окончанию преобразования, | (1 << ADPS0); // частота CLK/128 ADCSRB = 0x00; // режим автоизмерения: постоянно запущено DIDR0 |= (1 << PINB2); // запрещаем цифровой вход на ноге аналогового входа // Режим 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; // регистр сравнения (инвертированный сигнал ШИМ 0) OCR0B = 255; // регистр сравнения (инвертированный сигнал ШИМ 0) // настройка режима сна MCUCR |= (1 << SM1); // power-down mode, прерывание по изменению MCUCR &= ~(1 << SM0); // power-down mode sei(); //разрешаем глобально прерывания while(1) { if ((PINB & (1 << PB4)) && !flgLngPress) { sleep_MODE = false; _delay_ms(10); // задержка (защита от дребезга) while (PINB & (1 << PB4)) { butCount++; // начало отсчета нажатия кнопки _delay_ms(10); if (butCount > 200) break; // выходим после 2 сек в любом случае (время повтора) }// end while if (butCount >= 50){ // ~1 сек flgLngPress = true; flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if else flgPress = true; // клик }// end if if (flgLngPress && (PINB & (1 << PB4)) == 0){ // если отпустили после длительного нажатия switchLED = false; flgLngPress = false; flgPress = false; // сбрасываем флаг нажатия flgClick = false; }// end if if (flgPress && (PINB & (1 << PB4)) == 0){ // отпустили кнопку flgClick = true; // устанавливаем флаг клика flgPress = false; // сбрасываем флаг нажатия butCount = 0; // обнуляем счетчик времени нажатия }// end if if (flgLngPress && !switchLED){ // было удержание кнопки LedMode = !LedMode; // переключаем на другой светодиод i = 1; Set_PWM(); // устанавливаем режим светодиода switchLED = true; }// end if if (flgClick){ // был клик flgClick = false; // сбрасываем флаг клика i++; // инкрементируем режим PWM if (i > 3) i = 0; // обнуляем счетчик Set_PWM(); // устанавливаем режим светодиода if (i == 0) sleep_MODE = true; else sleep_MODE = false; }// end if if (lowBat){ i = 0; BlinkLed(); RunSleep(); }// end if if (sleep_MODE) RunSleep(); }// end while(1) }// end main
P. S. Все заработало и в железе на макетке, теперь буду печатку придумывать и светодиоды полевиками заменять. Ну и программу слегка причешу... Всем огромное спасибо за помощь! P.P.S. Проверил потребление, что много, видимо засыпает не полностью, аж целых 160-170 мкА.
|
|
| Сообщение # 27
|
nolpofaze
Постов: 442
Друзья |
34kilowatt, делитель АЦП съедает эти мкА.
|
|
| Сообщение # 28
|
34kilowatt
Постов: 75
ОК |
Не, не, не - это без учета делителя, делитель в макетном варианте (переменник 25к) еще 180мкА кушает (итого за 300-360мкА потребление, в зависимости от напряжения 3 - 4,2В).
|
|
| Сообщение # 29
|
34kilowatt
Постов: 75
ОК |
Не, не, не - это без учета делителя, делитель в макетном варианте (переменник 25к) еще 180мкА кушает (итого за 300-360мкА потребление, в зависимости от напряжения 3 - 4,2В).
Может МК просто в сон не уходит? Потому, что, когда начал прошивку сочинять, потребление просто при выключенных светодиодах такое-же примерно было. Попробую через sleep.h перевести в сон.
Добавлено (26.06.2019, 13:32) --------------------------------------------- Не получилось ниже 160мкА снизить потребление, ну никак. Потребляет именно МК, т.к. всю обвязку убрал и подключил. Может дело в самом МК (хотя в остальном проблем ни каких), заказаны были на Али, вроде как Tiny13А.
|
|
| Сообщение # 30
|
nolpofaze
Постов: 442
Друзья |
Да уж, а должен потреблять менее 0,1мкА в режиме power-down. Может и мк, замерял в схемке на mega8L, тоже режим power-down, выходит около 3мкА. Микра в дипе, успешно выдрана со счетной машинки, не китай.
|
|