คลาส C ++ สำหรับ Abstraction pin I / O


13

ฉันกำลังมองหา abstractions C ++ สำหรับจุดหรือพิน I / O ของฮาร์ดแวร์ สิ่งต่างๆเช่น in_pin, out_pin, inout_pin, open_collector_pin เป็นต้น

แน่นอนว่าฉันสามารถสร้างชุด abstractions ของตัวเองขึ้นมาได้ดังนั้นฉันจึงไม่ได้มองหาคำตอบประเภท 'เฮ้คุณอาจทำแบบนี้' แต่ตอบว่า 'ดูที่ห้องสมุดนี้ซึ่งถูกใช้ในสิ่งนี้และสิ่งนี้และ โครงการนี้'.

Google ไม่ได้ทำอะไรเลยอาจเป็นเพราะฉันไม่รู้ว่าคนอื่นจะเรียกสิ่งนี้อย่างไร

จุดประสงค์ของฉันคือการสร้างไลบรารี I / O ที่ยึดตามจุดดังกล่าว แต่ยังให้คะแนนเช่นนั้นดังนั้นจึงง่ายต่อการเชื่อมต่อ HD44780 LCd กับทั้ง IO IO ของชิปหรือ I2C (หรือ SPI) ตัวขยาย I / O หรือจุดอื่นใดที่สามารถควบคุมได้โดยไม่ต้องเปลี่ยนคลาส LCD

ฉันรู้ว่านี่อยู่บนขอบของอิเล็กทรอนิกส์ / ซอฟต์แวร์ขออภัยถ้ามันไม่ได้อยู่ที่นี่

@ leon: การเดินสายนั่นเป็นซอฟต์แวร์ถุงใหญ่ฉันจะต้องดูให้ดี แต่ดูเหมือนว่าพวกเขาไม่ได้ใช้สิ่งที่เป็นนามธรรมเช่นฉันต้องการ เช่นในการใช้แผงปุ่มกดฉันเห็น

digitalWrite(columnPins[c], LOW);   // Activate the current column.

นี่หมายความว่ามีหนึ่งฟังก์ชั่น (digitalWrite) ที่รู้วิธีเขียนไปยังพิน I / O สิ่งนี้ทำให้เป็นไปไม่ได้ที่จะเพิ่มพิน I / O ชนิดใหม่ (ตัวอย่างเช่นอันที่อยู่ใน MCP23017 ดังนั้นจึงต้องเขียนผ่าน I2C) โดยไม่ต้องเขียนฟังก์ชั่น digitalWrite ใหม่

@Oli: ฉันได้ทดลองใช้ Arduino IO แต่ดูเหมือนว่าจะใช้วิธีการเดียวกันกับห้องสมุด Wiring:

int ledPin = 13;                 // LED connected to digital pin 13
void setup(){
    pinMode(ledPin, OUTPUT);      // sets the digital pin as output
}

เรากำลังพูดอะไรไมโครคอนโทรลเลอร์ที่นี่?
Majenko

นั่นไม่เกี่ยวข้องเลย สำหรับไมโครคอนโทรลเลอร์โดยเฉพาะหมุด io ​​ของ uC นั้นจะใช้อินเตอร์เฟสที่เหมาะสม แต่นี่สำหรับ C ++ ดังนั้นให้นึกถึงชิป 32 บิตเช่น ARM, Cortex และ MIPS
Wouter van Ooijen

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

1
และสำหรับการเขียนฟังก์ชัน digitalWrite ใหม่ - ดูที่ "overloading" ใน C ++ เมื่อไม่นานมานี้ฉันได้เขียนฟังก์ชั่น digitalWrite ที่โอเวอร์โหลดสำหรับบอร์ดขยาย IO สำหรับ Arduino ตราบใดที่คุณใช้พารามิเตอร์ต่าง ๆ (ฉันแทนที่ "int" ตัวแรกด้วย "struct") มันจะเลือก digitalWrite ของคุณตามค่าเริ่มต้น
Majenko

1
ฉันได้พูดคุยเกี่ยวกับการประชุม C ++ ที่กรุงเบอร์ลินเกี่ยวกับงานของฉันในหัวข้อนี้ มันสามารถพบได้ใน youtube: youtube.com/watch?v=k8sRQMx2qUwตั้งแต่นั้นมาฉันเปลี่ยนไปใช้วิธีที่แตกต่างกันเล็กน้อย แต่การพูดคุยอาจจะน่าสนใจ
Wouter van Ooijen

คำตอบ:


3

คำตอบสั้น ๆ : เศร้าไม่มีห้องสมุดที่จะทำสิ่งที่คุณต้องการ ฉันทำด้วยตัวเองหลายครั้ง แต่มักจะไม่ใช่ในโครงการโอเพนซอร์ซ ฉันกำลังคิดจะวางอะไรบน github แต่ฉันไม่แน่ใจว่าจะทำได้

