Easyelectronics.ru

Электроника для всех
Текущее время: 26 июн 2017, 19:00

Часовой пояс: UTC + 5 часов



    • The World's Cheapest PCB Prototyping: 10 шт. 2-слоя 100*100mm 2$(около 140rub), изготовление за 24 часа.
    • Создание принципиальных схем и проектирование печатных плат
    • Крупнейший китайский онлайн магазин радиодеталей. Скидка 50%
    • Просмотр GERBER файлов

Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 19 авг 2012, 07:26 
Свой человек
Аватара пользователя

Зарегистрирован: 03 сен 2011, 02:04
Сообщения: 105
Собственно для включения некого бита неких битов порта не изменяя значения других использую общеизвестный подход:
Код:
PORTD |= (1<<2)|(1<<4);

Ну и для выключения:
Код:
PORTD &= (~((1<<2)|(1<<4)));


В реальных проектах (их было всего два) этого было предостаточно.

Но перечитывая старые статьи про работу с портами и мучая семисегментник на недавно приобретенной Pinboard II, захотелось изменить одновременно два бита включив один и выключив другой. При чем не изменяя остальных. Но все на что я попадал в Гугле - это рекомендации использовать макросы которые так или иначе сводятся к нескольким коммандам.

Уже почти сдался смирившись что красиво записать такой изврат не получится - увидел такую конструкцию:

Код:
ADMUX|=(0<<REFS1)|(1<<REFS0);

Но опробовав ее для того же порта D увидел что у меня она не работает!

Собственно детские вопросы:
1) Как Вы манипулируете с портами если нужно изменить значене нескольких бит сразу?
2) Насколько это вообще критично записать две строчки вместо одной? Будет ли в результате такая однострочная запись атомарной или все же для проделывания таких операций нужно больше чем одна комманда/такт (до Ассемблера пока не добрался)?
3) Будет ли работать последний пример кода независимо от того какие значения уже записаны для битов?


Последний раз редактировалось BOLTon 19 авг 2012, 18:49, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 08:02 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 3412
Откуда: г. Липецк
BOLTon писал(а):
2) Насколько это вообще критично записать две строчки вместо одной? Будет ли в результате такая однострочная запись атомарной или все же для проделывания таких операций нужно больше чем одна комманда/такт (до Ассемблера пока не добрался)?

Подумайте сами, AVR не имеет регистра для порта, который инвертирует выход. А значит несмотря на красивую однострочную запись на С, препроцессор компилятора преобразует эту запись в три ассемблерных команды: 1. чтение, 2. изменение по маске, 3. запись.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 08:08 
Свой человек

Зарегистрирован: 28 янв 2012, 21:27
Сообщения: 188
Откуда: Питер
PORTD = (PORTD | (1<<2)) & ~(1<<4);

Но anakost всё равно прав

BOLTon писал(а):
3) Будет ли работать последний пример кода независимо от того какие значения уже записаны для битов?

Неа
1 | 0 всё равно = 1


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 09:44 
Старожил
Аватара пользователя

Зарегистрирован: 06 май 2010, 11:00
Сообщения: 2810
Откуда: Н. Новгород
Полезный топик, - заныкал ссылку:
viewtopic.php?f=14&t=2505
viewtopic.php?p=176913#p176913


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 12:18 
Супермодератор
Аватара пользователя

Зарегистрирован: 26 янв 2010, 22:08
Сообщения: 7549
Откуда: Алма-ата
BOLTon писал(а):
Собственно детские вопросы:
1) Как Вы манипулируете с портами если нужно изменить значене нескольких бит сразу?]?

Сразу напомню, что пользуюсь компиляторами МикроЭлектроники.
Для изменения бит (не только портов, но и любых переменных) - использую или битовые операции:
Код:
PORTD.1 := 1; DORTD.3 := 0;

Или маской (для нескольких бит одновременно):
Код:
PORTD := PORTD and %11011101;
PORTD := PORTD or  %01001100;
Sost_Prm.5 := Sost_Prm.5 and $f0;
PORTC := PORTC xor $01;


