Форум myROBOT.ru » Шаг за шагом » Программирование микроконтроллеров » Вопрос по статье "Управление портами микроконтроллера"

Страниц (1): [1]
 

1. Admin - 05 Февраля, 2009 - 15:13:50 - перейти к сообщению
Через страницу "Контакты" пришло письмо от читателя myROBOT по имени Олег, который не указал свой правильный обратный адрес.

Поэтому ответ помещаю здесь.

Его вопрос заключался в следующем:

CODE:
Добрый день.

Прочитал статью http://www.myrobot.ru/stepbystep/pr_mcports.php.
Спасибо, полезная статья. Но у меня возник вопрос:
там есть такой код

"DDRD &= ~(1<<2);"
который далее объясняется и получается вот такой вывод:
"Таким образом, при побитном инвертировании 100 мы получаем 011"
Но это не верно, по-моему. Должно быть 11111011, для данного случая.

Разъясните пожалуйста.

С уважением, Олег.



При побитном инвертировании 100 (!!!) мы получаем именно 011, а не 11111011 или, допустим, 11111111111111111111011.

1<<2 - это 100

Единица сдвинута на две позиции влево.

Это число, а не состояние порта.

Именно это число инвертируют и умножают побитно на каждый бит порта.
2. redcat - 05 Февраля, 2009 - 16:08:27 - перейти к сообщению
... т.е меняется состояние бита в ячейках 0,1,2 а 3-7 не затрагиваются?
3. oleg - 05 Февраля, 2009 - 16:49:20 - перейти к сообщению
Добрый день.

Не знаю что имел ввиду Администратор по поводу "который не указал свой правильный обратный адрес", но ответ на мой вопрос мне на почту пришел.
Спасибо за оперативность.

А вот вопрос я этот поднял, потому как 2 операции над числом "1", а именно, "~(1<<2)", как это ни странно, обрабатываются с помощью регистров общего назначения. А так так рассказ идет на базе 8-битного микроконтроллера, то и регистр общего назначения равен 8 битам и операция логического умножения будет именно с 2-мя регистрами по 8 бит, а не с одним 8-битным и одним 3-битным.
А в регистре будет запись именно "11111011".
Вот потому и число "11111011", а не "11111111111111111111011".
4. digger - 05 Февраля, 2009 - 16:54:05 - перейти к сообщению
to redcat
При умножении значения бита на 1, его состояние не изменяется: A*1=A.

В данном примере изменится только состояние 2-го бита: A*0=0.

---

Если рассматривать случай, если, как пишет Олег, мы инвертируем байт, в котором хранится значение 00000100, то получившееся 11111011 при побитном умножении на каждый бит порта изменит также только значение 2-го бита.
5. oleg - 05 Февраля, 2009 - 16:56:54 - перейти к сообщению
Я это не отрицаю.

Просто это строчка вводит в заблуждение.
если запись была бы такая
"DDRD = ~(1<<2);"
То в DDRD хранилась бы не 11.
6. digger - 05 Февраля, 2009 - 17:14:07 - перейти к сообщению
to oleg
Вы безусловно правы.
Но при написании статей для начинающих было сделано очень много упрощений. Да и мне тоже кажется, что во многих случаях рассматривать просто числа, а не байты, несколько проще.

Весьма сложно представить работу с микроконтроллером "на пальцах" в очень сжатом виде. И, мне кажется, сатьи в "Шаг за шагом" со своей задачей вполне справляются. В них было сделано много улучшений и дополнений. Наверное, выраженное Вами опасение, нужно будет добавить в статью поясняющей врезкой.

Как Вы думаете, что лучше всего написать, чтобы при этом не вводить излишних усложнений? Чтобы у читателя не возникло в результате ощущение, что микроконтроллеры проще программировать на Бейсике. Улыбка
7. oleg - 05 Февраля, 2009 - 17:55:29 - перейти к сообщению
Я бы написал так:
Любые вычисления в 8-битном микроконтроллере проходят с использованием 8-битных регистров. Перед вычислениями аргументы помещаются в специальные регистры, с которыми напрямую может работать АЛУ. Перед вычислением выражения DDRD&=~(1<<2) аргументы 1 и 2 помещаются в разные вспомогательные регистры микроконтроллера, т.е. аргумент 1 - занимает целый регистр. Содержимое этого регистра в двоичном формате будет выглядеть так: 0b00000001.
1. Вначале осуществляется операция сдвига влево на 2 бита. В регистр запишется так информация: 0b00000100.
2. Далее осуществляется операция инвертирования: в регистр запишется такая информация: 0b11111011.
3. После этого осуществляется операция DDRD&=0b11111011, что запишет во второй бит DDRD значение 0.
8. Admin - 05 Февраля, 2009 - 20:15:28 - перейти к сообщению
Уважаемый Олег, прошу прощение за неувязку с почтой, видимо, письмо до Вас дошло уже со второй попытки.

Спасибо за Ваш комментарий. Перечитал сейчас статью. Действительно, ведущий ноль выглядит очень шероховато и чисто алгебраической формализации без дополнительного объяснения о регистрах может быть недостаточно.

Ваш комментарий, чуть чуть изменив, добавил в статью (я убрал двоичные префиксы). Посмотрите, пожалуйста, на то, что получилось. http://myrobot.ru/stepbystep/pr_mcports.php . По-моему, так немного проще и нагляднее.

