Прямой (низкоуровневый) доступ к портам. Библиотека

MaksVV
Offline
Зарегистрирован: 06.08.2015

Иногда возникает потребность побыстрее рулить портами или читать их. Чтобы не путаться при отладке в этих битовых закорючках , для наглядности пользуюсь такими функциями для атмеги 328 

void digital_Write (byte pin, bool state) 
{
  
  if (pin>=0 && pin<=7) {
       if (state) PORTD |= (1<<pin);
       else       PORTD &=~(1<<pin);
                        }
  
  else if (pin>=8 && pin<=13)  {
         if (state) PORTB |= (1<<pin-8);
       else         PORTB &=~(1<<pin-8);
                               }
  
  else if (pin>=14 && pin<=19) {
         if (state) PORTC |= (1<<pin-14);
       else         PORTC &=~(1<<pin-14);
                               }
}

bool digital_Read (byte pin) 
{
       if (pin>=0 && pin<=7)  {return ((PIND &(1<<pin))>>pin);}
  else if (pin>=8 && pin<=13) {return ((PINB &(1<<pin-8))>>pin-8);}
  else if (pin>=14 && pin<=19){return ((PINC &(1<<pin-14))>>pin-14);}
}

Есть несколько вопросов.

1. Правильно ли я сделал эти функции, или можно поизящнее выполнить? 

2. Насколько примерно задержка при пользовании такими функциями по сравнению с просто например PORTD |= (1<<5); ? 

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

kalapanga
Offline
Зарегистрирован: 23.10.2016
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Есть СyberLib, но там нельзя использовать переменные в качестве номеров пинов, а только константы.

Есть DigitalPins, там можно и то, и другое, но с константами получается всё мгновенно (как в CyberLib) а с переменными - вычисления типа Ваших. Там правда есть ещё одна вкусная фича - одновременное переключение пинов в пределах порта (одной командой). Это бывает полезно, когда что-то надо делать строго синхронно. Но у неё большой минус - она только для 328p и тинек 25-45-85. Никакие другие контроллеры она не поддерживает.

Есть ещё arhat.h, но она довольно глючная и, по заявлениям автора, заточена только на ATmega2561.

Есть ещё какая-то, сейчас не помню названия, но очень интересная - она построена на шаблонах классов - очень красиво получилось. Если хотите, поищу ссылку.

Других не знаю, но наверняка их существует ещё over9k.

Кстати, Ваши строки 23-24. Формально всё правильно, приоритеты операций именно таковы, но всё равно я бы скобки расставил - глаза режет.

MaksVV
Offline
Зарегистрирован: 06.08.2015

ок, пасиб

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

ЕвгенийП пишет:

Есть ещё какая-то, сейчас не помню названия, но очень интересная - она построена на шаблонах классов - очень красиво получилось. Если хотите, поищу ссылку.

Если не затруднит...
всё пытаюсь понять особнности поведения WAVGAT

Green
Offline
Зарегистрирован: 01.10.2015

ЕвгенийП пишет:

Кстати, Ваши строки 23-24. Формально всё правильно, приоритеты операций именно таковы, но всё равно я бы скобки расставил - глаза режет.


Я бы где то убрал, а где то добавил.) 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ua6em пишет:

ЕвгенийП пишет:

Есть ещё какая-то, сейчас не помню названия, но очень интересная - она построена на шаблонах классов - очень красиво получилось. Если хотите, поищу ссылку.

Если не затруднит...

Решение очень красивое

http://easyelectronics.ru/rabota-s-portami-vvoda-vyvoda-mikrokontrollero...

https://github.com/KonstantinChizhov/Mcucpp

MaksVV
Offline
Зарегистрирован: 06.08.2015

Green пишет:
Я бы где то убрал, а где то добавил.)

Если не затруднит) мне в академических целях

Green
Offline
Зарегистрирован: 01.10.2015

Если в академических, то это к Евгений П.)

bool digital_Read(byte pin) 
{
  if (pin <= 7)  return !!(PIND & 1 << pin); 
  if (pin <= 13) return !!(PINB & 1 << pin - 8); 
  if (pin <= 19) return !!(PINC & 1 << pin - 14);
}

 

Green
Offline
Зарегистрирован: 01.10.2015

Аналогично.

void digital_Write(byte pin, bool state) 
{
       if (pin <= 7)  state ? PORTD |= 1 << pin      : PORTD &= ~(1 << pin);
  else if (pin <= 13) state ? PORTB |= 1 << pin - 8  : PORTB &= ~(1 << pin - 8);
  else if (pin <= 19) state ? PORTC |= 1 << pin - 14 : PORTC &= ~(1 << pin - 14);
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Осталось pinMode еще написать. Да и работа с аналоговыми пинами не освещена.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Green пишет:

Если в академических, то это к Евгений П.)

bool digital_Read(byte pin) 
{
  if (pin <= 7)  return !!(PIND & 1 << pin); 
  if (pin <= 13) return !!(PINB & 1 << pin - 8); 
  if (pin <= 19) return !!(PINC & 1 << pin - 14);
}

 