Цитата:
2) Насколько это вообще критично записать две строчки вместо одной?

Пофигу. Компилятор все равно сделает столько команд ассемблера, сколько ему нужно для выполнения этой операции.

Цитата:
Будет ли в результате такая однострочная запись атомарной или все же для проделывания таких операций нужно больше чем одна комманда/такт (до Ассемблера пока не добрался)?

В контроллерах PIC изменить бит порта или ЛЮБОГО регистра всегда можно одной командой ассемблера. Там все порты и регистры - ОЗУ, регистры конфигурации, - равноправны для команд.

В AVR - из за их деления регистров, ОЗУ, и адресного пространства, на кучу кусков с разными свойствами и методами работы с ними, (даже 32 регистра "общего назначения" - отнюдь не равноправны), - это возможно не всегда. Надо смотреть конкретно для каждого отдельного случая. У большинства команд AVR есть только узко определенная область действия.

Про атомарность операции имеет смысл вспоминать только тогда, когда используемые в ней регистры, порты, и переменные, могут быть изменены в прерывании, или по ходу работы контроллера (например, флаги состояния в спецрегистрах). В большинстве остальных случаев атомарность не имеет особого значения.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 13:44 
Старожил

Зарегистрирован: 30 апр 2010, 22:56
Сообщения: 1521
Откуда: Киев
Я просто листинг приведу :) Компилятор WinAVR

Код:
   // Выставляем/снимаем один бит
   PORTA |= _BV(PA0);
  6c:   d8 9a          sbi   0x1b, 0   ; 27
   DDRA &= ~_BV(PA1);
  6e:   d1 98          cbi   0x1a, 1   ; 26

   // Выставляем/снимаем два бита
   PORTB |= (_BV(PB0) | _BV(PB1));
  70:   88 b3          in   r24, 0x18   ; 24
  72:   83 60          ori   r24, 0x03   ; 3
  74:   88 bb          out   0x18, r24   ; 24
   DDRB &= ~(_BV(PB1) | _BV(PB2));
  76:   87 b3          in   r24, 0x17   ; 23
  78:   89 7f          andi   r24, 0xF9   ; 249
  7a:   87 bb          out   0x17, r24   ; 23


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 16:59 
Старожил

Зарегистрирован: 12 апр 2011, 01:45
Сообщения: 852
Откуда: Россия
Хм... судя по листингу до 3х бит выгоднее устанавливать последовательно 2 строками, а 3 и больше бит - однострочной записью...


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 17:38 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 3412
Откуда: г. Липецк
Wraith писал(а):
Хм... судя по листингу до 3х бит выгоднее устанавливать последовательно 2 строками, а 3 и больше бит - однострочной записью...

Немного не так, для установки/сброса одного бита у AVR есть команда, если число изменяемых бит больше одного, используется цикл чтение/модификация/запись.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 19 авг 2012, 18:45 
Свой человек
Аватара пользователя

Зарегистрирован: 03 сен 2011, 02:04
Сообщения: 105
BBS писал(а):
PORTD = (PORTD | (1<<2)) & ~(1<<4);

Но anakost всё равно прав

Спасибо, именно такую красивую читабельную форму записи и искал - пускай в финале она и сводится к нескольим коммандам.

BBS писал(а):
BOLTon писал(а):
3) Будет ли работать последний пример кода независимо от того какие значения уже записаны для битов?

Неа
1 | 0 всё равно = 1


Ну теперь пазлы сошлись :)

Премного благодарен всем ответившим, пойду курить рекомендованые книги/топики.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 20 авг 2012, 01:05 
Старожил
Аватара пользователя

Зарегистрирован: 29 май 2010, 18:46
Сообщения: 4189
Откуда: Киев
BOLTon писал(а):
Спасибо, именно такую красивую читабельную форму записи и искал - пускай в финале она и сводится к нескольим коммандам.

Погодь-погодь. Я с дороги и не пившиевши, так что могу тупить, но как-то понял, что тебя беспокоило несколько иное. А именно: чтобы при выдаче в порт снятие одного (например) бита и установка другого происходили одной операцией. Так? Или тебя только запись интересует?

Если запись - то я тут не буду спорить и предлагать свое. Очевидно, есть способы сделать красивую (и не всегда очень уж наглядную) запись.

А если именно одной операцией изменять разные биты в "разные стороны" - дык... Чего уж проще? Приготовил в некоей промежуточной переменной нужное значение (считыванием из порта и манипуляцией с битами или просто создав с чистого листа тот байт, который нужен), а потом присвоил порту значение этой переменной. Гарантировано, что изменение битов порта произойдет в одной операции.

Код:
переменная = порт;
переменная = функция(переменая, новых битов); // Хоть сто строк и команд
порт = переменная; // железно одна операция, в которой изменятся все нужные биты


В чем проблема?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 03:00 
Администратор
Аватара пользователя

Зарегистрирован: 16 янв 2010, 06:09
Сообщения: 6175
Откуда: Челябинск
Инвертировать биты можно через XOR правда в одну команду все равно не выйдет. Минимум в три. Чтение, модификация, запись.

_________________
Хозяин дома


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 03:11 
Старожил
Аватара пользователя

Зарегистрирован: 05 фев 2010, 16:57
Сообщения: 2067
Откуда: Нальчик
Это если заранее известно состояние нужных битов, а если не известно, то XOR не пойдет (или надо будет выяснять состояние битов - что уже целая процедура.....)

Думаю минимум 4 команды надо: чтение, установка нужных бит, сброс нужных бит, запись.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 03:21 
Администратор
Аватара пользователя

Зарегистрирован: 16 янв 2010, 06:09
Сообщения: 6175
Откуда: Челябинск
Если их надо тупо инверснуть, пофиг что там - то ксор решает.

_________________
Хозяин дома


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 03:23 
Старожил
Аватара пользователя

Зарегистрирован: 05 фев 2010, 16:57
Сообщения: 2067
Откуда: Нальчик
Именно что надо какие то включить, а какие то выключить. А не просто инверснуть.....


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 07:52 
Супермодератор
Аватара пользователя

Зарегистрирован: 26 янв 2010, 22:08
Сообщения: 7549
Откуда: Алма-ата
DI HALT писал(а):
Инвертировать биты можно через XOR правда в одну команду все равно не выйдет. Минимум в три. Чтение, модификация, запись.

Не помню как у AVR, но у PIC - XOR любого порта или регистра с константой компилируется всего в 2 команды.
Вот в МикроПаскале:
Код:
      PORTC := PORTC xor $01;          {- Звук!}

А вот после компиляции:
Код:
;ROBO_SWG_1P32.mpas,124 ::                 PORTC := PORTC xor $01;          {- Звук!}
0x0025        0x3001              MOVLW      1
0x0026        0x0687              XORWF      PORTC, 1

Занесение константы в аккумулятор, затем собственно XOR его с чем угодно.
А чтение - модификация - запись - выполняется на уровне внутреннего микрокода контроллера, за один командеый цикл (8 тактов, за счет конвейера - 4).

Сейчас вставил ту же строчку ( PORTC := PORTC xor $01; {- Звук!}) в программу ЦК для Меги 128 (64). Результат - на лице:
Код:
      PORTC := PORTC xor $01;          {- Звук!}

Вот что получилось:
Код:
;CCR_M64_v460.mpas,167 ::          PORTC := PORTC xor $01;          {- Звук!}
0x10BC        0xB305            IN         R16, PORTC+0
0x10BE        0xE0B1            LDI        R27, 1
0x10C0        0x270B            EOR       R16, R27
0x10C2        0xBB05            OUT       PORTC+0, R16

Несмотря на 2х-тактовый командный цикл у AVR, вместо 2х имеем 4 команды, - чтение порта в регистр R16, загрузку константы в R27, EOR R16 c R27, и выгрузку результата из R16 обратно в порт...

