0 / 0 / 0
Регистрация: 03.12.2017
Сообщений: 34
|
|
1 | |
Помогите с СИ (Проблемы написания программ)04.05.2010, 23:03. Показов 25871. Ответов 54
Метки нет (Все метки)
Помогите пожалуйста...
Как вытащить переменную с обработчика прерываний? Например с АЦП. Вот код. #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
|
04.05.2010, 23:03 | |
Ответы с готовыми решениями:
54
Задачи для написания программ ПО для написания программ на Java. Оцените стоимость написания программ Правила написания Java-программ |
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
|
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
0
|
0 / 0 / 0
Регистрация: 24.02.2010
Сообщений: 804
|
|
06.05.2010, 01:41 | 14 |
Сообщение от PRS
Точно - 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 | |
06.05.2010, 23:59 | |
Помогаю со студенческими работами здесь
20
Написания небольших программ для вычислений Каковы современные решения написания программ? Где взять ТЗ для написания программ Нужна практика написания программ на Javascript Нужны идеи для написания программ Идеи написания программ новичку на Ассемблере Выбор ЯП для написания программ на основе Excel Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |