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

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

Пн янв 22, 2024 22:31:20

Спасибо С.Н.

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

Вт янв 23, 2024 10:12:02

а нафига там кольцевой буфер ? вы что собрались с ним делать ?

Добавлено after 9 hours 4 minutes 31 second:
uuu000 писал(а):while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
TIFR |=(1<<OCF1A); // сброс флаг OCF1A
adc ();
blink ();

я сказал примерно))
чтоб было точно - надо смотреть даташит...

имеем код:
Код:
#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)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}

что тут не так ?
:roll:

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

Вт янв 23, 2024 10:48:32

Все нормально, кроме постоянных зависаний в ожидании флагов. Может на прерывания перейти?

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

Вт янв 23, 2024 11:06:41

Программа осуществляет прямое управление частотой генерации некоего генератора. Все флуктуации кода АЦП будут сразу приводить в флуктуации частоты.
А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.
Источник опорного напряжения = источник питания. Если будет 10 разрядов АЦП, то шуметь он будет разряда на 3. Это всего ~4 мВ! Точность стабилизации блока питания скорее всего не лучше.
На мой взгляд, буфер тут будет и фильтровать помехи и добавит инерционный момент. Даже если Вы ручку крутанете от души, частота плавно будет перестраиваться.
Чем длиннее буфер, тем плавнее изменение.

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

Вт янв 23, 2024 11:56:28

Роман все правильно.Как я понял в внутри цикла while(1) есть еще один такой же цикл в условии которого проверяется состояние флага совпадения СТС .Кода есть совпадение счетчика и OCR1A условие цикла
обнуляется и на выходе МК появляется сгенерированный сигнал. Код в Proteus работает отлично,вплоть до OCR1A=10(при напряжении на входе АЦП около 50мВ) выдает около 1420 Гц.В железе конечно не так идеально ,ниже 500мВ (100бит) сильно гуляет частота
228-235 Гц ,при напряжении около 200-300мВ срывается до 1700Гц, возможно из за качества потенциометра или наводок при слишком низком напряжении на входе АЦП. Я не уверен что смогу управлять таким образом
шаговиком но проверить не могу- еше не получил драйверы от наших китайских " друзей".В любом случае спасибо за совет. Сейчас пока есть время (но нет драйверов ) попробую разобраться и использовать кольцевой
буфер.

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

Вт янв 23, 2024 15:16:33

Из функции blink() исключите Counter0_init().

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

Вт янв 23, 2024 16:04:51

Из функции blink() исключите Counter0_init().



Уже сделано. Спасибо.

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

Вт янв 23, 2024 17:43:36

Программа осуществляет прямое управление частотой генерации некоего генератора. Все флуктуации кода АЦП будут сразу приводить в флуктуации частоты.
А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.

1. есть программные флуктуации.
2. есть шум самого АЦП +/- 1...3 разряд
это разные вещи...

1. программные флуктуации мы устранили путём опроса флага переполнения таймера.
2. шум самого АЦП +/- 1...3 разряд... мы пока не устранили... для этого есть аппаратные и программные фильтры.
:tea:
Gennadiy писал(а):Из функции blink() исключите Counter0_init().

Из функции blink() исключите Counter1_init().... раз мы делаем на таймере 1 то писать надо правильно))

Код:
#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
}

/*** Настройка Counter1 ***/
void Counter1_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;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}


Добавлено after 4 minutes 12 seconds:
а нафига там "инициализация блинков" ?))


Код:
#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
}

/*** Настройка Counter1 ***/
void Counter1_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 (void)
{
   uint16_t u= i;
   OCR1A = u;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}


Добавлено after 4 minutes 40 seconds:
а нафига там две переменные i... u...
:dont_know:

Код:
#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t u;

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); // Ждем флага окончания преобразования
   u = (ADCL|ADCH << 8); // Считываем  ADC
}

/*** Настройка Counter1 ***/
void Counter1_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 (void)
{
   OCR1A = u;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}


Добавлено after 3 minutes 42 seconds:
вместо...
u = (ADCL|ADCH << 8); // Считываем ADC
можно написать так...
u = ADCW; // Считываем ADC

Код:
#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t u;

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); // Ждем флага окончания преобразования
   u = ADCW; // Считываем  ADC
}

/*** Настройка Counter1 ***/
void Counter1_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 (void)
{
   OCR1A = u;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}

и т.д. ))
:tea:

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

Вт янв 23, 2024 18:32:36

Спасибо

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

Вт янв 23, 2024 21:04:16

uuu000 писал(а):ниже 500мВ (100бит) сильно гуляет частота...

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

а тут ничего не смущает ?))
а флаг ADIF кто будет сбрасывать ?
вы читаете АЦП не дождавшись окончания преобразования... из-за этого показания АЦП могут "прыгать"...

флаг ADIF:
1. флаг ADIF - при использовании прерывания АЦП сбрасывается аппаратно (при выходе из обработчика прерывания).
2. флаг ADIF - без прерывания АЦП надо сбрасывать программно.
Screenshot_1.jpg
(47.29 KiB) Скачиваний: 11

у нас нет прерывания АЦП... значит надо сбрасывать флаг ADIF программно (точно так же как флаг в таймере).
Код:
void adc (void)
{
   ADCSRA |= (1 << ADSC);  // Начинаем преобразование
   while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
   ADCSRA |= (1<<ADIF); // сброс флаг ADIF
   u = ADCW; // Считываем  ADC
}

:tea:

Код:
#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t u;

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); // Ждем флага окончания преобразования
   ADCSRA |= (1<<ADIF); // сброс флаг ADIF
   u = ADCW; // Считываем  ADC
}

/*** Настройка Counter1 ***/
void Counter1_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 (void)
{
   OCR1A = u;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}

:tea:

Добавлено after 8 minutes 52 seconds:
я вместо флага ADIF опрашиваю флаг ADSC.
по окончанию преобразования флаг ADSC сбрасывается аппаратно.
Screenshot_2.jpg
(59.49 KiB) Скачиваний: 14

Код:
void adc (void)
{
   ADCSRA |= (1 << ADSC);  // Начинаем преобразование
   while ((ADCSRA&(1 << ADSC))== 1); // Ждем флага окончания преобразования. флаг ADSC сбрасывается аппаратно.
   u = ADCW; // Считываем  ADC
}

так проще))
:tea:

Код:
#define F_CPU 8000000UL // тактовая частота мк
#include <avr/io.h>
#include <avr/interrupt.h>
uint16_t u;

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 << ADSC))== 1); // Ждем флаг окончания преобразования (флаг ADSC сбрасывается аппаратно).
    u = ADCW; // Считываем  ADC
}

/*** Настройка Counter1 ***/
void Counter1_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 (void)
{
   OCR1A = u;
}


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

   while(1)
   {
   while (!(TIFR &=~(1<<OCF1A))); // флаг OCF1A предел счета Т1
   TIFR |=(1<<OCF1A); // сброс флаг OCF1A
   adc ();
   blink ();
   }
}

и т.д.
:tea:

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

Вт янв 23, 2024 22:48:43

roman.com,спасибо за участие. Понял,что читать datasheet нужно внимательнее,я об автоматическом сбросе флага.
Ответить