Easyelectronics.ru

Электроника для всех
Текущее время: 17 дек 2018, 17:55

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




Начать новую тему Ответить на тему  [ Сообщений: 32 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Вопрос по побитовым операциям
СообщениеДобавлено: 03 июл 2018, 23:11 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
Доброго времени суток!Прошу разъяснить для меня простую вещь.(Переписка с сайта http://narodstream.ru)
Изучаю побитовые операции И, ИЛИ, НЕ.Все вроде бы понятно.Но тут напрашивается вопрос, зачем Вы так усложнили код, тем более с обычным мигающим светодиодом?
Ваш код
Код:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
DDRD = 0xFF;
PORTD = 0b00000000;
while(1)
{
PORTD |= (1<<(PORTD0));
_delay_ms(500);
PORTD &= ~(1<<(PORTD0));
_delay_ms(500);
}
}

Мой код
Код:
#define F_CPU 8000000// указываем частоту в герцах
#include <avr/io.h>
#include <util/delay.h>

int main(void)// начало основной программы
{
DDRD = 0xFF;//Все выводы порта D будут сконфигурированы как выходы.
PORTD = 0b00000000;//устанавливаем на всех ножках принудительно ноль(во избежание остаточного мусора в регистрах)
while(1)
{
PORTD = 0b00000001;
_delay_ms(500);//делаем задержку в пол секунды
PORTD = 0b00000000;
_delay_ms(500);//делаем задержку в пол секунды
}
}

Хотя ведь можно было просто установить вот так как у меня и все так же работает.Если я не прав, то поясните в чем конкретно.Буду очень признателен.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 03 июл 2018, 23:15 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 2592
Хорошо, а если на одной ножке светодиод, мигающий с частотой 1 Гц, а на другой - светодиод, мигающий с частотой 3,73 Гц? Как тогда будете поступать?
Ну а пока думаете да соображаете, поясняю: операции AND, OR, XOR придуманы для того, чтобы воздействовать на один бит, не затрагивая других. Беда кроется в самом языке Си - у него нет типа данных с размерностью меньше байта, то есть нет типа данных "бит", поэтому обратиться к одному биту можно только через логические операции битового И, ИЛИ.
Еще есть возможность добраться до бита через структуру с членами длиной в один бит, но как компилятор реализует такой подход, это еще вопрос.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 03 июл 2018, 23:40 
Старожил
Аватара пользователя

Зарегистрирован: 05 фев 2013, 00:58
Сообщения: 3241
Откуда: Тольятти
В архитектуре 51 есть команды для побитного управления портами. Также есть прямо адресуемый битовый массив и команды пересылки одного бита.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 03 июл 2018, 23:41 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
BusMaster, я только учусь программировать.Я не знаю как одновременно заставить мигать 2 пина с частотой 1Гц и 3,73Гц.Только один.А два даже представить не могу.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 00:13 
Старожил
Аватара пользователя

Зарегистрирован: 18 фев 2014, 11:27
Сообщения: 217
На будущее сразу приучать себя работать с битовыми полями и масками, руля только нужными битами.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 00:45 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
BusMaster писал(а):
но как компилятор реализует такой подход, это еще вопрос.

Нормально реализует, я смотрел асм листинг. Если поле структуры задано длиною в 1 бит, то юзаются инструкции устанавливающие или очищающие один бит обычно, если таковые есть в архитектуре. Если больше одного бита, то соотв. и/или с маской. Короче ничем не отличается от обычных битовых операций со сдвигами.
Кстати часто использую битовые поля для размещения различных флагов в структуре когда память надо сэкономить, да и удобно довольно-таки имхо.


Последний раз редактировалось NStorm 04 июл 2018, 00:54, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 00:53 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
SergeyVT писал(а):
BusMaster, я только учусь программировать.Я не знаю как одновременно заставить мигать 2 пина с частотой 1Гц и 3,73Гц.Только один.А два даже представить не могу.

Ну это был просто пример. В вашем примере действительно результат будет один и тот же. Но представьте просто что хотя бы помимо светодиода на том же порту у вас скажем будет кнопка висеть. И надо будет светодиод зажигать по нажатию кнопки. Ваш подход уже не подойдет.
Разница 2 примеров в том, что в первом затрагивается только 1 бит во всём регистре PORTD. А вашем примере все остальные биты каждый раз принудительно устанавливаются в 0. Это вы еще не вникали в Read-Modify-Write.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 00:59 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
Код:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
   DDRD = 0xFF;
   PORTD = 0b00000000;
   while(1)
   
   {
      PORTD |= (1<<(PORTD1));
      _delay_ms(3703);
      PORTD &= ~(1<<(PORTD1));
      _delay_ms(3703);
   
   
      PORTD |= (1<<(PORTD0));
      _delay_ms(500);
      PORTD &= ~(1<<(PORTD0));
      _delay_ms(500);
   }
   
}
Ребята, это пишу в Atmel Studio7.Однако не работает PD0 в Proteus.Пытался решить задачку изложенную BusMaster.Поправьте меня пожалуйста.И если можно ткните что не так и почему.Спасибо!


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:05 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
NStorm писал(а):
BusMaster писал(а):
но как компилятор реализует такой подход, это еще вопрос.