Причем, если у PIC мы имеем атомарность (прерывание после загрузки константы не повлияет на результат, даже если в прерывании будет изменен PORTC - сама XOR делается одной командой), то для AVR прерывание может произойти в 3х точках между командами, и в случае изменения в прерывании PORTC, после загрузки порта по OUT PORTC+0, R16, это изменение будет анулировано... То есть для AVR слежение за атомарностью - более критично.

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

Да и по времени - несмотря на более короткий командный цикл у AVR (2 такта, за счет конвейера считают за 1), - время выполнения PORTC := PORTC xor $01; - получается не намного меньше... По крайней мере, не пара тактов, как хотелось бы.

И длина кода - 8 байт у AVR против 2 байт (точнее, 2 14-битные ячейки флеш) у PIC.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 20 авг 2012, 08:05 
Супермодератор
Аватара пользователя

Зарегистрирован: 26 янв 2010, 22:08
Сообщения: 7549
Откуда: Алма-ата
ShadS писал(а):
Именно что надо какие то включить, а какие то выключить. А не просто инверснуть.....

Иногда - достаточно инверснуть.

Типичный пример - получение звука без проблем.
Например, я в своих программах часто в прерывании системного таймера 1мс, которым формирую всякие задержки, инвертирую какую-нибудь ногу порта, на которой висит пищалка. Теперь достаточно в главном цикле эту ногу назначить на вывод, чтобы выдать звук частотой 500 Гц. Для его выключения - делаю эту ногу входом.

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

Можно также использовать XOR вывода для генерации разных частот (например, сделать на этом выводе маломощный преобразователь напряжения для индикатора, счетчика Гейгера, или еще чего).

В этих (и во многих других) случаях мне не надо знать текущее состояние ноги. Просто изменить его.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 20 авг 2012, 22:32 
Свой человек
Аватара пользователя

Зарегистрирован: 03 сен 2011, 02:04
Сообщения: 105
drvlas писал(а):
BOLTon писал(а):
Спасибо, именно такую красивую читабельную форму записи и искал - пускай в финале она и сводится к нескольим коммандам.

Погодь-погодь. Я с дороги и не пившиевши, так что могу тупить, но как-то понял, что тебя беспокоило несколько иное. А именно: чтобы при выдаче в порт снятие одного (например) бита и установка другого происходили одной операцией. Так? Или тебя только запись интересует?

Если запись - то я тут не буду спорить и предлагать свое. Очевидно, есть способы сделать красивую (и не всегда очень уж наглядную) запись.

А если именно одной операцией изменять разные биты в "разные стороны" - дык... Чего уж проще? Приготовил в некоей промежуточной переменной нужное значение (считыванием из порта и манипуляцией с битами или просто создав с чистого листа тот байт, который нужен), а потом присвоил порту значение этой переменной. Гарантировано, что изменение битов порта произойдет в одной операции.

Код:
переменная = порт;
переменная = функция(переменая, новых битов); // Хоть сто строк и команд
порт = переменная; // железно одна операция, в которой изменятся все нужные биты


В чем проблема?


Интересовало все перечисленное.

Главная цель сначала была чисто эстетическая - типа одной строчкой сказать "конкретно этот и этот бит должны быть включены, а эти два выключены - остальные не трогать - такое вот состояние порта мне нужно".

Но потом (почитав про доступные побитовые операции) засомневался будет ли от этого толк кроме как "эстетический". Поэтому и задал эти вопросы...

Проблемы с атомарностью лично испытывал когда имел "ситуацию гонок" - не было известно какое событие наступит быстрее но приходилось обходится ограниченым количеством прерываний и таймеров которые в дополнение ко всему боролись с дребезгом. Сколько блин времени убил чтобы оттестировать возможные комбинации с событиями... (здесь здорово выручил Протеус со своими программироваными генераторами). Конечно если б чётко знал как оно работает то навЕрное избежал бы многих просчетов.


