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

Re: Таймеры/счётчики в AVR

Вт дек 06, 2022 22:45:04

.

Re: Таймеры/счётчики в AVR

Ср дек 07, 2022 06:10:05

очень осмысленно

Re: Таймеры/счётчики в AVR

Вт апр 11, 2023 21:13:48

Добрый вечер. В таблице прескалеров AVR (ATmega328P/ATmega2560 напр.) при настройке 16-битных таймеров
есть режим "внешний источник синхронизации Tn_FALLING/Tn_RISING и лапа
на микроконтроллере для подключения этого самого источника синхронизации Tn.
Вопрос - как можно использовать такой прескалер, при каких режимах, с какими прерываниями.
Гуглил про "внешний источник синхронизации Tn_FALLING/Tn_RISING" - информации не очень много.
Может кто накинет простой примерчик.

Re: Таймеры/счётчики в AVR

Вт апр 11, 2023 23:50:24

В таблице прескалеров AVR (ATmega328P/ATmega2560 напр.) при настройке 16-битных
Не только. В 328-й с 8-битным Т0 это тоже работает. В 2560 не смотрел, ни к чему пока.
таймеров есть режим "внешний источник синхронизации
Нету там внешнего источника синхронизации! Есть внешний источник тактовой частоты. А синхронизация делается с внутренней тактовой частотой ядра, чтобы пользователь не пытался подать на входы Т0/Т1 частоту выше внутренней.
Вопрос - как можно использовать такой прескалер, при каких режимах, с какими прерываниями.
Во всех режимах, со всеми прерываниями.
Гуглил про "внешний источник синхронизации Tn_FALLING/Tn_RISING" - информации не очень много.
Чего там гуглить-то??? Всё расписано в даташите, глава 17 (T0&T1 Prescalers), 15 (8-bit T0) и 16 (16-bit T1). Ну подали тактовую частоту не изнутри, а снаружи, вот и все дела.

Re: Таймеры/счётчики в AVR

Пт апр 14, 2023 22:24:14

Вы правы. Сам себя немного запутал. Протеус виноват. Не показывал в режиме реального времени. Взял симулятор полегче SimulIDE и картина прояснилась. Просто тестирую библиотечку (ссылка на мой Google-диск) TimerHelpers.h. Все режимы проверил, а на таком застрял. Оказывается все очень просто.
Код:
/* ATmega328P/ATmega2560   AtmelStudio  -std=c++14 */
#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include "E:\lib\src\AVR\GPIO.h"
#include "E:\AVR_PWM\Timers328(test)\src\TimerHelpers.h"

// Частота регулируется предделителем. Режим 1
// для F_CPU 16000000
// clk/1    - 31,4 kHz,
// clk/8    - 3,9  kHz,    16000000/8    = 2000000 Hz
// clk/64   - 490  Hz,     16000000/64   =  250000 Hz
// clk/256  - 122  Hz,     16000000/256  =   62500 Hz
// clk/1024 -  30  Hz      16000000/1024 =   15625 Hz

TimerHelper16<1, PRESCALE::Tn_RISING, (PORT::SET_A_ON_COMPARE | PORT::SET_B_ON_COMPARE)> timer1;
   
 GPIO<BOARD::OC1A> OC1A;  // PinB1
 GPIO<BOARD::OC1B> OC1B;  // PinB2
 GPIO<BOARD::T1> T1;      // PinD5

int main(void){
   
// Порты на вывод
OC1A.output();
OC1B.output();

T1.input();
T1.high();

timer1.setMode<TimerControlRegister::TCCR_1A, TimerControlRegister::TCCR_1B>();
TCNT1 = 0; // 256 max

OCR1A = 200;
OCR1B = 200;

  while (1) {  }
      
return 0;   
}

Страница оригинала Timers and counters
Файла отсюда ->TimerHelpers.zip. Я лишь применил приемы метапрограммирования, строгой типизации ну и ещё там чего.. Вроде как фурычит, да и ничего в коде менять не надо при изменении микроконтроллера. Применимо для ATmega328P/ATmega2560. AtmelStudio -std=c++14.
Вложения
TEST-2.png
(33.45 KiB) Скачиваний: 32

