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

Re: Программирование ATtiny13

Пт сен 04, 2020 18:20:52

Вот еще такой вопрос. Известно что время процессора (микроконтроллера) это такты.
Ну допустим я настоил один из счетчиков процессора на 1 сек.
А как получится так что счетчик так и будет считать 1 сек если я добавлю еще какую-то работу процесоору, буду вызывать другие прерывания , не говоря уже о работе в цикле loop. Вывод данных тоже стоит каких то тактов. На чем эта вся стабильность держиться.?

Re: Программирование ATtiny13

Пт сен 04, 2020 21:41:05

Ни на чем она не держится, практически всегда все интервалы будут "дрожать", т. е. периодически будут удлиняться сверх нормы. Это называется джиттер.
Можно его минимизировать, но на 100% избавиться почти никогда не выйдет.
Да это почти никогда и не нужно.

Re: Программирование ATtiny13

Сб сен 05, 2020 10:08:36

Подбирается такая конфигурация аппаратных и программных ресурсов, при которой главная таймерная сетка определяется высшим приоритетом.
Остальные задачи и прерывания могут быть подторможены.
А уже флаги тиков главного таймера используются соответствующими подпрограммами.
В принципе там всегда будет соблюдаться фиксированное отклонение, получаемое на участках обработке флагов.
8)
Насчет таймера - при работе МК таймер(ы) тикает абсолютно автономно.
Т.е. у нас только время на команды запуска и обработчик прерывания (по соответствующему условию) "пересекаются" с работой основной программы.
Ошибка отсчета определяется временем обработки соответствующего прерывания и/или интервалами между ними.
В большинстве случаев если за прерываниями от таймера наивысший приоритет (исключения - прерывания по аппаратному RESET и аварийным ситуациям - там уже не до таймеров) то интервал между прерываниями фактически стабилен.
Джиттер в +/- пару тактов особо значения не имеет (относительно секундного интервала).
При варианте отсчета какого-то интервала средствами таймера также в основном фиксированные задержки, кои в документации раскопать можно.
:beer:

Re: Программирование ATtiny13

Сб сен 05, 2020 12:31:10

Ну допустим я настоил один из счетчиков процессора на 1 сек.
А как получится так что счетчик так и будет считать 1 сек если я добавлю еще какую-то работу процесоору, буду вызывать другие прерывания , не говоря уже о работе в цикле loop. Вывод данных тоже стоит каких то тактов. На чем эта вся стабильность держиться.?

Не счетчик, а таймер. Приоритет прерываний определяется их порядком (неизменным, который изначально задан в таблице векторов из ДШ). loop прервется ведь. Вход в прерывание - процесс поддающийся счету в тактах. Поэтому это можно учитывать. Плюс-минус некоторые вещи, которые невозможно учитывать, вроде текущей исполняющейся инструкции на момент срабатывания прерывания.

Re: Программирование ATtiny13

Ср окт 07, 2020 14:31:43

Здесь вот я переменным резистором на аналоговом входе PD4 регулирую напряжение.
потом строкой
OCR0B=ADCH;

регулирую скважность на цифором выходе PD1
Подскажите как мне посмотреть текущее значение допустим ADCH
Это все я делаю в протеусе. Там есть отладчик, как видите я завел переменную
типа insigned char i. В нее пытаюсь присовоить
t=OCR0B;
но отладчик показывает мне ff (255), Хотя я точно знаю что там должна быть половина питания
так как я организовал делитель из 2 резистором 5к (концы на плюс и массу, центр в PD4)

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

Код:
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
//#include <avr/delay.h>
unsigned char  t;

ISR(ADC_vect)  //Прерывание по АЦП
{
   
   // Крутим резистор
   // В переменной  ADCH оцифрованное значение напряжения на лапке PB4 (adc
 
   
   OCR0B=ADCH;
   t=OCR0B;
   }

int main(void)
    {
 
  //Инициализация АЦП
       ADMUX=0x22;
       ADCSRA=0xEA;
       ADCSRB=0x00;
       
       
       DDRB|=(1<<PB0)|(1<<PB1)|(0<<PB4);   // ОПРЕДЕЛИМ ПИНЫ КАК ВыХОДЫ
       PORTB|=(0<<PB0)|(0<<PB1);  // ВКЛЮЧИМ ИХ (ВЫСОКИЙ УРОВЕНЬ)
       DIDR0|=(1<<PB4);       
       
       //TCCR0A=0x83;
       TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (1<<WGM00);
       //TCCR0A=
       //(1<<COM0A1)  // ПОДКЛЮЧИМ ШИМ НА НОГУ OC0A
       // |(0<<COM0A0)  // НЕ ИНВЕРТИРУЮЩИЙ ШИМ
       //|(1<<COM0B1)  // ПОДКЛЮЧИМ ШИМ НА НОГУ ОС0B
       //|(0<<COM0B0)  //  инверт шим
       //|(1<<WGM01)   ///ФАЗОВАЯ
       //|(1<<WGM02);  ///КОРРЕКЦИЯ
       
      //TCCR0B=0x02;  // ЧАСТОТА И ДЕЛИТЕЛИ
       TCCR0B=(0<<CS02)|(0<<CS01)|(1<<CS00);  // 0-1-0 ДЕЛИТЕЛЬ НА 8 (150 КГЦ)
       
    TCNT0=0x00;  // Счетчик таймера (для инициализации Шима не нужен)
    OCR0A=0x00;   // Инициализация показателя ШИМа На PB0 0-255 (от него зависит Скважность шима)
    OCR0B=0x00;   // иНИциализация показателя Шима на PB1 0-255 (от него зависит Скважность шима)

   sei();
   
   
  while (1){}
}


