Обсуждаем контроллеры компании Atmel.
Ответить

LED Driver на Attiny13A

Пн авг 23, 2021 17:36:00

Первый опыт с аттиньками, поэтому прошу понимания у всех.

Задание:
1) При включении кнопки зажигается фонарик на полную мощность (кнопка фиксируемая) - 1 подаем на PB0
2) При полунажатии на кнопку должен переключиться режим, экономящий яркость - 1-ки подаем на PB0 и PB1
3) При повторном полунажатии фонарик должен вернуться в первоначальный режим (вот здесь и есть проблема, пока что всеми попытками переключение только в одну сторону)
4) Раз в минуту контролируется уровень батареи, подключенной к PB4 (он же ADC2), суть в считывании уровней АЦП (эта часть вроде как работает), при достижении определенных уровней, зажигаем синий или красный светодиоды.

Переключение режимов так же смотрится по уровню ADC2, при полунажатии происходит падение уровня, которое должно фиксироваться. Собрано на резистивном делителе с номиналами 30 кОм и 10 кОм. (Схема пинов во вложении)

Код:

#include "main.h" // < All settings are here
#include <util/delay.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <stdbool.h> // bool in C99
// Яркость нагрузки, 0 - выключен, 255 - максимальная (ШИМ)
u8 rate;
// Направление изменения яркости нагрузки, 1 - прибавить ШИМ, 0 - убавить ШИМ
u8 rate_dir = 0;
// Состояние заднего светодиода LED2
bool led_state = false; 
int count = 0;
uint8_t countMode = 0;            //????? ?????????? ??????
uint8_t reqChangeMode = 0;        //????, ???????????? ????? ????????? ???????? ?????
volatile _Bool direction = 0; // Направление бегущего огонька
u16 x;

void bat_check_low(void) {
   u8 adc_raw = bat_getvoltage();
   if (adc_raw < BAT_WARNING_BLUE) {
      while (adc_raw < BAT_WARNING_BLUE) {
         PORTB = 0b00000111;
      }
   }
   if (adc_raw < BAT_WARNING_RED)
   {
      PORTB = 0b00001011;
   }
   
   if (adc_raw > BAT_WARNING_BLUE)
   {
      PORTB = 0b00001111;
   }
   if (adc_raw < BAT_SHUTDOWN)
   PORTB = 0b00001100;      
}

ISR( TIM0_COMPA_vect)
{

}

void knopka_check(void) {
   // Проверка заряда батареи
   u8 adc_knopki = bat_getvoltage();
   u16 bat_time_low = 0;
   if (adc_knopki < 150)
   {
      while (adc_knopki < 150)
      {
         count++;
         if ((count < 250)&&(count > 30))
         {
            direction = !direction; // Меняем направление
            PORTB = 0b00001111;
            count = 0;
            #ifdef BAT_CHECK_LOW
            if (bat_time_low == BAT_CHECK_PERIOD)  { // Проверка заряда батареи через определенный интервал
               bat_time_low = 0;
               bat_check_low();   
         }
            bat_time_low++;
            #endif
            
            _delay_ms(1);
         }
      }
   }
}

int main(void)   {
   setup();
   sei ();
   u16 bat_time = 0;
   while(1)    {
      
      knopka_check();   
      #ifdef BAT_CHECK
      if (bat_time == BAT_CHECK_PERIOD)  {
         bat_time = 0;
         bat_check();   
      }
      bat_time++;
      #endif
      
      _delay_ms(1);
   }
}

ISR(INT0_vect) {}   
ISR(ADC_vect) {}   
   
void setup(void){
   ADMUX =
   (1 << ADLAR) | (1 << REFS0) | (1 << MUX1) | (0 << MUX0);     
   ACSR |= (1 << ACD);
   ADCSRA = (1 << ADIE);
   TCCR0B = (0 << CS02) | (1 << CS01) | (0 << CS00 );
   TCCR0A = (0 << WGM02) | (1 << WGM01) | (0 << WGM00);
   OCR0A = 69;
   TCNT0 = 0;
   TIMSK0|=(1<<OCIE0A)|(0<<TOIE0);
   DDRB = 0b00001111;
   PORTB = 0b00001101;
   wakeup();
}
 
void wakeup(void) {
   if (led_state)
   LED_RED_on   
   
   #ifndef RATE_REMEMBER // Если нет памяти яркости
      rate = RATE_DEFAULT; // включается сразу на мин. яркость
   #endif
   OCR0A = rate;
   
   ADCSRA |= (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN) ;
   ADCSRA |= (1 << ADSC);
}