Re: Таймеры/счётчики в AVR

Вт май 09, 2023 16:19:30

очень осмысленно

Приветствую.
Вроде как в стандарте писали про битовые поля. Что если размер битового поля не влезает в int то оно приводится к uint.

Re: Таймеры/счётчики в AVR

Чт июн 01, 2023 11:34:14

Проблема заключается в том, что меняя переменную fG частота на ножке PB0 остается одной и той же(244Гц), хотя я и меняю значение переменной, участвующей в расчете значения регистра сравнения OCR1A. Формула расчета тоже довольно простая, взята из даташита. На данный момент я бы хотел решить 2 проблемы:
1) Возможность задания частоты переменной fG.
2) Возможность задания выхода частоты с МК переменной nG.
PS: значение переменных nG и fG будут менятся по SPI(код еще не написал), интересен сам принцип подобной организации задержек.

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:03:04

warptred12, у тебя обновление регистров не там записано, или в ветвление их внеси или из цикла убери...
а флоаты там действительно нужны? как-никак 75% флеша поели....

Добавлено after 3 minutes 28 seconds:
да, и строка OCRnx_calc = ceil((TimDiv/Foc) - 1); не нужна...
хватит и OCRnx_calc = TimDiv; наверно... если я правильно понял замысел

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:13:53

Ivanoff-iv писал(а):warptred12, у тебя обновление регистров не там записано, или в ветвление их внеси или из цикла убери...
а флоаты там действительно нужны? как-никак 75% флеша поели....

Добавлено after 3 minutes 28 seconds:
да, и строка OCRnx_calc = ceil((TimDiv/Foc) - 1); не нужна...
хватит и OCRnx_calc = TimDiv; наверно... если я правильно понял замысел

Код:
#include <tiny2313.h>
#include <math.h>
#include <io.h>
#include <delay.h>

#define F_CPU (8000000)
#define   VFG_TIMER_MAX (65535)
#define   VFG_PIN0 PORTB0
#define   VFG_PIN1 PORTB1
#define   VFG_PIN2 PORTB2
#define   VFG_DDR DDRB
#define   VFG_PORT PORTB

unsigned int fG=100;
unsigned char nG;
unsigned int N[]={1,8,64,256,1024};

void Tim1Init(void)
{
    VFG_DDR = (1<<VFG_PIN0); // set pin as OUTPUT
    TCCR1A = (1<<COM1A0); //toggle on compare
    TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10); // set timer CTC mode
    TIMSK = (1<<OCIE1A);
    //SetUpTim1A(0);
    #asm("sei")   
}

void SetUpTim1A(unsigned int Foc)    //set value OCR1A register
{
 unsigned int TimDiv;
 unsigned char ClockSelect=0;
 unsigned char i=0;
 for(i=0;i<=4;i++) {
    TimDiv=(F_CPU/(2*Foc*N[i])-1);
    if(TimDiv >= 0 && TimDiv<VFG_TIMER_MAX){
     ClockSelect=i+1;
     break;
     OCR1A = TimDiv;
     TCCR1B = (1<<WGM12) | ClockSelect;
    }
    }
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    VFG_PORT ^= (1<<VFG_PIN0);
}

void main(void)
{
 unsigned char nG;
 Tim1Init();

   
#asm("sei")
while(1)
{
        fG=200;
        SetUpTim1A(fG);
        delay_ms(50);
        }
}

Ну как-то так получается, ceil'ом хотел знаки убрать после запятой, но они же и так должны по идее отпасть. Но результат получается все тот же, 244 герца. Уже несколько дней вожусь с этой шляпой, не могу понять, что не так. Можете объяснить где в коде должны обновляться регистры?

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:31:09

есть 2 варианта
1) если при вводе недопустимо маленькой частоты (например 0) нужно остановить генерацию то нужно вынести за пределы цикла (просто перенести закрывающую цикл скобку на 3 строки вверх)
2) если при вводе недопустимо маленького значения его нужно проигнорировать, то обновление регистров надо внести в условие, но поставить надо до брейка, а не после.

