พินแต่ละพอร์ตที่แตกต่างกันของไมโครคอนโทรลเลอร์สามารถแมปกับรีจิสเตอร์และค่าของมันจะเปลี่ยนไปเมื่อทำการเปลี่ยนค่ารีจิสเตอร์หรือไม่?


12

ถาม: สามารถแมปพินแต่ละพอร์ตของไมโครคอนโทรลเลอร์แต่ละตัวเข้ากับรีจิสเตอร์และเปลี่ยนค่าได้หรือไม่เมื่อเปลี่ยนค่ารีจิสเตอร์?

สถานการณ์สมมติ: ฉันใช้พินมากขึ้นจากแต่ละพอร์ต (8 บิต) ของไมโครคอนโทรลเลอร์ ตอนนี้ฉันต้องการเชื่อมต่ออุปกรณ์ที่ต้องการบัส 8 บิต (สมมติว่า D0 ถึง D7 IN SEQUENCE) กล่าวคือฉันต้องการ 8 พินจากคอนโทรลเลอร์เพื่อให้สามารถเชื่อมต่อได้ในแบบหนึ่งต่อหนึ่ง

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

แต่ฉันไม่มีพอร์ตทั้งหมด 8 พินซึ่งฉันสามารถเชื่อมต่อกับอุปกรณ์นี้ได้ แต่ฉันมีพินบางตัวจากพอร์ทเอ็กซ์บางตัวมาจากพอร์ทและบางพินจากพอร์ทซ สถานการณ์การเชื่อมต่อใหม่เป็น (การเชื่อมต่อจากไมโครคอนโทรลเลอร์ไปยังอุปกรณ์ตามลำดับ)

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
เมื่อไม่นานมานี้ฉันมีความคิดเดียวกัน ด้วย PICs นี่เป็นไปไม่ได้: microchip.com/forums/tm.aspx?high=&m=696277 - ฉันไม่คิดว่ามันจะเป็นไปได้ด้วย micro ใด ๆ แต่การแสดงรายการอุปกรณ์ของคุณจะมีประโยชน์

คำตอบ:


6

ดูเหมือนว่าคำถามของคุณจะมีค่า 8 บิตในเฟิร์มแวร์และต้องการอ่านและเขียนจากและไปยังคอลเลกชันพอร์ตพินโดยพลการ

ไม่มีวิธีที่ฮาร์ดแวร์โดยตรงในการทำเช่นนี้ คุณต้องเขียนรูทีนสองรายการเพื่ออ่านค่า 8 บิตและเขียนหนึ่งชุด คนอื่น ๆ พูดถึงการใช้สหภาพแรงงาน แต่นั่นเป็นความคิดที่ไม่ดี ด้วยสหภาพแรงงานคุณต้องจัดการทุก ๆ บิตแยกกันและรหัสจะขึ้นอยู่กับลำดับบิตของไมโคร นี่อาจเป็นวิธีที่จะไปถ้า 8 บิตทั้งหมดกระจัดกระจายอย่างอิสระ ถ้าเป็นเช่นนั้นคุณสามารถทำได้เพียงเล็กน้อย แต่ต้องสร้างรหัสพิเศษสำหรับแต่ละบิต

วิธีที่ดีกว่าในการทำเช่นนี้โดยเฉพาะอย่างยิ่งถ้าคุณสามารถจัดกลุ่มบิตเป็นชิ้น ๆ ที่ต่อเนื่องกันบนพอร์ตฟิสิคัลคือการใช้ masking, shift และ ORing ตัวอย่างเช่นหากไบต์ต่ำสามบิตของไบต์ภายในอยู่บนบิต <6-4> ของพอร์ตให้เลื่อนค่าพอร์ตนั้นด้วย 4 และ AND ด้วย 7 เพื่อรับบิตเหล่านั้นเข้าสู่ตำแหน่งสุดท้าย Shift และ mask บิต (หรือ mask และ shift) จากพอร์ตอื่นเข้าที่และประกอบไบต์ 8 บิตสุดท้ายโดย ORing ผลลัพธ์ลงไป

