CodeVision AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
amd9800
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Re: CodeVision AVR в вопросах и ответах

Сообщение amd9800 »

Сделал программу.
Установил таймер который тикает 1000 раз в секунду.
Использую три прерывания.
2 прерывания на таймер первое вызывается при совпадении второе при переполнении. Третье вызывается когда АЦП выдает результат.

в теле прерываний от таймера достаточно много кода. В теле прерывания АЦП мало кода. Ну и тело программы тоже небольшой код.

Контроллер работает на частоте 8Мгц. Получается у меня есть 8000 тактов на один отрезок времени в который выполняются 3 прерывания и кусочек основной программы. Основная программа не критична к времени.

Самое критично это исполнение кода в теле прерываний от таймера.

1. Вопрос как мне определить сколько тактов съедает каждый кусок кода, чтоб правильно все сбалансировать и избежать непредвиденных ошибок.

На АЦП я измеряю 3 параметра. 1 параметр очень критичный и я его измеряю при каждом такте в 1 мс таймера. Два других параметра измеряю 20 раз в секунду, то есть раз в 50мс.
Ясное дело что у меги 48 один АЦП, поэтому я 48 раз из 50 измеряю первый параметр и 1 раз второй и 1 раз третий.
После выполнения измерения в теле прерывания АЦП если нужно поменять канал я меняю его. Таким образом при следующем измерении уже заранее будет выбран нужный канал. Ясное дело что от выбора другого канала до измерения меньше 1 мс.

2. Вопрос - после смены канала требуется время чтоб провести новое измерение или нет. И если да какое время требуется?
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

1. Вопрос как мне определить сколько тактов съедает каждый кусок кода, чтоб правильно все сбалансировать и избежать непредвиденных ошибок.

1. открываете ассемблерный листинг и считаете ручками.
2. Если не ошибаюсь, IAR умеет считать циклы и такты.
3. В AVR studio в эмуляторе тоже вроде такая возможность была.
2. Вопрос - после смены канала требуется время чтоб провести новое измерение или нет. И если да какое время требуется?

Судя из описаний, дополнительного времени не требуется. Время на выбор канала вроде как входит во время измерения и занимает, если не изменяет память, первые 1,5 такта.
Fucking static initialization order fiasco
amd9800
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Re: CodeVision AVR в вопросах и ответах

Сообщение amd9800 »

Pink-Pank писал(а):1. открываете ассемблерный листинг и считаете ручками. .

как его открыть?
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

В папке проекта файл .lss обычным блокнотом. Только учитывайте, что некоторые команды выполняются более, чем за 1 такт.
Fucking static initialization order fiasco
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: CodeVision AVR в вопросах и ответах

Сообщение oleg110592 »

1) можно открыть cof файл, сгенерированный Codevision в Atmel AVR Studio и в режиме симуляции произвести замеры времени выполнения отдельных функций
2)задержка нужна, генератор кода так рекомендует

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

    ADMUX = adc_input | ADC_VREF_TYPE;
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    // Start the AD conversion
    ADCSRA |= 0x40;
    while ((ADCSRA & 0x10) == 0); // Wait for the AD conversion to complete
    ADCSRA |= 0x10;
    return ADCW;   

Время также зависит от выходного сопротивления источника, который подключен ко входу АЦП
.lss Codevision не делает - есть файлы с расширениями .asm и .lst
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

oleg110592 писал(а):задержка нужна, генератор кода так рекомендует

А еще генератор кода "рекомендует" обнулять регистры периферии при инициализации, в которых и так 0 содержится.
Fucking static initialization order fiasco
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: CodeVision AVR в вопросах и ответах

Сообщение oleg110592 »

и это правильно - после переходных процессов может быть и не ноль, если делаем правильную и надежную программу - "лучше перебдеть чем не добдеть"
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

После каких переходных процессов? )

Изображение

1) Смысл этой задержки, если апдейт MUX и REFs происходит ПОСЛЕ запуска преобразования?
2) 10 мкс для какой частоты работы контроллера/АЦП?

К тому же, Вы можете изменить MUX до окончания текущего преобразования - и это на само преобразование никак не повлияет.
Вложения
12345.png
(40.8 КБ) 1142 скачивания
Последний раз редактировалось Pink-Pank Ср июл 30, 2014 14:42:41, всего редактировалось 1 раз.
Fucking static initialization order fiasco
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: CodeVision AVR в вопросах и ответах

Сообщение oleg110592 »

При включении устройства, на микроконтроллере питание не появляется мгновенно:
http://thebard.narod.ru/EPUS/bileti/16perexproc.htm
Если не включена система контроля питания (BOD) в микроконтроллере, то микроконтроллер может за время переходного процесса питания запустится несколько раз, что будет с регистрами предсказать невозможно. Поэтому делал всегда перед настройками периферии и заданием переменных задержку и обязательное обнуление и выключение не задействованной периферии.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