Добавлено after 3 minutes 24 seconds:
получилось. Надо было просто сюда пост написать.

Re: Программирование ATtiny13

Ср окт 07, 2020 14:59:59

-
Последний раз редактировалось roman.com Ср окт 07, 2020 16:37:00, всего редактировалось 1 раз.

Re: Программирование ATtiny13

Ср окт 07, 2020 15:33:44

roman.com писал(а):Очень просто))
когда не читаешь тему, не вникаешь в проблему, всегда все просто. вы где у attiny13 видели PORTD?!

Re: Программирование ATtiny13

Ср окт 07, 2020 20:04:09

Надо как-то так:
Код:
...
volatile unsigned char  t;

ISR(ADC_vect)  //Прерывание по АЦП
{
   // Крутим резистор
   // В переменной  ADCH оцифрованное значение напряжения на лапке PB4 (adc
   t = ADCH;
   OCR0B = t;
}
...


1. Все переменные, меняющиеся в прерывании должны быть объявлены как volatile. Иначе компилятор просто ничего туда не станет писать, т.к. с его точки зрения вы эту переменную никогда не присваиваете и еще не используете.
2. Лучше не мучать регистры, а считать в t сначала, а потом из него записать уже в OCR0B. В данном случае может быть не важно, но в другом случае сыграет с вами злую шутку, когда регистр поменяется железом между операциями.
3. АЦП вы считываете только 8 бит из 10. Убедитесь, что выравнивание выставлено правильно, left-justified в данном случае емнип должно быть
4. Зачем вам t, когда в протеусе прямо можно смотреть регистры. Надо Watch Window открыть... или cpu registers или что-то такое в меню отладки. Поищите, сейчас нет возможности глянуть, но где-то точно смотреть можно.

Re: Программирование ATtiny13

Ср окт 07, 2020 21:59:29

NStorm писал(а):Зачем вам t, когда в протеусе прямо можно смотреть регистры. Надо Watch Window открыть
да. там, сразу ADCH и/или OCR0B смотреть можно

Re: Программирование ATtiny13

Чт ноя 26, 2020 23:53:47

подскажите такой момент
Код:
ISR(PCINT0_vect)
 
{
   
   if [b] ((PINB & (1<<BUTTON0))==0)[/b]
   {
      //PORTB ^= (1<<LED); //переключаем состояние светодиода (вкл./выкл.)


зачем меня заставляют писать if (PINB & (1<<BUTTON0))==0) в этом коде
если по умолчанию регистр MCUCR=(0<<ISC00)|(0<<ISC01);
то есть прерывание должно сработать по низкому уровню (при нажатии кнопки)

Но это почему то не работает и если убрать условие if (PINB & (1<<BUTTON0))==0)
то при нажатии на кнопку светодиод гаснет, апри отжатии снова загорается.
Как это понимать?

Добавлено after 15 minutes 3 seconds:
Сам разобрался когда написал вопрос. все по классике )))
Т.к. прерывание PCINT0 наступает при любом изменении логического уровня на входе, то нужно в обработчике проверять, была ли кнопка нажата, либо отпущена. Если любая из кнопок нажата, то выполняем нужное действие (инвертируем состояние выхода, к которому подключен светодиод):

Re: Программирование ATtiny13

Чт ноя 26, 2020 23:55:32

olegue, потому что MCUCR относится к прерыванию INT0. А у вас вектор прерывания PCINT0. Это разные прерывания совсем. Посмотрите на каких ногах есть INT0 и на каких PCINTx. PCINTx умеют только по изменению уровня работать, их нельзя настроить на спад или подъем фронта отдельно, в отличии от INT0. Поэтому и нужна проверка.

Re: Программирование ATtiny13

Чт ноя 26, 2020 23:56:18

<a href="./memberlist.php?mode=viewprofile&amp;u=89313">NStorm</a>, а я перепутал int0 и pcint0-5. у них настройк и разные и
MCUCR=(0<<ISC00)|(0<<ISC01) относится к int0 (pb1)

