|
AVR 5.11 Ошибка при двухбайтном сравнении! |
|
|
|
Feb 2 2009, 22:54
|

Частый гость
 
Группа: Свой
Сообщений: 76
Регистрация: 17-03-07
Из: Минск
Пользователь №: 26 243

|
Такой код:
volatile unsigned int msCounter = 0;
...
if (msCounter >= 1000) {
msCounter = 0;
//...
}
Иногда сравнение выполняется неправильно и входит в блок при значении msCounter = 768. Установлено, что при двухбайтном сравнении происходит прерывание, в котором инкрементируется msCounter, что и приводит в последствии к ошибке.
if (msCounter >= 1000) { 00014A E9EB LDI R30,0x9B 00014C E0F1 LDI R31,0x01 00014E 8100 LD R16,Z ...тут прерывание и инкрементирование сравниваемой величины... 000150 8111 LDD R17,Z+1 000152 3E08 CPI R16,0xE8 000154 4013 SBCI R17,0x03 000156 F390 BRCS 0x13C ...
Вопрос: Можно ли заставить компилятор автоматически разруливать такие вещи?? Или это нужно постоянно держать в голове и делать вот так:
__disable_interrupt();
if (msCounter >= 1000) {
msCounter = 0;
//...
}
__enable_interrupt();
Заранее благодарен!
|
|
|
|
|
 |
Ответов
|
Feb 2 2009, 23:18
|

Частый гость
 
Группа: Свой
Сообщений: 76
Регистрация: 17-03-07
Из: Минск
Пользователь №: 26 243

|
Цитата(zltigo @ Feb 3 2009, 01:04)  Нет. Для AVR это Ваши проблемы. Запрет прерываний или другой метод обеcпечения атомарности надо использовать явно. Для какой платформы это проблемы компилятора? Цитата(zltigo @ Feb 3 2009, 01:04)  Запрет прерываний или другой метод обеcпечения атомарности надо использовать явно. Другой метод? Какой например?
|
|
|
|
|
Feb 2 2009, 23:41
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(NewMaestro @ Feb 3 2009, 04:18)  Другой метод? Какой например? Код unsigned int tmp1, tmp2; do { tmp1=msCounter; tmp2=msCounter; } while(tmp1!=tmp2); if (tmp2 >= 1000) { ... } А вот с обнулением сложнее.  Это вообще неправильный подход к программированию когда volatile-переменная с неатомарным доступом модифицируется сразу в нескольких частях программы. Либо используйте дублирование этой переменной с семафором доступа, либо используйте семафор для ее обнуления. Вообще это так принципиально ее в майне обнулять?
|
|
|
|
|
Feb 3 2009, 07:53
|

Частый гость
 
Группа: Свой
Сообщений: 76
Регистрация: 17-03-07
Из: Минск
Пользователь №: 26 243

|
Цитата(rezident @ Feb 3 2009, 01:41)  Код unsigned int tmp1, tmp2; do { tmp1=msCounter; tmp2=msCounter; } while(tmp1!=tmp2); if (tmp2 >= 1000) { ... } А вот с обнулением сложнее.  Это вообще неправильный подход к программированию когда volatile-переменная с неатомарным доступом модифицируется сразу в нескольких частях программы. Либо используйте дублирование этой переменной с семафором доступа, либо используйте семафор для ее обнуления. Вообще это так принципиально ее в майне обнулять? Как-то уж очень геморно. Интеррапты запрещать как-то читабельней. Хотя, тоже фигня... А если не в майне обнулять, то где? Для того, чтобы ошибки не было нужно только там же, где приращение происходит, т.е. в прерывании. A volatile - это в данном случае и не обязательно как я понимаю. volatile ведь нужно применять для переменных, которые могут быть изменены аппаратно. А тут только софтово, просто в прерывании. Я тему открыл потому, что ситуация эта неправильная какая-то. Я считаю, что компилятор должен об этом заботиться, а он игнорирует и заставляет юзера принимать доп.меры. Вот я и пытаюсь узнать как заставить компилятор правильно компилировать. ...Дело в том, что таких ситуаций немеренно, когда в функциях происходят сравнения данных, которые могут быть изменены в прерывании. Это ж повсеместно!! И что?? Перед каждым if, case, while, for... запрещать прерывание, чтобы переменная правильно сравнивалась??????....... Ну не гемор разве?... PS. zltigo тему быстренько перенес в ветку для ламеров, а сам как всегда определенного ответа дать не смог. Сколько помню его, все ходит вокруг да около и мало кому реально помогает. Я уж и сомневаюсь что он профессионал.
|
|
|
|
|
Feb 3 2009, 17:07
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(NewMaestro @ Feb 3 2009, 12:53)  Как-то уж очень геморно. Вы же сами просили вариант без прерываний! Цитата(NewMaestro @ Feb 3 2009, 12:53)  А если не в майне обнулять, то где? Для того, чтобы ошибки не было нужно только там же, где приращение происходит, т.е. в прерывании. А на зачем ее вообще сбрасывать-то? Пущай переменная инкрементируется себе спокойно в прерывании, а вы используйте для отсчета интервалов (вам ведь интервал отмерить нужно?) локальную переменную и беззнаковую разность при проверке. Выглядеть это будет вот так. CODE volatile unsigned int msCounter; void main (void) { unsigned int tmp1, tmp2; (static) uinsigned int period; //static нужен, если эта или аналогичная по назначению переменная //будет использована в любой другой функции, кроме main ... do { tmp1=msCounter; tmp2=msCounter; } while (tmp2!=tmp1); //цикл для считывания msCounter не нужен, если прерывания еще не разрешены period=tmp2; //делаем первую засечку для отсчета интервала ... for (;;) { ... do { tmp1=msCounter; tmp2=msCounter; } while (tmp2!=tmp1); //считываем msCounter без запрета прерываний if ((tmp2-period)>=1000) //событие наступило? { period=tmp2; //делаем новую временнУю засечку для отсчета нового интервала ... //обрабатываем событие по данной временнОй засечке } ... } }
Тут главный нюанс состоит в том, что период переполнения msCounter должен быть не меньше, чем максимальный требуемый вам интервал и переменная должна быть именно беззнаковая. Причем при таком способе, используя всего лишь одну переменную счетчика, можно в программе завести сколько угодно переменных для временнЫх засечек и счетчиков интервалов. При вашем же способе (сброс где-то вне прерывания) пришлось бы инкрементировать в прерывании именно столько счетчиков, сколько вам потребовалось бы временных засечек/интервалов. Цитата(NewMaestro @ Feb 3 2009, 12:53)  A volatile - это в данном случае и не обязательно как я понимаю. volatile ведь нужно применять для переменных, которые могут быть изменены аппаратно. А тут только софтово, просто в прерывании. Фигню вы тут написали.  Переменные аппаратно не модифицируются. Аппаратно только какие-либо регистры периферии МК могут изменятся. Да, в зависимости от архитектуры МК для адресации они могут быть объявлены как volatile, но квалификтор volatile при этом вовсе не обозначает, что переменная аппаратно изменяется. Почитайте стандарт C99. Будет больше пользы, если вы сами найдете, "переварите", осознаете и запомните эту информацию.
|
|
|
|
Сообщений в этой теме
NewMaestro AVR 5.11 Ошибка при двухбайтном сравнении! Feb 2 2009, 22:54    zltigo Цитата(NewMaestro @ Feb 3 2009, 10:53) PS... Feb 3 2009, 08:22    haker_fox Цитата(NewMaestro @ Feb 3 2009, 15:53) PS... Feb 3 2009, 12:36 alux Цитата(NewMaestro @ Feb 3 2009, 01:54) Мо... Feb 3 2009, 09:12 zltigo Цитата(alux @ Feb 3 2009, 12:12) Для Ваше... Feb 3 2009, 12:07 Legotron Цитата(alux @ Feb 3 2009, 12:12) Для Ваше... Feb 3 2009, 16:14 xemul Цитата(NewMaestro @ Feb 3 2009, 01:54) Та... Feb 3 2009, 13:46 haker_fox Цитата(xemul @ Feb 3 2009, 21:46) Такой к... Feb 3 2009, 14:12  xemul Цитата(haker_fox @ Feb 3 2009, 17:12) Поч... Feb 3 2009, 14:22
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|