спасибо за оптимизацию. Разобраться надо конечно. Ну не программист я ниразу.

Хотел даже сказать «А вот нижние ифы надо все же на елсе ифы переделать» но потом мозг все таки заработал - дак ведь return))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А что этуфункция вернёт, если аргумент > 19 ?

sadman41
Offline
Зарегистрирован: 19.10.2016

Функция разорвет кристалл, не иначе.

nik182
Offline
Зарегистрирован: 04.05.2015

Люди! Ау! Вы совсем с головой не дружите? Зачем менять ардуиновское чтение и писание портов на недокостыль? Ну объясните пожалуйста. Это не операционка. Это проект, однажды залитый в процессор и никогда не меняющий динамически ноги. Если уж хочется ускорится просто напишите прямо в порт в нужную ногу. Не надо их перебирать ифами. Вы ведь точно знаете какая нога куда идёт. 

Green
Offline
Зарегистрирован: 01.10.2015

sadman41 пишет:

Функция разорвет кристалл, не иначе.


"Вдребезги напополам!") Да, хотя бы return false нужно добавить, иначе компилер должен ругаться.

Green
Offline
Зарегистрирован: 01.10.2015

nik182 пишет:

Люди! Ау! Вы совсем с головой не дружите? Зачем...


Кто как хочет, так и др. Сказано же "в академических целях".)
 

sadman41
Offline
Зарегистрирован: 19.10.2016

"У нас есть ТАКИЕ приборы! Но мы вам о них не расскажем." (C)

Arhat109-2
Offline
Зарегистрирован: 24.09.2015

sadman41 пишет:

"У нас есть ТАКИЕ приборы! Но мы вам о них не расскажем." (C)

Все есть выложенное в недрах этого форума по большей части. Собрать воедино, выкусить лишнее, дополнить своим .. не это ли отличает программиста от пользователя библиотекой? :)

В целом, даже опубликованный arhat.h вполне можно довести до состояния "замена Wiring" с небольшими ограничениями, в части работы с пинами, таймерами и прерываниями (кстати, там есть весь набор примитивов для PCINT тоже, чего нет в Cyberlib). Если учесть, что в конечном скетче пины назначены "железно", то можно иметь такой алгоритм разработки: пишем и отлаживаем на Wiring, а когда оно заработало переводим под arhat.h или Cyberlib с назначением пинов константно.

SLKH
Offline
Зарегистрирован: 17.08.2015

nik182 пишет:

Люди! Ау! Вы совсем с головой не дружите? Зачем менять ардуиновское чтение и писание портов на недокостыль? Ну объясните пожалуйста. .......

Если уж хочется ускорится просто напишите прямо в порт в нужную ногу. Не надо их перебирать ифами. Вы ведь точно знаете какая нога куда идёт.

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

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

SLKH пишет:

не всегда знаю, какая нога куда пойдет после отладки и пайки,

Тоже и у меня. Зачастую окончательное распределение ног устаканивается только в впроцессе разводки платы, когда стараешься развести поаккуратнее и с меньшим количеством перемычек. Хотя, даже не знаю, чем мне так не угодили перемычки - деталь как делаь, но почему-то всегда трахаюсь с минимзацией их количества.

nik182
Offline
Зарегистрирован: 04.05.2015

Ну а вайринг чем неудобен? 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

nik182 пишет:

Ну а вайринг чем неудобен? 

Всем удобен, пока нет каких-то особых требований.

Вот мой нынешний проект:

1. АЦП в режиме подавления шума (wiring не поддерживает)
2. PCINT  (wiring не поддерживает)
3. Таймер для равномерного (с частотой 2кГц) замера АЦП  (wiring не поддерживает)

Против digitalWrite/digitalRead в этом проекте ничего не имею, но раз уж всё равно столько всего писать руками, взял и для них DigitalPins (благо там синтаксис witing'овский, только подчерк перед названием функции добавлять надо, а так всё тоже - номера пинов там и т.п.). 

В результате, всё компилируется хоть в IDE, хоть в АВР-студии, и меня это по ряду причин удобно, специально так делал. Если бы я использовал wiring, в студии с компиляцией были бы проблемы - пришлось бы wiring целиком туда тащить.

SLKH
Offline
Зарегистрирован: 17.08.2015

nik182 пишет:

Ну а вайринг чем неудобен? 

удобен, но бывают варианты, для которых digitalWrite/digitalRead работают слишком медленно.

а макросы из Ciberlib несколько неудобны, если нужно поменять пины в программе.

Обсуждаемые функции обе эти проблемы решают.

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

SLKH пишет:

а макросы из Ciberlib несколько неудобны, если нужно поменять пины в программе.

Так бери DigitalPins. Там синтаксис вайринговский, типа

_digitalWrite(LED_BUILTIN, LOW);

т.е. пины менять вполне удобно.

Если пин - константа, то результат точно как у Cyberlib, если переменная, вставляется очень короткий код для вычисления.