Нескольно простых вопросов о программировании AVR на Си.

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
KorbenDallas
Встал на лапы
Сообщения: 93
Зарегистрирован: Пн окт 31, 2016 06:23:19

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение KorbenDallas »

[uquote="ARV",url="/forum/viewtopic.php?p=3646558#p3646558"]
baron_P писал(а)://Процедура атомарной записи в 16-битный регистр OCR1A (пример из датащита на Atmega8)

атомарные операции в AVR-GCC делаются не так[/uquote]

Ваш вариант - абсолютно то же самое, только завернутое в другой "синтаксический сахар". Так что никакого "не так" тут нет.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ARV »

KorbenDallas писал(а):Так что никакого "не так" тут нет.
конкретно это применение - да, "точно такое же". а что скажете на счет этого:

Код: Выделить всё

unsigned int ReadOCRA1(void){
   ATOMIC_BLOCK(ATOMIC_RESTORSETATE){
      return OCR1A;
   }
}
;) ?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="KorbenDallas",url="/forum/viewtopic.php?p=3646549#p3646549"]Во-первых, среднее у вас вычисляется не из `N_MAX` значений, как написано в комментарии, а из `2^N_MAX` значений.
Во-вторых, вышеприведенная функция возвращает новое среднее только на каждой `2^N_MAX` итерации. На остальных итерациях возвращается последнее вычисленное среднее. Это так и задумано?[/uquote]
1. Да, я забыл обновить комментарий после обновления кода.
2. Да, так и задумано, я ведь не получу новое среднее значение раньше, чем через 2^N_MAX операций. Наверно, можно было добавить флаг "обновлено/не обновлено" и записывать значение в OC1A, только если оно обновилось, но мне показалось это лишним в этом случае. В векторах прерываний тут ничего важного не происходит (может, индикатор потом прикручу), остановка прерываний раз в цикл не критична.

Не знал о существовании спец. библиотеки атомарных операций для AVR-GCC. Но какая разница - в датащите универсальный сишный вариант под любую среду разработки, насколько я понимаю. А атомарность операций нужна здесь "чтоб была" - в процессе борьбы ловли багов Протеуса добавил для надежности, Atmel ведь рекомендует.
We do what we must because we can (c) GLaDOS
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ARV »

baron_P писал(а):Но какая разница - в датащите универсальный сишный вариант под любую среду разработки, насколько я понимаю.
разница очень большая: если вы делаете атомарное ЧТЕНИЕ, то вам придется совершать без этого библиотечного макроса достаточно много "лишних" телодвижений - я привел код функции, возвращающей атомарно считанное значение регистра, попробуйте написать аналог без этого макроса :)
baron_P писал(а):я ведь не получу новое среднее значение раньше, чем через 2^N_MAX операций
да легко! только это будет не среднее за N_MAX семплов, а среднее за N_MAX предыдущих семплов. метод называется "скользящее среднее" и является простейшим вариантом какого-то там КИХ/БИХ (я нихрена в этом не понимаю) фильтра.
алгоритм вам ранее был описан словесно
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ARV",url="/forum/viewtopic.php?p=3646774#p3646774"]разница очень большая: если вы делаете атомарное ЧТЕНИЕ, то вам придется совершать без этого библиотечного макроса достаточно много "лишних" телодвижений - я привел код функции, возвращающей атомарно считанное значение регистра, попробуйте написать аналог без этого макроса :)
да легко! только это будет не среднее за N_MAX семплов, а среднее за N_MAX предыдущих семплов. метод называется "скользящее среднее" и является простейшим вариантом какого-то там КИХ/БИХ (я нихрена в этом не понимаю) фильтра.
алгоритм вам ранее был описан словесно[/uquote]
А чем плох этот пример чтения?

Код: Выделить всё

unsigned int TIM16_ReadTCNT1( void )
{
unsigned char sreg;
unsigned int i;
/* Save Global Interrupt Flag */
sreg = SREG;
/* Disable interrupts */
_CLI();
/* Read TCNT1 into i */
i = TCNT1;
/* Restore Global Interrupt Flag */
SREG = sreg;
return i;
}


