ฉันเริ่มเขียนโค้ดสำหรับ Arduino เมื่อเร็ว ๆ นี้ และข้อบกพร่องเหล่านี้ในรหัสกำลังฆ่าฉัน เนื่องจากไม่มีตัวดีบักฮาร์ดแวร์ใน Arduino serial.print () จึงเป็นทางเลือกเดียวของฉัน อะไรคือวิธีการ / แนวทางที่คุณใช้ในการดีบักรหัส Arduino?
ฉันเริ่มเขียนโค้ดสำหรับ Arduino เมื่อเร็ว ๆ นี้ และข้อบกพร่องเหล่านี้ในรหัสกำลังฆ่าฉัน เนื่องจากไม่มีตัวดีบักฮาร์ดแวร์ใน Arduino serial.print () จึงเป็นทางเลือกเดียวของฉัน อะไรคือวิธีการ / แนวทางที่คุณใช้ในการดีบักรหัส Arduino?
คำตอบ:
Modularity เป็นเพื่อนของคุณ เขียนลูปหลักของคุณเพื่อทำสิ่งนั้นโดยการเรียกใช้ฟังก์ชั่นที่เรียกใช้ฟังก์ชั่นการโทร ... จนกว่าจะถึงระดับที่ฟังก์ชั่นของคุณจะง่าย เริ่มต้นด้วยการวนรอบหลักและระดับถัดลงทำฟังก์ชัน stub ว่างเปล่า:
function foo(){
;
}
หรือปลอม:
function read_temperature(){
return(95);
}
ซึ่งไม่ทำอะไรเลย แต่คืนสิ่งที่ระดับการโทรต้องการเพื่อให้สามารถดำเนินการต่อได้ เมื่อระดับนั้นใช้งานได้ให้เลื่อนระดับและเริ่มกรอกรหัสง่าย ๆ ที่เรียกฟังก์ชั่นสตับ ค่อยๆยกเลิกการสตับทีละครั้งจนกว่าคุณจะมีแอปพลิเคชันที่ใช้งานได้
ในการดีบั๊กฟังก์ชั่นที่ส่งกลับค่าที่ไม่ดีหรือเพื่อสร้างโดยไม่มีผลกระทบใด ๆ จากส่วนที่เหลือของแอปพลิเคชันของคุณคุณสามารถสร้างนั่งร้าน - ร่างง่าย ๆ ที่เพียงดึงฟีดฟังก์ชั่นตัวอย่างค่าบางอย่างและภายในฟังก์ชัน และค่ากลางบางค่าจนกว่าคุณจะได้รับข้อมูลเชิงลึกว่าส่วนใดของฟังก์ชันที่ล้มเหลว ฉันได้ทำฟังก์ชั่นแกลลอรี่ที่แจ้งให้ฉันทราบถึงค่าที่จะส่งคืน (เห็นได้ชัดว่าเทคนิคนี้ใช้ได้เฉพาะในกรณีที่ระบบสามารถทนต่อความเร็วน้ำแข็งของมนุษย์เราได้! การใช้งานอื่นสำหรับนั่งร้าน)
การขัดถูทำงานได้ดีเป็นพิเศษสำหรับฟังก์ชั่นที่เชื่อมต่อกับฮาร์ดแวร์ช่วยให้คุณเริ่มนำแอพพลิเคชั่นขึ้นมาก่อนที่คุณจะต้องเจาะลึกลงไปในแผ่นข้อมูล, ปัญหาเรื่องเวลาและ minutiae อื่น ๆ (เช่นไม่มีชิ้นส่วน!) ความคืบหน้าของคุณ
เมื่อพูดถึงปัญหาเรื่องเวลาการสลับพินเอาต์พุต ณ จุดใดจุดหนึ่งในโปรแกรมของคุณเช่นการเข้าและออกจาก ISR จะให้คลื่นสี่เหลี่ยมที่พิน Arduino ซึ่งมีความถี่หรือวัฏจักรหน้าที่สามารถให้ข้อมูลเชิงลึกเกี่ยวกับเวลาภายใน ของโปรแกรมของคุณ รูปแบบพอร์ต -I / O โดยตรงเช่น
PORTC ^= 0x01;
digitalWrite()
จะบิดเบือนระยะเวลาน้อยกว่าการเรียก มีประโยชน์หากคุณมี 'ขอบเขตที่มีประโยชน์หรือหนึ่งใน DMM ที่มีความสามารถในการวัดความถี่และ / หรือรอบการทำงาน
ในทำนองเดียวกันคุณสามารถใช้หมุดเอาต์พุตแบบอะนาล็อกเพื่อส่งออกค่าตัวเลขไปยังเครื่องวัดของคุณจากภายในโปรแกรมโดยไม่รบกวนเวลามากเกินไปหรือ bloating รหัสด้วยฟังก์ชั่นอนุกรม I / O ใช้แบบฟอร์ม I / O โดยตรงที่นี่เช่นกัน
ฉันใช้ Serial.print () และฉันทำแฟลช LED
นั่นเป็นสิ่งที่คุณทำได้
นอกจากนี้ฉันตรวจสอบให้แน่ใจว่ารหัสนั้นสามารถอ่านได้และเข้าใจง่าย แบ่งสิ่งต่าง ๆ ออกเป็นขั้นตอนง่าย ๆ และสร้างฟังก์ชั่นสำหรับแต่ละขั้นตอนเพื่อให้คุณเห็นลำดับเหตุการณ์ที่แน่นอน
3 เทคนิคอื่น ๆ :
ภาพ Microปลั๊กอินสำหรับ Visual Studio ให้Arduino ตรวจแก้จุดบกพร่อง รวมการติดตามและการแตกซอร์สโค้ดนอกจากนี้ยังอนุญาตให้นิพจน์และตัวแปร "เฝ้าดู" และ / หรือแก้ไข
จากเครื่องมือที่หรูหราเช่น ARM หรือแพลตฟอร์มอื่น ๆ (AVR, PIC พร้อมเครื่องมือที่เหมาะสม) ฉันยอมรับว่าสิ่งอำนวยความสะดวกในการดีบัก Arduino นั้น จำกัด เกินไป แต่มันเป็นเครื่องมือเริ่มต้นที่มีการเข้าน้อย
Serial.print () คือเพื่อนของคุณ สำหรับโครงการเฉพาะของฉัน (วิทยาลัย) ฉันไม่ได้ติดหลอดไฟ LED ใด ๆ ดังนั้น Serial.print () จึงเป็น ถ้าฉันต้องการที่จะทดสอบว่ารหัสทำงานอย่างถูกต้องผ่านงบฉันมักจะวาง Serial.print ("A"); จากนั้นไปที่ B, C ฯลฯ หรือบางอย่างผ่านส่วนที่ฉันกำลังดีบั๊ก ฉันเปรียบเทียบตัวแก้จุดบกพร่องกับสิ่งที่ฉันคาดหวังว่าควรทำ
นอกเหนือจากนั้นจะไม่มีจุดพักหรือการเหยียบโค้ด Arduino ไม่มีอะไรมากไปกว่าบอร์ดที่มีชิป AVR atmega สภาพแวดล้อมการพัฒนา bootloader + และห้องสมุดซอฟต์แวร์มากมาย น่าเสียดายที่การทำงานกับ bootloader จำกัดความสามารถในการดีบัก
ในการใช้ประโยชน์จากการserial.print
ควบคุมที่มากขึ้นคุณสามารถกำหนดตัวแปรบูลีนส่วนกลางเพื่อสลับการเปิดและปิดการดีบัก บรรทัดใด ๆ ของserial.print
จะถูกรวมไว้ในif
คำสั่งที่จะถูกดำเนินการเฉพาะเมื่อการดีบักตั้งค่าสถานะเป็น ON วิธีนี้คุณสามารถปล่อยให้บรรทัดการดีบักในรหัสแม้เมื่อคุณทำเสร็จแล้ว แต่ต้องแน่ใจว่าตั้งค่าสถานะการดีบักเป็นปิดในภายหลัง
ดีกว่า serial.print โดยตรงให้ใช้มาโคร ตัวอย่าง:
#ifdef TRACE1
#define trace1(s) serial.print(s)
#define traceln1(s) serial.println(s)
#else
#define trace1(s)
#define traceln1(s)
#endif
ใช้มันแบบนี้:
function doIt(param1, param2) {
trace1("->doIt("); trace1("param1: "); trace1(param1); trace1(" param2: "); trace1(param2); traceln1(")");
...
traceln1("<-doIt");
}
คุณอาจมีระดับการติดตามต่างกัน(#ifdef TRACE2 ...)
พร้อมรายละเอียดเพิ่มเติม
และคุณอาจใช้ "F" (trace1(F("param1"));)
แมโคร แมโคร "F" ป้องกันไม่ให้สตริงใช้ SRAM ในปริมาณที่ จำกัด อย่างมาก
กะพริบไฟ LED พิมพ์สิ่งต่าง ๆ บนพอร์ตอนุกรมและเขียนและดีบักส่วนเล็ก ๆ ของรหัสในบางครั้งเพียงไม่กี่บรรทัด
มีหลายครั้งที่คุณสามารถทำให้เป็นโมดูลได้ ตัวอย่างเช่นถ้าใน C คุณสามารถพัฒนาและทดสอบฟังก์ชั่นการคำนวณเช่นที่ไม่ได้สัมผัสกับฮาร์ดแวร์บนโฮสต์คอมพิวเตอร์ตัวประมวลผลอื่นห่อฟังก์ชันด้วยม้านั่งทดสอบเพื่อป้อนอินพุตและตรวจสอบเอาต์พุต ฯลฯ
อีกวิธีที่คล้ายกันอาจจะใช้การจำลองการเรียนการสอนชุดถ้าคุณมีการเข้าถึงหนึ่ง (ถ้าไม่มันเป็นโครงการการศึกษาและให้รางวัลมากหลังจากที่คุณได้ทำบางอย่างที่คุณสามารถออกหนึ่งหรือสองสัปดาห์) ยิ่งไปกว่านั้นถ้ามีคนมี Verilog หรือ VHDL โคลนของตัวประมวลผล ( OpenCoresตัวอย่าง) คุณสามารถลอง GHDL, Verilatorหรืออิคารัส Verilog อาจใกล้พอที่จะรวมอุปกรณ์ต่อพ่วงที่คุณสนใจและคุณสามารถมองเห็นระดับสัญญาณในสิ่งที่เกิดขึ้นภายใน
ได้รับมันอาจจะไม่ได้เป็นโคลนที่สมบูรณ์แบบ แต่มันอาจจะดีพอ Verilator ทำให้การสร้างอุปกรณ์ต่อพ่วงใน C / C ++ เป็นเรื่องง่ายมากดังนั้นคุณสามารถจำลองสิ่งที่คุณมีอุปกรณ์ AVR ของคุณเชื่อมต่อได้
เอาท์พุท UART และไฟ LED กระพริบและ / หรือกระพริบเส้น GPIO และใช้ออสซิลโลสโคปหรือโวลต์มิเตอร์ กุญแจสำคัญที่จะไม่คลั่งไคล้คือการเขียนและแก้ไขจุดบกพร่องของรหัสส่วนเล็ก ๆ ฉันควรเขียนทีละ 10 บรรทัดและทำการทดสอบ 100 ครั้งกว่า 1,000 บรรทัดและพยายามดีบั๊กทั้งหมดในนัดเดียว โดยเฉพาะอย่างยิ่งเมื่อคุณค้นหาเอกสารข้อมูลทางเทคนิคและคู่มืออ้างอิงโปรแกรมเมอร์ส่วนใหญ่ไม่ได้ถูกต้องเสมอไป บางคนต้องการแฮ็คอยู่เสมอ