Чи можна окремі штифти різних портів мікроконтролера відобразити в регістр і змінити їх значення при зміні значення регістру?


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 );

Тепер, підходячи до головного питання, щоб уникнути цих індивідуальних обчислень на кожен біт на різних портах, чи можна окремі шпильки різних портів мікроконтролера відобразити в регістр і змінити їх значення при зміні значення регістру?


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

Відповіді:


6

Здається, ваше питання зводиться до наявності 8-бітового значення в мікропрограмному забезпеченні, і ви хочете прочитати і записати це з і до довільної колекції порт-штифтів.

Не існує прямого апаратного способу зробити це. Ви повинні написати дві підпрограми, одну - прочитати значення 8 біт і одну - записати. Інші згадували про використання спілок, але це погана ідея. З профспілками вам доведеться мати справу з кожним бітом окремо, і код стає залежним від порядку бітів мікро. Це може бути шлях у будь-якому випадку, якщо всі 8 біт розкидані повністю незалежно. Якщо це так, ви можете зробити мало чого, але зробити спеціальний код для кожного біта.

Кращий спосіб зробити це, особливо якщо ви можете згрупувати біти в декілька суміжних фрагментів на фізичних портах, це використовувати маскування, зсув та ORing. Наприклад, якщо три низьких біта внутрішнього байта знаходяться на бітах <6-4> порту, праворуч змістіть це значення порту на 4 та І на 7, щоб отримати ці біти у своє остаточне положення. Зсуньте і замаскуйте (або маскуйте і змістіть) біти з інших портів на місце і зберіть остаточний 8-бітовий байт, ORO підписавши в нього результати.

Цей тип подвійного твітлінгу на низькому рівні простіше зробити в асемблері, ніж C. Я, певно, поклав байт підпрограми для читання і запису в єдиний модуль асемблера і зробив інтерфейс для дзвінка з C.


6
Моя відповідь була б майже ідентичною вашій, за винятком того, що я б взагалі не використовував збірку; бітові маніпуляції тривіальні в C. Я думаю, що це було б більше головним болем (пере) вивченням специфічної конвенції C виклику для компілятора і як запустити лінкер. Дійсно залежить від компілятора і того, наскільки важко це ускладнює. :-)
akohlsmith

@Andrew: Серйозно? Конвенції про виклики чітко прописані в будь-якому посібнику з компілятора, який я бачив, де може виникнути потреба в взаємодії з асемблерним кодом. Маніпуляція з бітами може бути "тривіальною" для запису в C, але це область, де компілятори можуть виробляти жахливий код. Якщо швидкість або простір коду не має значення, використовуйте все, що вам більше комфортно. Мені зручніше асемблер для низькорівневого подвійного біттера, тому я б цим скористався. Якщо це рутичний режим з низьким рівнем швидкості, вам слід зробити це в асемблері. Це дійсно повинно бути легко.
Олін Латроп

1
Те, що я говорю, - це те, що мав би маніпулювати бітом - це не те, що я б робив, якщо не було дуже вагомої причини для цього. Ми не знаємо специфіки його паралельної шини, але в більшості шин подаються стробові сигнали, що усувають необхідність "майже атомних" оновлень усіх шин шини, тому відмова на збірку, ймовірно, зайва оптимізація та непотрібна складність (навіть якщо це прямолінійний).
akohlsmith

@Andrew: Це дуже просто, якщо ти не знаєш, що ти робиш, це складне завдання. Я думаю, що справжня проблема полягає в тому, що деякі люди бояться асемблера і не знають цього добре. Це помилка. Це має бути готовим інструментом у вашій панелі інструментів. Якщо ви цього не знаєте добре або вам це незручно, ви завжди будете виправдовувати, як слід робити щось іншим способом. Деякі речі простіші в асемблері, якщо ви знаєте це і HLL однаково добре. Більшість людей цього не роблять, але це проблема з ними, а не з використанням асемблера.
Олін Латроп

2
Я добре обізнаний у мові складання на ряді мікроконтролерів / мікропроцесорів. Я не згоден, що це повинен бути готовий інструмент; його слід використовувати ощадливо і лише в разі необхідності, як правило, для ініціалізації дуже низького рівня, коду, що відповідає критичному розміру, або в більш поширеному випадку, оптимізації області, яку ви вже визначили вузьким місцем. Я вважаю, що проекти, де автори, які переходять до складання, тому що там часто пишуть менш чіткий код або не розпізнають, коли алгоритм неправильно застосовується. Я конкретно не кажу, що це ти, а скоріше в більш загальному випадку.
akohlsmith

4

Загалом це неможливо. Наскільки я знаю, з PIC це неможливо.

Є лише один мікроконтролер, який я знаю, що може це зробити, Cypress PSoC . Це чітко налаштована система на чіпі. З багатьох речей, які ви можете зробити, це буквально визначити власний реєстр (1-8 біт) і підключити його до будь-яких штифтів, які вам подобаються, або навіть до внутрішніх схем.

Підключення PSoC

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

PSoC шпильки

На мікросхемі я можу вирішити виділити ці шпильки на будь-який із доступних штифтів GPIO. (Це сірі на зображенні)


1
LPC800 також повинен це робити, оскільки функції можуть вільно призначатися штифтам.
starblue

-1

Ви можете спробувати наступне. Напишіть власну структуру, яка відображає відповідні шпильки двох портів (які мають бути використані). Оновлення значення у цьому реєстрі має встановити / скинути шпильки цих двох портів. Просто спробуйте і повідомте нам, чи спрацювало !!

Я впевнений, що це має працювати.


2
У C ви можете зіставити структуру на місце пам’яті, і ви можете зіставити біти вашої структури (бітові поля), щоб збити зсуви, але немає можливості запобігти компілятору не возитися з бітами 'inbetween', і тепер є спосіб перегляду «загальної» структури єдине ціле значення. Це не спрацює.
Wouter van Ooijen

-1

Якщо я правильно зрозумів це питання, досить просто:

Декларація загального типу, може бути повторно використана для будь-якого реєстру:

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

Варто ознайомитись з структурами, спілками, typedefs та перерахунками - все це робить життя набагато приємнішим у вбудованих та взагалі!


OP хоче об'єднати кілька біт з різних портів в "один байт". Я не бачу, як це зробить? Олін Летроп пояснює, чому це неможливо.

Це насправді не вирішує проблему, і залежно від того, наскільки "смерть" ваш компілятор, може створити цілий новий набір проблем для налагодження.
akohlsmith
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.