спасибо.

Re: Программирование ATtiny13

Пт ноя 27, 2020 18:25:46

Меня таки не оставляет желает сделай свой алгоритм радиоуправления на tinny13
Я такие допускаю что я придумал какую то фигню. А может ее уже придумали до меня. Ну не важно.

Я решил подать на вход тиньки импульсны сигнал и попытаться его распознать.

Подал сигнал с периодом 20мс. Делаю это все в Протеусе.
И написал такой алгоритм распознавания.
Суть его проста.
Пин сконфигурирован как вход (типа кнопка на PB4)
На нем как известно HIGH, если кнопка не нажата и LOW если пришел низкий уровень.
В алгоритме я проверяю если пришел низкий уровень, то жду 25мс и проверяю опять ли низкий, если низкий, то жду 20мс и опять должен быть низкий. В итоге на 3-4 проверке можно сделать вывод что это именно мой сигнал и включить лампочку.
Потом я еще делаю задержку 3сек, что бы отделить команды.
Потом можно сделать проверку по High


Код:
ISR(PCINT0_vect)
     //|| (PINB & (1<<BUTTON2)) == 0
{
  if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
  {
    _delay_ms(25);  //Ждем мсек
     if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
     {
   _delay_ms(25);
        if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
          {
        _delay_ms(25);
           if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
           {
           _delay_ms(25);
           if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
         {
          PORTB ^= (1<<LED); //переключаем состояние светодиода (вкл./выкл.)
         _delay_ms(3000);
         }
           }
      }
      }
  }
}


Но как вы уже поняли, раз я сюда пишу значит что-то не срастается.
На мой розум первая проверка должны быть после 25мс - я попадаю по центру, а остальные после 20мс
Но лампочка исправно зажигается только есил ставлю 25мс на всех проверка.
Короче, даже если это все бред, расскажите почему не работает так как я это себе представляю. Спасибо.

Re: Программирование ATtiny13

Пт ноя 27, 2020 19:20:35

Вообще то...
Любое взаимодействие между МК проще начинать отлаживать с обыкновенного "проволочного" интерфейса связи.
а потом уже думать о каком-то "эфиро-опто-звуковом" канале.
Ограничения - сигнал должен иметь линии передачи (TxD) и приема (RxD) сигнал является АСИНХРОННЫМ относительно абонентов.
Собственно даже простая кнопа в таком случае содержит фрагмент начальной синхронизации и далее собственно данные в пакете предачи.
Затем пауза в ожидании ответа абонента о получении команды.
А уж ежли не получено - повторяем попытку "достучаться" определенный интервал времени.
Это "универсалка"...
Можно конечно грузить канал непрерывно пересылаемыми синхроимпульсами... Но... Тогда каналы на основе радио и светового/(ультра)звукового носителей будут жестко однонаправленными.
Обработка кнопы тут вторична - она лишь активирует процесс обмена...
:roll:
Может я чего не понял?...
:dont_know:
Пы.Сы...
Под ассемблером я б подсказал конкретно, а под Си... разве что в рамках адуринки (хоша... алгоритмы под Си вроде должны бысть подобны)...
:roll:
Фильтрацию по имеющимся данным можно и по
if()/else
и по
swith/case
выполнять...
и...
совсем необязательно в самом прерывании - там только захват данных и установка флага для последующего анализа.
Сам анализ делаем в основной программе. Иначе столкнемся со спецификой блокировки прерыванием функций контроля интервалов времени.
:roll:

Re: Программирование ATtiny13

Пт ноя 27, 2020 19:54:29

BOB51, может я действительно что то спутано рассказал.
Но у меня нет двухстороннего обмена.
У меня есть череда имупльсов, например 5 импульсов с периодом 20мс
Я хочу распознасть эти импульсы. Пускай пока нет никаких радио-оптики.
Потом можно усложнить, сделать импульсы разной длительности и так далее.

Re: Программирование ATtiny13

Пт ноя 27, 2020 20:28:29

а зачем импульсы разные? нельзя ли лампочку прямо к кнопке подключить? :)

а если серьезно посмотрите, например, здесь http://www.poprobot.ru/theory/ppm-pcm

Re: Программирование ATtiny13

Сб ноя 28, 2020 09:58:41

emax писал(а):а если серьезно посмотрите, например, здесь http://www.poprobot.ru/theory/ppm-pcm


ок. годится, так я себе это все и представляют.
тока то что я придумал
olegue писал(а):В алгоритме я проверяю если пришел низкий уровень, то жду 25мс и проверяю опять ли низкий, если низкий, то жду 20мс и опять должен быть низкий. В итоге на 3-4 проверке можно сделать вывод что это именно мой сигнал и включить лампочку.