Добавлено after 5 minutes 30 seconds:
второй вариант вашего кода совсем негоден - там условие не выполнится никогда, т.к. переменная просто переполнится

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:45:55

есть 2 варианта
1) если при вводе недопустимо маленькой частоты (например 0) нужно остановить генерацию то нужно вынести за пределы цикла (просто перенести закрывающую цикл скобку на 3 строки вверх)
2) если при вводе недопустимо маленького значения его нужно проигнорировать, то обновление регистров надо внести в условие, но поставить надо до брейка, а не после.

Добавлено after 5 minutes 30 seconds:
второй вариант вашего кода совсем негоден - там условие не выполнится никогда, т.к. переменная просто переполнится

ваш вариант помог, спасибо, а как мне в прерывании
Код:
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    VFG_PORT ^= (1<<VFG_PIN0);
}
дергать другими ножками в зависимости от переменной ng?

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:52:52

а как надо дёргать?
nG это номер ноги или маска?
задействован весь порт?
обнулять неиспользуемые ноги надо? (в момент переключения ноги там ведь и 1 может остаться)

Добавлено after 3 minutes 15 seconds:
ПС:
1) не цитируй прошлое сообщение, ответ итак подразумевает, что он следует за прошлым сообщением.
2) не цитируй всё сообщение, допустимо выделять только главную мысль (иногда допустимо выделять г.м. и в прошлом сообщении)
за полное цитирование могут забанить.

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 10:55:09

я хочу чтобы в зависимости от значения переменной nG частота генерировалась на определенной ножке контроллера, напрмер: при nG=0, мы генерируем частоту заданную пременной fG на ножке PB0, при этом все остальные ножки отключаются, при nG=1 на ножке PB1 и тд.

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 11:23:30

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{unsigned char msc=(1<<nG);
VFG_DDR = msc;
VFG_PORT = (VFG_PORT^msc)&(msc);
}

Добавлено after 1 minute 3 seconds:
nG придётся сделать глобальной
(локальное в майн её объявление убери)

Добавлено after 11 minutes 1 second:
для экономии времени в прерывании желательно маску msc вычислять за его пределами, например написать ф-ю её обновления (ф-ю переключатель пина) и вызывать её.

Добавлено after 3 minutes 23 seconds:
тогда это будет выглядеть так:

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 11:31:10

При симуляции в протеусе, напряжение есть только на выводе PB0, но на пинах, заданных переменной nG - напряжения нет, но на их выводах есть частота. Это протеус шалит или так и должно быть ?
Так же при задании переменной fG частот 0, 1, 2, 3 на выходе получается частоты 4, 5, 4.5, 14 Гц соответственно, а должны быть частоты 0, 1, 2, 3 Гц. Может быть у вас будут какие нибудь мысли по этому поводу. Откорректированный код прикрепляю ниже.
Код:
#include <tiny2313.h>
#include <math.h>
#include <io.h>
#include <delay.h>

#define F_CPU (8000000)
#define   VFG_TIMER_MAX (65535)
#define   VFG_PIN0 PORTB0
#define   VFG_PIN1 PORTB1
#define   VFG_PIN2 PORTB2
#define   VFG_DDR DDRB
#define   VFG_PORT PORTB

unsigned int fG=100;
unsigned char nG;
unsigned int N[]={1,8,64,256,1024};

void Tim1Init(void)
{
    TCCR1A = (1<<COM1A0); //toggle on compare
    TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10); // set timer CTC mode
    TIMSK = (1<<OCIE1A);
    //SetUpTim1A(0);
    #asm("sei")   
}

