В: Можно ли привязать к регистру отдельные выводы разных портов микроконтроллера и изменить их значения при изменении значения регистра?
Сценарий: я израсходовал несколько контактов от каждого порта (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 );
Теперь, переходя к основному вопросу, чтобы избежать этих отдельных вычислений для каждого бита на разных портах, можно ли отдельные выводы разных портов микроконтроллера сопоставить с регистром и изменить их значения при изменении значения регистра?
Похоже, ваш вопрос сводится к тому, что в прошивке есть 8-битное значение, и вы хотите читать и записывать его из и в произвольный набор контактов порта.
Прямого аппаратного способа сделать это нет. Вы должны написать две подпрограммы, одну для чтения 8-битного значения и одну для его записи. Другие упоминали об использовании союзов, но это плохая идея. С объединениями приходится иметь дело с каждым битом отдельно, и код становится зависимым от порядка битов микро. В любом случае это может быть выходом, если все 8 битов разбросаны совершенно независимо. Если это так, вы мало что можете сделать, кроме как создать специальный код для каждого бита.
Лучший способ сделать это, особенно если вы можете сгруппировать биты в несколько смежных фрагментов на физических портах, — использовать маскирование, сдвиг и операцию ИЛИ. Например, если младшие три бита внутреннего байта находятся в битах <6-4> порта, сдвиньте значение этого порта вправо на 4 и И на 7, чтобы получить эти биты в их конечной позиции. Сдвиньте и замаскируйте (или замаскируйте и сдвиньте) биты из других портов на место и соберите окончательный 8-битный байт, объединив с ним результаты ИЛИ.
Такого рода перестановку битов на низком уровне легче выполнить на ассемблере, чем на C. Я бы, вероятно, поместил процедуры чтения и записи байтов в один модуль ассемблера и сделал интерфейс вызываемым из C.
В общем случае это невозможно. Насколько я знаю, с PIC это невозможно.
Я знаю только один микроконтроллер, который может это сделать, Cypress PSoC . Это хорошо настраиваемая система на чипе. Из многих вещей, которые он позволяет вам сделать, это буквально определить свой собственный регистр (1-8 бит) и подключить его к любым контактам, которые вам нравятся, или даже к внутренним схемам.
Например, здесь я создал 6-битный регистр управления. 5 бит идут прямо на контакты, а 6-й бит я использую для XOR с вводом с 7-го контакта.
На чипе я могу назначить эти контакты любому из доступных контактов GPIO. (Это серые на изображении)
Вы можете попробовать следующее. Напишите свою собственную структуру, которая сопоставляется с соответствующими контактами двух портов (которые должны использоваться). Теперь обновление значения в этом регистре должно установить/сбросить контакты этих двух портов. Просто попробуйте и дайте нам знать, если это сработало !!
Я уверен, что это должно сработать.
Если я правильно понял вопрос, в 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
Стоит прочитать о структурах, объединениях, определениях типов и перечислениях — все это делает жизнь намного приятнее во встраиваемых системах и в целом!
пользователь17592