CodeVision AVR в вопросах и ответах
Re: CodeVision AVR в вопросах и ответах
Сделал программу.
Установил таймер который тикает 1000 раз в секунду.
Использую три прерывания.
2 прерывания на таймер первое вызывается при совпадении второе при переполнении. Третье вызывается когда АЦП выдает результат.
в теле прерываний от таймера достаточно много кода. В теле прерывания АЦП мало кода. Ну и тело программы тоже небольшой код.
Контроллер работает на частоте 8Мгц. Получается у меня есть 8000 тактов на один отрезок времени в который выполняются 3 прерывания и кусочек основной программы. Основная программа не критична к времени.
Самое критично это исполнение кода в теле прерываний от таймера.
1. Вопрос как мне определить сколько тактов съедает каждый кусок кода, чтоб правильно все сбалансировать и избежать непредвиденных ошибок.
На АЦП я измеряю 3 параметра. 1 параметр очень критичный и я его измеряю при каждом такте в 1 мс таймера. Два других параметра измеряю 20 раз в секунду, то есть раз в 50мс.
Ясное дело что у меги 48 один АЦП, поэтому я 48 раз из 50 измеряю первый параметр и 1 раз второй и 1 раз третий.
После выполнения измерения в теле прерывания АЦП если нужно поменять канал я меняю его. Таким образом при следующем измерении уже заранее будет выбран нужный канал. Ясное дело что от выбора другого канала до измерения меньше 1 мс.
2. Вопрос - после смены канала требуется время чтоб провести новое измерение или нет. И если да какое время требуется?
Установил таймер который тикает 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 в вопросах и ответах
1. Вопрос как мне определить сколько тактов съедает каждый кусок кода, чтоб правильно все сбалансировать и избежать непредвиденных ошибок.
1. открываете ассемблерный листинг и считаете ручками.
2. Если не ошибаюсь, IAR умеет считать циклы и такты.
3. В AVR studio в эмуляторе тоже вроде такая возможность была.
2. Вопрос - после смены канала требуется время чтоб провести новое измерение или нет. И если да какое время требуется?
Судя из описаний, дополнительного времени не требуется. Время на выбор канала вроде как входит во время измерения и занимает, если не изменяет память, первые 1,5 такта.
Fucking static initialization order fiasco
Re: CodeVision AVR в вопросах и ответах
Pink-Pank писал(а):1. открываете ассемблерный листинг и считаете ручками. .
как его открыть?
- Pink-Pank
- Опытный кот
- Сообщения: 721
- Зарегистрирован: Ср июн 11, 2014 09:43:13
- Откуда: США
- Контактная информация:
Re: CodeVision AVR в вопросах и ответах
В папке проекта файл .lss обычным блокнотом. Только учитывайте, что некоторые команды выполняются более, чем за 1 такт.
Fucking static initialization order fiasco
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: CodeVision AVR в вопросах и ответах
1) можно открыть cof файл, сгенерированный Codevision в Atmel AVR Studio и в режиме симуляции произвести замеры времени выполнения отдельных функций
2)задержка нужна, генератор кода так рекомендует
Время также зависит от выходного сопротивления источника, который подключен ко входу АЦП
.lss Codevision не делает - есть файлы с расширениями .asm и .lst
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 в вопросах и ответах
oleg110592 писал(а):задержка нужна, генератор кода так рекомендует
А еще генератор кода "рекомендует" обнулять регистры периферии при инициализации, в которых и так 0 содержится.
Fucking static initialization order fiasco
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: CodeVision AVR в вопросах и ответах
и это правильно - после переходных процессов может быть и не ноль, если делаем правильную и надежную программу - "лучше перебдеть чем не добдеть"
- Pink-Pank
- Опытный кот
- Сообщения: 721
- Зарегистрирован: Ср июн 11, 2014 09:43:13
- Откуда: США
- Контактная информация:
Re: CodeVision AVR в вопросах и ответах
После каких переходных процессов? )