void SetUpTim1A(unsigned int Foc)    //set value OCR1A register
{
 unsigned int TimDiv, OCRnx_calc=0;
 unsigned int ret_OCRnx=0;
 unsigned char ClockSelect=0;
 unsigned char i=0;
 for(i=0;i<=4;i++) {
    TimDiv = (F_CPU/(2*16*Foc*N[i])-1);
    OCRnx_calc = TimDiv;
    if(OCRnx_calc >= 0 && OCRnx_calc<VFG_TIMER_MAX){
     ClockSelect=i+1;
     break;
    }
 }
    ret_OCRnx = (unsigned int)OCRnx_calc;
    OCR1A = ret_OCRnx;
    TCCR1B = (1<<WGM12) | (ClockSelect<<CS10);
}

void UpdateTim1A(unsigned int freq) //хранение старого значения
{
   static unsigned int fG_old = 0;

   if (fG_old != freq)
   {
      SetUpTim1A(freq);
      fG_old = freq;
   }
}

interrupt [TIM1_COMPA] void timer1_compa_isr(void){
unsigned char msc=(1<<nG);
VFG_DDR = msc;
VFG_PORT = (VFG_PORT^msc)&(msc);
}

void main(void)
{
 static unsigned int fG_old = 0;
 Tim1Init();
 UpdateTim1A(fG);
 
#asm("sei")
for(;;) {
 if (fG_old != fG) {   //проверка, не изменилось ли старое значение
    SetUpTim1A(fG);
    fG_old = fG;
 }
 nG=0; //номер генератора
 fG=4;  //частота генератора
 SetUpTim1A(fG);
 delay_ms(50);
 }
}

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 11:42:03

в коде приберись, должно заработать...

Добавлено after 59 seconds:
длинные портянки стоит заворачивать в спойлер, так проще потом ориентироваться на странице

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 11:45:37

Спасибо за помощь, столько проблем помогли решить :chmoked:

Re: Таймеры/счётчики в AVR

Пт июн 02, 2023 11:46:22

:beer:

Re: Таймеры/счётчики в AVR

Пт авг 25, 2023 17:42:51

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

Так вот, есть робот на старой ArduinoNANO. Среда ардуина считает его как ATmega328P. Хочу снять механические характеристики - зависимость скорости от "приложенного напряжения". Напряжение устанавливается функцией
Код:
const uint8_t MOTOR_RIGHT_PWM = 10;
const uint8_t MOTOR_LEFT_PWM = 9;
analogWrite(MOTOR_RIGHT_PWM, pwm);
Ну и по схеме они подключены к A9-A10. Частота ШИМ настраивается записью в TCCR1B - это первый таймер?

Так, теперь как измерить скорость? у моторов есть два датчика холла которые объединены исключающим ИЛИ и заведены на D2, D3 (левый/правый) и один из дачиков заведен отдельно на D4, D5 (тоже левый/правый). Можно ли при таком включении задействовать какой из таймеров с захватом, чтобы измерить периоды импульсов (хотя бы одного колеса!). В самом роботе тахометры дают просто прерывание по перепаду уровня и просто считается расстояние (не скорость!).

схема включения

Ожидаемая частота импульсов: максимальные обороты моторов около 30 тысяч в минуту, т.е. 500 оборотов в секунду и магнитный диск имеет 6 полюсов - т.е. 3000 отсчетов в секунду.

Беглый просмотр даташита мне оптимизма насчет таймера 0 и 2 не дал. Похоже, единственная надежда на один канал захвата таймера 1...

Re: Таймеры/счётчики в AVR

Сб авг 26, 2023 07:12:58

Можно использовать захват, если в качестве формирования периода ШИМ не выбран режим с использованием регистра ICR1.
В Вашем случае выражение определения скорости вращения
S[1/мин]=(60/6)*Fo*Nx/nox, где
Fo- частота тактирования таймера 1
Nx- число периодов измеряемой скорости за время измерения
nox- число периодов частоты тактирования за время прохождения Nx. Определив числитель константой, нужно просто определить nox.
Например
Fo=16000000
Nx=1
p_pwm=3333 период ШИМ
начальное значение ICR1=1253
конечное значение ICR1=3253
число полных периодов p_pwm=1
nox= -1253+3333+3253=5333
S[1/мин]=160000000/5333~30'001,8
Ответить