Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.78/141: Рейтинг темы: голосов - 141, средняя оценка - 4.78
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
1

Помогите с СИ (Проблемы написания программ)

04.05.2010, 23:03. Показов 25871. Ответов 54
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Помогите пожалуйста...
Как вытащить переменную с обработчика прерываний?

Например с АЦП. Вот код.

#include <avr/io.h>
#include <avr/interrupt.h> // доступ к функции sei
#include <avr/syknal.h> // доступ к макросу interrupt
#define sei()

unsykned int ADCdata; // буф переменная хранения

INTERRUPT(SIG_ADC) //Обработчик прерывания от АЦП
{

ADCdata = ADCW; //результата преобразования

ADCSR=ADCSR | 0x40; //Устанавливаем разряд ADSC в регистре
//ADCSR, чтобы начать новое преобразование
}

int main (void)
{
DDRD = 7; // Три младших разряда порта В - выходы
ADMUX = 1; // Назначаем в качестве аналогового входа PC3
ADCSR = 0xCE /* 0b11001110 - активизируем АЦП с коэффициентом
деления 64, разрешаем прерывание от АЦП и
начинаем преобразование */
sei(); //Общее разрешение прерываний
while(1); //Бесконечный цикл в ожидании прерывания от АЦП
return 0;
}

Вот. Мне значение переменной ADCdata надо вытащить в int main (void).
Помогите срочно нужно.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.05.2010, 23:03
Ответы с готовыми решениями:

Задачи для написания программ
Изучаю с++ в течение месяца: знаком с функциями, указателями, ссылками, классами, циклами, if,...

ПО для написания программ на Java.
Какое программное обеспечение нужно иметь у себя на компе, чтоб написать Веб-приложение на Java?...

Оцените стоимость написания программ
кто может помощь с написанием программ. Скажите свой e-mail и webmony и сколько будет стоить 3...

Правила написания Java-программ
Ребята. Подскажите где можно прочитать/узнать про: 1. Какую структуру каталогов лучше всего...

54
0 / 0 / 0
Регистрация: 12.07.2011
Сообщений: 2
04.05.2010, 23:14 2
while(1); //Бесконечный цикл в ожидании прерывания от АЦП
Никакие прерывания этот цикл не прервут.
return 0;
А по этому возврату разные компиляторы поступают по разному. Кто-то делает ресет, а кто-то делает глухой цикл.

Так что или добавляй еще логическую переменную конца преобразования (bool ADC_End) и делай while(ADC_End) или заноси в ADCdata что-нибудь маловероятное и жди в цикле пока оно не изменится.
0
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
04.05.2010, 23:28 3
Компилятор WinAVR. Отладка через AVR Studyo. Ну а если буду выжедать изменение переменной то дальше я все равно не смогу ее в главную функцию(int main (void)) кинуть.
0
SWK
04.05.2010, 23:36 4
И зачем такой геморрой? Я вон в МикроПаскале просто пишу:
Код
        U_Bat := ADC_Read(4);  // read 10-bit ADC from AN4
и получаю значение с нужного канала АЦП, остальное компилятор сам делает. И запустит преобразование, и конец отследит. И никаких проблем.
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
04.05.2010, 23:37 5
Спасибо большое! Буду разбераться!
0
0 / 0 / 0
Регистрация: 24.01.2010
Сообщений: 727
05.05.2010, 00:08 6
как-то некорректно вопрос задан...
что значит вытащить значение? оно в глобальной переменной, его вытаскивать не надо, оно везде есть
0
txim
05.05.2010, 04:49 7
Непонятно, зачем Вы дефайните sei(). Тем более ничем о_О. В interrupt.h уже есть его дефайн.
Во-вторых надо в main(), а точнее, в Вашем случае - в while(1), использовать значение ADCdata, впрочем, возможно вы просто не написали использование нам :)
А по существу - оптимизатор может при определенных условиях проверки ADCdata в main() не подумать о том, что эта переменная может меняться в прерывании и логика исполнения программы нарушится. Поэтому в объявлении этой переменной добавьте volatile ("изменчивый", указывает компилятору, что эта переменная может меняться в прерывании и ее оптимизировать надо осторожно):
volatile unsykned int ADCdata;
Эта переменная глобальная и будет видна и в main().
Надеюсь, что я правильно понял вопрос, а если вам нужно отловить сам факт считывания АЦП, тогда вводите флаги, делайте так, как сказал PRS.

