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

Не могу получить стабильный меандр

Вс янв 21, 2024 22:48:40

Для управления шаговым двигателем хочу сделать генератор на таймере Т1
Atmega 8. На вход АЦП поступает напряжение с ползунка потенциометра.
После АЦП переменная меняет регистр OCR1A,т.е. частоту на ножке выхода АЦП
В Протеусе симуляция нормальная,но в железе постоянно срывается генерация.
Возможно я зря затеял генератор на таймере, но рассчитывал получить удобный способ регулировки скорости.
для шаговика. Может быть есть более надёжные варианты .Прошу совета или помощи
у более опытных пользователей.
Спасибо.
Вложения
F001_proteus.rar
(20.67 KiB) Скачиваний: 29
GccApplication1.rar
(18.51 KiB) Скачиваний: 30

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 07:18:44

Стоит поставить небольшой конденсатор на измерительную ножку около процессора, а так же снизить частоту АЦП. При условии, что резистор вообще исправен.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 12:21:48

Спасибо за ответ,но ,к сожалению , проблема не решилась заменой потенциометра ,микроконтроллера ,снижением частоты АЦП и подбором емкости на входе АЦП.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 12:22:34

Proteus не у всех стоит. Поэтому, просьба. Выложить схему картинкрй.
Как вы, определили, что срыв генерации? Опишите подробно, что происходит на железе.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 13:48:54

Код читать лень, даже rar не открывал.

Совет, может будет полезно.

Для поиска проблемы выбрасывайте из кода "все лишнее".
У вас на ножке выхода таймера неправильный сигнал? Зачем Вам при поиске проблемы в этом случае какой то АЦП? Перепишите чтение АЦП, сначала считайте, что из АЦП считывается константа и добейтесь, чтобы на ножке было то, что Вы задумали. Потом, сделайте так, что из АЦП считывается какая-то последовательность, для которой легко проконтролировать сигнал на выходной ножке таймера, т.е. понять, что для этого конкретного тестового сигнала, на выходе таймера сигнал именно такой, как и задумано.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 14:34:08

Изображение

Добавлено after 9 minutes 19 seconds:
Изображение

Добавлено after 38 seconds:
Изображение

Добавлено after 53 seconds:
Изображение

Добавлено after 1 minute 12 seconds:
Изображение

ВИДЕО НЕ СМОГ ЗАГРУЗИТЬ

Добавлено after 3 minutes 59 seconds:
Изображение

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 14:34:46

Для начала всё же покажите в читаемом виде схему и программу. Авось видео и не понадобится вовсе.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 15:53:25

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

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 16:41:38

тут мы делали радиоуправление... viewtopic.php?f=28&t=190542
подключали разные моторы))

конкретно по теме вопроса:

имеем код:
Код:
#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t i;
void adc_ini (void)
{
   /*** Настройка АЦП ***/
   ADCSRA |= (1 << ADEN) // Включение АЦП
   |(1 << ADPS1)|(1 << ADPS0);    // предделитель на 8
   ADMUX |= (0 << REFS1)|(1 << REFS0) // внешний ИОН
   |(1 << MUX0)|(1 << MUX1); // вход PC3
}

void adc (void)
{
   ADCSRA |= (1 << ADSC);  // Начинаем преобразование
   while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
   i = (ADCL|ADCH << 8); // Считываем  ADC
}

void Counter0_init()
{
   TCCR1B |= (1 << CS12);
   TCCR1B &= ~(1 << CS11);
   TCCR1B &= ~(1 << WGM10);
   TCCR1B &= ~(1 << WGM11);
   TCCR1B |= (1 << WGM12);//режим СТС
   TCCR1B &= ~(1 << WGM13);
   TCCR1A &= ~(1 << COM1A1);
   TCCR1A |= (1 << COM1A0);
   DDRB |= (1 << PB1);
}
// инициализация блинков
void blink_ini(void)
{
   DDRB|=(1<<PB1);
}
void blink (void)
{
   uint16_t u= i;
   OCR1A = u;
   Counter0_init();
}




int main(void)
{
   DDRD|=(1<<PD0)|(1<<PD1);
   adc_ini ();
   blink_ini(); // инициализация блинков
   sei();// глобально разрешить прерывания
   
   while(1)
   {
      adc ();
      blink ();
   }
}

для стабильной работы рекомендуется синхронизировать таймер с частотой опроса АЦП...
для этого есть два варианта:
1- измерять АЦП в прерывании таймера - для этого надо засунуть функцию adc (); в обработчик прерывания таймера.
2- измерять АЦП в главном цикле - для этого надо опрашивать флаг переполнения таймера.

вместо этого:
Код:
   while(1)
   {
      adc ();
      blink ();
   }