u8 bat_getvoltage(void) {
   _delay_us(50);
   ADCSRA |= (1 << ADSC);
   while (ADCSRA & (1 << ADSC));
   return ADCH;
}

void bat_check(void) {
   u8 adc_raw = bat_getvoltage();
   if (adc_raw < BAT_WARNING_BLUE) {
      while (adc_raw < BAT_WARNING_BLUE) {
         PORTB = 0b00000101;
      }
   }
   if (adc_raw < BAT_WARNING_RED)
   {
   PORTB = 0b00001001;
   }
   if (adc_raw < BAT_SHUTDOWN)
      PORTB = 0b00001100;

   if (adc_raw > BAT_WARNING_BLUE)
   {
      PORTB = 0b00001101;
   }

}

Вложения
Безымянный.jpg
(52.76 KiB) Скачиваний: 196

Re: LED Driver на Attiny13A

Пн авг 23, 2021 19:19:19

в этом месте
while (adc_raw < BAT_WARNING_BLUE) {
PORTB = 0b00000111;
у тебя прошивка просто повесится и никуда дальше не пойдет.
убери строку
while (adc_raw < BAT_WARNING_BLUE) {
и закрывающую ее скобку.
оставь также, как сделано в других if.
дальше я смотреть не стал. там тоже может быть куча ошибок.

Re: LED Driver на Attiny13A

Ср авг 25, 2021 17:19:56

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

В этом кусочке функции bat_check надо добавить мигание раз в 3 секунды примерно.
Код:
   if (adc_raw < BAT_WARNING_RED)
   {
   PORTB = 0b00001001;
   }


А в этом кусочке тоже мигание, но раз в секунду.

Код:
   if (adc_raw < BAT_SHUTDOWN)
      PORTB = 0b00001100;


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

Re: LED Driver на Attiny13A

Ср авг 25, 2021 20:13:10

Лучше всего через машину конечных состояний.

Re: LED Driver на Attiny13A

Ср авг 25, 2021 21:16:49

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

Re: LED Driver на Attiny13A

Чт авг 26, 2021 08:57:53

Bondosha писал(а):кнопка фиксируемая
Bondosha писал(а):При полунажатии на кнопку
А что за кнопка такая интересная?

Re: LED Driver на Attiny13A

Чт авг 26, 2021 11:40:29

Dimon456, да просто гавно кетайское у меня такая стояла сначала из 20нажатий тока 12-14 -включали ее...
пришла в кетаянском приборе с завода когда из 20 нажатий она стала срабатывать 4-5 раз терпение лопнуло и я взялся за паяло и заменил гавно брендом... и забыл про это...
конечно можноб наехать на шопик по гарантии на предмент ремонта за их щет но ждать по полгода замены ну нах...

Re: LED Driver на Attiny13A

Чт авг 26, 2021 17:18:08

Starichok51, а можно в этот раз вас попросить с примером, пожалуйста? а то сегодня пыталась, и ничего не изменилось

Re: LED Driver на Attiny13A

Чт авг 26, 2021 17:58:16

во-первых, я не пишу на Си для МК, хотя и понимаю, что там написано.
во-вторых, у меня сейчас нет времени составлять пример.
в-третьих, есть в этом разделе тема "Таймеры/счётчики в AVR". скорее всего там достаточно примеров использования таймеров и прерываний для них.

Re: LED Driver на Attiny13A

Пт авг 27, 2021 02:03:33

Первый опыт с аттиньками, поэтому прошу понимания у всех.

Задание:
1) При включении кнопки зажигается фонарик на полную мощность (кнопка фиксируемая) - 1 подаем на PB0
2) При полунажатии на кнопку должен переключиться режим, экономящий яркость - 1-ки подаем на PB0 и PB1
3) При повторном полунажатии фонарик должен вернуться в первоначальный режим (вот здесь и есть проблема, пока что всеми попытками переключение только в одну сторону)
4) Раз в минуту контролируется уровень батареи, подключенной к PB4 (он же ADC2), суть в считывании уровней АЦП (эта часть вроде как работает), при достижении определенных уровней, зажигаем синий или красный светодиоды.

Переключение режимов так же смотрится по уровню ADC2, при полунажатии происходит падение уровня, которое должно фиксироваться. Собрано на резистивном делителе с номиналами 30 кОм и 10 кОм. (Схема пинов во вложении)

