|
Проблема с volatile переменной - помогите плиз. |
|
|
|
Aug 19 2008, 14:21
|
Участник

Группа: Участник
Сообщений: 39
Регистрация: 18-10-07
Пользователь №: 31 472

|
Добрый день господа форумчане. У меня возникла проблема - очень надеюсь на вашу помощь. Пишу программу под PIC16F876 на PICC от HT-PICC. В программе захотел сделать функцию антидребезг. unsigned char do_antiripple_pin(volatile struct data_unit * data , char time_conversion);В эту функцию передаю время проверки на дребезг и указатель на структуру в которой содержиться иформация о ножке процессора. volatile struct data_unit { volatile unsigned char pin_addres; // Адрес пина на цоколевке процессора. unsigned char time_to_end; // Показывает сколько времени до конца преобразования unsigned char temp_pin_value; // Сохраняет временное значение на меняющимся пине проца. unsigned char changing_data; // Переменная с которой прграмма работает как с ножкой проца unsigned char diferences_counter; // Счетчик несовпадений пина и значения переменой за интервал };Проблема с полем pin_addres - это у меня просто имя пина ( допустим RA0), я объявил глобальный экземпляр структуры volatile struct data_unit button_data = {0,0,1,1,0};потом в main(); присвоил полю pin_addres значение RA0 button_data.pin_addres = RA0;ниже вызываю функцию do_antiripple_pin(&button_data,100);и надеюсь что у меня в функцию передасться значение с ножки порта, причем не просто значение а мгновенное, так как я везде где можно поставил volatile. Но этого не происходит. Программа как один раз зафиксировала в памяти значение button_data.pin_addres = RA0;так больше его не меняет, хотя значение на ножке меняется (это я вижу через IDC2). Выкладываю программу , там в листинге более понятно, чем я тут объясняю. Программма как следует не работает, но если закоментировать стр 31, и раскоментировать стр 92 тогда все работает нормально. Нормально так же все работает если передавать в функцию просто назвние ножки порта. Но вот почему не работает как мне надо??? (Т.е в том виде в котором выложил!) Помогите пожалуйста разобраться.
|
|
|
|
|
Aug 19 2008, 15:25
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
При вызове функции do_antiripple_pin квалификатор volatile относится непосредственно к указателю, а не к полям структуры, указатель на которую передается. Я не пойму зачем вам этот геморрой с указателями, если у вас структура глобальная? Обращайтесь в функции do_antiripple_pin непосредственно к ее полям, типа Код data_unit.temp_pin_value = data_unit.pin_addres; Если же вы хотите разнести работу со структурой по разным модулям, то создайте новый тип со всеми нужными volatile квалификаторами. И используйте этот тип в применении как к структурам, так и к указателям на них. Код #pragma pack(1) typedef struct data_unit_t { volatile unsigned char pin_addres; // Адрес пина на цоколевке процессора. unsigned char time_to_end; // Показывает сколько времени до конца преобразования unsigned char temp_pin_value; // Сохраняет временное значение на меняющимся пине проца. unsigned char changing_data; // Переменная с которой прграмма работает как с ножкой проца unsigned char diferences_counter; // Счетчик несовпадений пина и значения переменой за интервал } data_unit_t; #pragma pack() объявление структуры Код data_unit_t button_data = {0,0,1,1,0}; функция Код unsigned char do_antiripple_pin(data_unit_t * data , char time_conversion) { ... } А вообще, советую вам пересмотреть алгоритм и отказаться от бездумного использования квалификатора volatile где попало.
|
|
|
|
|
Aug 20 2008, 06:46
|
Участник

Группа: Участник
Сообщений: 39
Регистрация: 18-10-07
Пользователь №: 31 472

|
Уважаемый rezident. Я попробовал сделать как вы советовали. Результат тот же - ничего не получается. Поле pin_addres не обновляеися согласно со значением ножки RA0. А вот насчет того что истользовать volatile где попало не следует, я с вами согласен. Просто в программе пытался найти верный вариант методом проб и ошибок, по этому и поставил volatile где только возможно. И еще я передаю в функцию только указатель на структуру, что бы избежать лишнего копирования при передачи аргументов в функцию. Но главный вопрос так и остался открытым : "Почему переменная обьявлення как volatile и которой присвоено значение ножки процессора, на меняется согласно с изменением сигнала на этой ноге процессора ??? " Прикладываю новую версию программв с изменениями которые советовал внести г-н rezident.
|
|
|
|
|
Aug 20 2008, 15:29
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(Илья_ @ Aug 20 2008, 12:46)  Но главный вопрос так и остался открытым : "Почему переменная обьявлення как volatile и которой присвоено значение ножки процессора, на меняется согласно с изменением сигнала на этой ноге процессора ??? " Да потому, что вы никак не можете понять, что указатель это тоже переменная, которая содержит адрес переменной к которой вы обращаетесь с помощью этого указателя. Так вот значение адреса не меняется. Меняется содержимое переменной, которую вы адресуете с помощью указателя. Так что квалификатор volatile в определении указателя никак не влияет на считывание значения переменной с помощью этого указателя. Пример. Имеем условный 8-ми битный порт M по адресу 0x0010. Его определение в хидерах скорее всего такое portsdef.h Код #ifndef PORTSDEF_H #define PORTSDEF_H __no_init volatile unsigned char PORT_M @ 0x0010; #endif main.c Код #include "portsdef.h"
#define BIT0 0x01
unsigned char *pPortM;
void main(void) { pPortM=(unsigned char *)&PORT_M; ... if ((*pPortM&BIT0)==0) //Проверяем состояние первого бита порта M { ... } ... } Вне зависимости от того, как мы объявили указатель Код unsigned char *pPortM; или Код volatile unsigned char *pPortM; У нас содержимое самого указателя не меняется и всегда равно 0x0010. А меняется содержимое порта PORT_M по адресу 0x0010, адрес которого содержит указатель. Так, что для считывания реальных данных с порта нужно использовать специальную конструкцию заложенную компилятором (см. выше) и его непосредственный адрес. Код if ((PORT_M&BIT0)==0) { ... } Либо попробовать симмитировать ее, как-то так Код if ((((volatile unsigned char)(*pPortM))&BIT0)==0) { ... }
|
|
|
|
|
Aug 20 2008, 18:36
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Цитата(Илья_ @ Aug 20 2008, 10:46)  Уважаемый rezident.
Я попробовал сделать как вы советовали. Результат тот же - ничего не получается. Поле pin_addres не обновляеися согласно со значением ножки RA0.
А вот насчет того что истользовать volatile где попало не следует, я с вами согласен.
Просто в программе пытался найти верный вариант методом проб и ошибок, по этому и поставил volatile где только возможно.
И еще я передаю в функцию только указатель на структуру, что бы избежать лишнего копирования при передачи аргументов в функцию.
Но главный вопрос так и остался открытым : "Почему переменная обьявлення как volatile и которой присвоено значение ножки процессора, на меняется согласно с изменением сигнала на этой ноге процессора ??? "
Прикладываю новую версию программв с изменениями которые советовал внести г-н rezident. Уважаемый Илья! Поймите раз и навсегда. Переменная (или поле в структуре) - это значение, лежащее в некоторой ячейке памяти. Указатель на эту переменную - адрес этой ячейки памяти. Улавливаете, что никакими ножками порта тут не пахнет? Значит надо обеспечить программно чтение значения этой ноги и ее сохранение в вашей переменной. Volatile к этому процессу ну никаким образом. Volatile лишь запрещает компилятору оптимизировать эту переменную. Опрашивать состояние ножки можно либо в каком-либо программном цикле, либо по прерыванию, если можно организовать такое, по изменению значения на ноге (зависит от конкретного процессора)
|
|
|
|
|
Aug 20 2008, 20:15
|
Участник

Группа: Участник
Сообщений: 39
Регистрация: 18-10-07
Пользователь №: 31 472

|
Уважаемые господа, sergeeff и rezident. То что указатель содержит адрес ячейки памяти, в которой храниться значение переменной на которую этот указатель указывае - это азы Си. И они мне уверяю вас известны. А то что модификатор voltile в обьявлениии указателя может указывать что указатель, так сказать волатильный( т.е. может измениться не только из программы, как регистры переферии ), и может модификатор voltile указывать что указатель указывае на волатильную перменную. Вот цитата из прервода документации по компилятору HT-PICC: "Чтобы четче определить поведение и особенности указателя и объекта на который он указывает можно комбинировать различные квалификаторы. К наиболее часто употребимым квалификаторам относятся const, volatile, persistent. Применяя комбинации этих квалификаторов необходимо следить за соответствием (отсутствием противоречий) квалификаторов, оказывающих воздействие на свойства собственно указателя и объекта на котрый он указывает. Правила, которые помогут сделать все правильно, просты: если квалификатор находится слева от “*” в описании указателя, то он воздействует на объект, адресуемый указателем. Если квалификатор находится справа, то он воздействует на собственно указатель. Проиллюстрируем это примерами: volatile char * nptr; объявляет указатель на volatile символ. Другими словами в этом примере квалификатор воздействует на объект, адресуемый указателем nptr. char * volatile ptr; так как квалификатор располагается справа от “*”, то он будет воздействовать на собственно указатель ptr, а не на объект. И заключительный пример по этому поводу: volatile char * volatile nnptr; теперь будет описан volatile указатель на volatile переменную. Рассмотрим некоторые аспекты применения константных указателей. Они применяются для косвенного обращения к переменным описанным как const. В общем их поведение (константных указателей) не отличается от поведения обычных указателей, но компилятор препятствует выполнению операций записи с использованием этих указателей. Вот несколько примеров: const char * cptr; при этом выражение: char ch = *cptr; абсолютно легально, в то время как выражение: *cptr = ch; недопустимо и вызовет ошибку"Судя по тому что написано в описании, я совершенно правильно использовал квалификатор volatile, а то что сам указатель не меняется так это тоже верно. А я написал функцию которая выполняет антидребезг. И передаю в нее время , в течении которого проводить проверку на дребезг, и так же передаю в функцию структуру которая содержит информацию о пине. Так как антидребезг мы можем производить для любой из ножек контроллера к которой подклюен датчик или кнопка. Так вот я мог бы пердавать в функцию явно номер пина RA0 или RC5 и это бы работало. А если передавать структуру, в которой одним из полей будет номер пина (RA0 или RC5) то функция работает некоретно. И вот вопрос ПОЧЕМУ??? Кстати я пробовал работать и без указателей, тоже ничего не выходит, если номер пина я вляется полем структуры - так что видите что вазговоры о том что указатель волатильный, а сама переменная нет, по моему беспочвенны. Хотя быть может вы меня переубедите, если предложите другие аргументы.
|
|
|
|
|
Aug 20 2008, 20:29
|

Частый гость
 
Группа: Свой
Сообщений: 186
Регистрация: 14-01-06
Из: Украина, г.Харьков
Пользователь №: 13 168

|
Цитата(Илья_ @ Aug 19 2008, 17:21)  В эту функцию передаю время проверки на дребезг и указатель на структуру в которой содержиться иформация о ножке процессора. volatile struct data_unit { volatile unsigned char pin_addres; // Адрес пина на цоколевке процессора. unsigned char time_to_end; // Показывает сколько времени до конца преобразования unsigned char temp_pin_value; // Сохраняет временное значение на меняющимся пине проца. unsigned char changing_data; // Переменная с которой прграмма работает как с ножкой проца unsigned char diferences_counter; // Счетчик несовпадений пина и значения переменой за интервал }; Проблема с полем pin_addres - это у меня просто имя пина ( допустим RA0), я объявил глобальный экземпляр структуры volatile struct data_unit button_data = {0,0,1,1,0};потом в main(); присвоил полю pin_addres значение RA0
button_data.pin_addres = RA0;
ниже вызываю функцию do_antiripple_pin(&button_data,100); и надеюсь что у меня в функцию передасться значение с ножки порта, причем не просто значение а мгновенное, так как я везде где можно поставил volatile.
Но этого не происходит. Программа как один раз зафиксировала в памяти значение Уважаемый Илья  volatile тут вообще не причем  ваша программа работает строго так, как вы написали. "volatile unsigned char pin_addres " - Какой же это адрес ?!? Если адрес должен выглядеть как "volatile unsigned char * pin_addres". "button_data.pin_addres = RA0;" - как раз ОДИН РАЗ присваивает байтовой переменной pin_addres (которая адресом только называется и застряла в вашем воображении) ЗНАЧЕНИЕ пина RA0. а должно быть что-то вроде "button_data.pin_addres = &RA0;". Отсюда вывод - учить букварь по Си. А еще лучше учиться писать на Ассемблере, чтобы начать действительно понимать Си  А вообще (я именно про PIC не в курсе) - возможно для PIC такое косвенное обращение к портам ввода-вывода вообще невозможно, либо делается другими средствами.
|
|
|
|
|
Aug 20 2008, 21:26
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(rezident @ Aug 20 2008, 23:51)  Кстати, вы так и не привели выдержку о том, что представляет из себя символьное обозначение RA0. Дедуктивно предположу, что это разыменованный указатель на volatile переменную типа bit. Этот тип является расширением языка HI-TECH компилятора для пиков. И если компилятор позволяет делать указатели на такие типы (в чем я сомневаюсь, зная систему команд пика), то поле структуры должно быть объявлено как bit volatile * pin_address; или volatile bit * pin_address;, что одно и то же.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 21 2008, 10:12
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(rezident @ Aug 21 2008, 01:06)  А это как-то поможет с реализацией задуманного автором при использовании его структуры? Если бы архитектура пиков поддерживала указатели на биты (о чём Сергей и сказал), то помогло бы. Просто надо было бы так. Код unsigned char do_antiripple_pin(struct data_unit * data , char time_conversion) { ... if( data->changing_data != *data->pin_addres) // И если новые данные отличаются от старых { data->temp_pin_value = *data->pin_addres; // то сохраняем временные данные; data->diferences_counter++; // и увеличиваем счетчик несовпадений пина } Аналогично и Ваш пример Цитата(rezident @ Aug 20 2008, 18:29)  Либо попробовать симмитировать ее, как-то так Код if ((((volatile unsigned char)(*pPortM))&BIT0)==0) { ... } можно изменить так Код if ( ( (*(volatile unsigned char*)pPortM) & BIT0) ==0) { ... } Или вообще сразу объявить pPortM как volatile unsigned char * Тут достаточно адресуемости всего порта, но номер ножки придётся передавать отдельно и делать маску на месте. Так что автору вопроса надо что-то в духе Код struct data_unit { volatile unsigned char *port_address; unsigned char pin_number; // Дальше остальные поля, не факт, что все они должны быть volatile, это надо смотреть // Всю структуру делать volatile врядли надо, это как минимум сделает volatile и сам port_address, что // явно не нужно. Хотя, если сделать лишь одно обращение к полю port_address, как это сделано // ниже, квалифицирование port_address как volatile не приведёт к раздуванию кода ... };
...... unsigned char new_state = 0;
if( *data->port_address & (1 << data->pin_number) ) new_state = 1;
if( data->prev_state != new_state) { data->temp = new_state; ... // ну и дальше по вкусу, я не вникал в тонкости именно этого варианта подавления дребезга
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 21 2008, 12:01
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(AHTOXA @ Aug 21 2008, 13:56)  Можно ещё вот так: Код typedef int (* ReadStateFunc)(void); // прототип функции для чтения состояния ноги
// структура ноги typedef struct { ReadStateFunc ReadState; ...
}PinData;
... Можно и так. Причём в зависимости от архитектуры и прочего может оказаться, что это будет работать даже быстрее (косвенный вызов против сдвига в цикле деинички для создания маски). Что характерно, после этого возникает вопрос - а что там за споры были про С++? Неужели С-шная ручная эмуляция виртуальной функции опроса вывода кардинально эффективнее встроенной в язык поддержки? Она будет эффективнее, так как в С++ идёт рассчёт на возможное большое количество таких функций и в каждом экземпляре хранятся не непосредственно указатели на функции, а указатель на таблицу виртуальных функций класса, будет не просто выборка из структуры адреса функции и вызов, а выборка указателя на таблицу, выборка из неё указателя на функцию и только потом вызов. Но для большинства архитектур это не будет жутким перерасходом ресурсов.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Aug 21 2008, 12:21
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(ReAl @ Aug 21 2008, 18:01)  Можно и так. Причём в зависимости от архитектуры и прочего может оказаться, что это будет работать даже быстрее (косвенный вызов против сдвига в цикле единички для создания маски). Ну, маску можно сделать членом структуры:-) Но выигрыш будет всё равно мизерный. Цитата Что характерно, после этого возникает вопрос - а что там за споры были про С++? Это не ко мне, я-то как раз за Си++ :-)
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 22 2008, 07:32
|
Участник

Группа: Участник
Сообщений: 39
Регистрация: 18-10-07
Пользователь №: 31 472

|
Добрый день господа форумчане. Ваши советы, деийствительно дельные и очень помогают. Всем большое спасибо за это. Отдельное спасибо форуму за то что, объединяет профессоналов и людей интересующихся электроникой и является местом где можно изложить свою проблему. А грамотно изложив проблему людям с сам уже на полпути продвиншься к решению. Ибо не даром сказано "Кто ясно мыслит - тот ясно излагает." И чего следует, что надо время от времени ясно излагать что ды достичь ясности в мыслях.... Извините, за лиричиское отступление  (Остапа, как говориться, понесло....) Итак к делу: 1) Для большей ясности для начала отвечаю на вопрос г-на residenta: "Кстати, вы так и не привели выдержку о том, что представляет из себя символьное обозначение RA0." Вот ответ: static volatile bit RA0 @ (unsigned)&PORTA*8+0; static volatile unsigned char PORTA @ 0x05; и еще выдержка из описания к компилятору: " 2.9 Статические переменные Глобальные или статические переменные могут располагаться по абсолютному адресу. Для этого в описании переменной используется специальная конструкция “@ <адрес>”. Например: volatile unsigned char Portvar @ 0x06; Такое описание дает возможность обращаться к абсолютному адресу 0х06 посредствам переменной Portvar. Надо учитывать, что в этом случае компилятор не резервирует память под размещение этой переменной. С точки зрения ассемблера это описание выглядит следующим образом: Portvar equ 06h"2) Прав г-н Олег Хохлов написав: ""volatile unsigned char pin_addres " - Какой же это адрес ?!? Если адрес должен выглядеть как "volatile unsigned char * pin_addres"." Вводя в структуру поле pin_addres я имел ввиду что мне нужна переменная , входящая, которая будет содержать тоже что и переменная RA0 в любой момент времени. А то что надо просто связать мое поле структуры и ножку RA0 через адрес у меня в голове на тот момент четко не оформилось. 3) И вот тут я подошел к тому о чем писал г-н Сергей Борщ : "И если компилятор позволяет делать указатели на такие типы (в чем я сомневаюсь, зная систему команд пика), то поле структуры должно быть объявлено как bit volatile * pin_address; или volatile bit * pin_address;, что одно и то же" Да, компилятор не прозволяет делать указатели на переменные типа бит и следует, ввести структуру поле - адрес номера порта, и поле - номер бита в порте, тогда проблема решается. Но об этом же написал г-н ReAl И вот тут я пришел к тому, что нехочется мне в структру вводить дополнительное поле и я решил сделать по другому - см. прикрепленные файлы. Все в таком работает отлично, только мне опять приходиться опять перед вызовом функции антидребезг обновлять значение ножки порта в структуре. Как бы мне от этого избавиться , что бы один раз(при инициализаци) связать значение ножки порта и поле структуры? Г-ну AHTOXе хочу сказать что его вариант конечно интересный, но писать одинаковые функции для каждой ножки порта я нахожу громоздким. А если ножек 80 как в PIC18f87j10? Я же хочу написать универсальную функцию.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|