для 2021 года дичь дичайшая.

"новая задумка" - измерение импульсов с помощью таймера

Код:
ISR(PCINT0_vect)
   
{
   TCNT0=0x00;
   
  if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
  {
     TCCR0B=0x05; // запустим счетчик и поделим клок на 1024, шоб не шибко быстро.
     while ( (PINB & (1<<BUTTON2)) == 0 ) { } // ждём отпускания кнопки -это и есть длина импульса
 
     stat=TCNT0;  // получаем время ожидания отпускания кнопки  -это и есть длина импульса
     TCNT0=0x00;  // обнуляем счетчик
        if (stat=33)  // если длина первого импульса нас устраивает, то
          { 
            // продолжаем упражнения  и если
           if ( (PINB & (1<<BUTTON2)) == 0  ) // если LOW
              {
                ИзмеряемСледущийИмпульс();
               }
          }
     
  }


Что скажете?

Добавлено after 5 minutes 22 seconds:
Я ж самое главное забыл написать.

Как мне в протеусе сделать генератор произвольных импульсов?
Я ж не могу 2 тиньки рядом поставить? И такое можно?

Re: Программирование ATtiny13

Сб ноя 28, 2020 17:18:33

olegue, у вас переполнение таймера не проверяется. А в прерывании слишком долго ждете. Так нельзя. Тем более у вас во время ожидания может случится еще прерывание.
Вообще делается обычно так - таймер запускается и работает всегда. По прерыванию просто проверяете уровень, записываете значение в некий буфер и обнуляете таймер. Без ожидания когда изменится уровень. Просто когда он изменится в следующий раз на другой - вот вам и длина импульса. А ждать сидеть в прерывании нельзя.
Вообще для таких вещей лучше выбрать другой МК, у которого есть таймер с режимом захвата - гораздо удобнее.
В Протеусе есть генератор, там прям вкладка так и называется вроде. Вторую тиньку тоже можно, но смысла чисто для генерации ставить нет, можно проще сделать.

Re: Программирование ATtiny13

Сб ноя 28, 2020 20:35:08

С приходом фронта импульса запускаем генератор УЕ (или оный ВСЕГДА включен - тогда команда разрешения счета его переполнений).
Далее программный счетчик подсчитывает количество этих УЕ. С одновременным контролем статуса линии на отпускание.
По отпускании содержимое счетчика УСЛОВНЫХ ЕНОТОВ подлежит табличной дешифрации.
Никаких таймеров не используем - единственно генератор системной сетки частот и программные счетчики.
Когда-то подобный алгоритм использовал при подсчете количества ии формата выскочивших из копировального аппарата листочков.
Это ежли проводим селекцию импульса по длине.
Ежли по количеству (и без антидребезга) там простейший программный опрос линии ввода с последующим складированием результата в переменной и далее используем ту переменную в качестве данных для селектора.
Единственно надо добавить соизмеримый интервал паузы между пакетами импульсов, чтобы можно было отличить полезный участок от "простоя".
8)
Сейчас МК весьма шустрые - на той же адуринье селекция импульсов с параметрами период одного импульса в 20 миллисекунд вполне программным способом решаема.
:roll:
Насчет модуляции...
В принципе удобнее, когда длительность периода ОДИНАКОВА, а меняется только соотношение длительности 1/0.
(подобие того же протокола для WS2812/фазовая манипуляция).
Или протоколы ИК дистанционок...
Тут уже кому чего попридумается.
:beer:

Re: Программирование ATtiny13

Сб ноя 28, 2020 21:19:17

NStorm писал(а):у вас переполнение таймера не проверяется.


ок, а зачем мне конролить переполнение есил я TTCR0B=0x05 делитель на 1024
слок делим на 1024 (1.2мгц /1024=1172 кгц. ) 1/1172=0.000853.... -853 микросекунды на 1 тик счетчика. Значит счетчик может измеритить до переполнения *256= 0.218= 218 миллисекунд. Я оперирую длителностями 10 мс. У меня счетчик никак не может переполнится. И после получения результата я делаю ТСНТ0=0x00. -

Проблема в том что я не вижу эти длительности. Я поулчаю какие то цифры но свести их не могу.

например если я подаю на вход частоту 50гц -это период 20мс. Это 2 длительности по 10м (high и low)
счет 8 битный -256 значений (0-255) испльзуя делитель на 1024 =имею 1172 кгц. ОДин оборот счетчика даст мне вычислить длительность 0.000853*256=0.218с =218мс. Значит ожидаемо,что 256*10мс/0.218= примерно 11-12 единиц счетчика. А я получаю 92. Т.е 92*0.000853= пример 80 мс. Откуда эти 80мс хоть стрэляй не пойму.
Кроче, что то не так а где концы искать по ка не знаю.
Ответить