Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Запись в EEPROM
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
smk
ATtiny24

Имеется код:
void EEPROM_write(unsigned char Address, unsigned char Data)
{
while (EECR & (1<<EEPE));
EECR = (0<<EEPM1) | (0>>EEPM0)
->EEARH=0b00000000;
EEARL= Address;
EEDR = Data;
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
}

Имеется сообщение об ошибке:
../1.c: In function 'EEPROM_write':
../1.c:23: error: called object '0' is not a function

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

Пример 'один в один'. Написано в WinAVR 2007, симулятор AVR Studio 4.13

Помогите разобраться в чем причина? Заранее благодарен!

Кстати нижеприведенный код проблем не вызывает:
unsigned char EEPROM_read (unsigned char Address)
{
while (EECR & (1<<EEPE));
EEARL= Address;
EECR |= (1<<EERE);
return EEDR;
}
Сергей Борщ
Цитата(smk @ Jan 11 2008, 20:06) *
если строчку закомментировать, то указатель покажет на ту что под ней, ошибка та же.
Вы забыли точку с запятой в конце предыдущей строки поставить.
smk
Цитата
Вы забыли точку с запятой в конце предыдущей строки поставить.

Точно! Благодарю за совет, очень признателен , простите что отвлек по такой простой причине.
smk
Теперь другая непонятная штука. Не выполняется оператор i++; Он просто пропускается симулятором. Почему?

unsigned char i;
while (i<240)
{
while(TIFR1 & (1<<TOV1))
{
TCNT1H = 0xF8;
TCNT1L = 0x5F;
i++;
PORTA^=0b00000100;
TIFR1 |= (1<<TOV1);
}
}

Буду благодарен за подсказку.
Stanislav
Цитата(smk @ Jan 11 2008, 23:48) *
Теперь другая непонятная штука. Не выполняется оператор i++; Он просто пропускается симулятором. Почему?

unsigned char i;
while (i<240)
{
while(TIFR1 & (1<<TOV1))
{
TCNT1H = 0xF8;
TCNT1L = 0x5F;
i++;
PORTA^=0b00000100;
TIFR1 |= (1<<TOV1);
}
}

Буду благодарен за подсказку.

Э-э, а чему равно начальное значение i ?

PS. Пропускаться может по такой причине: переменная i у Вас во внутреннем цикле явно не используется, поэтому она была "оптимизирована" компилятором.

Не разобрался, сперва для чего нужно i. Для того, чтобы не оптимизилось, операцию нужно сделать volatile.
smk
Цитата
чему равно начальное значение i ?

равно 0.

применил volatile - проблема снялась. странно почему заоптимизировал....
Stanislav
Цитата(smk @ Jan 12 2008, 00:34) *
равно 0.
Вообще-то, инициализировать нужно обязательно, если это не глобальная переменная.
Цитата(smk @ Jan 12 2008, 00:34) *
применил volatile - проблема снялась. странно почему заоптимизировал....
Точно.
Видимо, оптимизатор за рамки вложенного цикла вылезти не может. Впрочем, здесь я не спец; возможно, старшие товарищи разъяснят. smile.gif

PS. Кстати, лажа у Вас, по-моему, написана...
zltigo
Цитата(smk @ Jan 11 2008, 23:34) *
применил volatile - проблема снялась.

Главная проблема не снялась - написан мягко говоря непонятный код. Не понятный ни человеку ни тем более компилятору.
1. Даже если переменная i глобальная, то обнулена она будет только при первом проходе.
2. i бесконтрольно и независимо увеличивается во внутреннем цикле. Чем ограничено количество внутренних циклов? 1 - 100 - миллион? Что будет с i при, например, 256 циклах - Вам ведомо?
3. Вы хоть сами сможете словами обьяснить для чего пляски с бубном вокруг i ?
4. Остальное выглядит еще хуже sad.gif
5. Если после всего этого несчастному симулятору снесет крышу, я не решусь его упрекнуть.
Gogan
Цитата(smk @ Jan 11 2008, 22:48) *
while(TIFR1 & (1<<TOV1))