пишем типа этого:
Код:
   while(1)
   {
            while (!(TIFR1 & 0b00000001)); // флаг TOV1 - верхний предел счета TOV1.
            TIFR1 |= 0b00000001;              // сброс флаг TOV1
            adc ();
            blink ();
   }

в этом случае АЦП и таймер оказываются синхронизированы.
при этом всё работает стабильно. Проблем нет))
:tea:
Вложения
main.c
(1.15 KiB) Скачиваний: 22

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 17:06:32

Можно обновлять регистр сравнения в прерывании TIM1_COMPA. А запуск преобразования оставить в While.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 17:27:27

можно... можно по всякому))
в радиоуправлении мы использовали все возможные варианты... и в главном цикле... и в прерывании... и обновляли регистр сравнения в прерывании... и т.д.
подключали к таймерам разные моторы и приводы... синтезировали различные сигналы (PPM)... синтезировали звуковые сигналы (мелодии) в режиме СTС...
и т.д. и т.п. ))
у нас всё работает стабильно. Потому что у нас всё жёстко синхронизировано.
:tea:

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:00:14

С флагами прерывания я раньше не работал,но вначале поместил функцию adc () в обработчик прерывания по переполнению таймера Т2.

ISR(TIMER2_OVF_vect)
{
adc ();
}
Затем заменил флаг переполнения Т1 TOV1 на флаг OCF1A,т.к. имеет место прерывание по СТС.

while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
TIFR |=(1<<OCF1A); // сброс флаг OCF1A
adc ();
blink ();
В результате генерация пропала вообще.
Таймер Т1 в режиме СТС без связи с АЦП с помощью потенциометра работает нормально,при записи в OCR1A любого числа(от 1 до 16 бит) на выходе есть устойчивая генерация с расчетной частотой.
Я ранее использовал этот код для получения определенного набора фиксированных частот с помощью оператора switch и кнопки,причем АЦП работал в режиме измерения напряжения батареи питания.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:06:15

Я один обратил внимание на какую-то дичь, типа постоянного вызова инициализации таймера в главном цикле?

Код:
void blink (void)
{
   uint16_t u= i;
   OCR1A = u;
   Counter0_init(); //!!!
}

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:07:45

Изображение

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:11:15

Ну зачем сразу "дичь". Человек начинает. Не получается пробует как умеет.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:25:59

Да metan прав,я убрал из blink() и соответственно из цикла while() Counter0_init() и поместил его в main, но это просто упрощает ,хотя тоже имеет значение

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 20:40:57

Можно тоже выскажусь. Вероятно, просто пропустил эти моменты в Вашем листинге.
1. Надо организовать программу обработки прерывания от таймера как советовал Gennadiy. Там и только там вносить в регистр OCR1A новое значение из локальной переменной (пусть это будет ADC_OCR1A).
2. Работу АЦП, как советовал Gennadiy, оставить в main(), НО! Отсчеты АЦП должны поступать в кольцевой буфер длиной 8-32 значений АЦП.
3. После помещения туда каждого нового значения АЦП осуществляем передвижение указателя по кольцевому буферу (по кругу). После каждого такого размещения - усреднение по всему буферу. Среднее значение в локальную переменную ADC_OCR1A. Всё - обратная связь замкнулась!
Для начала сам сделал бы п2 и п3 и вывел бы ADC_OCR1A на UARТ или, если есть библиотеки, на какое-нибудь устройство типа индикатора.
И отдельно следует проверить работу таймера при фиксированном ОCR1A. Лично я эмуляторам не доверяю.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 21:35:53

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

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 21:42:24

Таймер работает нормально, но, как правильно заметил roman.com, не было синхронизации работы таймера с получением результата преобразования (т.к. преобразование ADC работает быстрее таймера). Поэтому регистр сравнения таймера успевал обновляться несколько раз за один свой период. Что получалось, если новые данные были выше, то таймер, получив новое значение, досчитывал до него и формировал сигнал на выходе. А вот если новые данные были ниже, текущего состояния счетного регистра, то таймеру ничего не оставалось, как сделать полный круг без сигнала совпадения, т.к. такового не было. И только на следующем круге совпадение могло сработать, если данные из преобразования не менялись. Точно такой же глюк мог происходить на границе совпадения, за один такт до события.

Re: Не могу получить стабильный меандр

Пн янв 22, 2024 22:26:58

Спасибо С.Н.
Вот теперь буду вникать в теорию,
связанную с таймером и прерываниями.
Мне явно не хватает знаний. по Си.
А что касается кольцевого буфера,я
только встречал иногда этот термин на форумах,теперь придется заняться этим
вплотную.

Вам в личку забросил листинг. Правда он для Arduino, и Ардуинщики справедливо будут ругаться. Там прерывание и кольцевой буфер. В работе не пробовал. Компилируется. Просто как пример слёту.
Ответить