SWG - спасибо за развернутые коментарии и контекстные примеры! Хотя.. наверное я и сам бы догадался обо всем этом.. лет так через 5.... возможно.... :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 20 авг 2012, 23:42 
Свой человек

Зарегистрирован: 15 авг 2012, 16:42
Сообщения: 68
здесь на сайте читал, что при чтении данных из порта могут проскакивать помехи на выходных ножках.
там рекомендовалось использовать переменную для хранения значения порта.
и все преобразования делать с ней, а потом выводить в орт.
так ли это?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 21 авг 2012, 00:31 
Старожил
Аватара пользователя

Зарегистрирован: 29 май 2010, 18:46
Сообщения: 4189
Откуда: Киев
Kanycma писал(а):
здесь на сайте читал, что при чтении данных из порта могут проскакивать помехи на выходных ножках.

Ну, трудно представить такое. А где говорилось, найти сможешь?
И про чтение чего именно: PIN или PORT? Если порт, то еще как-то под наркозом можно вообразить: все же открывается буфер, подключенный к ножке (и то, если DDR=1). А если речь идет о пине - дык... Не представляю. Не поверю, скажу честно.
Мож опытные товарищи откроют новое знание. А если промолчат, то так понимай: ерунда все это.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битовых значений для порта одной строчкой для AVR
СообщениеДобавлено: 21 авг 2012, 11:14 
Старожил

Зарегистрирован: 31 янв 2010, 20:19
Сообщения: 4935
Откуда: Донецк-Мариуполь
Kanycma писал(а):
здесь на сайте читал, что при чтении данных из порта могут проскакивать помехи на выходных ножках.
там рекомендовалось использовать переменную для хранения значения порта.
и все преобразования делать с ней, а потом выводить в орт.
так ли это?


наверняка ты что-то перепутал или не так понял...
а так вообще-то да - если у тебя со значением порта нужно провести более одной операции за раз - то действительно, нужно использовать переменную.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 28 ноя 2012, 23:34 
Старожил

Зарегистрирован: 06 фев 2011, 15:16
Сообщения: 527
Откуда: Челябинск
DI HALT писал(а):
Инвертировать биты можно через XOR правда в одну команду все равно не выйдет. Минимум в три. Чтение, модификация, запись.
Можно и одной командой
Код:
bis  PIND, 1    ; Инвертировать бит 1 у PORTD
Или нет?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 28 ноя 2012, 23:55 
Старожил

Зарегистрирован: 10 июн 2011, 23:01
Сообщения: 2565
Bill писал(а):
Можно и одной командой
Код:
bis  PIND, 1    ; Инвертировать бит 1 у PORTD
Или нет?

это работает отнюдь не во всех AVRах.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 29 ноя 2012, 00:02 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 3412
Откуда: г. Липецк
Bill писал(а):
Можно и одной командой bis PIND, 1 ;

Не могли бы вы и подсказать мимоходом у каких Tuny или Mega есть эта команда?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 29 ноя 2012, 00:59 
Старожил

Зарегистрирован: 10 июн 2011, 23:01
Сообщения: 2565
anakost писал(а):
Bill писал(а):
Можно и одной командой bis PIND, 1 ;

Не могли бы вы и подсказать мимоходом у каких Tuny или Mega есть эта команда?

дело не в команде, а в реакции на запись в регистр PINx, который обычно только читают.
а bis пожалуй просто опечатка от sbi.
в atmega48/88/168 работает.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Установка битов порта одной строчкой - AVR (решено)
СообщениеДобавлено: 29 ноя 2012, 01:05 
Старожил

Зарегистрирован: 06 фев 2011, 15:16
Сообщения: 527
Откуда: Челябинск
anakost писал(а):
Bill писал(а):
Можно и одной командой bis PIND, 1 ;

Не могли бы вы и подсказать мимоходом у каких Tuny или Mega есть эта команда?

Например, я пользуюсь этим в Tiny2313. Есть также в Mega48/88/168. А в предыдущем моем сообщении действительно есть опечатка. Команда - sbi.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB