Не могу получить стабильный меандр
Re: Не могу получить стабильный меандр
Спасибо С.Н.
- Реклама
Re: Не могу получить стабильный меандр
а нафига там кольцевой буфер ? вы что собрались с ним делать ?
Добавлено after 9 hours 4 minutes 31 second:
чтоб было точно - надо смотреть даташит...
имеем код:
что тут не так ?

Добавлено 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 ();
}
}
- Gennadiy
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Чт июн 17, 2010 07:40:31
- Откуда: Россия
Re: Не могу получить стабильный меандр
Все нормально, кроме постоянных зависаний в ожидании флагов. Может на прерывания перейти?
-
С.Н.
- Потрогал лапой паяльник
- Сообщения: 307
- Зарегистрирован: Пн окт 26, 2020 08:37:51
- Откуда: г.Волгоград
Re: Не могу получить стабильный меандр
Программа осуществляет прямое управление частотой генерации некоего генератора. Все флуктуации кода АЦП будут сразу приводить в флуктуации частоты.
А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.
Источник опорного напряжения = источник питания. Если будет 10 разрядов АЦП, то шуметь он будет разряда на 3. Это всего ~4 мВ! Точность стабилизации блока питания скорее всего не лучше.
На мой взгляд, буфер тут будет и фильтровать помехи и добавит инерционный момент. Даже если Вы ручку крутанете от души, частота плавно будет перестраиваться.
Чем длиннее буфер, тем плавнее изменение.
А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.
Источник опорного напряжения = источник питания. Если будет 10 разрядов АЦП, то шуметь он будет разряда на 3. Это всего ~4 мВ! Точность стабилизации блока питания скорее всего не лучше.
На мой взгляд, буфер тут будет и фильтровать помехи и добавит инерционный момент. Даже если Вы ручку крутанете от души, частота плавно будет перестраиваться.
Чем длиннее буфер, тем плавнее изменение.
ФУОЗ на платформе Ардуино: https://radiokot.ru/forum/viewtopic.php ... 6#p4366626
ВК - "ФУОЗ на микроконтроллере Atmega328P (МПСЗ)"
ВК - "ФУОЗ на микроконтроллере Atmega328P (МПСЗ)"
Re: Не могу получить стабильный меандр
Роман все правильно.Как я понял в внутри цикла while(1) есть еще один такой же цикл в условии которого проверяется состояние флага совпадения СТС .Кода есть совпадение счетчика и OCR1A условие цикла
обнуляется и на выходе МК появляется сгенерированный сигнал. Код в Proteus работает отлично,вплоть до OCR1A=10(при напряжении на входе АЦП около 50мВ) выдает около 1420 Гц.В железе конечно не так идеально ,ниже 500мВ (100бит) сильно гуляет частота
228-235 Гц ,при напряжении около 200-300мВ срывается до 1700Гц, возможно из за качества потенциометра или наводок при слишком низком напряжении на входе АЦП. Я не уверен что смогу управлять таким образом
шаговиком но проверить не могу- еше не получил драйверы от наших китайских " друзей".В любом случае спасибо за совет. Сейчас пока есть время (но нет драйверов ) попробую разобраться и использовать кольцевой
буфер.
обнуляется и на выходе МК появляется сгенерированный сигнал. Код в Proteus работает отлично,вплоть до OCR1A=10(при напряжении на входе АЦП около 50мВ) выдает около 1420 Гц.В железе конечно не так идеально ,ниже 500мВ (100бит) сильно гуляет частота
228-235 Гц ,при напряжении около 200-300мВ срывается до 1700Гц, возможно из за качества потенциометра или наводок при слишком низком напряжении на входе АЦП. Я не уверен что смогу управлять таким образом
шаговиком но проверить не могу- еше не получил драйверы от наших китайских " друзей".В любом случае спасибо за совет. Сейчас пока есть время (но нет драйверов ) попробую разобраться и использовать кольцевой
буфер.
- Реклама
- Gennadiy
- Первый раз сказал Мяу!
- Сообщения: 23
- Зарегистрирован: Чт июн 17, 2010 07:40:31
- Откуда: Россия
Re: Не могу получить стабильный меандр
Из функции blink() исключите Counter0_init().
Re: Не могу получить стабильный меандр
[uquote="Gennadiy",url="/forum/viewtopic.php?p=4534185#p4534185"]Из функции blink() исключите Counter0_init().[/uquote]
Уже сделано. Спасибо.
Уже сделано. Спасибо.
Re: Не могу получить стабильный меандр
[uquote="С.Н.",url="/forum/viewtopic.php?p=4534086#p4534086"]Программа осуществляет прямое управление частотой генерации некоего генератора. Все флуктуации кода АЦП будут сразу приводить в флуктуации частоты.
А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.[/uquote]
1. есть программные флуктуации.
2. есть шум самого АЦП +/- 1...3 разряд
это разные вещи...
1. программные флуктуации мы устранили путём опроса флага переполнения таймера.
2. шум самого АЦП +/- 1...3 разряд... мы пока не устранили... для этого есть аппаратные и программные фильтры.
Добавлено after 4 minutes 12 seconds:
а нафига там "инициализация блинков" ?))
Добавлено after 4 minutes 40 seconds:
а нафига там две переменные i... u...
Добавлено after 3 minutes 42 seconds:
вместо...
u = (ADCL|ADCH <<
; // Считываем ADC
можно написать так...
u = ADCW; // Считываем ADC
и т.д. ))

