Можно ли привязать отдельные выводы другого порта микроконтроллера к регистру и изменить их значения при изменении значения регистра?

12

В: Можно ли привязать отдельные контакты другого порта микроконтроллера к регистру и изменить их значения при изменении значения регистра?

Сценарий: я использовал несколько выводов от каждого порта (8 бит) микроконтроллера. Теперь я хочу подключить устройство, которому нужна 8-битная шина (предположим, от D0 до D7 ПОСЛЕДОВАТЕЛЬНО), то есть мне нужно 8 контактов от контроллера, чтобы я мог подключить их один-к-одному

portx0  -> D0 // x is the name of port followed by bit location on that port
portx1  -> D1
...
portx7  -> D7

но у меня нет целого порта из 8 контактов, который я могу подключить к этому устройству, скорее, у меня есть несколько контактов из portx, некоторые из porty и некоторые из portz. Новый сценарий подключения выглядит так (подключение от микроконтроллера к устройству соответственно)

portx0  -> D0
portx1  -> D1
portx2  -> D2
porty4  -> D3
porty5  -> D4
porty6  -> D5
porty7  -> D6
portz1  -> D7

В этом состоянии, если я хочу отправить значение, скажем

unsigned char dataReg = 0xFA;

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

portx0 = ((dataReg & 0x01) >> 0 );  // Masking and shifting as bit position
portx1 = ((dataReg & 0x02) >> 1 );
portx2 = ((dataReg & 0x04) >> 2 );
porty4 = ((dataReg & 0x08) >> 3 );
porty5 = ((dataReg & 0x10) >> 4 );
porty6 = ((dataReg & 0x20) >> 5 );
porty7 = ((dataReg & 0x40) >> 6 );
portz1 = ((dataReg & 0x80) >> 7 );

Теперь, перейдя к основному вопросу, чтобы избежать этих индивидуальных вычислений для каждого бита на разных портах, можно ли сопоставить отдельные выводы разных портов микроконтроллера с регистром и изменить их значения при изменении значения регистра?

Osaid
источник
1
У меня была та же идея некоторое время назад. С PIC это невозможно: microchip.com/forums/tm.aspx?high=&m=696277 - Я не думаю, что это возможно с любым микро, но перечисление вашего устройства было бы полезно.

Ответы:

6

Похоже, ваш вопрос сводится к наличию 8-битного значения в прошивке и желанию прочитать и записать это из произвольной коллекции выводов портов.

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

Лучший способ сделать это, особенно если вы можете сгруппировать биты в несколько смежных кусков на физических портах, это использовать маскирование, сдвиг и ORing. Например, если младшие три бита внутреннего байта находятся в битах <6-4> порта, сдвиньте значение этого порта вправо на 4 и AND на 7, чтобы получить эти биты в их окончательном положении. Сдвиньте и замаскируйте (или замаскируйте и сдвиньте) биты с других портов на место и соберите последние 8-битные байты, ИЛИ результаты в него.

Такого рода низкоуровневое переключение битов легче выполнить в ассемблере, чем в C. Я бы, вероятно, поместил процедуры чтения и записи байтов в один модуль ассемблера и сделал бы интерфейс вызываемым из C.

Олин Латроп
источник
6
Мой ответ был бы почти идентичен вашему, за исключением того, что я бы вообще не использовал сборку; битовые манипуляции тривиальны в Си. Я думаю, что это было бы скорее головной болью (переучиванием) конкретного соглашения о вызовах Си для компилятора и того, как запустить компоновщик. Действительно зависит от компилятора и от того, насколько он сложен. :-)
akohlsmith
@ Андрей: Серьезно? Соглашения о вызовах четко изложены в любом руководстве по компиляции, которое я видел, где может возникнуть необходимость взаимодействия с кодом сборки. Манипулирование битами может быть «тривиальным» для написания на C, но это область, где компиляторы могут создавать ужасный код. Если скорость или пространство кода не имеют значения, используйте то, что вам удобнее. Я более удобен с ассемблером для низкоуровневого поворота битов, так что я бы использовал это. Если это низкоуровневая процедура, ограничивающая скорость, вы должны сделать это на ассемблере. Это действительно должно быть легко.
Олин Латроп
1
То, что я говорю, - это то, что я должен был бы потрудиться с этим для чего-то такого же тривиального, как битовая манипуляция, если бы не было очень веской причины для этого. Мы не знаем специфику его параллельной шины, но большинство шин имеют строб-сигналы, которые устраняют необходимость «почти атомарных» обновлений всех выводов шины, поэтому переход к сборке, вероятно, является ненужной оптимизацией и ненужной сложностью (даже если это straightforwardish).
akohlsmith
@Andrew: Это только мешает или сложно, если вы не знаете, что делаете. Я думаю, что настоящая проблема заключается в том, что некоторые люди боятся ассемблера и плохо его знают. Это ошибка Это должен быть готовый инструмент в вашем наборе инструментов. Если вы плохо это знаете или вам это неудобно, вы всегда будете оправдывать, как все должно быть сделано иначе. Некоторые вещи проще в ассемблере, если вы знаете это и HLL одинаково хорошо. Большинство людей этого не делают, но это проблема с ними, а не с использованием ассемблера.
Олин Латроп
2
Я хорошо разбираюсь в языке ассемблера по ряду микроконтроллеров / микропроцессоров. Я не согласен с тем, что это должен быть готовый инструмент; его следует использовать экономно и только в случае необходимости, как правило, для инициализации на очень низком уровне, кода, критичного по времени или размеру, или в более общем случае для оптимизации области, которую вы уже определили как узкое место. Я нахожу те проекты, где авторы, которые переходят на сборку, потому что там часто пишут менее понятный код или не распознают, когда алгоритм используется неправильно. Я не говорю конкретно, что это вы, а скорее в более общем случае.
akohlsmith
4

