Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
1

Как вызвать функцию через промежуток времени?

06.01.2020, 06:09. Просмотров 878. Ответов 65
Метки нет (Все метки)

Даже не то чтобы вызвать, а две булевые переменные чтобы сбрасывались/устанавливались через 40000мс и 20000мс.
40000мс true потом 40000мс false, и т.д.

Я понял, что можно считать в main, да только там занято и непонятно сколько времени тратится на обработку кода в цикле.
Гуглил, есть способ с использованием счётчиков таймеров, но тут тоже что-то используется.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#if defined(AT168_COMPATIBLE)
#define mustPollControllers()   (TIFR2 & (1 << OCF2A))
#define clrPollControllers()    do {TIFR2 = 1 << OCF2A;} while(0)
#else
#define mustPollControllers()   (TIFR & (1 << OCF2))
#define clrPollControllers()    do {TIFR = 1 << OCF2;} while(0)
#endif
 
int main(void)
{
    //...
    while(1)
    {
        //...
        if(mustPollControllers())
        {
            clrPollControllers();
            //...
        }
        //...
    }
    return 0;
}
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.01.2020, 06:09
Ответы с готовыми решениями:

Плавное включение шим, за заданный промежуток времени.
Всем доброй ночи. У меня такой вопрос : как написать код на Си, для плавного включения ШИМ к...

Как вызывать метод (функцию) в определенный промежуток времени?
То есть каким способом можно вызывать функцию, например, раз в секунду. Предположим есть цикл...

Как вывести строку через промежуток времени?
Здравствуйте! как вывести строку через промежуток времени? пр: 1) $f = @fopen(&quot;1.txt&quot;, &quot;r&quot;); ...

Как менять случайное число через какой-то промежуток времени?
как менять случайное число через какой то промежуток времени на C# ? Добавлено через 31 минуту...

Архивирование записей из БД, через определённый промежуток времени. Как лучше сделать?
Предположим есть БД, в которую сервер сливает данные из большого кол-ва однотипных источников....

65
microsystems
6 / 5 / 1
Регистрация: 26.12.2019
Сообщений: 11
06.01.2020, 09:26 2
"Тут" используется таймер 2, который "тикает" и через равные промежутки времени устанавливает флаг OCF2.
В главном цикле этот флаг проверяется. Если флаг установлен, значит заданный интервал отсчитан. Снимаем флаг и снова ждем установки флага. Таким образом имеем заданную периодичность.
1
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
06.01.2020, 16:39  [ТС] 3
Спасибо, мне стало чуть понятней(без сарказма), собирался почитать что это за фигня.

А для чего это делать в цикле, do на сколько мне известно выполняется 1 раз.
Не проще просто:
C
1
TIFR = 1 << OCF2;
Чем городить какую-то ерунду:
C
1
do {TIFR = 1 << OCF2;} while(0)
0
microsystems
6 / 5 / 1
Регистрация: 26.12.2019
Сообщений: 11
06.01.2020, 16:43 4
Да, правильно, "ту" фигню городить не нужно. Это кто-то от большого ума нагородил.
1
06.01.2020, 16:43
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
06.01.2020, 17:23  [ТС] 5
В даташите сказано, что Atmega8 имеет 3 счётчка/таймера(я так понял можно использовать как таймер, или счётчик времени).
Два таймера по 8 бит и один 16 битный.
– Two 8-bit Timer/Counters with Separate Prescaler, one Compare Mode
– One 16-bit Timer/Counter with Separate Prescaler, Compare Mode, and Capture
Либо я неправильно понял, и таймера всего 2 по 8 бит, но если нужно, то будет один, но 16 битный.

В моём случае в коде используется один из 8 битных таймеров TIFR2.
Получается TIFR1 и ещё один(если их всё таки 3) 16 битный свободны?
0
microsystems
6 / 5 / 1
Регистрация: 26.12.2019
Сообщений: 11
06.01.2020, 17:42 6
В ATmega8 три таймера/счетчика: два 8-битных и один 16-битный.
Счетчик потому, что может считать импульсы с внешнего входа. Т.е., когда приращение счетного регистра TCNTn выполняется от внешнего сигнала, подключенного ко входу Tn.