А флуктуации кода АЦП будут! Это реальный мир, а не эмулятор. Сам АЦП обязан щуметь на +- 1 разряд, плюс помехи полезут по земле и через ручку от окружающих систем, опорное напряжение.[/uquote]
1. есть программные флуктуации.
2. есть шум самого АЦП +/- 1...3 разряд
это разные вещи...
1. программные флуктуации мы устранили путём опроса флага переполнения таймера.
2. шум самого АЦП +/- 1...3 разряд... мы пока не устранили... для этого есть аппаратные и программные фильтры.
Из функции blink() исключите Counter1_init().... раз мы делаем на таймере 1 то писать надо правильно))Gennadiy писал(а):Из функции blink() исключите Counter0_init().
Код: Выделить всё
#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 ();
}
}
а нафига там "инициализация блинков" ?))
Код: Выделить всё
#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 ();
}
}а нафига там две переменные i... u...
Код: Выделить всё
#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 ();
}
}вместо...
u = (ADCL|ADCH <<
можно написать так...
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 ();
}
}Re: Не могу получить стабильный меандр
uuu000 писал(а):ниже 500мВ (100бит) сильно гуляет частота...
Код: Выделить всё
void adc (void)
{
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
u = ADCW; // Считываем ADC
}а флаг ADIF кто будет сбрасывать ?
вы читаете АЦП не дождавшись окончания преобразования... из-за этого показания АЦП могут "прыгать"...
флаг ADIF:
1. флаг ADIF - при использовании прерывания АЦП сбрасывается аппаратно (при выходе из обработчика прерывания).
2. флаг ADIF - без прерывания АЦП надо сбрасывать программно. у нас нет прерывания АЦП... значит надо сбрасывать флаг ADIF программно (точно так же как флаг в таймере).
Код: Выделить всё
void adc (void)
{
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA&(1 << ADIF))== 0); // Ждем флага окончания преобразования
ADCSRA |= (1<<ADIF); // сброс флаг ADIF
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); // Ждем флага окончания преобразования
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 ();
}
}Добавлено after 8 minutes 52 seconds:
я вместо флага ADIF опрашиваю флаг ADSC.
по окончанию преобразования флаг ADSC сбрасывается аппаратно.
Код: Выделить всё
void adc (void)
{
ADCSRA |= (1 << ADSC); // Начинаем преобразование
while ((ADCSRA&(1 << ADSC))== 1); // Ждем флага окончания преобразования. флаг ADSC сбрасывается аппаратно.
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 << 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 ();
}
}Re: Не могу получить стабильный меандр
roman.com,спасибо за участие. Понял,что читать datasheet нужно внимательнее,я об автоматическом сбросе флага.