Я слышал про этот метод, но мне он не нужен в данном случае - частота входного сигнала очень низкая.
We do what we must because we can (c) GLaDOS
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ARV »

baron_P писал(а):А чем плох этот пример чтения?
хотя бы тем, что он в 3 раза объемнее по строкам :) соответственно, в 3 раза выше вероятность где-то ошибиться.
baron_P писал(а):мне он не нужен в данном случае - частота входного сигнала очень низкая
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде.
но, разумеется, хозяин - барин :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ARV",url="/forum/viewtopic.php?p=3646787#p3646787"]
baron_P писал(а):А чем плох этот пример чтения?
хотя бы тем, что он в 3 раза объемнее по строкам :) соответственно, в 3 раза выше вероятность где-то ошибиться.
baron_P писал(а):мне он не нужен в данном случае - частота входного сигнала очень низкая
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде.
но, разумеется, хозяин - барин :)[/uquote]
Это копипаста из датащита - в нажатии двух кнопок ошибиться трудно :))
Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.
We do what we must because we can (c) GLaDOS
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ARV »

:facepalm:
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

[uquote="baron_P",url="/forum/viewtopic.php?p=3646805#p3646805"]Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.[/uquote]
может лучше контрольные суммы использовать?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ozonn",url="/forum/viewtopic.php?p=3646821#p3646821"][uquote="baron_P",url="/forum/viewtopic.php?p=3646805#p3646805"]Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.[/uquote]
может лучше контрольные суммы использовать?[/uquote]
Не соображу, как это можно сделать здесь. Железка с 12-ю открытыми коллекторами соединена со входами контроллера. Иногда, значения на входах меняются по желанию этой железки. Куда тут контрольную сумму можно воткнуть? :)
We do what we must because we can (c) GLaDOS
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

т.е. за входной сигнал ты не в ответе? Ну, а о нем хоть что-то известно?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ozonn",url="/forum/viewtopic.php?p=3646826#p3646826"]т.е. за входной сигнал ты не в ответе? Ну, а о нем хоть что-то известно?[/uquote]
Не в ответе. О том, какие значения будут выставлены в конкретный момент - нет, не известно. Есть еще тринадцатый бит, который говорит о том, что сигнал с 12 остальных можно читать. Я собираю значения со входов только когда активен этот бит.
Код (лишнее выкинулЮ нужное добавил):
Спойлер

Код: Выделить всё

/*
МК ATMEGA8
Частота МК = 8 МГц
Fuse High Byte
BODLEVEL = 0 - нижний порог напряжения питания 4 В
BODEN    = 0 - слежение за напряжением питания вкл.
SUT1     = 0 \ время включения 6СК + 64 ms
SUT0     = 0 /
CKSEL3   = 0 \
CKSEL2   = 1 - встроенный источник тактовых импульсов
CKSEL1   = 0 - с частотой 8 МГц
CKSEL0   = 0 /
Fuse Low Byte
RSTDISBL = 1 - переназначение вывода ~RESET выкл.
WDTON    = 1 - постоянная работа сторожевого таймера выкл.
SPIEN    = 0 - внутрисхемное программирование вкл.
CKOPT    = 1 - опции работы с внешним кварцевым резонатором выкл.
EESAVE   = 1 - защита EEPROM от стирания выкл.
BOOTSZ1  = 0 \ размер загрузочного сектора
BOOTSZ0  = 0 / 1024 слова, начальный адрес $0C00
BOOTRST  = 1 - перенос стартового сектора в область загрузчика выкл.
*/

//Подключенные файлы
#include <avr/io.h>         // Стандартные функции ввода/вывода для МК
#include <avr/wdt.h>        // Стандартные функции работы cо сторожевым таймером

//Подстановки
#define PWM_MAX 4095    // Максимальное значение скважности для 12-битиного ШИМ (PWM_MAX = 2^12 - 1)
#define N_MAX 3         // Максимальное количесво значений для получения средне арифметичесого (2^N_MAX = 8)
#define U_INT_MAX 65535 // Максимальное значение типа unsigned int