Нормально реализует, я смотрел асм листинг.

Вот кстати касаемо именно AVR примеры, одинаково получается:
Код:
#define STATUS_ENABLE

struct DeviceState {
    uint8_t status;
    uint8_t enabled : 1;
}

static struct DeviceState myState;

myState.status |= STATUS_ENABLED;
myState.enabled = 1;
...

    myState.status |= STATUS_ENABLE;
00003746  LDS R24,0x20B5            Load direct from data space
00003748  ORI R24,0x01              Logical OR with immediate
00003749  STS 0x20B5,R24            Store direct to data space

    myState.enabled = TRUE;
0000374B  LDS R24,0x20B4            Load direct from data space
0000374D  ORI R24,0x01              Logical OR with immediate
0000374E  STS 0x20B4,R24            Store direct to data space


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:09 
Старожил
Аватара пользователя

Зарегистрирован: 14 апр 2014, 11:06
Сообщения: 1403
Откуда: Курск
Можно проще переключать порт, записью 1 в PIND1


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:11 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
SergeyVT писал(а):
Ребята, это пишу в Atmel Studio7.Однако не работает PD0 в Proteus.Пытался решить задачку изложенную BusMaster.Поправьте меня пожалуйста.И если можно ткните что не так и почему.Спасибо!

Его задачка явно не так решается. В вашем примере сначала PORTD1 будет гореть 3.7с, потом ничего не будет не гореть 3.7с, а потом PORTD0 будет гореть 0.5с, и опять ничего не горит 0.5с. Одновременно они не загорятся никогда.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:19 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
NStorm писал(а):
SergeyVT писал(а):
Ребята, это пишу в Atmel Studio7.Однако не работает PD0 в Proteus.Пытался решить задачку изложенную BusMaster.Поправьте меня пожалуйста.И если можно ткните что не так и почему.Спасибо!

Его задачка явно не так решается. В вашем примере сначала PORTD1 будет гореть 3.7с, потом ничего не будет не гореть 3.7с, а потом PORTD0 будет гореть 0.5с, и опять ничего не горит 0.5с. Одновременно они не загорятся никогда.
Ок.А как тогда? Если не трудно расскажите.И если вообще не трудно код приведите.Так нагляднее будет.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:32 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
Нагляднее, да неправильно ) Лучше я вам приведу графики как у вас получилось и как должно быть. Ну и сразу скажу что 3700 мс задержки и 3.7Гц - разные вещи, надеюсь тут сами поймете.
В том же самом протеусе нарисованные по-быстрому. Вот что получилось у вас:
Изображение
И вот как должно быть:
Изображение

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


Последний раз редактировалось NStorm 04 июл 2018, 01:38, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:37 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
Про частоту я понимаю.Но у меня был вопрос как зажечь 2 светодиода одновременно? Например на PD0 и PD1?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:40 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
А в чем проблема? Например так:
Код:
      PORTD |= (1<<(PORTD1));
      _delay_ms(500);
      PORTD |= (1<<(PORTD0));
     _delay_ms(500);
      PORTD &= ~(1<<(PORTD0));
      _delay_ms(500);
      PORTD &= ~(1<<(PORTD1));
      _delay_ms(500);


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:45 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
Если захочется такой код переписать как:
Код:
PORTD = 0b00000010;
_delay_ms(500);
PORTD = 0b00000011;
_delay_ms(500);
PORTD = 0b00000010;
_delay_ms(500);
...