я бы это заменил на if, так как при первом же проходе устанавливается регистр так, чтобы след. раз условие не выполнялось... и наглядней.
Хотя не понятно зачем считывать флаг прерываний вместо того, чтобы использовать само прерывание.
Можно либо разрешить прерывание по переполнению и в нем выполнять
TCNT1H = 0xF8;
TCNT1L = 0x5F;
i++;
PORTA^=0b00000100;
где i должна быть глобальной
либо запустить режим сброса таймера по сравнению (CTC mode), чтобы он считал от 0 до сравнения (например до OCR1A=0xFFFF - 0xF85F=0x7A0), затем в прерывании по сравнению делать тоже кроме обновления счетчика.
smk
Цитата
1. Даже если переменная i глобальная, то обнулена она будет только при первом проходе.

да, она глобальная. пользую везде где нужен счетчик.

Цитата
2. i бесконтрольно и независимо увеличивается во внутреннем цикле. Чем ограничено количество внутренних циклов? 1 - 100 - миллион? Что будет с i при, например, 256 циклах - Вам ведомо?

Программа жздет появление флага переполнения таймера,
while(TIFR1 & (1<<TOV1))
выполняет предустановку
{
выполняет предустановку
TCNT1H = 0xF8;
TCNT1L = 0x5F;
наращивает счетчик
i++;
делает что-то полезное
PORTA^=0b00000100;
сбрасывает флаг
TIFR1 |= (1<<TOV1);
}
и так до очередного выброса флага...

когда i=240 - программа выходит из внешнего цикла. прерывания не использовал т.к. нет нужды делать чего-то во время ожидания.
Цитата
запустить режим сброса таймера по сравнению (CTC mode)

так и есть, режим СТС.

ну мне так видится, а как бы вы написали? я учусь и мне юудет интересно посмотреть на иные решения. Заранее спасибо.

Цитата
4. Остальное выглядит еще хуже

все может быть... а как правильнее?

Цитата
3. Вы хоть сами сможете словами обьяснить для чего пляски с бубном вокруг i ?

попробую... суть в том, что мне нужно отмерять промежутки времени, кратные 1 с, сигнализируя об их течении мигающим светодиодом или выполняя какие-либо действия в иные промежутки:
промежуток 1 - действие 1;
промежуток 2 - действие 2;
.
.
.
промежуток N - действие N.


а так лучше?

while((TIFR1 & (1<<TOV1))&(i<240))
{
TCNT1H = 0xF8;
TCNT1L = 0x5F;
i++;
PORTA^=0b00000100;
TIFR1 |= (1<<TOV1);
}
Gogan
Цитата(smk @ Jan 12 2008, 10:23) *
а так лучше?

while((TIFR1 & (1<<TOV1))&(i<240))

Тут ошибка, нужно while((TIFR1 & (1<<TOV1))&&(i<240)) (второе И логическое а не побитное)
Вобщем, если ничего более выполнять не нужно, либо оно выполняется в других прерываниях, тогда ваш вариант решения сойдет, да и проще чем через прерывания.
Сергей Борщ
Цитата(smk @ Jan 12 2008, 10:23) *
да, она глобальная. пользую везде где нужен счетчик.
И очень напрасно. Если бы вы заводили ее каждый раз локально, компилятор мог бы, во-первых, разместить ее в регистре (что очень хорошо как для скорости, так и для размера) и, во-вторых, не сохранять ее значение после окончания цикла (оно ведь вам не нужно).