Да, если 8-битный таймер 2 уже используется, то в запасе остается еще 2 таймера: 8-битный таймер 0 и 16-битный таймер 1.
1
COKPOWEHEU
2239 / 1349 / 306
Регистрация: 09.09.2017
Сообщений: 5,358
07.01.2020, 00:56 7
Цитата Сообщение от microsystems Посмотреть сообщение
Да, правильно, "ту" фигню городить не нужно. Это кто-то от большого ума нагородил.
Все он правильно нагородил. do{...}while(0) - стандартная обертка для макросов, страхующая от ошибок.
Например, есть макрос #define SET_LEDS() LED1=1; LED2=1. Если его вызывать просто в коде, ничего плохого не случится. А если по условию if(x) SET_LEDS();? Легко увидеть, что такой вариант развернется в if(x) LED1=1; LED2=1;, причем вторая операция выполнится в любом случае, независимо от условия.
Попробуем добавить фигурные скобки: #define SET_LEDS() {LED1=1; LED2=1;}. Теперь обычное условие сработает нормально. А если там есть блок else? if(x)SET_LEDS(); else x=1;. Такая конструкция развернется в if(x) {LED1=1; LED2=1;}; else x=1;, что приведет к ошибке компиляции.
А вот если "нагородить" обертку #define SET_LEDS() do{LED1=1; LED2=1;}while(0), получим if(x) do{LED1=1; LED2=1;}while(0); else x=1;. И уже такой код выполняется нормально.
Можно возразить, что для одной команды это избыточно, но уж лучше сразу привыкнуть к правильному стилю.
2
microsystems
6 / 5 / 1
Регистрация: 26.12.2019
Сообщений: 11
07.01.2020, 10:22 8
А зачем вы меняете условия? Там была всего одна логическая операция сброса флага. Вы же привели пример с двумя операциями. А между тем, задача была разобраться с таймерами, а не с макросами. Вот когда будет тема про макросы, то там и будете умничать. А в данном случае эти макросы нужно вообще выкинуть из кода, дабы не загромождать текст.
1
COKPOWEHEU
2239 / 1349 / 306
Регистрация: 09.09.2017
Сообщений: 5,358
07.01.2020, 12:44 9
Цитата Сообщение от microsystems Посмотреть сообщение
А зачем вы меняете условия? Там была всего одна логическая операция сброса флага.
Перечитайте последнее предложение моего предыдущего поста, ответ на ваш вопрос там.
Цитата Сообщение от microsystems Посмотреть сообщение
А в данном случае эти макросы нужно вообще выкинуть из кода, дабы не загромождать текст.
Если макрос назван осмысленно (в данном случае лично мне название не кажется удачным), замена им даже одной команды имеет смысл для улучшения читаемости, причем без накладных расходов.
0
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
07.01.2020, 18:01  [ТС] 10
Запутался.
Эти дебильные даташиты - ничего не понятно.

У меня Atmega8-16ua с внешним кварцем в 12мГц.
Функцию мне нужно вызывать с частотой 12,5Гц, каждые 0,08с.

В счётчике есть делитель частоты, максимально 1024.
12000000Гц / 1024 = 11718,75Гц.
Счётчик 8битный.
1с / 11718,75Гц = 0.00008533333 раз в секунду * 255 = 0.02176 вместимость счётчика.

Беру 2 сотые секунды.
0.02 / 0.00008533333 = 234.375009155

Получается так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
bool turboslow[2] = {0, 0};
int counter[2] = {0, 0};
 
int main(void)
{
    TCNT0 = 0;
    TCCR0 = 0b00000101; // Таймер0 - 8 бит. Делитель 1024 такта.
 
    while(1)
    {
        if(TCNT0 >= 234) // Если насчитало 234 раза по 1024 такта
        {
            TCNT0 = 0; // Сбросить счётчик
            
            if(++counter[0] > 3) // Вызывается каждые 0,08с т.е. 12,5Гц
            {
                counter[0] = 0; // Сбросить счётчик
                turboslow[0] = !turboslow[0] // Поменять значение переменной
                
                if(++counter[1] > 1) // Вызывается каждые 0.16c т.е. 25Гц
                {
                    counter[1] = 0; // Сбросить счётчик
                    turboslow[1] = !turboslow[1]; // Поменять значение переменной
                }
            }
        }
    }
    return 0;
}
Не понятно как делитель выставлять и сказать, чтобы от внешнего кристалла считал.
12121212121212.jpg