การบิดสองบิตระดับต่ำแบบนี้ทำได้ง่ายกว่าในแอสเซมเบลอร์มากกว่าซีฉันอาจใส่รูทีนการอ่านและการเขียนในโมดูลแอสเซมเบลอร์เดียวและทำให้อินเตอร์เฟสสามารถเรียกใช้ได้จาก C


6
คำตอบของฉันจะเหมือนกับคุณเกือบทั้งหมดยกเว้นว่าฉันจะไม่ใช้ชุดประกอบเลย การจัดการบิตนั้นเล็กน้อยใน C. ฉันคิดว่ามันน่าปวดหัวกว่า (อีกครั้ง) การเรียนรู้หลักการเรียก C เฉพาะสำหรับคอมไพเลอร์และวิธีเรียกใช้ตัวเชื่อมโยง ขึ้นอยู่กับคอมไพเลอร์จริงๆและมันยากขนาดไหน :-)
akohlsmith

@Andrew: อย่างจริงจัง? อนุสัญญาการโทรถูกสะกดอย่างชัดเจนในคู่มือผู้เรียบเรียงใด ๆ ที่ฉันเคยเห็นซึ่งอาจจำเป็นต้องเชื่อมต่อกับรหัสแอสเซมบลี การจัดการบิตอาจเป็น "เรื่องไม่สำคัญ" ในการเขียนใน C แต่นี่เป็นพื้นที่ที่คอมไพเลอร์สามารถสร้างโค้ดที่น่ากลัว หากความเร็วหรือโค้ดพื้นที่ไม่สำคัญให้ใช้สิ่งที่คุณคุ้นเคยมากกว่า ฉันสบายใจกับแอสเซมเบลอร์สำหรับการบิดสองบิตระดับต่ำดังนั้นฉันจะใช้ หากนี่เป็นรูทีนแบบ จำกัด ความเร็วระดับต่ำคุณควรทำในแอสเซมเบลอร์ มันควรจะง่ายจริงๆ
Olin Lathrop

1
สิ่งที่ฉันพูดคือการต้องจัดการกับสิ่งเล็ก ๆ น้อย ๆ เช่นการจัดการบิตไม่ใช่สิ่งที่ฉันจะทำถ้าไม่มีเหตุผลที่ดีสำหรับมัน เราไม่ทราบถึงข้อมูลเฉพาะของบัสขนานของเขา แต่รถโดยสารส่วนใหญ่มีสัญญาณไฟแฟลชที่ไม่จำเป็นต้องมีการอัพเดท "ใกล้กับอะตอม" ของหมุดบัสทั้งหมดดังนั้นการปล่อยให้แอสเซมบลีน่าจะเป็นการเพิ่มประสิทธิภาพที่ไม่จำเป็น straightforwardish)
akohlsmith

@ แอนดรูว์: มันแค่ทำให้สับสนหรือซับซ้อนถ้าคุณไม่รู้ว่าคุณกำลังทำอะไรอยู่ ฉันคิดว่าปัญหาที่แท้จริงคือบางคนกลัวแอสเซมเบลอร์และไม่รู้ว่าดี นั่นเป็นความผิดพลาด มันต้องเป็นเครื่องมือที่พร้อมในกล่องเครื่องมือของคุณ หากคุณไม่รู้จักหรือรู้สึกไม่สบายใจคุณจะต้องให้เหตุผลเสมอว่าควรทำสิ่งอื่นอย่างไร แอสเซมเบลอร์บางสิ่งง่ายขึ้นถ้าคุณรู้และ HLL เท่ากัน คนส่วนใหญ่ทำไม่ได้ แต่เป็นปัญหากับพวกเขาไม่ใช่ด้วยการใช้แอสเซมเบลอร์
Olin Lathrop

2
ฉันมีความเชี่ยวชาญในภาษาแอสเซมบลีบนไมโครคอนโทรลเลอร์จำนวนมาก / ไมโครโปรเซสเซอร์ ฉันไม่เห็นด้วยว่าควรเป็นเครื่องมือที่พร้อมใช้งาน ควรใช้เท่าที่จำเป็นและโดยปกติแล้วสำหรับการเริ่มต้นในระดับต่ำมากรหัสเวลาหรือขนาดที่สำคัญหรือในกรณีที่พบบ่อยมากขึ้นการเพิ่มประสิทธิภาพของพื้นที่ที่คุณกำหนดไว้แล้วว่าจะเป็นคอขวด ฉันพบว่าโครงการที่ผู้เขียนที่ข้ามไปประกอบเนื่องจากมักจะเขียนโค้ดที่ชัดเจนน้อยลงหรือไม่รู้จักเมื่ออัลกอริทึมถูกใช้งานผิด ฉันไม่ได้บอกว่าเป็นคุณโดยเฉพาะ แต่ในกรณีทั่วไปมากกว่า
akohlsmith

4

โดยทั่วไปไม่สามารถทำได้ เท่าที่ฉันรู้มันเป็นไปไม่ได้กับ PICs

มีเพียงคนเดียวที่ฉันรู้ไมโครคอนโทรลเลอร์ที่สามารถทำเช่นนี้คือCypress PSoC มันเป็นระบบที่กำหนดค่าได้สูงบนชิป ในหลาย ๆ สิ่งที่คุณสามารถทำได้คือกำหนดทะเบียนของคุณเอง (1-8 บิต) และเชื่อมต่อกับหมุดใด ๆ ที่คุณชอบหรือแม้กระทั่งวงจรภายใน

การเดินสาย PSoC

ตัวอย่างเช่นที่นี่ฉันได้สร้างการลงทะเบียนควบคุม 6 บิต 5 บิตตรงไปที่หมุดในขณะที่บิตที่ 6 ที่ฉันใช้กับ XOR ด้วยอินพุตจากขาที่ 7

พิน PSoC

บนชิปฉันสามารถเลือกที่จะจัดสรรพินเหล่านี้กับพิน GPIO ที่มีอยู่ (มันเป็นสีเทาซึ่งเป็นหนึ่งในภาพ)


1
LPC800 ควรทำเช่นนั้นได้เนื่องจากฟังก์ชั่นสามารถกำหนดให้กับพินได้อย่างอิสระ
starblue

-1

คุณอาจลองทำสิ่งต่อไปนี้ เขียนโครงสร้างของคุณเองซึ่งแมปกับหมุดที่เกี่ยวข้องของ 2 พอร์ต (ซึ่งจะใช้) ตอนนี้การปรับปรุงค่าในการลงทะเบียนนี้จะต้องตั้งค่า / รีเซ็ตพินของ 2 พอร์ตเหล่านั้น แค่ลองและแจ้งให้เราทราบว่ามันใช้งานได้ !!

ฉันมั่นใจว่ามันควรจะใช้ได้


2
ใน C คุณสามารถแมปโครงสร้างไปยังตำแหน่งหน่วยความจำและคุณสามารถแมปบิตของโครงสร้างของคุณ (บิตฟิลด์) เป็นบิตออฟเซ็ตได้ แต่ไม่มีวิธีใดที่จะป้องกันคอมไพเลอร์ไม่ให้ยุ่งกับบิต 'inbetween' และตอนนี้ วิธีดูโครงสร้าง 'โดยรวม' เป็นจำนวนเต็มค่าเดียว สิ่งนี้ใช้ไม่ได้
Wouter van Ooijen

-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

คุ้มค่าที่จะอ่านข้อมูลเกี่ยวกับ structs, unions, typedefs และ enums - ทั้งหมดนี้ทำให้ชีวิตดีขึ้นมากในการฝังตัวและโดยทั่วไป!


OP ต้องการรวมหลายบิตจากพอร์ตที่แตกต่างกันเป็น 'หนึ่งไบต์' ฉันไม่เห็นว่าจะทำเช่นนี้ได้อย่างไร Olin Lathrop อธิบายว่าทำไมมันเป็นไปไม่ได้

สิ่งนี้ไม่ได้แก้ไขปัญหาจริง ๆ และขึ้นอยู่กับว่า "smrt" คอมไพเลอร์ของคุณคืออะไรสามารถสร้างปัญหาชุดใหม่ทั้งหมดเพื่อแก้ไขข้อบกพร่อง
akohlsmith
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.