В общем, это невозможно. Насколько я знаю, это невозможно с PIC.

Я знаю только один микроконтроллер, который может это сделать, Cypress PSoC . Это настраиваемая система на чипе. Из многих вещей, которые он позволяет вам делать, это буквально определять свой собственный регистр (1-8 бит) и подключать его к любым выводам, которые вам нравятся, или даже к внутренним цепям.

PSoC Wiring

Например, здесь я создал 6-битный регистр управления. 5 бит идут прямо на контакты, а 6-й бит я использую для XOR с входом от 7-го контакта.

PSoC Pins

На микросхеме я могу выбрать размещение этих выводов для любого из доступных выводов GPIO. (Это серые одно изображение)

Rocketmagnet
источник
1
LPC800 также должен уметь это делать, поскольку функции могут свободно назначаться контактам.
Starblue
-1

Вы можете попробовать следующее. Напишите свою собственную структуру, которая сопоставляется с соответствующими выводами 2 портов (которые будут использоваться). Теперь при обновлении значения в этом регистре устанавливаются / сбрасываются выводы этих 2 портов. Просто попробуйте и дайте нам знать, если это сработало !!

Я уверен, что это должно работать.

Рахул Ранджан
источник
2
В C вы можете отобразить структуру в ячейку памяти, и вы можете отобразить биты вашей структуры (битовые поля) на битовые смещения, но нет никакого способа предотвратить компилятор возиться с битами 'inbetween', и теперь есть способ просмотра «общей» структуры одним целочисленным значением. Это не сработает.
Воутер ван Оойен
-1

Если я правильно понял вопрос, это достаточно просто в C:

Объявление общего типа, может быть повторно использовано для любого регистра:

typedef union    // Generic 8-bit register Type
{
  uint8 reg; // Whole register
  struct
  {
    unsigned  bit7     : 1;  // Bit 7 
    unsigned  bit6     : 1;  // Bit 6 
    unsigned  bit5     : 1;  // Bit 5 
    unsigned  bit4     : 1;  // Bit 4 
    unsigned  bit3     : 1;  // Bit 3 
    unsigned  bit2     : 1;  // Bit 2 
    unsigned  bit1     : 1;  // Bit 1 
    unsigned  bit0     : 1;  // Bit 0 
  } bit;
} typ_GENERIC_REG8;

Итак, чтобы определить порт, к которому мы хотим обратиться:

#define MCU_GPO_PORTx   (*(volatile typ_GENERIC_REG8 *)(0x12345678)) // Number is address

И непосредственно крутить булавку на этом порту:

#define MCU_PORTx_PINn  (MCU_GPO_PORTx.bit.bit0)

В коде:

MCU_PORTx_PINn = 1; // Set pin high

Весь регистр:

MCU_GPO_PORTx.reg = 0xF; // All pins high

Стоит почитать о структурах, союзах, типах и перечислениях - все это делает жизнь во встроенном и в целом намного приятнее!

Джон У
источник
OP хочет объединить несколько битов из разных портов в один байт. Я не понимаю, как это могло бы сделать это? Олин Латроп объясняет, почему это невозможно.
На самом деле это не решает проблему и, в зависимости от того, насколько «смрт» ваш компилятор, может создать целый новый набор проблем для отладки.
akohlsmith