//Прототипы функций
//Процедура инициализации входов/выходов
void init_IO(void);
//Процедура инициализации ТС1
void init_TC1(void);
//Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ
void data_conv_PWM(unsigned int);
//Функция чтения 12-битного значения задания со входов
unsigned int data_read(void);


/********** Главная фунция **********/
void main(void)
{

    //Инициализация входов/выходов
    init_IO();
    //Инициализация ТС1
    init_TC1();
   
    //Инициализация локальных переменных
    //Значение числа с 12-битного входа
    unsigned int data_input = 0;
   
    //Включение сторожевого таймера с периодом 1с
    wdt_enable(WDTO_1S);
   
    //Рабочий цикл
    while(1)
    {
        //Если на входе присутствует сигнал чтения
        if (PINB & (1 << PB0))
        {
            //Чтение 12-битного значения задания со входов
            data_input = data_read();
           
            //Получение среднего арифметического из 2^N_MAX значений и выдача его в ШИМ
            data_conv_PWM(data_input);
        }

        //Сброс сторожевого таймера
        wdt_reset();
    };

}



/********** Функции **********/
//Процедура инициализации входов/выходов
void init_IO(void)
{
    //12-битный вход, собранный из входов портов D и B
    //Младшие биты входа 7-0 (порт D)
    DDRD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0));
    //Старшие биты входа 11-8 (порт B), PB0 - вход сигнала чтения
    DDRB &= ~((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4) | (1 << PB0));
    //Подтяжка входов к единице
    PORTD |= (1 << PD7) | (1 << PD6) | (1 << PD5) | (1 << PD4) | (1 << PD3) | (1 << PD2) | (1 << PD1) | (1 << PD0);
    PORTB |= (1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4) | (1 << PB0);

    //Неиспользуемые выводы назначаются входами
    DDRB &= ~((1 << PB3) | (1 << PB2));
    DDRC &= ~((1 << PC5) | (1 << PC4) | (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
    //Подтяжка неиспользуемых входов к единице
    PORTB |= (1 << PB3) | (1 << PB2);
    PORTC |= (1 << PC5) | (1 << PC4) | (1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0);
}


//Процедура инициализации ТС1 (формирование выходного аналогового напряжения)
void init_TC1(void)
{
    //Вывод PB1 (OC1A) - выход ШИМ
    DDRB |= (1 << PB1);
    //Сброс в ноль выхода OC1A при совпадении, режим FastPWM (ICR1)
    TCCR1A |= (1 << COM1A1) | (1 << WGM11);
    //Предделитель 1
    TCCR1B |=  (1 << WGM13) | (1 << WGM12) | (1 << CS10);
    //Маскимальное значение скважности
    ICR1 = PWM_MAX;
    //Начальное (нулевое) значение скважности ШИМ
    OCR1A= 0;
}


//Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ
void data_conv_PWM(unsigned int data_in)
{
    //Суммарное значение 2^N_MAX полученных
    static unsigned int data_sum;
    //Счетчик количества просуммированых значений
    static unsigned char data_n;
   
    //Если количество просуммированных значений меньше заданного
    if (data_n < (1 << N_MAX))
    {
        //Добавляем полученное значение к сумме предыдущих (предельное значени data_in = PWM_MAX*2^N_MAX = 32670)
        data_sum += data_in;
        //Инкрементируем счетчик полученных значений
        data_n++;
    }
    else
    {
        //Иначе, обновляем предыдущее средне-арифметическое значение
        data_sum = (data_sum >> N_MAX);

        //Выдача заданния скважности ШИМ в регистр сравнения
        OCR1A= data_sum;

        //Обнуляем сумму полученных значений
        data_sum = 0;
        //Обнуляем счетчик полученных значений
        data_n = 0;
    }
}


//Функция чтения 12-битного значения задания со входов
unsigned int data_read(void)
{
    //Значения с входов соотв. портов
    unsigned char data_in_D = 0, data_in_B = 0;
    //Значение числа с 12-битного входа
    unsigned int data_in = 0;
   
    //Чтение значений со входов
    //Порт D без изменений
    data_in_D = PIND;
    //Порт B с очисткой неиспользуемых младших битов
    data_in_B = PINB & ((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));

    //Преобразование полученных значений в 12-битное число (0b00 4бита PortB 8 битов PortD)
    data_in = (data_in_B << 4) | data_in_D;

    //Возвращение полученного 12-битного числа
    return data_in;
}
We do what we must because we can (c) GLaDOS
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

[uquote="baron_P",url="/forum/viewtopic.php?p=3646836#p3646836"]Не в ответе. О том, какие значения будут выставлены в конкретный момент - нет, не известно.[/uquote]
а частота тоже неизвестна?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ozonn",url="/forum/viewtopic.php?p=3646843#p3646843"][uquote="baron_P",url="/forum/viewtopic.php?p=3646836#p3646836"]Не в ответе. О том, какие значения будут выставлены в конкретный момент - нет, не известно.[/uquote]
а частота тоже неизвестна?[/uquote]
Частота тоже неизвестна. Известно, что имеют место быть импульсные помехи около 10 кГц частотой. На входах будет подаваться 24 В через делитель 20 кОм - 3,9 кОм. Параллельно 3,9 кОм будут конденсаторы 0,01 мкФ, чтобы срезать все, что выше 1 кГц.
We do what we must because we can (c) GLaDOS
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

тогда отфильтровать весьма непросто. Усреднения может ничего не дать. А какова длительность импульса на 13 контакте?
Аватара пользователя
baron_P
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Вт сен 14, 2010 23:07:10
Откуда: Ростов

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение baron_P »

[uquote="ozonn",url="/forum/viewtopic.php?p=3647026#p3647026"]тогда отфильтровать весьма непросто. Усреднения может ничего не дать. А какова длительность импульса на 13 контакте?[/uquote]
И того я, пока, не знаю. Документации нет, вопрос прояснится, когда получится добраться до железки с осциллографом.
We do what we must because we can (c) GLaDOS
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ПростоНуб »

baron_P, от импульсных помех избавляются медианный фильтром, а не усреднением. То бишь, формируем скользящее окно из N показаний. N - нечётное. Окно лучше формировать списком. В списке держим N последних показаний в отсортированном порядке. Среднее показание - наша медиана. При поступлении нового показания удаляем из списка самое старое показание и вставляем в список, сохраняя сортировку по значениям показаний, новое показание. Средний элемент списка снова наша медиана.
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

[uquote="ПростоНуб",url="/forum/viewtopic.php?p=3647130#p3647130"]baron_P, от импульсных помех избавляются медианный фильтром, а не усреднением. То бишь, формируем скользящее окно из N показаний. N - нечётное. Окно лучше формировать списком. В списке держим N последних показаний в отсортированном порядке. Среднее показание - наша медиана. При поступлении нового показания удаляем из списка самое старое показание и вставляем в список, сохраняя сортировку по значениям показаний, новое показание. Средний элемент списка снова наша медиана.[/uquote]
короче, надо знать, что представляют собой эти самые показания и можно ли их вообще фильтровать
Аватара пользователя
ПростоНуб
Собутыльник Кота
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ПростоНуб »

ozonn, так ТС же явно сказал, что "имеют место быть импульсные помехи". Если только импульсные помехи - то медианного фильтра достаточно. Если не столько ипульсные, сколько шум при известном спектре полезного сигнала - то уравнение Винера.
В общем случае - собираем мегабайты статистики, берем R в зубы, находим функцию распределения и от нее уже пляшем.
ozonn
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Re: Нескольно простых вопросов о программировании AVR на Си.

Сообщение ozonn »

[uquote="ПростоНуб",url="/forum/viewtopic.php?p=3648578#p3648578"]ozonn, так ТС же явно сказал, что "имеют место быть импульсные помехи". Если только импульсные помехи - то медианного фильтра достаточно. Если не столько ипульсные, сколько шум при известном спектре полезного сигнала - то уравнение Винера.
В общем случае - собираем мегабайты статистики, берем R в зубы, находим функцию распределения и от нее уже пляшем.[/uquote]
а теперь представь, что полезная информация - это буквы. И ты бльшую часть из них фильтруешь. Короче, надо знать, какую инфу нисут в себе принимаемые числа
Ответить

Вернуться в «AVR»