1) Смысл этой задержки, если апдейт MUX и REFs происходит ПОСЛЕ запуска преобразования?
2) 10 мкс для какой частоты работы контроллера/АЦП?
К тому же, Вы можете изменить MUX до окончания текущего преобразования - и это на само преобразование никак не повлияет.
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 в вопросах и ответах
При включении устройства, на микроконтроллере питание не появляется мгновенно:
http://thebard.narod.ru/EPUS/bileti/16perexproc.htm
Если не включена система контроля питания (BOD) в микроконтроллере, то микроконтроллер может за время переходного процесса питания запустится несколько раз, что будет с регистрами предсказать невозможно. Поэтому делал всегда перед настройками периферии и заданием переменных задержку и обязательное обнуление и выключение не задействованной периферии.
http://thebard.narod.ru/EPUS/bileti/16perexproc.htm
Если не включена система контроля питания (BOD) в микроконтроллере, то микроконтроллер может за время переходного процесса питания запустится несколько раз, что будет с регистрами предсказать невозможно. Поэтому делал всегда перед настройками периферии и заданием переменных задержку и обязательное обнуление и выключение не задействованной периферии.
- Pink-Pank
- Опытный кот
- Сообщения: 721
- Зарегистрирован: Ср июн 11, 2014 09:43:13
- Откуда: США
- Контактная информация:
Re: CodeVision AVR в вопросах и ответах
Вообще-то для этого выставляется фьюзами время запуска МК. И обычно оно составлет 65 мсек, что в значительной мере превышает большинство всех переходных процессов. т.е. тактирование начнется после 65 мс устойчивой работы.
Fucking static initialization order fiasco
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: CodeVision AVR в вопросах и ответах
Вообще-то для этого выставляется фьюзами время запуска МК.
в моих устройствах нужны были задержки до 200мс.
насчет ацп рекомендую почитать известного человека: http://leoniv.livejournal.com/194681.html
- Pink-Pank
- Опытный кот
- Сообщения: 721
- Зарегистрирован: Ср июн 11, 2014 09:43:13
- Откуда: США
- Контактная информация:
Re: CodeVision AVR в вопросах и ответах
Это я читал. тема интересная. Но АЦП AVRки и STM значительно разнятся. ) Хотя принцип тот же.
Fucking static initialization order fiasco
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: CodeVision AVR в вопросах и ответах
Всем доброго времени суток.
Есть вопросик в программном исполнении АЦП на АТмега8.
С регистрами разобрался, примеры программ смотрел. Но что-то не на 100% работает.
Программа простая: на ножке ADC0 смотрим напряжение, передаём значения ADC на терминал по UART. Проще некуда, но ...
Удачно вывести значение получается только из старшего байта ADCH ... Когда ставлю хочу вывести значения 2-х байтового регистра ADCW, то вижу всевозможный "спам" вместо значений. Даташит перечитал, аж в глазах рябит ... Помогите, где ошибся?
Программа:
#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);
}
}
Есть вопросик в программном исполнении АЦП на АТмега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 в вопросах и ответах
ADMUX = 0x60; //0b01100000 - AVCC , ACD0
У Вас выравнивание по левому краю стоит. Бит ADLAR уберите - и выводите два регистра.
У Вас выравнивание по левому краю стоит. Бит ADLAR уберите - и выводите два регистра.
Fucking static initialization order fiasco
Re: CodeVision AVR в вопросах и ответах
Pink-Pank писал(а):ADMUX = 0x60; //0b01100000 - AVCC , ACD0
У Вас выравнивание по левому краю стоит. Бит ADLAR уберите - и выводите два регистра.
Убрал бит ADLAR ... Всё равно из ADCW сыпятся непонятные, всё время разные значения...
PS. нашёл ошибку. Дело в оглашении переменной функии unsigned char ADC_result(void) ... Тут как ни крути только 255 значений. Поменял на int - работает! Спасибо!
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Re: CodeVision AVR в вопросах и ответах
Продолжу задавать глупые вопросы
Пошёл дальше и решил сделать, чтобы результаты расчёта АЦП выводились в UART только по нажатии на кнопку (по прерыванию INT0). Мат часть изучил, код написал - не работает. Пляски с бубном пока не помогают.
Прошу помощи у добрых котов...
Программа:
#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;
};
}
}
Пошёл дальше и решил сделать, чтобы результаты расчёта АЦП выводились в UART только по нажатии на кнопку (по прерыванию INT0). Мат часть изучил, код написал - не работает. Пляски с бубном пока не помогают.
Прошу помощи у добрых котов... Программа:
Спойлер
#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 в вопросах и ответах
volatile unsigned char i
про volatile инфу найдите сами.
про volatile инфу найдите сами.
Fucking static initialization order fiasco
Re: CodeVision AVR в вопросах и ответах
Pink-Pank, огромное спасибо за внимание к моей "проблеме". Да, за volatile знаю, спасибо. Попробовал - увы, косяк где-то в другом... Возможно в инициализации прерывания, проверю.
Попутно другой вопрос (извините за мою любопытность) :
Шаг за шагом вдумчиво изучаю программирование и дописываю/изменяю программу, исследую новые возможности.
Теперь решил выводить значения ADC (АЦП) или же напряжения на светодиодный 7-сегментный индикатор.
Задачу поставил себе так, чтобы не было "мерцания" из-за меняющегося значения ADC.
Сначала думал делать замер нескольких значений и выводить среднее значение, но как-то не сраслось. Не понял как, знаний мало.
Выход из ситуации нашёл таким, что расчёт значений АЦП идёт по таймеру0 на частоте 8 кГц, а после идёт обработчик прерывания по таймеру2 на 100 кГц ... Результат устроил, в принципе. Мерцания нет.
Вопрос в том: как правильно делать? Хотелось, чтобы АЦП вычислялось раз в 0,2 сек (например) и затем выводились на индикатор.
Как это сделать? В основном цикле, почему-то, вызывать функцию обработки АЦП и делать задержку не получается... Индикатор несёт ахинею...
PS. извините за "многабукаф" ...
Программа:
#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)
{
}
}
Попутно другой вопрос (извините за мою любопытность) :
Шаг за шагом вдумчиво изучаю программирование и дописываю/изменяю программу, исследую новые возможности.
Теперь решил выводить значения 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 в вопросах и ответах
DataLife писал(а):Попробовал - увы, косяк где-то в другом... Возможно в инициализации прерывания, проверю.
Инициализацию я смотрел - вроде все норм. Без кнопки-то пробовали? Выводит значения?
DataLife писал(а):Вопрос в том: как правильно делать? Хотелось, чтобы АЦП вычислялось раз в 0,2 сек (например) и затем выводились на индикатор.
Сделать можно по разному. Можно через таймеры, можно через прерывания от АЦП, а можно вообще без прерываний. У Вас проблема была скорее всего в объемности расчетов из-за которых МК не успевал вывести значение на экран. Попробуйте оптимизировать код перевода 2->10. Вы несколько раз делите на кратные числа. Можно, например, ввести промежуточную переменную и остаток скажем, от деления на 1000 потом использовать для вычисления остатка от деления на 100, поделив его еще на 10 и т.д. Плавающую точку тоже не желательно использовать - много ресурсов ядра ест.
Усреднение АЦП можно делать "скользящим окном" с хранением последней суммы и . Тогда для вычисления следующей суммы нужно всего лишь вычесть первый элемент и добавить вновь полученный. количество элементов лучше брать кратным 2, чтобы операцию деления потом заменить операцией сдвига. Например, 8 элементов, заместо деления суммы пишем S=S>>3;
P.S. Правильный тот вариант - который работает так, как задумано, а не тот, который более красиво написан.
Fucking static initialization order fiasco