นี่เป็นความเห็น / ความคิดเห็นมากกว่าคำตอบ
คุณไม่ต้องการและไม่ควรเขียนโปรแกรมใน C. C ++ เมื่อใช้อย่างถูกวิธีจะดีกว่ามาก (ตกลงฉันต้องยอมรับเมื่อใช้ในทางที่ผิดมันแย่กว่า C. ) ซึ่ง จำกัด คุณให้ชิปที่มีคอมไพเลอร์ C ++ ที่ทันสมัยซึ่งเป็นสิ่งที่สนับสนุน GCC รวมถึง AVR (ด้วย ข้อ จำกัด บางอย่าง filo กล่าวถึงปัญหาของพื้นที่ที่อยู่ที่ไม่สม่ำเสมอ) แต่ยกเว้น PICs เกือบทั้งหมด (PIC32 สามารถรองรับได้ แต่ฉันยังไม่เห็นพอร์ตที่เหมาะสม)
เมื่อคุณเขียนโปรแกรมอัลกอริธึมใน C / C ++ ความแตกต่างระหว่างตัวเลือกที่คุณพูดถึงนั้นมีขนาดเล็ก (ยกเว้นว่าชิป 8 หรือ 16 บิตจะเสียเปรียบอย่างมากเมื่อคุณทำเลขคณิต 16, 32 หรือสูงกว่า) เมื่อคุณต้องการออนซ์ประสิทธิภาพครั้งสุดท้ายคุณอาจจำเป็นต้องใช้แอสเซมเบลอร์ (ทั้งของคุณเองหรือรหัสที่จัดทำโดยผู้จัดจำหน่ายหรือบุคคลที่สาม) ในกรณีนี้คุณอาจต้องการพิจารณาชิปที่คุณเลือกอีกครั้ง
เมื่อคุณเขียนโค้ดลงในฮาร์ดแวร์คุณสามารถใช้เลเยอร์นามธรรมบางอย่าง (มักจัดทำโดยผู้ผลิต) หรือเขียนของคุณเอง (ตามแผ่นข้อมูลและ / หรือรหัสตัวอย่าง) abstractions ที่มีอยู่ของ IME (mbed, cmsis, ... ) มักจะใช้งานได้ (เกือบ) ถูกต้อง แต่ล้มเหลวอย่างมากในการทำงาน พวกเขาต้องการแสดงการทำงานทั้งหมดของชิปเฉพาะกับคุณซึ่งในเกือบทุกกรณีที่คุณไม่ต้องการและไม่สนใจและจะล็อครหัสของคุณกับผู้จำหน่ายรายนั้น (และอาจเป็นชิปนั้น)
นี้จะเป็น C ++ สามารถทำได้ดีกว่ามากเมื่อทำอย่างถูกต้องชุดขาสามารถไปถึง 6 ชั้นหรือมากกว่านามธรรมเลย (เพราะที่ทำให้ดีขึ้น (แบบพกพา) อินเตอร์เฟซและรหัสสั้นเป็นไปได้!) ให้อินเตอร์เฟซที่เป็นเป้าหมายอิสระ สำหรับกรณีง่าย ๆและยังคงส่งผลให้รหัสเครื่องเดียวกับที่คุณจะเขียนในแอสเซมเบลอร์
ตัวอย่างของรูปแบบการเขียนที่ฉันใช้ซึ่งอาจทำให้คุณกระตือรือร้นหรือหันเหความกลัว:
// GPIO part of a HAL for atsam3xa
enum class _port { a = 0x400E0E00U, . . . };
template< _port P, uint32_t pin >
struct _pin_in_out_base : _pin_in_out_root {
static void direction_set_direct( pin_direction d ){
( ( d == pin_direction::input )
? ((Pio*)P)->PIO_ODR : ((Pio*)P)->PIO_OER ) = ( 0x1U << pin );
}
static void set_direct( bool v ){
( v ? ((Pio*)P)->PIO_SODR : ((Pio*)P)->PIO_CODR ) = ( 0x1U << pin );
}
};
// a general GPIO needs some boilerplate functionality
template< _port P, uint32_t pin >
using _pin_in_out = _box_creator< _pin_in_out_base< P, pin > >;
// an Arduino Due has an on-board led, and (suppose) it is active low
using _led = _pin_in_out< _port::b, 27 >;
using led = invert< pin_out< _led > >;
ในความเป็นจริงมีบางสิ่งที่เป็นนามธรรมมากขึ้น แต่การใช้งานครั้งสุดท้ายของผู้นำก็เปิดใช้งานไม่แสดงความซับซ้อนหรือรายละเอียดของเป้าหมาย (สำหรับ arduin uno หรือยาเม็ดสีน้ำเงิน ST32 รหัสจะเหมือนกัน)
target::led::init();
target::led::set( 1 );
คอมไพเลอร์ไม่ได้ถูกข่มขู่โดยเลเยอร์เหล่านั้นทั้งหมดและเนื่องจากไม่มีฟังก์ชั่นเสมือนที่เกี่ยวข้องกับเครื่องมือเพิ่มประสิทธิภาพที่มองเห็นทุกสิ่ง
mov.w r2, #134217728 ; 0x8000000
ldr r3, [pc, #24]
str r2, [r3, #16]
str r2, [r3, #48]
ซึ่งเป็นวิธีที่ฉันจะได้เขียนไว้ในแอสเซมเบลอร์ - ถ้าฉันรู้ว่าการลงทะเบียน PIO สามารถใช้กับออฟเซ็ตจากฐานทั่วไป ในกรณีนี้ฉันอาจจะ แต่คอมไพเลอร์ดีกว่าที่จะเพิ่มประสิทธิภาพสิ่งต่าง ๆ มากกว่าฉัน
ดังนั้นเท่าที่ฉันมีคำตอบก็คือ: เขียนเลเยอร์สิ่งที่เป็นนามธรรมสำหรับฮาร์ดแวร์ของคุณ แต่ทำใน C ++ (แนวความคิดเทมเพลต) ที่ทันสมัยดังนั้นมันจึงไม่เป็นอันตรายต่อประสิทธิภาพการทำงานของคุณ คุณสามารถสลับไปยังชิปอื่นได้อย่างง่ายดาย คุณยังสามารถเริ่มพัฒนาชิปสุ่มที่คุณวางไว้มี familiair มีเครื่องมือดีบั๊กสำหรับและอื่น ๆ และเลื่อนตัวเลือกสุดท้ายจนกระทั่งในภายหลัง (เมื่อคุณมีข้อมูลเพิ่มเติมเกี่ยวกับหน่วยความจำที่ต้องการความเร็วซีพียู ฯลฯ )
IMO หนึ่งในข้อบกพร่องของการพัฒนาที่ฝังอยู่คือการเลือกชิปก่อน (มันเป็นคำถามที่ถามบ่อยในฟอรัมนี้: ฉันควรเลือกชิปตัวใดสำหรับ .... คำตอบที่ดีที่สุดคือโดยทั่วไป: มันไม่สำคัญ)
(แก้ไข - ตอบสนองต่อ "ดังนั้นประสิทธิภาพฉลาด, C หรือ C ++ จะอยู่ในระดับเดียวกันหรือไม่")
สำหรับโครงสร้างเดียวกัน C และ C ++ เหมือนกัน C ++ มีโครงสร้างมากขึ้นสำหรับนามธรรม (เพียงไม่กี่: คลาส, แม่แบบ, constexpr) ซึ่งสามารถเช่นเดียวกับเครื่องมือใด ๆ ที่จะใช้สำหรับการที่ดีหรือไม่ดี เพื่อให้การอภิปรายน่าสนใจยิ่งขึ้น: ทุกคนไม่เห็นด้วยกับสิ่งที่ดีหรือไม่ดี ...