По циклу - лучше переменную увеличивать прямо в месте проверки или сразу перед ним - тогда компилятор сможет для проверки воспользоваться флагами, остающимися от операции инкремента. Еще с точки зрения эффективности лучше инициализировать i числом и потом уменьшать, проверяя на ноль.
zltigo
Это BLINKS раз моргнет светодиодиком используя опрос флага переполнения таймера.
Код
#define BLINKS 120
#define BIT_MY_LED (1<<2)
#define T1_DIV 0xF85F

for( uint_least8_t  i = (BLINKS)<<1;; )
{
    if( TIFR1 & (1<<TOV1) ) )
   {    TCNT1H = (unsigned char)((T1_DIV)>>8);
         TCNT1L = (unsigned char)T1_DIV;
         PORTA ^= BIT_MY_LED;
         TIFR1 |= (1<<TOV1); // Уверены, что сбрасывается '1' а не нулем?
         if( !--i )
              break;
    }
}


Если честно, то я из тестового описания не уверен, что понял. Проблема Вашего описаня в том, что Вы задачу так ине сформулировали. Задача, например, - выкопать канаву. Вместо этого Вы попыталтсь рассказать как Вы держите лопату и как далеко кидаете землю и прочее.... Понято, что что-то хотите выкопать, но что уже не совсем понятно sad.gif
smk
Цитата
Задача, например, - выкопать канаву

Задача держать включенным некий прибор в течение определенного времени (например 1 мин), мигая при этом светодиодом. Далее проверяем условие и решаем что делать дальше в зависимости от результата.
zltigo
Цитата(smk @ Jan 12 2008, 16:26) *
Задача ...

Тогда приведенное выше где-то как-то может послужить мигалкой.
smk
Строчка:
for( uint_least8_t i = (BLINKS)<<1;; )
привела вот к такому сообщению:
../1.c:157: error: 'for' loop initial declaration used outside C99 mode

а вообще не уверен что аналог...
zltigo
Цитата(smk @ Jan 12 2008, 17:44) *
../1.c:157: error: 'for' loop initial declaration used outside C99 mode

Переключите компилятор в режим следования свежему 1999 года стандарту языка "C".
Если вдруг найдутся неведомые мне причины не использовать современные компиляторы, то тогда
так:
Код
{
   uint_least8_t  i = (BLINKS)<<1;
   for(;; )
   {
......
   }
}


Цитата
а вообще не уверен что аналог...

Договаривайте.
smk
Цитата
Переключите компилятор в режим следования свежему 1999 года стандарту языка "C".


не могу разобраться как... пробовал в makefile, но не дает. в makefile из директории WinAVR установлен режим gnu99. а есть ли возможность из AVR Studio изменить этот режим?

gnu99
gnu9x The 1999 C standard plus GNU extensions.

вот такое сейчас включено. если я не ошибаюсь, по умолчанию всегда так у WinAVR.
zltigo
Цитата(smk @ Jan 12 2008, 18:57) *
но не дает....

Что такое "не дает" мне не ведомо, но найдите, где можно добавить ключи для командной строки относящиеся ко всему проекту и допишите туда:
-std=c99
или
-std=gnu99



Цитата(smk @ Jan 12 2008, 19:21) *
если я не ошибаюсь, по умолчанию всегда так у WinAVR.

без понятия, разнообразными IDE не пользуюсь в принципе.
smk
попробовал - решение действительно хорошее и код стал меньше.


А чем i = (BLINKS<<1); лучше i=240?
zltigo
Цитата(smk @ Jan 12 2008, 20:21) *
А чем i = (BLINKS<<1); лучше i=240?

240 это какое-то число, а BLINKS это осмысленное количество морганий. На код, естественно, совершенно не повлияет, но ошибиться задав нечтное число - нельзя, читать и потом сопровождать - удобнее.
smk
Цитата
BLINKS это осмысленное количество морганий

Спасибо за идею!
тогда уже i = (BLINKS<<2); - длительность включения нагрузки в секундах. это точно лучше. А количество морганий - главное чтоб не нудно мограло, а живенько более-менее.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.