То это потому что вы знаете в какой момент должно быть состояние сразу всех пинов порта. А что если это неизвестно? Что если состояние меняется к примеру в зависимости от внешнего условия? Для этого и используются логические (или битовые) операции, чтобы поменять определенные биты регистра и не затронуть другие.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:47 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
NStorm писал(а):
Высота на графике разная исключительно для наглядности, чтобы не рисовать 4 картинки. Имеет значение лишь длины "импульсов".Дальше думайте сами, но вообще такое на таймере делается. Давайте я вам куда более простой пример подкину, который можно нарисовать на delay'ях, но нельзя с вашим вариантом без логических операций из 1го поста... сейчас

Код:
int main(void)
{
   DDRD = 0xFF;
   PORTD = 0b00000000;
   while(1)
   
   {
      PORTD |= (1<<(PORTD0));
      _delay_ms(500);
      PORTD |= (1<<(PORTD1));
      _delay_ms(500);
      PORTD &= ~(1<<(PORTD1));
      _delay_ms(500);
      PORTD &= ~(1<<(PORTD0));
      _delay_ms(500);
      
   }
   
}

Вот так.Однако все равно поочередно загораются и гаснут.И спасибо за помощь.


Последний раз редактировалось SergeyVT 04 июл 2018, 01:50, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 01:48 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
NStorm, Так я как раз как Вы и делаю.Почему то с задержкой включаются и выключаются.Хотя задержки одинаковые.Код написал выше.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 02:07 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
Ура! Заработало.Подобрал логику работы.
Код:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
   DDRD = 0xFF;
   PORTD = 0b00000000;
   while(1)
   
   {
      PORTD |= (1<<(PORTD0)) | (1<<(PORTD1));
      _delay_ms(1000);
      PORTD &= ~(1<<(PORTD0)) &  ~(1<<(PORTD1));
      _delay_ms(1000);
   }
   
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 02:11 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
В смысле с задержкой? В прошлом варианте должен загораться 1, потом 2ой, потом гаснет 2ой, потом первый. Код правильный был, в какой-то момент должны были "гореть оба светодиода".
А во втором примере да, так сразу 2 бита устанавливаются/снимаются.
Запись
PORTD |= (1<<(PORTD0)) | (1<<(PORTD1));
Аналогична записи
PORTD = PORTD | ((1<<(PORTD0)) | (1<<(PORTD1)));
В свою очередь аналогично
PORTD = PORTD | ((1<<0) | (1<<1));
Что в свою очередь равнозначно:
PORTD = PORTD | 0b00000011;

Просто со временем первый вариант привычнее и нагляднее становится.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 02:15 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
NStorm, я с задачей справился?Вы видел программу выше?Теперь все работает как надо.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 08:58 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 2592
Да, только оба светодиода мигают одновременно.
Чтобы задавать разные периоды мигания, нужно либо использовать прерывания от таймера, отсчитывающего миллисекунды (или любые другие кратные интервалы), либо использовать неблокирующую проверку.
Типа такого:
Код:
unsigned int i = 0;   // счетчик миллисекунд
while(1)
{
    if ((i % 500) == 0) PORTD ^= 1 << PORTD0;   // если счетчик кратен 500 мс, переключить D0, частота мигания 1 Гц
    if ((i % 135) == 0) PORTD ^= 1 << PORTD1;   // если счетчик кратен 135 мс, переключить D1, частота мигания 3,7 Гц
    i++;     // инкремент счетчика миллисекунд
    Delay_ms(1);  // вызов функции задержки на 1 мс
}

Выражение (i % 500) означает остаток от деления числа i на 500. Если число i кратно 500, то остаток от деления = 0.
Такой способ тоже не лишен недостатков. Delayms(1) не учитывает времени исполнения кода на условиях if, поэтому интервал немного больше, чем 1 мс. Хороший способ - это интервалы на прерываниях.
PS. ^= означает операцию XOR - исключающее ИЛИ. Работает как переключатель бита на противоположное состояние. Гляньте таблицу истинности для исключающего ИЛИ.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 11:35 
Только пришел