Вообще-то для этого выставляется фьюзами время запуска МК. И обычно оно составлет 65 мсек, что в значительной мере превышает большинство всех переходных процессов. т.е. тактирование начнется после 65 мс устойчивой работы.
Fucking static initialization order fiasco
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: CodeVision AVR в вопросах и ответах

Сообщение oleg110592 »

Вообще-то для этого выставляется фьюзами время запуска МК.

в моих устройствах нужны были задержки до 200мс.
насчет ацп рекомендую почитать известного человека: http://leoniv.livejournal.com/194681.html
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

Это я читал. тема интересная. Но АЦП AVRки и STM значительно разнятся. ) Хотя принцип тот же.
Fucking static initialization order fiasco
Аватара пользователя
oleg110592
Друг Кота
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Re: CodeVision AVR в вопросах и ответах

Сообщение oleg110592 »

Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Re: CodeVision AVR в вопросах и ответах

Сообщение DataLife »

Всем доброго времени суток. :beer:
Есть вопросик в программном исполнении АЦП на АТмега8.
С регистрами разобрался, примеры программ смотрел. Но что-то не на 100% работает.

Программа простая: на ножке ADC0 смотрим напряжение, передаём значения ADC на терминал по UART. Проще некуда, но ...
Удачно вывести значение получается только из старшего байта ADCH ... Когда ставлю хочу вывести значения 2-х байтового регистра ADCW, то вижу всевозможный "спам" вместо значений. Даташит перечитал, аж в глазах рябит ... Помогите, где ошибся?

Программа:

Спойлер#include <mega8.h>
#include <stdio.h>
#include <delay.h>

//наши переменные
unsigned int res;

//Функция измерения
unsigned char ADC_result(void)
{
ADCSRA = 0x8E; //0b10001110 - предделитель на 64, прерывания разрешены, ADC включён
ADMUX = 0x60; //0b01100000 - AVCC , ACD0
delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40; //начинаем измерение
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA |=0x10;
return ADCW; //Возвращаем
}


void main(void)
{

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x00;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600 (при 8 МГц)
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;

while (1)
{
res=ADC_result(); //значение измерения присваиваем переменной RES
printf("ADC=%d",res); // выводим значение в UART
delay_ms(500);
}



}
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

ADMUX = 0x60; //0b01100000 - AVCC , ACD0
У Вас выравнивание по левому краю стоит. Бит ADLAR уберите - и выводите два регистра.
Fucking static initialization order fiasco
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Re: CodeVision AVR в вопросах и ответах

Сообщение DataLife »

Pink-Pank писал(а):ADMUX = 0x60; //0b01100000 - AVCC , ACD0
У Вас выравнивание по левому краю стоит. Бит ADLAR уберите - и выводите два регистра.

Убрал бит ADLAR ... Всё равно из ADCW сыпятся непонятные, всё время разные значения...

PS. нашёл ошибку. Дело в оглашении переменной функии unsigned char ADC_result(void) ... Тут как ни крути только 255 значений. Поменял на int - работает! Спасибо!
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Re: CodeVision AVR в вопросах и ответах

Сообщение DataLife »

Продолжу задавать глупые вопросы :oops:
Пошёл дальше и решил сделать, чтобы результаты расчёта АЦП выводились в UART только по нажатии на кнопку (по прерыванию INT0). Мат часть изучил, код написал - не работает. Пляски с бубном пока не помогают. :dont_know: Прошу помощи у добрых котов...

Программа:

Спойлер#include <mega8.h>
#include <stdio.h>
#include <delay.h>

//наши переменные
unsigned int res;
unsigned int volt;
unsigned char i;

// // Функция внешнего прерывания по INT0
interrupt [EXT_INT0] void ext_int0_isr(void)
{
i=1;
}


//Функция измерения
unsigned int ADC_result(void)
{
ADCSRA = 0x8E; //0b10001110 - предделитель на 64, прерывания разрешены, ADC включён
ADMUX = 0x40; //0b01000000 - AVCC , ACD0, ADLAR off
delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40; //начинаем измерение
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA |=0x10;
return ADCW; //Возвращаем функции значение регистра ADCW
}


void main(void)
{

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;

PORTD=0x04; // устанавливаем подтягивающий резистор на ногу PD2 (INT0)
DDRD=0x00;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600 (при 8 МГц)
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;

// Настройка прерываний:

GICR |= (1<<INT0); // разрешение внешнего прерывания по INT0
MCUCR |= (1<<ISC01); // прерывание по заднему фронту

#asm("sei")
while (1)
{
if (i)
{
res=ADC_result(); //значение измерения присваеваем переменной RES
volt=(float)res*0.0048828125*100; // 5 Вольт = 0,0048.. мВ/ед. Умножаем на 100 ддля точности до сотых.
printf("V=%u.%u ",volt/100,volt%100); // выводим значение в UART
delay_ms(50);
i=0;
};
}



}
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

