|
bit set, C |
|
|
|
Jul 22 2007, 09:14
|

Участник

Группа: Участник
Сообщений: 35
Регистрация: 8-07-07
Пользователь №: 28 963

|
Правильно ли я понял: 1) Код TIMSK = (1 << OCIE2); 2) Код TIMSK |= (1 << OCIE2); ---------- В первом случае установится только бит OCIE2, остальные будут нулями. Во втором случае все биты кроме OCIE2 останотся неизменными, а этот бит станет единицей. ---------- Правильно? -dmitry.
|
|
|
|
|
Jul 22 2007, 18:40
|

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

|
Цитата(i.dmitry @ Jul 22 2007, 12:14)  Во втором случае все биты кроме OCIE2 останотся неизменными, а этот бит станет единицей. Если строго, то не "останутся неизменными", а "в них запишется то, что из них прочиталось". Обычно это одно и то же. Но в регистрах, где есть биты, сбрасываемые записью "1", при такой операции эти биты будут сброшены.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 22 2007, 19:45
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(_artem_ @ Jul 22 2007, 22:03)  в iar mожно еще так : PORTA_Bit4 = 1; Не стоит пользоваться. Крайне сомнительное расширение  , ибо: 1. Не переносима; 2. Неявное чтение может либо просто быть лишним, либо даже вредным, если из регистра не читается записанное значение, либо регистр содержит зарезервированные биты, либо операция чтения имеет побочные эффекты.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jul 22 2007, 19:52
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Вообще говоря результат действия 1 << OCIE2 зависит от того, какое число сопоставлено символьному имени OCIE2. Выражение вида "1<<x" означает "сдвинуть число 1 на x разрядов влево", т.е. в сторону старших разрядов. Справа (в младший разряд) при таком сдвиге дописывается нуль. Насколько я понимаю OCIE2 это седьмой (если счет от нуля) бит в регистре TIMSK. Если имени OCIE2 сопоставлено число 7 Код #define OCIE2 7 то результат операции Код TIMSK |= (1<<OCIE2); что эквивалентно Код TIMSK = TIMSK |(1<<OCIE2); а макроподстановка даст выражение Код TIMSK = TIMSK|(1<<7); будет верным - в регистре TIMSK будет установлен седьмой бит (счет от нуля). Если же символьному имени OCIE2 сопоставлена битовая маска регистра TIMSK (что чаще всего и используют в хидерах компиляторов) Код #define OCIE2 0x80 то результат будет неадекватным. Т.к. в результате макроподставноки получится выражение Код TIMSK = TIMSK|(1<<128); которое будет означать "совершить операцию побитного сложения содержимого регистра TIMSK с числом 1, сдвинутым влево на 128 бит (0x80=128), и записать результат в TIMSK". Так что i.dmitry перед использованием символьного обозначения убедитесь в его значении!
|
|
|
|
|
Jul 22 2007, 20:17
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(ReAl @ Jul 22 2007, 21:40)  Если строго, то не "останутся неизменными", а "в них запишется то, что из них прочиталось". Обычно это одно и то же. Но в регистрах, где есть биты, сбрасываемые записью "1", при такой операции эти биты будут сброшены. Если хотите говорить строго, то или будьте точны или не будьте так категоричны. Сказанное Вами правильно при работе с регистрами на которые не распространяются команды SBI, CBI (в частности регистра TIMSK). И возможно, это справедливо для некоторых компиляторов. Скажем команда PORTA |= (1<<5); компилятором IAR компильнётся в SBI PORTA,5 что, очевидно, не затронет остальные биты.
|
|
|
|
|
Jul 22 2007, 21:30
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(SasaVitebsk @ Jul 22 2007, 20:17)  Сказанное Вами правильно при работе с регистрами на которые не распространяются команды SBI, CBI (в частности регистра TIMSK). И возможно, это справедливо для некоторых компиляторов. Скажем команда PORTA |= (1<<5); компилятором IAR компильнётся в SBI PORTA,5 что, очевидно, не затронет остальные биты. Известно, что для аврок нового поколения команда sbi pinb,1 изменяет состояние пина на противоположное. Отсюда вопрос, как сказать такое си компилятору? Должно быть что-то типа PINB |= (1<<1); или я не прав?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Jul 22 2007, 22:07
|

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

|
Цитата(SasaVitebsk @ Jul 22 2007, 22:17)  Если хотите говорить строго, то или будьте точны или не будьте так категоричны.  Давайте договоримся: прежде, чем указывать мне на то, что я должен быть точен - как минимум сами делайте то, что делаю я - проверяйте достоверность своих утверждений. Цитата(SasaVitebsk @ Jul 22 2007, 22:17)  Сказанное Вами правильно при работе с регистрами на которые не распространяются команды SBI, CBI (в частности регистра TIMSK). И возможно, это справедливо для некоторых компиляторов. Скажем команда PORTA |= (1<<5); компилятором IAR компильнётся в SBI PORTA,5 что, очевидно, не затронет остальные биты. Блажен, кто верует. Продолжайте дальше в том же духе, только не тащите в свою веру остальных. Не "не затронет", а "запишет в них то, что в них было". Для PORTA эти два утверждения эквивалентны, а вот для ACSR... Пишем маленькую функцию (тут atmega64, но на atmega8515 это тоже проверялось в железе): Код #define AC_MINUS E,3,L void sbi_test(void) { dbg_putstr_P(dbg_always, PSTR("SBI RMW behavior test\n")); DRIVER(AC_MINUS,OUT); OFF(AC_MINUS); ACSR = _BV(ACBG); _delay_us(100); // let bandgup on ACSR |= _BV(ACI); // clr interrupt flag dbg_printf_P(dbg_always, PSTR("Initial ACSR = 0x%02X\n"), ACSR); ON(AC_MINUS); _delay_us(2); // AC propagation delay dbg_printf_P(dbg_always, PSTR("AC- toggled, ACSR = 0x%02X\n"), ACSR); ACSR |= _BV(ACIE); dbg_printf_P(dbg_always, PSTR("ACSR |= _BV(ACIE), ACSR = 0x%02X\n"), ACSR); } Вот что нагенерил avr-gcc, прошу обратить внимение на на строку для ACSR |= _BV(ACIE), она там старательно выделена. CODE 00002804 <sbi_test>: #define AC_MINUS E,3,L void sbi_test(void) { 2804: 60 ed ldi r22, 0xD0 ; 208 2806: 72 e0 ldi r23, 0x02 ; 2 2808: 80 e0 ldi r24, 0x00 ; 0 280a: 0e 94 6d 2a call 0x54da ; 0x54da <dbg_putstr_P> dbg_putstr_P(dbg_always, PSTR("SBI RMW behavior test\n")); DRIVER(AC_MINUS,OUT); 280e: 13 9a sbi 0x02, 3 ; 2 OFF(AC_MINUS); 2810: 1b 9a sbi 0x03, 3 ; 3 ACSR = _BV(ACBG); 2812: 80 e4 ldi r24, 0x40 ; 64 2814: 88 b9 out 0x08, r24 ; 8 void _delay_loop_1(uint8_t __count) { __asm__ volatile ( 2816: 85 ef ldi r24, 0xF5 ; 245 2818: 8a 95 dec r24 281a: f1 f7 brne .-4 ; 0x2818 <sbi_test+0x14> _delay_us(100); // let bandgup on ACSR |= _BV(ACI); // clr interrupt flag 281c: 44 9a sbi 0x08, 4 ; 8 dbg_printf_P(dbg_always, PSTR("Initial ACSR = 0x%02X\n"), ACSR); 281e: 88 b1 in r24, 0x08 ; 8 2820: 99 27 eor r25, r25 2822: 9f 93 push r25 2824: 8f 93 push r24 2826: 89 eb ldi r24, 0xB9 ; 185 2828: 92 e0 ldi r25, 0x02 ; 2 282a: 9f 93 push r25 282c: 8f 93 push r24 282e: 1f 92 push r1 2830: 0e 94 d9 29 call 0x53b2 ; 0x53b2 <dbg_printf_P> ON(AC_MINUS); 2834: 1b 98 cbi 0x03, 3 ; 3 void _delay_loop_1(uint8_t __count) { __asm__ volatile ( 2836: 84 e0 ldi r24, 0x04 ; 4 2838: 8a 95 dec r24 283a: f1 f7 brne .-4 ; 0x2838 <sbi_test+0x34> _delay_us(2); // AC propagation delay dbg_printf_P(dbg_always, PSTR("AC- toggled, ACSR = 0x%02X\n"), ACSR); 283c: 88 b1 in r24, 0x08 ; 8 283e: 99 27 eor r25, r25 2840: 9f 93 push r25 2842: 8f 93 push r24 2844: 8d e9 ldi r24, 0x9D ; 157 2846: 92 e0 ldi r25, 0x02 ; 2 2848: 9f 93 push r25 284a: 8f 93 push r24 284c: 1f 92 push r1 284e: 0e 94 d9 29 call 0x53b2 ; 0x53b2 <dbg_printf_P> ACSR |= _BV(ACIE);
2852: 43 9a sbi 0x08, 3 ; 8 <<<================================== SBI !!!
dbg_printf_P(dbg_always, PSTR("ACSR |= _BV(ACIE), ACSR = 0x%02X\n"), ACSR); 2854: 88 b1 in r24, 0x08 ; 8 2856: 99 27 eor r25, r25 2858: 9f 93 push r25 285a: 8f 93 push r24 285c: 8a e7 ldi r24, 0x7A ; 122 285e: 92 e0 ldi r25, 0x02 ; 2 2860: 9f 93 push r25 2862: 8f 93 push r24 2864: 1f 92 push r1 2866: 0e 94 d9 29 call 0x53b2 ; 0x53b2 <dbg_printf_P> 286a: 8d b7 in r24, 0x3d ; 61 286c: 9e b7 in r25, 0x3e ; 62 286e: 0f 96 adiw r24, 0x0f ; 15 2870: 0f b6 in r0, 0x3f ; 63 2872: f8 94 cli 2874: 9e bf out 0x3e, r25 ; 62 2876: 0f be out 0x3f, r0 ; 63 2878: 8d bf out 0x3d, r24 ; 61 287a: 08 95 ret
А вот что получено на терминалке. Цитата SBI RMW behavior test Initial ACSR = 0x40 AC- toggled, ACSR = 0x70 ACSR |= _BV(ACIE), ACSR = 0x68 Т.е. команда SBI не только установила бит 3 (ACIE), но и сбросила бит 4 (ACI). Если же вместо ACSR |= _BV(ACIE); написать ACSR = (ACSR & ~_BV(ACI)) | _BV(ACIE); то бит ACIE взводится, но бит ACI не сбрасывается. Так кто из нас неоправданно категоричен? Цитата(defunct @ Jul 22 2007, 23:45)  Что за AVRки нового поколения? укажите хотя бы модель мк, в котором вы такое видели.
PINB это входной порт вообще-то.. команда SBI - сокращение от Set Bit IO (она по идее не может делать CLR, она только SET) Ой, да для многих уже. Хоть бы atmega48/88/168. Посмотрите для них картинку 10.2 - структуру порта, там триггер в PORT через инвертор может получить своё состояние себе на вход при записи "1" в PIN (элемент И на управление мультиплексором и стробом записи). =GM=, а вот в свете RMW (Read-Modify-Write) сути команды sbi, см. мой ответ SasaVitebsk, я бы её не использовал с такой целью. Лучше запись PINB = (1 << 1) - так Вы гарантированно запишете 1-ку только в один триггер (а если захотите - то инвертируете группу ног). Кстати, интересно - проверьте (мне лень макетку с мегой48 доставать). Если SBI и на PIN* себя ведёт так же, как и на ACSR (странно будет, если по-другому) то после SBI PINB,... на порту B переключится на противоположное состояние PULL-UP-ов на тех входах, на которых в этот момент была 1-ка. Ой как долго можно такой глюк ловить
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 22 2007, 23:43
|
Частый гость
 
Группа: Новичок
Сообщений: 173
Регистрация: 3-09-04
Из: Moscow
Пользователь №: 595

|
Цитата из ДШ мега48 Some of the Status Flags are cleared by writing a logical one to them. Note that, unlike most other AVRs, the CBI and SBI instructions will only operate on the specified bit, and can therefore be used on registers containing such Status Flags. The CBI and SBI instructions work with registers 0x00 to 0x1F only. И такое поведение команд CBI и SBI свойственно для всех АВРок, начиная с тини13, то есть, все выпущенные за последние 3 года модели. Неужели некоторые уже 3 года не читали даташитов? А вера здесь не при чём. А атмегу64 и 8515 выбросьте, пожалуйста. Им не место на столе эмбеддера. Цитата Посмотрите для них картинку 10.2 - структуру порта, там триггер в PORT через инвертор может получить своё состояние себе на вход при записи "1" в PIN (элемент И на управление мультиплексором и стробом записи). Цитата Кстати, интересно - проверьте (мне лень макетку с мегой48 доставать). Если SBI и на PIN* себя ведёт так же, как и на ACSR (странно будет, если по-другому) то после SBI PINB,... на порту B переключится на противоположное состояние PULL-UP-ов на тех входах, на которых в этот момент была 1-ка. Выход триггера PORT соединён с ножкой микросхемы через повторитель (см. ту самую схему), поэтому внешний потенциал на ножке никак не может повлиять на операции с этим триггером. В случае, когда ножка работает как вход, то запись 1 в PINB приведёт к инверсии соответствующего бита PORTB. Разница лишь в том, что в режиме выхода этот порт определяет уровень на ножке выхода, а в режиме входа - подтяжку. Поэтому в режиме входа запись единички в PINB будет инвертировать пул-апы. Ничего удивительного. Собственно, это следует из ДШ. Никакого глюка тут нет.
Сообщение отредактировал CD_Eater - Jul 23 2007, 00:10
|
|
|
|
|
Jul 23 2007, 04:32
|

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

|
Цитата(CD_Eater @ Jul 23 2007, 01:43)  Неужели некоторые уже 3 года не читали даташитов? Да легко. Некоторые вон плохо себе представляют, как и где в С автоматические переменные создаются и что они не есть угрозой для реентрабельности - и ничего, живут и часто их интересно послушать. Цитата А атмегу64 и 8515 выбросьте, пожалуйста. Им не место на столе эмбеддера. Ну с с выбросом меги8515 действительно можно согласиться, пусть даже она самим атмелом в устаревшие не записана, а что с мегой162 будем делать? Ей-то замены пока нет, хоть ей и больше 3 лет. А почему меге64/128 не место - я не пойму. Личная неприязнь? Цитата Поэтому в режиме входа запись единички в PINB будет инвертировать пул-апы. Ничего удивительного. Собственно, это следует из ДШ. Никакого глюка тут нет. Тут нет, я ещё не настолько туп. Глюк был бы, если бы SBI для этого кристалла было RMW с байтом. К счастью, этого нет в новых кристаллах. Тем лучше.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jul 23 2007, 06:52
|

Местный
  
Группа: Свой
Сообщений: 345
Регистрация: 10-10-05
Пользователь №: 9 459

|
Цитата Ну с с выбросом меги8515 действительно можно согласиться, Цитата Им не место на столе эмбеддера Выступлю в защиту м8515! Что вам там в ней не нравится? Нормальный кристал! Ног дофига. Цена приличная для серийки. Ну нету АЦП, не во всех задачах он и нужен!
--------------------
Если задачу можно решить, то не надо тревожиться. А если нельзя решить, то тревожиться бесполезно.
|
|
|
|
|
Jul 23 2007, 09:26
|

учащийся
    
Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249

|
Цитата(zltigo @ Jul 22 2007, 22:45)  Не стоит пользоваться. Крайне сомнительное расширение  , ибо: 1. Не переносима; 2. Неявное чтение может либо просто быть лишним, либо даже вредным, если из регистра не читается записанное значение, либо регистр содержит зарезервированные биты, либо операция чтения имеет побочные эффекты. Согласен, но я эту форму только для gpio использую наверно эту форму iar сделал специально для явной генерации опкода по битустановке. при работе с регистрами иногда нужно бывает записать какое то значение в бит не зная его заранее. подытоживая три варианта которые я применяю для GPIO: Код if(val == 0) PORTA &= (~(1<<PA4)); else PORTA |= (1<<PA4);
или
PORTA = (PORTA & (~(1<<PA4))) | ((val == 0? 0:1) << PA4 )
или
PORTA_Bit4 = (val == 0? 0:1);
--------------------
Зачем лаять на караван , когда на него можно плюнуть?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|