to SWK

Но с другой стороны, такая функция останавливает выполнение программы до конца считывания с АЦП. Даже, если АЦП установить на 200 кГц, то при длительности считывания в 13 тактов АЦП и частоте ядра, скажем, в 8 МГц, получается задержка в 520 тактов. Иногда это бывает многовато.. И тогда геморрой с прерываниями необходим.
0 / 0 / 0
Регистрация: 28.01.2010
Сообщений: 569
05.05.2010, 07:55 8
В обработчике флаг выставить, в главном цикле его опрашивать, а после "переваривания" ADCdata сбросить.
0
SWK
05.05.2010, 08:56 9
Цитата Сообщение от txim
Но с другой стороны, такая функция останавливает выполнение программы до конца считывания с АЦП. Даже, если АЦП установить на 200 кГц, то при длительности считывания в 13 тактов АЦП и частоте ядра, скажем, в 8 МГц, получается задержка в 520 тактов. Иногда это бывает многовато.. И тогда геморрой с прерываниями необходим.
У меня, правда, PIC, при 16МГц время преобразования 24мкс, вся функция полностью отрабатывает меньше чем за 40мксек. (Из них во время преобразования крутится программная задержка 22мкс). Можно и подождать, (если, конечно, не делать выборки непрерывно). Я запускаю ее раз в 100 милисек. Если функцию считывания с АЦП перебьет прерывание - тоже проблем не вижу. Так что никаких остановок программы... Все в свое время.
txim
05.05.2010, 17:05 10
to SWK
Ну да, все зависит от конкретной задачи. В вашем случае функция подходит, а если захотеть, скажем, поизвращаться и записать во внешний флеш с АЦП голос (первое, что на ум пришло), то выборки будут идти почти непрерывно. Для каждой задачи - свой способ хорош. :)
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
05.05.2010, 23:19 11
Мне непрерывное преобразование не к чему, один раз преобразовал, а потом вышел в главную функцию main() и использовать дальше в других функциях(А если потебуется то можно опять преобразование сделать). Несмотря что это глобальная переменная, все равно в main() её поймать немогу. Помогите если можете выложите код. А то 2 дня с такой фигней ковыряюсь немогу сделать, опыта маловато.
0
0 / 0 / 0
Регистрация: 24.02.2010
Сообщений: 804
06.05.2010, 01:13 12
Не совсем понял, что именно хочет автор, но программу малость надо переделать:
Во-первых тот цикл является самой низкоприоритетной задачей в МК, и обычно урпавление остается в этом цикле на вечно (пока питание не отключат). Так что переделываем:

int main (void)
{
DDRD = 7; // Три младших разряда порта В - выходы
ADMUX = 1; // Назначаем в качестве аналогового входа PC3
ADCSR = 0xCE /* 0b11001110 - активизируем АЦП с коэффициентом
деления 64, разрешаем прерывание от АЦП и
начинаем преобразование */
sei(); //Общее разрешение прерываний
while(1)
{

}
return 0;
}