Не понял, что за кнопка такая… потому использовал распространённый вариант – кнопка без фиксации. Питание МК подразумевается от двух батареек ААА.
Как понял алгоритм, так и написал. А именно:
1. При удержании нажатой кнопки более 3 сек. – на выводе РВ0 появляется лог 1.
2. При лог 1 на выводе РВ0, последующими короткими нажатиями кнопки (менее 3 сек) осуществляется управление выводом РВ1 – режим триггера. При первом коротком нажатии появляется лог 1. При повторном коротком нажатии лог 1 сбрасывается в 0.
3. При лог 1 на выводе РВ0 и удержании нажатой кнопки более 3 сек. – на выводе РВ0 лог 1 сбрасывается в 0.
4. Напряжение питания измеряется раз в минуту.
5. При снижении напряжения примерно ниже 2,6 В, начнёт мигать жёлтый светодиод (раз в три сек.)
6. При снижении напряжения ниже 2 В, начнёт мигать красный светодиод (раз в сек.).


Схема:
Изображение
Прошивка:
LED_Driver.hex

МК тактируется на заводских установках (1,2 МГц). Компаратор отключил.

Re: LED Driver на Attiny13A

Пт авг 27, 2021 20:23:17

Название темы LED Driver на Attiny13A, ну так создайте LED Driver - стабилизатор тока светодиодов.

Потребуется компаратор, к сожаления у внутреннего компаратора AVR вывод сравнения не выведен наружу, этот вывод выведен наружу только в PIC, поэтому внешний. Пока батарея не сядет до какого-то значения световой поток будет постоянен.

Re: LED Driver на Attiny13A

Пт авг 27, 2021 22:59:06

Dimon456, Вы читали первый пост ТС? Или Вам не важно какое устройство необходимо ТС?

Re: LED Driver на Attiny13A

Сб авг 28, 2021 06:51:14

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

Я хочу сказать следующее, толку от вашего указателя заряда акб - ноль.
Акб еще не разредился до такого напряжения, что бы контроллер заряда, встроенный в саму акб, отключил акб, а фонарик светит уже тускло.
За то при полном заряде акб слишком большой ток идет на светодиоды - они имеют свойство быстро выходить из строя.
Самсусамыч писал(а):Вы читали первый пост ТС?
я так и не добился, что же за кнопка такая? если как на фотоаппарате - так там два контакта.
Самсусамыч писал(а):Или Вам не важно какое устройство необходимо ТС?
Название темы LED Driver, пишите тогда - LED Выключатель.

Re: LED Driver на Attiny13A

Сб авг 28, 2021 10:27:37

у мну есть вот такой фонарик...

Так как такого акб не найдешь, был заменен на акб от сотового телефона, +добавлена для ограничения тока заряда такая платка...

Я хочу сказать следующее, толку от вашего указателя заряда акб - ноль.

Касаемо Вашей схемы возможно и так, а вот что касаемо схемы ТС, возможно и нет. В любом случае это будет оценивать ТС, а не Вы. Или Вы экстрасенс? Знаете чем и как ТС будет управлять? А если ТС подобным устройством планирует управлять уже готовым токовым стабилизатором для светодиодов? Не стоит бежать впереди паровоза… нужно дождаться ответа ТС, и тогда будет ясно...
Акб еще не разредился до такого напряжения, что бы контроллер заряда, встроенный в саму акб, отключил акб, а фонарик светит уже тускло.
За то при полном заряде акб слишком большой ток идет на светодиоды - они имеют свойство быстро выходить из строя.

Правильно ли я понял, что Вы описываете вариант переделанный схемы своего фонарика? Тогда зачем Вы недостатки своей схемы пытаетесь переложить на схему ТС, которую ни разу не видели? Это как-то выглядит странно, если не сказать глупо.
Название темы LED Driver, пишите тогда - LED Выключатель.

Что за манера придираться к словам не понимая их значения? Драйвер в электронике переводится как устройство (или схема) управления... так, что в названии ТС нет противоречий. А то что Вы себе напридумывали свои определения, так это никому не интересно.

Re: LED Driver на Attiny13A

Сб авг 28, 2021 12:31:15

{я так и не добился, что же за кнопка такая? }
Я думаю, что это кнопка с фиксацией, только «полунажатие» это когда контакты уже замкнулись, но ещё не зафиксировались. При отпускании контакты размыкаются.

Re: LED Driver на Attiny13A

Сб авг 28, 2021 14:01:05

Возможно. Тогда возникает вопрос – по какой схеме ТС подключил кнопку к МК.

Re: LED Driver на Attiny13A

Вт сен 07, 2021 17:38:45

Так, если кто-то еще смотрит эту тему, дошла я до такого варианта.
В итоге при постоянном опросе АЦП на таком участке if (adc_raw < BAT_SHUTDOWN) ловились помехи, в итоге работало некорректно. Сделала опрос заряда батареи раз в 100 циклов, в итоге теперь не реагирует на timer1 и timer2 для режимов с миганием, а мигает с периодом этих 100 циклов на уровне примерно 0.65 В. Как поправить, чтобы реагировало на все счетчики?

Код:
#ifndef MAIN_H_
#define MAIN_H_

// Frequency definition for gcc. Do not forget to set proper fuses.
// Определение частоты для компилятора. Не забудь выставить частоту фьюзами.
#define F_CPU 1200000UL  // Attiny13 1.2MHz / PWM 4.6 KHz / CKDIV8 = 0
//#define F_CPU 9600000UL  // Attiny13 9.6MHz / PWM 36.8 KHz / CKDIV8 = 1

#include <util/delay.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <stdbool.h> // bool in C99

#define nop __asm__ __volatile__ ("nop");
typedef uint8_t u8;
typedef uint16_t u16;

int main(void);
static void setup(void);
static void wakeup(void);;
static u8 bat_getvoltage(void);

#endif /* MAIN_H_ */

#include <util/delay.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <stdbool.h> // bool in C99
int count = 0;
volatile uint8_t STATUS = 0;            //????? ?????????? ??????
volatile uint8_t reqChangeSTATUS = 0;        //????, ???????????? ????? ????????? ???????? ?????
volatile uint8_t timer1 = 0;
volatile uint8_t timer2 = 0;
volatile uint8_t timerADC = 0;
volatile uint8_t countMode = 0;            //????? ?????????? ??????
volatile uint8_t reqChangeMode = 0;        //????, ???????????? ????? ????????? ???????? ?????
u8 adc_raw = 0;

ISR(TIM0_COMPA_vect)
{
}

ISR(TIM0_OVF_vect)
{
   timer1++;
   timer2++;
   timerADC++;
}


ISR(WDT_vect)      // Watchdog timeout interrupt service routine// обработка прерыания WDT
{}

void bat_check(void)
{
   u8 adc_raw = bat_getvoltage();
   if ((adc_raw <= 207)&&(adc_raw > 183))
   {
      if (countMode == 1)
      {
         PORTB = 0b00000111;
         timer1 = 0;
         timer2 = 0;
      }
      if (countMode == 0)
      {
         PORTB = 0b00000101;
         timer1 = 0;
         timer2 = 0;
      }
   }
   if (adc_raw <= 183)//&&(adc_raw >= 130))
   {
      if (countMode == 1)
      {
         PORTB = 0b00001011;
         if(timer1 == 25)
         {
            PORTB = 0b00001000;
            timer1 = 0;
         }
      }
      if (countMode == 0)
      {
         PORTB = 0b00001001;
         if(timer1 == 25)
         {
            PORTB = 0b00001000;
            timer1 = 0;
         }
      }
   }
   if (adc_raw < 150) //(second30 >= 128)
   {
      if (countMode == 1)
      {
         PORTB = 0b00001100;
         if (timerADC >= 25)
         {
            PORTB = 0b00001111;
         }
         if (timerADC >= 27)
         {
            PORTB = 0b00001100;
            timerADC = 0;
         }
      }
      if (countMode == 0)
      {
         PORTB = 0b00001100; //PORTB = 0b00001101;
         if (timerADC >= 25)
         {
            PORTB = 0b00001101;
         }
         if (timerADC >= 27)
         {
            PORTB = 0b00001100;
            timerADC = 0;
         }
      }
   }
   if (adc_raw > 210)
   {
      if (countMode == 1)
      {
         PORTB = 0b00001111;
         //timer1 = 0;
      }
      if (countMode == 0)
      {
         PORTB = 0b00001101;
         //timer1 = 0;
      }
   }
   if (adc_raw < 30)
   {
      DDRB = 0b00000011;
      PORTB = 0b00000000;
   }
}

void knopka_check(void) {
   u8 adc_knopki = bat_getvoltage();
   if (adc_knopki < 90) //adc_knopki 90
   {
      if (count < 250)
      count++;
      } else {
      if (count > 0)
      count--;
      if ((count >= 4)&&(count < 50))
      {
         countMode = (countMode + 1) & 0x1;
         reqChangeMode = 1;
         count = 0;
      }
   }
}

int main(void)   {
   setup();
   sei ();
   // Main LOOP
   while(1)    {
      knopka_check();
      if (reqChangeMode) {        //???? ????????? ???????? ?????
         reqChangeMode = 0;          //???????? ?????????
         switch (countMode) {        //?????????? ????? ??????
            case 0:
            {
               PORTB = 0b00001101;
            }
            break;
            case 1:
            {
               PORTB = 0b00001111;
               if (timerADC == 50)
               {
                  bat_check();
                  timerADC = 0;
               }
            }
            break;
         }
      }
         if (timerADC == 50)
         {
            bat_check();
            timerADC = 0;
         }
      
         }
}


ISR(INT0_vect) {}   // Прерывание ничего не делает, кроме пробуждения МК
ISR(ADC_vect)
{}   // Прерывание ничего не делает, кроме пробуждения МК

void setup(void){
   // Настройка МК после подачи питания

   // Настройка АЦП. Attiny13 datasheet, page 92
   ADMUX =
   (1 << ADLAR) |     // left shift result (for 10-bit values)
   (1 << REFS0) |     // Sets ref. voltage to internal 1.1V, bit 0
   (1 << MUX1)  |     // use ADC1 for input (PB2), MUX bit 1
   (0 << MUX0);      // use ADC1 for input (PB2), MUX bit 0
   //ACSR |= (1 << ACD); // Отключаем компаратор (по умолчанию включен)
   ADCSRA |= (1 << ADEN)  // Разрешение АЦП
   //|(1 << ADSC)   // Запуск преобразования
   |(1 << ADPS2)|(1 << ADPS1); // Предделитель на 64 (частота АЦП 125kHz)
   //|(1 << ADIE); // Разрешение прерывания от АЦП
   // Выключаем аналоговый компаратор
   ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (1<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0);
   TCCR0B = (0 << CS02) | (1 << CS01) | (1 << CS00 ); // 001 - тактовый генератор CLK/1 (скорость шим = CLK/256 = 4687.5 Гц)
   //TCCR0A = (0 << WGM02) | (1 << WGM01) | (0 << WGM00); // 11 - Режим CTC
   //OCR0A = 69;
   TCNT0 = 0;
   //TIMSK0|=(1<<OCIE0A)|(0<<TOIE0);
   TIMSK0|= (1 << TOIE0); // Прерывание по переполнению
   //WDTCR|=(1<<WDCE)|(1<<WDTIE)|(0 << WDP0);   //предделитель на 1 сек. //(1<<WDP1)|(1<<WDP2)|
   DDRB = 0b00001111;
   PORTB = 0b00001101;
   wakeup();
}

void wakeup(void) {
   ADCSRA |= (1 << ADSC); // Пробная конверсия (необходимо провести первый раз после включения для стабилизации АЦП)
}

u8 bat_getvoltage(void) {
   _delay_us(50); // Стабилизируем напряжение после отключения мощной нагрузки, Занимает 12 байт
   ADCSRA |= (1 << ADSC); // Начинаем преобразование
   while (ADCSRA & (1 << ADSC)); // ждем окончания преобразования
   _delay_ms(3);
   return ADCH;
}

Re: LED Driver на Attiny13A

Вт сен 07, 2021 18:44:02

Код:
void bat_check(void)
{
  u8 adc_raw = bat_getvoltage();
  if(adc_raw > 210) {
    PORTB |= _BV(2) | _BV(3); // для примера
  } else if(adc_raw > 183) {
    ...
  } else if(adc_raw > 150) {
    ...
  } else if(adc_raw > 30) {
    ...
  } else { // adc_raw <= 30
    ...
  }
}

Re: LED Driver на Attiny13A

Вт сен 07, 2021 18:52:13

Карбофос, и это поможет решить проблему с таймерами?

Re: LED Driver на Attiny13A

Вт сен 07, 2021 18:59:48

А какая у вас проблема с таймерами?
Единственное, в коментарии написано
// 001 - тактовый генератор CLK/1 (скорость шим = CLK/256 = 4687.5 Гц)
а реально сконфигурирован на clkIO/64, T=53.(3)us.
Ответить