volatile unsigned char i
про volatile инфу найдите сами.
Fucking static initialization order fiasco
Аватара пользователя
DataLife
Вымогатель припоя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Re: CodeVision AVR в вопросах и ответах

Сообщение DataLife »

Pink-Pank, огромное спасибо за внимание к моей "проблеме". Да, за volatile знаю, спасибо. Попробовал - увы, косяк где-то в другом... Возможно в инициализации прерывания, проверю.

Попутно другой вопрос (извините за мою любопытность) :
Шаг за шагом вдумчиво изучаю программирование и дописываю/изменяю программу, исследую новые возможности.
Теперь решил выводить значения ADC (АЦП) или же напряжения на светодиодный 7-сегментный индикатор.
Задачу поставил себе так, чтобы не было "мерцания" из-за меняющегося значения ADC.
Сначала думал делать замер нескольких значений и выводить среднее значение, но как-то не сраслось. Не понял как, знаний мало.
Выход из ситуации нашёл таким, что расчёт значений АЦП идёт по таймеру0 на частоте 8 кГц, а после идёт обработчик прерывания по таймеру2 на 100 кГц ... Результат устроил, в принципе. Мерцания нет.
Вопрос в том: как правильно делать? Хотелось, чтобы АЦП вычислялось раз в 0,2 сек (например) и затем выводились на индикатор.
Как это сделать? В основном цикле, почему-то, вызывать функцию обработки АЦП и делать задержку не получается... Индикатор несёт ахинею...


PS. извините за "многабукаф" ...

Программа:
Спойлер#include <mega8.h>
#include <delay.h>

//наши переменные

//----------
char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x80};

volatile unsigned char segcounter = 0;
volatile unsigned int adc_data = 0;
volatile unsigned int ADC_res=0;

void ADC_init(void)
{
ADCSRA = 0x8E; //0b10001110 - предделитель на 64, прерывания разрешены, ADC включён
ADMUX = 0x40; //0b01000000 - AVCC , ACD0, ADLAR off
}


// Обработчик прерывания по переполнению таймера0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
ADCSRA |= 0x40; //начинаем измерение
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA |=0x10;
adc_data=ADCW;
ADC_res=adc_data*0.00488*100;

}

// Обработчик прерывания по переполнению таймера2
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{


PORTD = 0x00; // гасим все разряды
PORTB = (1<< segcounter); //выбираем следующий разряд
switch (segcounter)
{
case 0:
PORTD = (SEGMENTE[ADC_res % 10000 / 1000]); // Раскладываем число на разряды. Тысячи.
break;
case 1:
PORTD = (SEGMENTE[ADC_res % 1000 / 100]); // Сотни.
break;
case 2:
PORTD = (SEGMENTE[ADC_res % 100 / 10]); // Десятки.
break;
case 3:
PORTD = (SEGMENTE[ADC_res % 10]); // Единицы.
break;
}
if ((segcounter++) > 2) segcounter = 0;
}


void main(void)
{

PORTB=0x00;
DDRB|=(1<<0)|(1<<1)|(1<<2)|(1<<3);

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0xFF;

TIMSK |= (1 << TOIE2)|(1<< TOIE0); // разрешение прерывания по таймеру2 и таймеру0
TCCR2 |= (1 << CS21); //предделитель таймера2 на 8
TCCR0=0x05; // предделитель таймера0 на 1024

ADC_init();

#asm ("sei") // глобально разрешаем прерывания.
while (1)
{

}

}
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: CodeVision AVR в вопросах и ответах

Сообщение Pink-Pank »

DataLife писал(а):Попробовал - увы, косяк где-то в другом... Возможно в инициализации прерывания, проверю.

Инициализацию я смотрел - вроде все норм. Без кнопки-то пробовали? Выводит значения?

DataLife писал(а):Вопрос в том: как правильно делать? Хотелось, чтобы АЦП вычислялось раз в 0,2 сек (например) и затем выводились на индикатор.


Сделать можно по разному. Можно через таймеры, можно через прерывания от АЦП, а можно вообще без прерываний. У Вас проблема была скорее всего в объемности расчетов из-за которых МК не успевал вывести значение на экран. Попробуйте оптимизировать код перевода 2->10. Вы несколько раз делите на кратные числа. Можно, например, ввести промежуточную переменную и остаток скажем, от деления на 1000 потом использовать для вычисления остатка от деления на 100, поделив его еще на 10 и т.д. Плавающую точку тоже не желательно использовать - много ресурсов ядра ест.
Усреднение АЦП можно делать "скользящим окном" с хранением последней суммы и . Тогда для вычисления следующей суммы нужно всего лишь вычесть первый элемент и добавить вновь полученный. количество элементов лучше брать кратным 2, чтобы операцию деления потом заменить операцией сдвига. Например, 8 элементов, заместо деления суммы пишем S=S>>3;

P.S. Правильный тот вариант - который работает так, как задумано, а не тот, который более красиво написан.
Fucking static initialization order fiasco
Ответить

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