Зарегистрирован: 03 июл 2018, 23:06
Сообщения: 13
Заработал Ваш код.Правда для первых шагов в C немного сложновато.Я ранее чуть-чуть на ASMe писал(учил по книге Мортон Д. — Микроконтроллеры AVR. Вводный курс).Но т.к. в книге на много ошибок как в коде так и в некоторых схемах, пришлось забросить после десятка неудачных попыток на уроке "Частотомер"(этот урок ближе к концу книги) и вопросов на форумах.Сказали только что писать на ASMe "Частотомер" это слишком замудрено, и что автор сильно намудрил.Проще было на С сделать.А спросить мне не у кого было.А я очень хочу научиться.Вот и задаю порой такие глупые вопросы.
Код:
#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)

{
   unsigned int i = 0;   // счетчик миллисекунд
   DDRD = 0xFF;
   PORTD = 0b00000000;
   while(1)
   
   {
       if ((i % 500) == 0) PORTD ^= 1 << PORTD0;   // если счетчик кратен 500 мс, переключить D0, частота мигания 1 Гц
       if ((i % 135) == 0) PORTD ^= 1 << PORTD1;   // если счетчик кратен 135 мс, переключить D1, частота мигания 3,7 Гц
       i++;     // инкремент счетчика миллисекунд
       _delay_ms(1);  // вызов функции задержки на 1 мс
   }
   
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 12:43 
Старожил
Аватара пользователя

Зарегистрирован: 22 июл 2017, 11:48
Сообщения: 2592
Ну тогда для изучения Си есть хорошая книга авторов Ритчи и Керниган "Язык программирования Си", а так же сокращенный он-лайн вариант справочника для "быстрого старта".
AVR нынче считается неперспективным и дорогим для изучения микроконтроллером. Ассемблер - тоже уже устаревший подход. На ассемблере пописывали поделки еще лет 12-15 назад.
У того варианта, который я показал, есть еще один подводный камень. Я сейчас не помню, для AVR размерность типа int - это сколько, 16 или 32 бита? Если 16 бит, то счетчик миллисекунд имеет цикл в 65536 мс, то есть, каждые 65,5 с будет идти небольшой скачок (укорачивание) длительности интервала. Избежать этого можно другим способом, введя дополнительные счетчики миллисекунд, которые будут сбрасываться каждый полный цикл их счета:
Код:
unsigned int i1 = 0;
unsigned int i2 = 0;
while(1)
{
    if (i1 == 500)    // если отсчитан интервал 500 мс,
    {
            i1 = 0;          // сброс счетчика i1
            PORTD ^= 1 << 0;  // переключение первого светодиода каждые 500 мс
    }

    if (i2 == 135)    // если отсчитан интервал  135 мс,
    {
            i2 = 0;          // сброс счетчика i2
            PORTD ^= 1 << 1;  // переключение второго светодиода каждые 135 мс
    }
    i1++; // инкремент счетчика i1
    i2++; // инкремент счетчика i2
    Delay_ms(1);   // задержка на 1 мс
}


еще лучше будет работать вариант, основанный не на блокирующей задержке Delay_ms(), а на флаге от аппаратного таймера, который отсчитывает точно миллисекундные интервалы. Я по прошествии лет уже не помню, как там в AVR выглядят флаги таймеров, но в условном виде вместо строчки Delay_ms(1); поставим строчку ожидания флага таймера:
Код:
    while (timer_flay == 0) {    }

эта строчка означает "пока нет флага от таймера, оставаться тут в этой же строчке, выполняя пустой код в { }"


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос по побитовым операциям
СообщениеДобавлено: 04 июл 2018, 13:07 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 1291
BusMaster писал(а):
Я сейчас не помню, для AVR размерность типа int - это сколько, 16 или 32 бита?

Чтобы не задаваться такими вопросами я давно всем рекомендую всегда пользоваться типами из stdint.h.


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

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


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

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


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

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

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