Еще раз спасибо!
Возможно Вы встретили еще какие-то моменты, которые кажутся на Ваш взгляд шероховатыми. Будем благодарны за Ваши комментарии и помощь в улучшении раздела "Шаг за шагом".
9. VCOM - 05 Февраля, 2009 - 20:55:02 - перейти к сообщению
Блин, стока написал, а оно тока до 2 Кб понимает.... Ж)))
Вот кароче че писал Ж))))
В крацце.

1) В С достаточно расплывчато описаны типы данных. CHAR это 8 бит везде, INT может быть 16 бит 32 бит и т.д. Я уж не говорю про float и double. Поэтому читайте доку на ВАШ компилятор!

2) DDRD в виду 8 разрядности архитектуры АВР имеет тип char.

3) В операции DDRD = ~(1<<2); есть тока 1 аргумент. В IAR оно выглядит так
00077E E004 LDI R16,0xFB
000780 BB08 OUT DDRD,R16

Пачему? Патамучто ~(1<<2) константа. Пачему 8 бит? Патамучто DDRD описан как байт.

4) В С есть понятие авто кастинг
unsigned int a;
a=4;
PORTB=a;

00077E E004 LDI R16,0x04
000780 E010 LDI R17,0x00
000782 BB08 OUT PORTB,R16

Что такое авто кастинг? Это действие, в результате которого компилятор в автоматическом порядке пытаецца преобразовать формат источника в формат приемника... Есть также принудительный кастинг это когда явно написано

float a=125.123;
int b;
b=(int)a;

b в результате равно 125.

5) Администрация! Давайте сделаем раздел посвященный С, С++! Особенно в приложении ембеддед. Ибо я вижу разброд и шатание в головах начинающих робостроителей!
10. Admin - 06 Февраля, 2009 - 00:17:45 - перейти к сообщению
VCOM пишет:
Блин, стока написал, а оно тока до 2 Кб понимает....


Увеличил до 3-х. Очень жаль, уважаемый VCOM, что так вышло. Улыбка

1.
По-моему, здесь
AVR GCC :: ПЕРЕМЕННЫЕ И КОНСТАНТ Ы
для AVR GCC все достаточно недвусмысленно изложено (и таблица типов есть).
Или Вы считаете, что должна быть врезка про другие компиляторы?

2.
VCOM пишет:
2) DDRD в виду 8 разрядности архитектуры АВР имеет тип char.

Не совсем понял. Вы считате, что регистры для начинающих стоит описывать типами. Может, пока оставить все на уровне битов?

3.
Да, действительно неувязочка получается.
А как бы Вы описали выполнение конструкции
DDRD &= ~(1<<2);
на уровне компилятора и на уровне контроллера?

5.
Вы имеете ввиду раздел на форуме или раздел со статьями?
Не так давно добавили на сайт wiki-раздел . Могу сделать в нем раздел (хотя это может сделать любой желающий, все редактируется свободно), посвященный C и C++ для встраиваемых систем.

Пока в wiki почти совершенно пусто, но предполагается ее наполнение и тесная интеграция со всеми разделами сайта с помощью перекрестных ссылок. Таким образом, сайт будет в гораздо большей степени оправдывать свое название. Уже сейчас каждый может поделиться своими достижениями, выложить фотографии и описание своих роботов.

Кроме того, предполагается расширение и улучшение разделов сайта за счет материалов в wiki, которые может редактировать и создавать каждый. Соответственно во всех разделах предполагаются ссылки на материалы в wiki.

Обращаться с викой очень легко - Вводный курс .
11. VCOM - 06 Февраля, 2009 - 07:31:36 - перейти к сообщению
1) Да не. Просто раз сайт на ВинАВР рассчитпн, то и пускай про него и рассказывает. Просто других копиляторов вагон и маленькая тележка. Это еще больше народ запутает Ж))))) Могу тока сказать что довольго часто встречаются вот такие вещи: int16 int32 int64. Т.е. в самом типе написана его разрдность.

2)Вообе говор полезно в хедеры заглядывать, и смотреть что в них написано Ж))))
Вот оно как в iar выглядит
****************************************************************************
* An example showing the SFR_B() macro call,
* the expanded result and usage of this result:
*
* SFR_B(AVR, 0x1F) Expands to:
* __io union {
* unsigned char AVR; // The sfrb as 1 byte
* struct { // The sfrb as 8 bits
* unsigned char AVR_Bit0:1,
* AVR_Bit1:1,
* AVR_Bit2:1,
* AVR_Bit3:1,
* AVR_Bit4:1,
* AVR_Bit5:1,
* AVR_Bit6:1,
* AVR_Bit7:1;
* };
* } @ 0x1F;
* Examples of how to use the expanded result:
* AVR |= (1<<5);
* or like this:
* AVR_Bit5 = 1;
***************************************************************************/
SFR_B(TWBR, 0x00) /* TWI Bit rate Register */
SFR_B(TWSR, 0x01) /* TWI status Register */
SFR_B(TWAR, 0x02) /* TWI Address Register */

т.е. все регистры представлены как юнионы. И причем четко написаны что они unsigned char. И в каждом ессно есть 8 бит Ж)))) Причем оно так описано что для начинающих, что для заканчивающих Ж)))))

3) Да запросто Ж)))
DDRD &= ~(1<<2);
0007A8 988A CBI 0x11,2

еще проще чем
DDRD = ~(1<<2);
00077E E004 LDI R16,0xFB
000780 BB08 OUT DDRD,R16 Помираю со смеху


Сразу напишу:
DDRD |= 0xAA;
0007A8 B301 IN R16,DDRD
0007AA 6A0A ORI R16,0xAA
0007AC BB01 OUT DDRD,R16

5)Ух ты! Я и не заметил! Нада будет че нить там понаписать Ж))))