ทำไมต้อง C ++

  1. คอมไพเลอร์มีอิสระที่จะใช้การประเมินผลการแสดงออกขนาดคำแบบไดนามิก C แพร่กระจายไปยัง int หน้ากาก / กะไบต์ของคุณสามารถทำได้เร็วขึ้น / เล็กลง
  2. การจัด
  3. การดำเนินการ Templatizing ช่วยให้คุณสามารถเปลี่ยนขนาดคำและคุณสมบัติอื่น ๆ ด้วยความปลอดภัยประเภท

5

ให้ผมเสียบลงคอโครงการที่มาเปิดของฉันhttps://Kvasir.io ส่วน Kvasir :: Io มีฟังก์ชันการจัดการพิน คุณต้องกำหนดพินของคุณก่อนโดยใช้ Kvasir :: Io :: PinLocation ดังนี้:

constexpr PinLocation<0,4> led1;    //port 0 pin 4
constexpr PinLOcation<0,8> led2;

ขอให้สังเกตว่านี่ไม่ได้ใช้ RAM จริง ๆ เพราะเป็นตัวแปร constexpr

ตลอดรหัสของคุณคุณสามารถใช้ตำแหน่งพินเหล่านี้ในฟังก์ชั่น 'action factory' เช่น makeOpenDrain, set, clear, makeOutput และอื่น ๆ 'โรงงานการกระทำ' ไม่ได้ดำเนินการการกระทำจริง ๆ แต่จะส่งกลับ Kvasir :: ลงทะเบียน :: การกระทำซึ่งสามารถดำเนินการได้โดยใช้ Kvasir :: ลงทะเบียน :: Apply () เหตุผลสำหรับสิ่งนี้คือนำไปใช้ () ผสานการกระทำที่ส่งไปเมื่อดำเนินการกับหนึ่งและการลงทะเบียนเดียวกันดังนั้นจึงมีประสิทธิภาพเพิ่มขึ้น

apply(makeOutput(led1),
    makeOutput(led2),
    makeOpenDrain(led1),
    makeOpenDrain(led2));

เนื่องจากการสร้างและการรวมการกระทำเสร็จสิ้นในเวลารวบรวมจึงควรให้รหัสแอสเซมเบลอร์เดียวกับรหัสทั่วไปที่เทียบเท่า:

PORT0DIR |= (1<<4) | (1<<8);
PORT0OD |= (1<<4) | (1<<8);

3

โครงการ Wiring ใช้สิ่งที่เป็นนามธรรมเช่นนั้น:

http://wiring.org.co/

และคอมไพเลอร์เขียนใน C ++ คุณควรพบตัวอย่างมากมายในซอร์สโค้ด ซอฟต์แวร์ Arduino ใช้สายไฟ


ตอบในเนื้อความของคำถาม
Wouter van Ooijen

2

ใน C ++ เป็นไปได้ที่จะเขียนคลาสเพื่อให้คุณสามารถใช้พอร์ต I / O เสมือนเป็นตัวแปรเช่น

  PORTB = 0x12; / * เขียนไปยังพอร์ต 8 บิต * /
  if (RB3) LATB4 = 1; / * อ่านหนึ่ง I / O bit และเขียนอีกหนึ่งเงื่อนไข * /

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

  if (IO_PORTS.bbRB3) IO_PORTS.bbLATB4 = 1;

ซึ่งจะถูกประมวลผลในสิ่งที่ชอบ:

  ถ้า (!! (PORTB & 8)) (1? (PORTB | = 16): (PORTB & = ~ 16));

คอมไพเลอร์ควรสังเกตเห็นนิพจน์คงที่ในตัวดำเนินการ?: และรวมส่วน "true" เท่านั้น อาจเป็นไปได้ที่จะลดจำนวนของคุณสมบัติที่สร้างโดยให้แมโครขยายไปยังสิ่งที่ต้องการ:

  if (IO_PORTS.ppPORTB [3]) IO_PORTS.ppPORTB [4] = 1;

หรือ

  if (IO_PORTS.bb (addrPORTB, 3)) IO_PORTS.bbPORTB (addrPORTB, 4) = 1;

แต่ฉันไม่แน่ใจว่าคอมไพเลอร์จะสามารถอินไลน์โค้ดได้ดี

ฉันไม่เคยต้องการที่จะบอกเป็นนัยว่าการใช้พอร์ต I / O ราวกับว่าพวกเขาเป็นตัวแปรเป็นความคิดที่ดี แต่เนื่องจากคุณพูดถึง C ++ มันเป็นกลอุบายที่มีประโยชน์ที่จะรู้ การกำหนดค่าตามความชอบของฉันเองใน C หรือ C ++ หากไม่จำเป็นต้องใช้ความเข้ากันได้กับโค้ดที่ใช้สไตล์ดังกล่าวข้างต้นอาจเป็นการกำหนดแมโครบางประเภทสำหรับแต่ละบิต I / O แล้วกำหนดแมโครสำหรับ "readBit", "writeBit" "setBit" และ "clearBit" พร้อมเงื่อนไขว่าอาร์กิวเมนต์การระบุบิตที่ส่งไปยังมาโครเหล่านั้นจะต้องเป็นชื่อของพอร์ต I / O ที่มีไว้สำหรับใช้กับมาโครดังกล่าว ตัวอย่างข้างต้นจะเขียนเป็น

  if (readBit (RB3)) setBit (LATB4);

และแปลว่า

  ถ้า (!! (_ PORT_RB3 & _BITMASK_RB3)) _PORT_LATB4 | = _BITMASK_LATB4;

นั่นจะเป็นการทำงานที่มากขึ้นสำหรับตัวประมวลผลล่วงหน้ากว่าสไตล์ C ++ แต่มันจะทำงานน้อยลงสำหรับคอมไพเลอร์ นอกจากนี้ยังจะช่วยให้การสร้างรหัสที่ดีที่สุดสำหรับการใช้งาน I / O จำนวนมากและการใช้รหัสที่เหมาะสมสำหรับเกือบทั้งหมด


3
อ้างจากคำถาม: "ฉันไม่ได้มองหา 'คำตอบ' เฮ้คุณอาจทำมันด้วยวิธีนี้ 'คำตอบ" ...
Wouter van Ooijen

ฉันคิดว่าฉันไม่ชัดเจนว่าคุณกำลังมองหาอะไร แน่นอนฉันคาดหวังว่าหลาย ๆ คนที่มีความสนใจในชั้นเรียนสำหรับการฟื้นฟูพิน I / O ก็จะสนใจที่จะรู้ว่าการใช้คุณสมบัติหนึ่งสามารถสร้างรหัสที่เขียนขึ้นสำหรับ I / O สไตล์หนึ่งใช้อะไรก็ได้ ฉันใช้คุณสมบัติเพื่อสร้างข้อความเช่น "LATB3 = 1;" ส่งคำขอ I / O ไปยังสตรีม TCP
supercat

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

@Wouter van Ooijen: "หมุด I / O ชนิดใหม่" แบบไหนที่คุณคาดหวังไว้? หากซอร์สโค้ดเขียนด้วยไวยากรณ์เช่น "if (BUTTON_PRESSED) MOTOR_OUT = 1;" ฉันคาดว่าสำหรับกลไกใด ๆ ที่โปรเซสเซอร์อาจอ่านการควบคุมปุ่มหรือมอเตอร์หนึ่งสามารถเขียนไลบรารีดังนั้นแหล่งที่มาด้านบน รหัสจะเปิดมอเตอร์ถ้ากดปุ่ม ห้องสมุดดังกล่าวอาจไม่ได้เป็นวิธีที่มีประสิทธิภาพสูงสุดในการเปิดมอเตอร์ แต่มันก็ใช้ได้
supercat

@Wouter van Ooijen: อาจช่วยเพิ่มประสิทธิภาพได้หากจำเป็นต้องใช้ซอร์สโค้ดเรียกใช้มาโคร UPDATE_IO () หรือ UPDATE_INPUTS () บางครั้งก่อนที่จะอ่านอินพุตและดำเนินการ UPDATE_IO () หรือ UPDATE_OUTPUTS () ในบางครั้งหลังจากเอาต์พุต ซีแมนทิกส์ที่อินพุตสามารถสุ่มตัวอย่างได้ที่โค้ดที่อ่านหรือที่การร้องขอ UPDATE_INPUTS () / UPDATE_IO () ก่อนหน้านี้ ผลลัพธ์เช่นเดียวกันอาจเกิดขึ้นทันทีหรือถูกเลื่อนออกไป หากมีการใช้ I / O โดยใช้บางอย่างเช่น shift register การเลื่อนการทำงานออกจะทำให้สามารถรวมการดำเนินการหลาย ๆ
supercat

1

หากคุณกำลังมองหาบางสิ่งที่ยอดเยี่ยมมากที่จะทำให้ฮาร์ดแวร์เป็นนามธรรมและคุณมั่นใจในทักษะ C ++ ของคุณคุณควรลองรูปแบบนี้:

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

ฉันใช้มันในความพยายามครั้งเดียวเพื่อฮาร์ดแวร์นามธรรมสำหรับชิป Cortex-M0 ฉันยังไม่ได้เขียนอะไรเกี่ยวกับประสบการณ์นี้ (ฉันจะทำมันสักวัน) แต่เชื่อฉันว่ามันมีประโยชน์มากเพราะลักษณะ polymorphic คงที่: วิธีการเดียวกันสำหรับชิปที่แตกต่างกันไม่มีค่าใช้จ่าย (เทียบกับไดนามิกหลากหลาย)


ในปีที่ผ่านมาตั้งแต่โพสต์นี้ฉัน stettled ใน "เรียน" แยกต่างหากสำหรับ pin_in, pin_out, pin_oc และ pin_in_out เพื่อประสิทธิภาพที่ดีที่สุด (ขนาดและความเร็ว) ฉันใช้คลาสคงที่ส่งผ่านเป็นพารามิเตอร์เทมเพลต ฉันพูดคุยเกี่ยวกับเรื่องนี้ในการประชุม C ++ ที่กรุงเบอร์ลิน
Wouter van Ooijen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.