Вот. Теперь в этом цикле уже делайте с глобальной переменной, где хранится ADC, все, что вашей душе угодно. Это во-первых.
Во вторых, вы включаете прерывание, и в нем записываете глобальную переменную. А переменная у вас 4 байта. А AVR ки 8ми битные (если на AVR32 делаете, то можете это пропустить). А это значит, что все переменные, которые больше одного байта, пишутся/читаются в несколько циклов. А это, в свою очередь, означает, что в момент чтения переменной в основном цикле main может произойти прерывание от ADC и произойдет запись перменной, половину которой вы уже считали. Т.е.: в main считался, скажем один байт из перменной, произошло прерывание, после которого остальные три байта уже не отностятся к первому результату. Таким образом после считывания переменной имеем в ней один байт от старого значения и три - от нового, и в целом - полную чепуху.
Это называется Multitasking Error. Встречается сплош и рядом и решается обычно либо разграничением доступа с помощью флагов/семафоров, либо двойным буферированием.
Ну и попутно вопрос:
А что конкретно и где вы хотите делать с этой переменной?
Упдт.
И как тут уже указали - уберите строчку
#define sei()
а то никакого прерывания у вас не произойдет, поскольку вы переопределяете этот макрос в пустую строку и в итоге глобальный флаг не установится.
0
0 / 0 / 0
Регистрация: 12.07.2011
Сообщений: 2
06.05.2010, 01:32 13
Цитата Сообщение от MostirOtyxiy
Во вторых, вы включаете прерывание, и в нем записываете глобальную переменную. А переменная у вас 4 байта.
Почему 4 байта? Два. И читать ее можно между cli и sei. Тогда случайное изменение ей не грозит.
0
0 / 0 / 0
Регистрация: 24.02.2010
Сообщений: 804
06.05.2010, 01:41 14
Цитата Сообщение от PRS
Цитата Сообщение от MostirOtyxiy
Во вторых, вы включаете прерывание, и в нем записываете глобальную переменную. А переменная у вас 4 байта.
Почему 4 байта? Два. И читать ее можно между cli и sei. Тогда случайное изменение ей не грозит.
Точно - int на аврках - 2 байта.
А отключение прерываний грозит тем, что будет пропущено прерывание от ADC, а так как новый цикл конверсии включается именно в прерывании, то на этом измерения и закончатся.
А прерывание, какое нибудь, да пропустится, не первое, так десятое. Это уже проверенный факт.
Вообще - не рекомендуется отключать глобальный флаг прерываний именно по этой причине, если не хотите пропустить что либо.
0
0 / 0 / 0
Регистрация: 12.07.2011
Сообщений: 2
06.05.2010, 01:49 15
Ничего пропущено не будет. Флаги конкретных прерываний будут выставлены точно так же. И сработают сразу после их глобального разрешения. Максимум будет задержка вызова этого прерывания.
0
0 / 0 / 0
Регистрация: 24.02.2010
Сообщений: 804
06.05.2010, 02:37 16
Блин. Действительно, не пропускается. Знать упустил этот момент. Ну тогда автору только проще будет читать эту переменную.
0
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
06.05.2010, 23:12 17
Спасибо за помощь. Два дня с ней ковырялся, а сегодня утром встак выпил кофе и "ЭВРИКА!". Написал код за 10 минут, немного по другому и все работает как хотел. А конкретно данную программу хотел для считывания напряжения с аккомулятора. Сделал все отдельной функцией, один раз преобразовал и получил значение.
0
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
06.05.2010, 23:33 18
Новая говоломка как десятичное число преобразовать в двоичное чтобы выводить по биту на один из выходов. Пробую преобразовывать в двоичное делением на два, потом по остатку определяю бит, но код получается объемный и лишнюю работу МК дает. Уверен что есть другие способы, но незнаю о них. Нет ли более элегантного решения?
0
0 / 0 / 0
Регистрация: 24.01.2010
Сообщений: 727
06.05.2010, 23:41 19
Вообще самое элегантное решение в данном случае - ассемблер. А так... можно проверять SREG на выставление флага переноса.
0
0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
06.05.2010, 23:59 20
Нет с ассемблером облом потому-что это все одна программа, продолжение просто. А на Си че можно сделать?
0
06.05.2010, 23:59
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.05.2010, 23:59
Помогаю со студенческими работами здесь

Написания небольших программ для вычислений
Здравствуйте. Возникла необходимость написания небольших программ для вычислений, построении...

Каковы современные решения написания программ?
Уже пол года как изучаю с++. За это время решил не мало задачек и перечитал литературы. Писал все...

Где взять ТЗ для написания программ
Привет всем. Вот начал изучение и столкнулся с проблемой практикования своих знаний. Что сейчас...

Нужна практика написания программ на Javascript
Посмотрел несколько длинных видео уроков про яваскрипт, читал в интернете, пару программок написал...

Нужны идеи для написания программ
Решил учить си путём написания программ от простых к сложным. Так вот, идей чего-бы сделать нету, а...

Идеи написания программ новичку на Ассемблере
Здравствуйте, уважаемые жители данного форума! Я обращаюсь к Вам с просьбой &quot;кинуть&quot; сюда идеи...

Выбор ЯП для написания программ на основе Excel
Добрый день, друзья! Прошу Вашего совета. Не исключено, что мой сегодняшний выбор может стать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru