Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/4: Рейтинг темы: голосов - 4, средняя оценка - 5.00
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
1

Atmega2560,прерывание в таймере 1 вызванное событием на выходе из компаратора

19.02.2021, 02:41. Просмотров 690. Ответов 15
Метки нет (Все метки)

Что хочу:
Измерить параметры сигнала в прерывании таймера вызванном по захвату от аналогового компаратора, т.е. целью является выделенное жирным. С выводом на дисплей как самого сигнала, так и его параметров.
Что делал:
Сначала подал сигнал на ICP4, в прерывании по захвату таймера 4 измерил частоту, вывел значение в числовом виде на дисплей.
Т.к. таймер 4 не позволяет совершить захват от компаратора, перешел на таймер 1, а у того, в свою очередь, нет на плате ножки ICP1, т.ч. пошагово переползти от таймера 4 к таймеру 1 не получилось, сразу прыжком. Сигнал от генератора теперь подал на пин ADC0, и по моей задумке он должен пройти через компаратор. Проверьте, пожалуйста, правильно ли настроил регистры, или в чем-то другом ошибка, по факту на дисплее осциллограмма сигнала получена, но с показаниями частоты беда, что-то показывается, какой-то набор редко изменяющихся констант, хотя на таймере 4 частоту показывало нормально. показания "дышали". Проверяется все сразу в железе, без симуляции.

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
//#include <math.h>
#include "n5110.h"
//--------------------
unsigned char arr [83];
unsigned int rising=0,risingL=0,risingH=0, f=0;
//volatile unsigned long risingL=0,risingH=0, rising=0;
unsigned int ADC_read(unsigned int v)
{
ADMUX |=(1<<REFS0)|(1<<ADLAR);
ADCSRA|=(1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(0<<ADIF)|(0<<ADIE)|(1<<ADPS2)|(0<<ADPS1)|(0<<ADPS0);
ADCSRA|=(1<<ADSC); 
while(!(ADCSRA & (1<<ADIF)));  
ADCSRA|=(1<<ADIF);   
return (ADC);
}
//-------------------------
 
void init_AC(void)
{
ACSR |=(1<<ACBG)|(1<<ACO)|(1<<ACIC);
//ADCSRB= 0b00000000;
}
//------------------
 
void init_PWM_timer(void)//
{
    TCCR1A=0b00000000;
    TCCR1B|=(1<<ICES1)|(1<<CS11)|(0<<WGM13)|(0<<WGM12);
        TIMSK1|=(1<<ICIE1);
}
//------------------
 
ISR (TIMER1_CAPT_vect)
{
TCNT1=0;
risingL=ICR1L;
risingH=ICR1H;
rising = risingH*256+risingL+10;
f=(unsigned int)(2000000/rising);//эта переменная выводится на дисплей
}
 
int main(void)
{
Lcd_init();
init_PWM_timer();
init_AC();
sei();
....
}
Добавлено через 9 минут
Еще из непонятного, на таймере 4 без бита TOIE4 частоту не показывало, а на таймере 1 не показывает что с ним (0Гц), что без него (константа).
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.02.2021, 02:41
Ответы с готовыми решениями:

Внешнее прерывание ATmega2560 в ASM
Добрый день! Не могу настроить прерывание по кнопке на INT0 у МК ATmega2560. Посмотрите...

непонятное прерывание от компаратора atmega128
Здравствуйте все! Делаю программу проверки активности оператора, используя два 8-разрядных...

Не срабатывает прерывание компаратора(AIN0)
Не срабатывает прерывание при подача сигнала через кнопку с подтяжкой,в результате прихода сигнала...

С# Сохранение текущего времени в таймере при выходе из программы
Доброго времени суток, у меня в программе есть таймер, допустим с интервалом 15 секунд, запускаем...

15
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
20.02.2021, 23:14  [ТС] 2
После того как в инициализации компаратора регистр ADCSRB записал в виде ADCSRB |=(1<<ACME) частоту показывать стало правдиво, но только не текущую частоту, а снимок той частоты которая подавалась от генератора в момент подачи питания на микроконтроллер. Последущее изменение частоты потенциометром показания не меняют, они стоят как памятник. Чтобы увидать новую частоту, которую задал потенциометром, нужно перевключить питание МК, либо нажать кнопку ресет на плате ардуины. Такое впечатление что вход в прерывание по захвату присутствует только какое-то непродолжительное время, а потом программа туда войти не может. Пробовал поднимать амплитуду импульсов, включал усилитель в компараторе, игрался опорным напряжением, ничего не помогает. Мысли кончились, прошу помощь зала.
0
1854 / 1179 / 114
Регистрация: 04.01.2010
Сообщений: 4,192
21.02.2021, 00:46 3
Переменная "f" должная быть volatile. Остальные, используемые в прерывании - перенесите в само прерывание. Если они используются где-то еще - тоже должны быть "volatile". И еще - читайте сразу: "rising = ICR1;" Арифметика, которую вы написали - она ни к чему. Да и вообще - делить 'long int' в прерывании - это "то" еще занятие, в AVR. Деление лучше перенести прямо перед выводом значения.

Аналоговый компаратор вообще непонятно - что Вы им хотите сделать. В описании вы пишете, что "по прерыванию компаратора", но в коде его нет...

PS: посоветую поставить Code Vision AVR и настроить все регистры согласно выбору режимов в мастере проекта. Это намного проще, чем проверять Ваши (простите) каракули битов регистров, которые на память помнят далеко не все, да еще и без комментариев ни к битам, ни к коду.
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
22.02.2021, 20:44  [ТС] 4
Код выложил полностью и причесал как советовали.
Цитата Сообщение от Voland_ Посмотреть сообщение
Аналоговый компаратор вообще непонятно - что Вы им хотите сделать. В описании вы пишете, что "по прерыванию компаратора", но в коде его нет...
Да, ошибся с названием темы, в тот момент не знал что бывает еще и прерывание в самом компараторе, отсюда путаница. В тексте первого сообщения пытался исправиться, но вышло как в поговорке "первое слово дороже второго". Если можно исправьте заголовок на следующий: "прерывание в таймере 1 вызванное событием на выходе из компаратора", это то что я пытаюсь построить.
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#define F_CPU 16000000L
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
//#include <math.h>
#include "n5110.h"
//--------------------
unsigned char arr [83];
volatile unsigned int f=0;
unsigned int ADC_read(unsigned int v)
{
ADMUX |=(0<<REFS1)|(1<<REFS0)//установка опорного 5в
|(1<<ADLAR)//выравнивание по левому краю
|(0<<MUX4)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
 
ADCSRA|=(1<<ADEN)//включаем преобразование АЦП
|(0<<ADSC)|(0<<ADATE)|(0<<ADIF)|(0<<ADIE)
|(1<<ADPS2)|(0<<ADPS1)|(0<<ADPS0);//выбор делителя для частоты АЦП: 16000000/16
ADCSRB |=(1<<ACME)//описание этого бита нет в разделе таймер даташита, но есть в описании
//компаратора. Включил там, включил и здесь.
|(0<<MUX5);
ADCSRA|=(1<<ADSC);   // старт преобразования
while(!(ADCSRA & (1<<ADIF)));   // ждем выставление флага окончания преобразования
ADCSRA|=(1<<ADIF);   // очистим ADIF когда преобразование закончится
return (ADC); //возвращаем рассчитанное значение АЦП
}
//-------------------------
 
void init_AC(void)
{
ACSR |=(1<<ACBG)//опорное 5вольт подключаем к неинвертирующему входу компаратора, сам сигнал подается на ADC0.
|(1<<ACO)//активируем выход копаратора
|(1<<ACIC);//разрешаем совместную работу таймера 1 и компаратора
ADCSRB |=(1<<ACME);//включаем мультиплексор
}
//------------------
 
void init_PWM_timer(void)//
{
TCCR1A|=(0<<WGM11)|(0<<WGM10);//режим normal mode (overflow)
TCCR1B|=(0<<ICNC1)|(1<<ICES1)//событием для захвата является восходящий фронт сигнала
|(0<<WGM13)|(0<<WGM12)
|(0<<CS12)|(1<<CS11)|(0<<CS10);//устанавливаем частоту таймера делением на 8
TCNT1=00;
TIMSK1|=(1<<ICIE1)//прерывание таймера вызывается по событию в сигнале на выходе из компаратора
|(0<<OCIE1A)|(0<<TOIE1);
}
//------------------
ISR(TIMER1_CAPT_vect)
{
TCNT1=0;
f=ICR1;// убрал из кода вычисление частоты, просто вывожу значение ICR1
}
//--------------------
int main(void)
{
Lcd_init();
init_AC();
init_PWM_timer();
sei();
 
    while(1)
    {
        Lcd_clear();
        char buff[20];
        itoa(f, buff, 10);//вывожу f на дисплей
        Lcd_print(0, 0, FONT_1X,(unsigned char *)buff);
        Lcd_update();
//рисуем осциллограмму (ниже)    
byte col=0,str=0;// byte соответствует unsigned char из библиотеки дисплея
    unsigned int a=0,x=0,y=0,i=0;
 
    for(i =0;i<83;i++)
    {
    arr[i] =ADC_read(ICR1)/1024;//преобразование АЦП
    x=arr[i]-arr[i+1];//вычисляем разницу между двумя соседними значениями сигнала
    if(x>y)//находим макс. разницу
    {
    y=x;
    a=i;//останавливаем бег осциллограммы
    }
    }
    
    for(col=0;col<82;col++)
        {
        str=38-arr[a];//опускаю нулевое значение сигнала в низ дисплея
 
        Lcd_pixel (col,str,PIXEL_ON);//рисуем одну точку осциллограммы
        a++;
        if(a>82)
        a=0;
        }
 
    Lcd_update();
    }
     _delay_ms(200);
}
Последнее что обнаружил, если убрать из кода строчку с преобразованием АЦП
C
1
arr[i] =ADC_read(ICR1)/1024;
то показания количества тиков (ICR1) становятся показаниями в реальном времени. Если вернуть АЦП в код, то показания становятся константой, на изменение частоты не реагируют, это подробно уже описывал. Получается что одновременно вывести осциллограмму сигнала и текущее значение его частоты мне недоступно. Либо то, либо другое. Почему так?
Переменные объявлял всеми возможными способами, на основную проблему это никак не влияет.
0
Миниатюры
Atmega2560,прерывание в таймере 1 вызванное событием на выходе из компаратора  
1854 / 1179 / 114
Регистрация: 04.01.2010
Сообщений: 4,192
22.02.2021, 21:34 5
Цитата Сообщение от mode2 Посмотреть сообщение
TIMSK1|=(1<<ICIE1)//прерывание таймера вызывается по событию в сигнале на выходе из компаратора
|(0<<OCIE1A)|(0<<TOIE1);
а где хендлер прерывания?
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
22.02.2021, 23:20  [ТС] 6
Строки 51-55 разве не он?
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
23.02.2021, 11:06 7
а что эта строка делает?
C
1
arr[i] =ADC_read(ICR1)/1024;
Добавлено через 21 минуту
и зачем в функцию передаётся ICR1?

Добавлено через 12 минут
допустим в ADC у нас 50.
что будет в arr[i]?
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
23.02.2021, 19:28  [ТС] 8
Цитата Сообщение от Grey Посмотреть сообщение
а что эта строка делает?
arr[i] =ADC_read(ICR1)/1024;
А это уже зашквар, конечно же так:
77 arr[i] =ADC_read(ADC)/1024;
Оно так и было изначально, просто уже запутался. Все сказанное мной выше в описании проблемы справедливо и для исправленного аргумента.
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
23.02.2021, 22:23 9
Цитата Сообщение от mode2 Посмотреть сообщение
ADC_read(ADC)
функция возвращает значение ADC. зачем его передавать в функцию?
тем более внутри функции это значение не используется.
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
23.02.2021, 23:02  [ТС] 10
Действительно, зачем. В таком виде будет корректно?
77 arr[i] =ADC_read(1)/1024;
Но вывод переменной f в реальном времени от этого не появился.
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
24.02.2021, 00:25 11
раз не используется, правильней так
C++
1
arr[i] =ADC_read()/1024;
проблема не там.
мне больше интересен этот вопрос
Цитата Сообщение от Grey Посмотреть сообщение
допустим в ADC у нас 50.
что будет в arr[i]?
Добавлено через 1 час 6 минут
https://chipenable.ru/index.ph... r/item/193
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
24.02.2021, 17:57  [ТС] 12
Цитата Сообщение от Grey Посмотреть сообщение
допустим в ADC у нас 50.
что будет в arr[i]?
Будет 0.

Добавлено через 2 минуты
Цитата Сообщение от Grey Посмотреть сообщение
раз не используется, правильней так
arr[i] =ADC_read()/1024;
В таком виде получаю error
... too few arguments to function 'ADC_read'
Добавлено через 4 минуты
Напрашивается вывод, что если не будет корректного АЦП преобразования таймер не увидит фронты, и следовательно не будет захвата. Так?

Добавлено через 5 минут
С другой стороны, частоту показывает корректно как раз в то время когда я вообще удаляю строку с АЦП преобразованием, например, вместо:
arr[i] =ADC_read(0);
запишу:
arr[i] =5;
Изображения сигнала естественно теперь нет, но частота - реальна.
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
24.02.2021, 18:49 13
Цитата Сообщение от mode2 Посмотреть сообщение
В таком виде получаю error
а функцию исправил?
C
1
2
3
unsigned int ADC_read(void){
//код
}
Цитата Сообщение от mode2 Посмотреть сообщение
Будет 0.
вот я и не понимаю как строится осциллограмма.
может так попробовать
C
1
arr[i] =ADC_read()/32;
0
1 / 1 / 0
Регистрация: 28.03.2015
Сообщений: 93
24.02.2021, 22:45  [ТС] 14
Я тут подумал, если я пропускаю сигнал через компаратор, что я собственно собираюсь после него АЦПировать? Там и будет либо 0, либо единица. А то что я считаю осциллограммой сигнала, может просто является выходом компаратора? Просто сигнал подаю прямоугольный, и у компаратора на выходе тоже прямоугольный будет, при любом сигнале на входе, хоть синусоиду подавай.
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
25.02.2021, 11:51 15
C
1
str=38-arr[a];//
думаю там от 0 до 1023.
от 38 отнять единицу, такая осцилограмма не получится.
хотя я и сейчас не понимаю как она получается.
0
Тутошний я
1982 / 1085 / 200
Регистрация: 03.11.2009
Сообщений: 3,757
Записей в блоге: 2
25.02.2021, 21:57 16
короче, подсчёт частоты придётся делать програмно.
чтоб включить компаратор нужно в ADEN записать 0.
но при этом АЦП не работает.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.02.2021, 21:57

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Предусмотреть возможность изменения компаратора (реализация компаратора в виде передаваемой в подпрограмму функции)
**Реализовать сортировку данных с помощью &quot;пузырькового&quot; алгоритма. (Сделал) **Реализовать...

Рассчитать напряжение на выходе . Изобразить график напряжения на выходе
Рассчитать напряжение на выходе(поподробнее) . Изобразить график напряжения на выходе. На схеме...

Перехват события вызванное программы
Добрый день! Хочу написать для программы на c# функционал на плюсах, который будет вызывать...

Исключение , вызванное ViewBag.Title
Всем доброго времени суток. Подскажите пожалуйста в чем может быть ошибка. Исходник не выкладываю...

Как разрушить вызванное popup - окно?
Помогите люди... как сломать окно popup чтоб то что в него подгружается выгружалось из документа...

Некорректное вычисление суммы, вызванное неоправданным округлением
Добрый вам вечер господа. Помогите, не могу понять. По умолчанию в форму Text9, Text3, Text4...


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

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

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