И ещё не понятно с кодом, который уже есть.
Убрал дефайны для более удобного чтения, и я ошибся у меня используется счётчик TIFR, а не TIFR2, т.к. AT168_COMPATIBLE не определён.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(void)
{
    TCNT2 = 0;
    TCCR2 = (1 << WGM21) | (1 << CS22) | (1 << CS21) | (1 << CS20); // Таймер2 - 8 бит.
    OCR2 = 196; // 60 Гц
    
    //...
    while(1)
    {
        //...
        if(TIFR & (1 << OCF2))
        {
            TIFR = 1 << OCF2;
            //...
        }
    }
    return 0;
}
Не понятно что устанавливается в TCCR2(в даташите ничего нет про 4й бит).
C
1
2
3
4
5
TCCR2 = (1 << WGM21) | (1 << CS22) | (1 << CS21) | (1 << CS20);
//>>>
TCCR2 = (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
//>>>
TCCR2 = 0x00001111;
Потом OCR2, это же не имеет никакого отношения к счётчику?
Я нагуглил, что это заполнение сигнала ШИМ.

Ну и вот это:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if(TIFR & (1 << OCF2))
{
    TIFR = 1 << OCF2;
    //...
}
//>>>
if(TIFR & (1 << 7))
{
    TIFR = 1 << 7;
    //...
}
//>>>
if(TIFR & 128)
{
    TIFR = 128;
    //...
}
//>>>
if(TIFR & 0x10000000)
{
    TIFR = 0x10000000;
    //...
}
Что такое TIFR, и почему бы не сделать так:
C
1
2
3
4
5
if(TIFR > 127)
{
    TIFR = 128;
    //...
}
0
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
07.01.2020, 19:57  [ТС] 11
Не учёл, что 12,5гц - это нажатие и отжатие вместе, посчитал неправильно. Ну увеличу в 2 раза.
0
sharpey
385 / 175 / 37
Регистрация: 21.09.2008
Сообщений: 574
07.01.2020, 19:59 12
Найдите в Сети скан книги на русском языке "Программирование микроконтроллеров ATMEL на языке С", автор Прокопенко Вадим Сергеевич, изд-ва МК-Пресс и Корона-Век, 2012. -320 с.. Там как раз со стр. 31 разбираются примеры расчётов параметров для счётчиков TCNT0/1/2 для учета времени и настройки ШИМ. Применительно к AT90S2313, но суть одна.
1
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
07.01.2020, 22:05  [ТС] 13
Да вроде всё правильно сделал, единственное проверить не могу, идиотский протеус пишет ошибку:
Invalid opcode 0xFFFF at PC=0x1F02 на 0.004085416с.

Прицепил светодиод на свободную ногу, и в самый верх main:
C
1
2
3
DDRD  |= 0b00000100;
PORTD |= 0b00000100;
_delay_ms(12000000);
И всё равно ошибка сразу же.
Гуглил говорят стек куда-то выпадает, а где его искать - х.з.
0
COKPOWEHEU
2239 / 1349 / 306
Регистрация: 09.09.2017
Сообщений: 5,358
08.01.2020, 10:16 14
Цитата Сообщение от артист Посмотреть сообщение
Эти дебильные даташиты - ничего не понятно.
попробуйте поискать Евстифеева "микроконтроллеры AVR семейства Mega"
1
sharpey
385 / 175 / 37
Регистрация: 21.09.2008
Сообщений: 574
08.01.2020, 10:41 15
Цитата Сообщение от артист Посмотреть сообщение
_delay_ms(12000000);
А ничего, что здесь написано, что максимальная продолжительность задержки в функции _delay_ms будет (262.14 ms / F_CPU), где F_CPU в мегагерцах? Т.е. на 20 МГц "камне" максимальная задержка будет 13,107 миллисекунд.
Делайте цикл на 1200000 вызовов с задержкой на 10 мс, что и даст искомые 12000 с.
1
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
08.01.2020, 13:45  [ТС] 16
Всё получилось, оказалось из-за фьюзов не работало.
Хотел светодиодом посмотреть, меняются ли переменные, что-то не работает толком...
0
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
08.01.2020, 20:06  [ТС] 17
Не работает этот таймер дурацкий...
0
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
12.01.2020, 10:41  [ТС] 18
Почему эта дрянь не моргает светодиодом, а постоянно горит?

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#define F_CPU 12000000UL
 
#include <avr/io.h>
#include <util/delay.h>
 
int counter = 0;
 
int main(void)
{
    TCNT0 = 0;
    TCCR0 = (1 << CS22) | (1 << CS20); // Таймер0 - 8 бит. .Считать на подьёме.
    
    OCR2 = 196;  // 60 Гц
    
    DDRD    = 0b00000001;
    PORTD   = 0b00000001;
    
    while(1) 
    {
        if(TCNT0 > 233) // Если насчитало 234 раза по 1024 такта - 0.02с.
        {
            TCNT0 = 0; // Сбросить счётчик
 
            counter++;
            
            if(counter > 1) // Вызывается каждые 0.04c т.е. 25Гц / 2 = 12,5Гц
            {
                counter = 0; // Сбросить счётчик
 
                if(PIND3 == 1) PORTD &= ~0b00000001;
                else PORTD |= 0b00000001;
                
                int i = 0;
                
                while(++i < 10000) _delay_ms(10);
            }
        }
    }
}
0
sharpey
385 / 175 / 37
Регистрация: 21.09.2008
Сообщений: 574
12.01.2020, 18:03 19
Цитата Сообщение от артист Посмотреть сообщение
Почему эта дрянь не моргает светодиодом, а постоянно горит?
Из-за условия в строке 30. Вы сравниваете значение PIND3, определённое в заголовочном файле <avr/iom8.h> и равною трём, с единицей. Естественно, они не равны, поэтому выполняется условие после else, т.е. PORTD |= 0b00000001; устанавливает высокий потенциал на выходе ножки МК и светодиод горит. Почему? Потому что "... Я так думаю!" (с) х/ф "Мимино"
1
артист
95 / 22 / 20
Регистрация: 17.09.2014
Сообщений: 1,283
Завершенные тесты: 3
12.01.2020, 18:36  [ТС] 20
Насмотрелся видео, так можно, и так можно...
Получается надо так:
C
1
if(PIND3 & 0x01)
?
0
12.01.2020, 18:36
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.01.2020, 18:36

Как изменить фоновое изображение формы через какой-то промежуток времени?
Как изменить фоновое изображение формы в С# через какой то промежуток времени

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.