Trushin A.N., Harutyunyan M.G. การจัดระเบียบการเชื่อมต่อและการแลกเปลี่ยนข้อมูลผ่านบลูทูธระหว่างแอปพลิเคชัน Arduino และ iOS พารามิเตอร์โปรโตคอลสำหรับการแลกเปลี่ยนข้อมูลระหว่าง Arduino และการแลกเปลี่ยนข้อมูล Arduino ESP8266

มาดาวน์โหลดกัน ตัวอย่างมาตรฐาน“Physical Pixel” ผ่านเมนู File\Examples\4.Communication\PhysicalPixel โปรแกรมนี้รอข้อมูลจากคอมพิวเตอร์ เมื่อได้รับสัญลักษณ์ 'H' ไฟแสดงการทดสอบจะสว่างขึ้น เมื่อได้รับสัญลักษณ์ 'L' ไฟจะดับลง ลองดูซอร์สโค้ดของมัน:

int เอาท์พุตพิน = 13 ; //เก็บเบอร์ติดต่อไว้ที่นี่
อินท์วาล; //สัญลักษณ์ที่ได้รับจะถูกเก็บไว้ที่นี่

การตั้งค่าเป็นโมฆะ ()
{
อนุกรมเริ่มต้น(9600); //ตั้งค่าพอร์ตเป็น 9600 bps
pinMode(พินเอาท์พุต, เอาท์พุต); // ตั้งค่าพิน 13 เป็นโหมดเอาท์พุต
}

เป็นโมฆะวน()
{
ถ้า (Serial.available()) ( //ถ้ามีตัวละครที่ยอมรับ
วาล = Serial.read(); // จากนั้นอ่านแล้วบันทึกลงใน val
ถ้า (val == "H" ) ( // หากยอมรับอักขระ "H" แล้ว...
digitalWrite (พินเอาท์พุต, สูง); // จากนั้นเปิดไฟ LED
}
ถ้า (val == "L" ) ( // หากยอมรับอักขระ "L"
digitalWrite (พินเอาท์พุต, ต่ำ); // จากนั้นปิดไฟ LED
}
}
}

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

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

เราใช้มอนิเตอร์พอร์ต COM ที่สร้างขึ้นในสภาพแวดล้อมการพัฒนา Arduino

นี่เป็นวิธีที่ง่ายและเข้าใจได้มากที่สุดสำหรับผู้เริ่มต้น

มอนิเตอร์พอร์ต COM เปิดใช้งานผ่านเมนู Tools\Serial Monitor หรือผ่านแถบเครื่องมือ ในซอฟต์แวร์เวอร์ชันเก่า จอภาพจะสามารถเข้าถึงได้ผ่านแถบเครื่องมือเท่านั้น: โดยการเรียกจอภาพ ตรวจสอบให้แน่ใจว่าได้เลือกอัตรารับส่งข้อมูลเดียวกันกับในโปรแกรมไมโครคอนโทรลเลอร์ ตอนนี้คุณสามารถป้อนอักขระใด ๆ ในช่องป้อนข้อมูลทางด้านขวาแล้วกดปุ่ม "ส่ง" - อักขระที่ป้อนจะถูกส่งไปยังพอร์ตและโปรแกรมของคุณจะยอมรับอักขระเหล่านั้นที่นั่น ป้อนตัวอักษรละติน "H" ที่นั่นคลิก "ส่ง" - ไฟ LED ทดสอบจะสว่างขึ้น หากคุณส่ง "L" มันจะดับลง อย่างไรก็ตามข้อมูลทั้งหมดที่โปรแกรมของคุณจะส่งไปยังพอร์ต COM จะแสดงในหน้าต่างด้านล่าง

เราใช้โปรแกรมจำลองเทอร์มินัล HyperTerminal

นี่เป็นตัวเลือกการแลกเปลี่ยนที่ยากขึ้นเล็กน้อยในการดำเนินการ

Windows มักจะมีโปรแกรมจำลองเทอร์มินัลที่เรียกว่า HyperTerminal ใน Windows XP สามารถพบได้ในเมนู Start\All Programs\Programs\Accessories\Communications\HyperTerminal เมื่อเริ่มต้น คุณต้องปฏิเสธที่จะสร้างการเชื่อมต่อ เลือกเมนู File\Properties ในกล่องโต้ตอบที่ปรากฏขึ้น ให้เลือกพอร์ต COM ของคุณ คลิก "กำหนดค่า" และกำหนดค่าพารามิเตอร์การสื่อสารตามรูป:

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

คลิก "ตกลง" ในทั้งสองหน้าต่าง และหนึ่งครั้งในหน้าต่างโปรแกรมหลัก ปุ่มใดๆ บนแป้นพิมพ์ - HyperTerminal จะเชื่อมต่อกับพอร์ต COM ตอนนี้อักขระทั้งหมดที่พิมพ์บนแป้นพิมพ์จะผ่านพอร์ต COM ไปยังไมโครคอนโทรลเลอร์ และทุกสิ่งที่ไมโครคอนโทรลเลอร์ส่งไปจบลงที่หน้าจอ กดปุ่ม "H" และ "L" (ดูภาษาและเคสที่เลือก) - ไฟ LED ทดสอบควรสว่างขึ้นและดับลง

มาเขียนโปรแกรมของเราเองสำหรับพีซีกันเถอะ!

ตัวเลือกนี้เหมาะสำหรับผู้ที่ชื่นชอบการเขียนโปรแกรมไม่เพียงแต่ Freeduino เท่านั้น แต่ยังรวมถึงพีซีด้วย ทำไมไม่? เราไม่จำเป็นต้องเรียนรู้รายละเอียดการเขียนโปรแกรม พอร์ตอนุกรมภายใต้ Windows หรือสิ่งที่ซับซ้อนอื่นๆ โดยเฉพาะอย่างยิ่งสำหรับการแก้ปัญหาง่ายๆ ดังกล่าว มีภาษาในการประมวลผล (http://processing.org) ซึ่งคล้ายกันมากในด้านไวยากรณ์และแม้แต่สภาพแวดล้อมการพัฒนากับซอฟต์แวร์ Arduino

ติดตั้งและเปิดใช้งานการประมวลผล - คุณจะเห็นสภาพแวดล้อมการพัฒนาที่คล้ายกับ Arduino

ซอร์สโค้ดสำหรับโปรแกรมภาษาประมวลผลอยู่ในความคิดเห็นด้านล่างข้อความหลักของตัวอย่าง Physical Pixel นี่คือการแสดงโดยมีการเปลี่ยนแปลงเล็กน้อย - เราได้แก้ไขการเปิดพอร์ตเพื่อให้คุณสามารถเปลี่ยนหมายเลขได้อย่างง่ายดาย:

นำเข้าการประมวลผลซีเรียล.* ;
พอร์ตอนุกรม;
การตั้งค่าเป็นโมฆะ ()
{
ขนาด(200 , 200 ) ;
ไม่มีโรคหลอดเลือดสมอง() ;
อัตราเฟรม (10);
พอร์ต = อนุกรมใหม่ (นี่คือ "COM5", 9600); - ลงทะเบียนพอร์ต COM ของคุณที่นี่!!!
}
mouseOverRect() บูลีน //คืนค่าเป็นจริงหากเคอร์เซอร์อยู่ในสี่เหลี่ยมจัตุรัส
{
กลับ ((mouseX >= 50 ) && (mouseX<= 150 ) && (mouseY >= 50 ) & (เมาส์Y<= 150 ) ) ;
}
ถือเป็นโมฆะ ()
{
พื้นหลัง(#222222 ) ;
ถ้า (mouseOverRect()) // หากเคอร์เซอร์อยู่ในสี่เหลี่ยม...
{
กรอก(#BBBBB0) ; //เปลี่ยนสีให้สว่างขึ้น
พอร์ต.write("H"); // ส่ง "H" ไปยังไมโครคอนโทรลเลอร์
) อื่น ( //ถ้าไม่อยู่ข้างใน...
กรอก(#666660 ) ​​​​; //เปลี่ยนสีให้เข้มขึ้น
พอร์ต.write("L"); // ส่ง "L" ไปยังไมโครคอนโทรลเลอร์
}
ตรง(50 , 50 , 100 , 100 ) ; // วาดรูปสี่เหลี่ยม
}

เรียกใช้โปรแกรม (ผ่านเมนู Sketch\Run) - หน้าต่างที่มีสี่เหลี่ยมจัตุรัสจะปรากฏขึ้น เมื่อคุณวางเคอร์เซอร์ของเมาส์ไว้ ไฟ LED บน Freeduino จะสว่างขึ้น

คำอธิบายของภาษาการประมวลผลและความสามารถของมันนั้นอยู่นอกเหนือขอบเขตของการบรรยายง่ายๆ นี้ แต่ตัวอย่าง Arduino จำนวนมากในความคิดเห็นด้านล่างข้อความโปรแกรมหลักแสดงรหัสการประมวลผลพีซีที่โต้ตอบกับ Freeduino

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

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

ก่อนอื่นเรามาเขียนภาพร่างและอัปโหลดไปยัง Arduino (Freeduino)

#include การตั้งค่าเป็นโมฆะ() (

อนุกรมเริ่มต้น(9600); // ตั้งค่าความเร็วพอร์ต

พินโหมด(9, เอาท์พุต); // ตั้งค่าขาที่ 9 เป็นเอาต์พุตสำหรับลำโพง

) โมฆะห่วง()

จำนวน int ยาว; Serial.print("ใส่หมายเลข: ");

หมายเลข = SerialInput.InputNumber(); // กรอกตัวเลข Serial.print("ผลลัพธ์ = ");

Serial.println(หมายเลข * หมายเลข, ธ.ค.);

เสียงบี๊บ(500);

} เสียงบี๊บเป็นโมฆะ (ความล่าช้าของถ่านที่ไม่ได้ลงนาม)(

อะนาล็อกเขียน(9, 20); // ค่าต้องอยู่ระหว่าง 0 ถึง 255

//ทดลองเพื่อให้ได้โทนเสียงที่ดี

อะนาล็อกเขียน(9, 0); // 0 — ปิดปิโซ

ความล่าช้า(ล่าช้า); // หยุดความล่าช้าชั่วคราว ms

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

และตอนนี้สิ่งที่น่าสนใจที่สุดคือถึงเวลาลองแล้ว ในการเชื่อมต่อกับคอนโทรลเลอร์ ฉันแนะนำให้ใช้โปรแกรมฟรี สีโป๊ว- ในการตั้งค่าประเภทการเชื่อมต่อ ให้เลือก Serial และป้อนหมายเลขพอร์ตที่ถูกต้องแทน COM1 (คุณสามารถดูได้ในเมนู Tools->Serial Port ในสภาพแวดล้อมการเขียนโปรแกรม Arduino) เรากด Open และเราเห็นข้อความ Enter number ในคอนโซลป้อนตัวเลขใดก็ได้ (ภายในเหตุผล) กด Enter แล้วเราจะเห็นผลลัพธ์

เพียงเท่านี้คุณก็สามารถชื่นชมยินดีและกระโดดด้วยความดีใจได้ โดยปกติแล้วทั้งหมดนี้สามารถปรับปรุงได้ เช่น แสดงเมนูก่อน ส่งจากคอนโทรลเลอร์ไปยังคอนโซล ซึ่งคุณสามารถอธิบายคำสั่งโดยละเอียดได้ ตัวอย่างเช่นป้อนตัวเลข 0 - เปิด แสงไฟ LEDกด 1 - มันจะดับ ดังนั้น คุณสามารถใส่คำสั่งได้อย่างน้อย 100,500 คำสั่ง ตราบใดที่มีหน่วยความจำไมโครคอนโทรลเลอร์เพียงพอ (ซึ่งมีขนาดเล็กมาก) เราจะพูดถึงวิธีขยายหน่วยความจำที่มีอยู่ครั้งต่อไป

UPD: ส่วนหนึ่งของโค้ดถูกตัดโดยโปรแกรมแยกวิเคราะห์เครื่องยนต์ ดังนั้นนี่คือแหล่งที่มา

เช่นเดียวกับนัก DIY คนอื่นๆ ฉันใช้ไมโครคอนโทรลเลอร์ AVR เป็นประจำสำหรับโปรเจ็กต์งานอดิเรกทุกประเภท และด้วยแนวคิด Arduino งานฝีมือเหล่านี้จึงมีรูปลักษณ์ที่หรูหราเช่นกัน แน่นอนสำหรับประมาณ 300-400 รูเบิลเราได้รับบอร์ดหลายชั้นขนาดเล็กพร้อมมาสก์การพิมพ์ซิลค์สกรีนและอุปกรณ์ต่อพ่วงแบบกระจายอย่างสมบูรณ์สำหรับไมโครคอนโทรลเลอร์ (และในเวอร์ชัน SMD!) ฉันไม่ได้พูดถึงโมดูลปลั๊กอินทุกประเภทในซีรีส์ “Arduino” เดียวกันด้วยซ้ำ: เซ็นเซอร์ ตัวควบคุม จอแสดงผล และอุปกรณ์ต่อพ่วงเพิ่มเติมทั้งชุดที่เราต้องการมาก และขอย้ำอีกครั้งว่าทุกอย่างมีราคาไม่แพงและมีประสิทธิภาพเป็นเลิศ ในทางปฏิบัติแล้วไม่จำเป็นต้องเจือจางและดื่มอะไรบนเข่าอีกต่อไป

แต่งานฝีมือสมัครเล่นต่างๆ เหล่านี้ล้วนต้องการโดยธรรมชาติ การเขียนโปรแกรมล่วงหน้าและต่อมาด้วยการปรับปรุงต่างๆ งานฝีมือเหล่านี้จึงมีความจำเป็นอย่างต่อเนื่อง รีเฟรช- เห็นได้ชัดว่าการทำเช่นนี้จากระยะไกลสะดวกกว่าการพกพาไปให้โปรแกรมเมอร์ทั่วไป โดยทั่วไป ต้องขอบคุณแพลตฟอร์ม Arduino เดียวกัน ทำให้มีตัวเลือกมากมายที่นี่: บลูทูธ, ZigBee, ช่องสัญญาณวิทยุพร้อมโปรโตคอลส่วนตัวของคุณ, IR และแม้แต่ Wi-Fi ทั้งหมดนี้ช่วยให้คุณสามารถสร้างการติดต่อแบบไร้สายกับไมโครคอนโทรลเลอร์ของคุณได้ แต่เราจะมุ่งเน้นไปที่ตัวเลือกสุดท้าย มีสี่เหตุผลหลัก:

1: ทันสมัย ​​อินเทอร์เน็ตของสรรพสิ่ง!

2: เราเตอร์ไร้สายได้ทุกอพาร์ตเมนต์ ลงทะเบียนได้ที่ เครือข่ายภายในบ้านอุปกรณ์ของคุณและ voila!

3: งานฝีมือของคุณกำลังก้าวกระโดดในการพัฒนา ไม่เพียงแต่สามารถตั้งโปรแกรมได้จากระยะไกลเท่านั้น แต่ยังสื่อสารกับโลกรอบตัวได้อีกด้วย: นาฬิกาอิเล็กทรอนิกส์เอามันเอง เวลาที่แน่นอนจากเซิร์ฟเวอร์นาฬิกา NTP แอคชูเอเตอร์จะถูกควบคุมจากอีกฟากของเมืองหรือประเทศ อุปกรณ์บันทึกจะบันทึกข้อมูลที่สะสมไว้บนคลาวด์ ฯลฯ ฯลฯ

4: มีชิป ESP8266 ซีรีส์ที่ยอดเยี่ยมซึ่งไม่ใช่เรื่องง่ายที่จะนำไปใช้ทั้งหมดนี้

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

สันนิษฐานว่าผู้อ่านคุ้นเคยกับโมดูล "Arduino" (โล่) และการเชื่อมต่อและเฟิร์มแวร์ของ ESP8266 แล้ว ในความเป็นจริงมีการโพสต์เนื้อหาจำนวนมากบนอินเทอร์เน็ตซึ่งอธิบายพื้นฐานของการทำงานกับอุปกรณ์เหล่านี้และฉันไม่อยากพูดซ้ำที่นี่ สำหรับผู้เริ่มต้น จะมีรายการอยู่ท้ายบทความ ลิงค์ที่เป็นประโยชน์ในประเด็นเหล่านี้ซึ่งคุณสามารถค้นหาข้อมูลมากมายว่าทำไมทั้งหมดนี้จึงไม่เหมาะกับคุณ จากประสบการณ์ของฉันในฐานะอดีตวิศวกรอิเล็กทรอนิกส์ ฉันสามารถระบุได้อย่างมีความรับผิดชอบว่า 99% ของปัญหาเกิดจากสาเหตุต่อไปนี้:

1. การติดต่อที่ไม่ดี เนื่องจากโล่ "Arduino" หมายถึงการแลกเปลี่ยนซึ่งกันและกันผ่านสาย "ชาย - หญิง" และไม่ผ่านการบัดกรี บ่อยครั้งมีบางสิ่งหลุดออกมา ตรวจสอบ. และโดยทั่วไปอย่างที่พวกเขากล่าวว่าอิเล็กทรอนิกส์เป็นศาสตร์แห่งการสัมผัส

2. ปัญหาโภชนาการ. ห้ามจ่ายไฟ 5 โวลต์หากจำเป็นต้องใช้ 3.3 บางครั้งทำให้เกิดควันออกมาจาก ESP8266 แม้ว่าในทางกลับกันมันจะย่อยสัญญาณลอจิคัลจากอุปกรณ์ห้าโวลต์โดยไม่มีปัญหา

3. ปัญหาเกี่ยวกับแหล่งจ่ายไฟที่เพียงพอ ESP8266 มีลักษณะแอบแฝงและบางครั้งอาจกินไฟเกือบสามร้อยมิลลิแอมป์แม้ว่าก่อนหน้านั้นจะพอใจกับสามสิบก็ตาม ดังนั้นโคลง 3.3 โวลต์ที่อ่อนแอของบอร์ด Arduino ที่คุณเชื่อมต่อโดยไม่ลังเลจะลดลงเป็นค่ากล้องจุลทรรศน์ทันที และคุณไม่สามารถเข้าใจได้ว่าทำไมบางครั้งมันถึงได้ผล บางครั้งมันก็ไม่ได้ผล

4. ความสับสนกับข้อสรุป ตรวจสอบเสมอว่าสัญญาณใดไปที่ใด ตัวรับ RXD ต้องเชื่อมต่อกับเครื่องส่งสัญญาณ TXD เช่นเดียวกับ TXD กับ RXD แต่ MOSI ต้องเชื่อมต่อกับ MOSI และ MISO กับ MISO และอื่นๆ

5. อย่าพึ่งพาตัวต้านทานแบบดึงขึ้นในวงจรใน ESP8266 ดึงหมุดไปที่ศูนย์หรือกำลังเสมอผ่านตัวต้านทานภายนอก 5-10 กิโลโอห์ม และไม่ใช่แค่ด้วยจัมเปอร์เท่านั้น มิฉะนั้นอย่างดีที่สุดคุณจะได้รับการบริโภคในปัจจุบันอย่างที่ไม่เคยมีมาก่อนจากนั้นจึงได้กลิ่นอันไม่พึงประสงค์ของพลาสติกที่ถูกเผา

6. วงกบ ซอฟต์แวร์- เนื่องจากซอฟต์แวร์สำหรับผู้ใช้แต่ละรายเขียนโดยผู้ที่ชื่นชอบคนเดียวกัน ข้อบกพร่องและข้อบกพร่องในเฟิร์มแวร์จึงปรากฏขึ้นเป็นระยะเมื่ออัปเดตเวอร์ชันของเฟิร์มแวร์เดียวกัน ได้รับการปฏิบัติโดยการรวบรวมข้อมูลผ่านฟอรัมที่เกี่ยวข้อง บางครั้งอาจเป็นฟอรัมภาษาอังกฤษด้วยซ้ำ สหายบางคนถึงกับแย้งว่าชิป ESP นั้นชื้นพอๆ กับสภาพอากาศในเซนต์ปีเตอร์สเบิร์ก แต่ในทางกลับกันก็มีความเห็นว่าตั้งแต่ปี 2014 (ปีที่เปิดตัวครั้งแรก) สถานการณ์นี้ดีขึ้นอย่างมาก (ไม่เหมือนกับสภาพอากาศ)

7. ข้อบกพร่องลึกลับ นี่เป็นปรากฏการณ์ที่หาได้ยากแต่น่าสะเทือนใจ ตัวอย่างเช่น ฉันไม่สามารถเย็บอุปกรณ์ “Arduino” หนึ่งเครื่องจากระยะไกลได้ หรือค่อนข้างใช้งานได้ แต่มีข้อผิดพลาด แต่มันทำงานได้โดยไม่มีข้อผิดพลาดหากสายเคเบิลจากโปรแกรมเมอร์แขวนอยู่ (แต่ไม่มีโปรแกรมเมอร์เอง) “อ๋อ” ฉันพูดกับตัวเองและบัดกรีตัวเก็บประจุ 15 pF ระหว่างพินข้อมูลและพินนาฬิกา ทุกอย่างทำงานได้ แต่วันนั้นก็ฆ่า

เริ่มจากสิ่งที่ง่ายที่สุดกันก่อน เรามีแขนขากลไก MechArm (แต่ไม่ใช่แบบที่ Howard Wolowits สร้างขึ้น) ที่ผลิตในจีนและ คอมพิวเตอร์ส่วนบุคคลด้วยวินโดวส์ ภารกิจคือการแฟลชโปรแกรมจากระยะไกลและควบคุมจากคอมพิวเตอร์


สำหรับคอนโทรลเลอร์ เรามาเอาผ้าพันคอจิ๋วน่ารักๆ กันดีกว่า อาร์ดูโน่ นาโนด้วยหิน ATmega328P บอร์ดนี้ติดตั้งเข้ากับแขนกลได้พอดี


ตอนนี้เรามาตัดสินใจว่าเราจะตั้งโปรแกรมอย่างไร มีสามวิธีหลักที่เหมาะสมที่สุดสำหรับเฟิร์มแวร์ระยะไกล: ผ่านอินเทอร์เฟซ SPI, ผ่าน bootloader ในตัว, ผ่านพอร์ต JTAG

แน่นอนว่าตัวเลือกที่ง่ายที่สุดคือ bootloader ในตัว นี่คือหน่วยความจำที่ลงทะเบียนล่วงหน้าใน FLASH ซึ่งเป็นโปรแกรมที่รับรหัสโดยใช้โปรโตคอลบางอย่าง (เช่น การใช้ UART ที่ง่ายที่สุด) และใช้คำสั่งพิเศษเพื่อเขียนไปยังตำแหน่งของโปรแกรมที่โหลด นี่คือวิธีการทำงานของ ARDUINO IDE bootloader หลังจากรีเซ็ตหรือสตาร์ทแล้ว bootloader จะรอสักระยะหนึ่งเพื่อให้รับข้อมูล และหากไม่รอ โปรแกรมจะเริ่มรันโปรแกรมจากที่อยู่ศูนย์ หากมีข้อมูลเข้ามาก็จะเขียนลงในส่วนของโปรแกรม หลังจากการรีเซ็ตครั้งถัดไป โปรแกรมที่โหลดไว้จะเริ่มดำเนินการ ฉันอาจอธิบายรายละเอียดไม่ถูกต้อง แต่นั่นคือสาระสำคัญของมัน ด้วยเหตุนี้เราจึงต้องการเพียงสามพินในการเขียนโปรแกรม: ตัวรับสัญญาณ RTD รีเซ็ต รีเซ็ตและกราวด์ GND โดยทั่วไปแล้ว เครื่องส่ง TRD ยังใช้เพื่อตรวจสอบโปรแกรมที่บันทึกไว้ด้วย แต่สำหรับการใช้งานสาธิตง่ายๆ (ไม่ใช่สำหรับโรงไฟฟ้านิวเคลียร์) การยืนยันสามารถละเว้นได้

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

ตัวเลือกที่สองคือการเขียนโปรแกรมโดย อินเตอร์เฟซแบบอนุกรมเอสพีไอ. ที่นี่ไม่มีโปรแกรมโหลดบูตภายใน และเราตั้งโปรแกรมโดยการส่งคำสั่งพิเศษแล้วส่งข้อมูลผ่านอินเทอร์เฟซที่กล่าวมาข้างต้น ที่นี่เรามี bootloader ภายนอกอยู่แล้ว แต่เรายังต้องเขียนมัน ในระหว่างการส่ง นอกจาก RESET และ GND แล้ว ยังมีการใช้พินเพิ่มเติมอีกสี่พิน: MOSI, MISO - ข้อมูล, การซิงโครไนซ์ SLK, CS - การเลือกคริสตัล แต่โดยทั่วไปคุณสามารถลบ MISO และ CS ได้เช่นกัน ข้อมูลจะได้รับเท่านั้น (จะไม่มีการตรวจสอบโปรแกรม) และเรามีคริสตัลเพียงอันเดียวเท่านั้น

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

เพื่อสร้าง ช่องสัญญาณไร้สายดังที่ได้กล่าวไปแล้วฉันเลือกชิป ESP8266 ที่เป็นที่รู้จักอย่างกว้างขวางในปัจจุบัน - ไมโครคอนโทรลเลอร์หรือ SoC ทั้งหมด (System-on-Chip) ผู้ผลิตจีน Espressif พร้อมอินเทอร์เฟซ Wi-Fi นอกจาก Wi-Fi แล้ว ยังโดดเด่นด้วยความสามารถในการรันโปรแกรมจากหน่วยความจำแฟลชภายนอก สำหรับโปรเจ็กต์ของฉันโดยเฉพาะ ฉันใช้ ESP8266-07 ที่มีหน่วยความจำออนบอร์ด 512 KB


โดยทั่วไปแล้ว ESP8266 ใด ๆ ก็เหมาะสมซึ่งมีขาพิเศษสำหรับการนำ SPI ไปใช้ ดังนั้น ESP8266-01 ที่ง่ายที่สุดจึงไม่เหมาะกับเรา เนื่องจากมีพินสำหรับพอร์ต I/O น้อยมาก แต่ในทางกลับกันความแตกต่างของราคาระหว่างพวกเขาน้อยกว่าร้อยรูเบิลและมีจำหน่ายอย่างเท่าเทียมกัน บอร์ดดีบั๊กขนาดใหญ่ที่มี ESP ซึ่งแยกอุปกรณ์ต่อพ่วงจำนวนมากเพื่อความสะดวกก็ไม่เหมาะสำหรับเราเช่นกันเนื่องจากไม่พอดีกับตำแหน่งที่เราต้องการผลักมันลงในมือกลของเรา

สาระสำคัญระดับโลกของแนวคิดโดยทั่วไปมีดังนี้ เนื้อความของโปรแกรมที่โหลดลงในไมโครคอนโทรลเลอร์จะถูกถ่ายโอนจากคอมพิวเตอร์ไปยัง ESP แบบไร้สายผ่าน WI-FI (ภายในเครือข่ายในบ้านของคุณ) และ ESP ได้เขียนโปรแกรมนี้ผ่านสายโดยใช้อินเทอร์เฟซ SPI ลงในหน่วยความจำ FLASH ของไมโครคอนโทรลเลอร์โดยตรง จากนั้นมันจะรีเซ็ตตามธรรมชาติและอนุญาตให้โปรแกรมที่โหลดมาทำงาน นอกจากนี้ ESP จะต้องมีบล็อกอิสระที่จัดการการแลกเปลี่ยนข้อมูลกับไมโครคอนโทรลเลอร์ด้วย เนื่องจากเราไม่เพียงต้องการเขียนโปรแกรมเท่านั้น แต่ยังต้องการแลกเปลี่ยนข้อมูลด้วย โดยเฉพาะอย่างยิ่งสำหรับโปรเจ็กต์ MechArm หลังจากบันทึกโปรแกรมแล้ว เรายังส่งสัญญาณควบคุมไปยังเซอร์โวเพื่อตั้งแขนนี้ให้เคลื่อนไหว ดังนั้นใน ESP เองจึงแนะนำให้เราเพิ่ม เซิร์ฟเวอร์ TCPสำหรับถ่ายโอนโปรแกรมและเซิร์ฟเวอร์ UDP สำหรับควบคุม MechArm ดังนั้น เซิร์ฟเวอร์เหล่านี้จะเข้าร่วมเครือข่ายในบ้านและตั้งใจฟังเพื่อดูว่ามีคนที่นั่นไหมที่ต้องการอัปโหลดโค้ดใหม่ไปที่ MechaArm หรือโบกมือให้ใครสักคน

ฉันพบบนอินเทอร์เน็ตว่าเฟิร์มแวร์อนุญาตให้คุณผลิตได้แล้ว การเขียนโปรแกรม AVRทางอากาศ แต่ปัญหาหลักคือเฟิร์มแวร์นี้ไม่สามารถใช้กับสิ่งอื่นได้อีกต่อไป และเราต้องการสื่อสารกับ AVR จากระยะไกลหลังการเขียนโปรแกรม

เราจะใช้ซอฟต์แวร์อะไร:

สำหรับพีซี ฉันเขียนทุกอย่างในสภาพแวดล้อม JAVA, IntelliJ IDEA แต่โดยหลักการแล้วคุณสามารถใช้อะไรก็ได้สิ่งสำคัญสำหรับเราคือการเขียนไคลเอนต์ที่จะส่งโปรแกรมให้ เฟิร์มแวร์ AVRบน ESP8266

ฉันเขียนโปรแกรมสำหรับ AVR ใน ATMEL STUDIO ใน C ซึ่งไม่ค่อยมีในแอสเซมเบลอร์ ฉันไม่ได้ใช้ภาพร่างของ Arduino เป็นหลักการ เกือบทุกไลบรารีที่จำเป็นสามารถเขียนได้ภายในหนึ่งชั่วโมงหรือประมาณนั้น และด้วยความเข้าใจในการทำงานของมันอย่างสมบูรณ์ ฉันลองสเก็ตช์ภาพแล้ว แต่คุณยังไม่มีใน AVR ระบบปฏิบัติการภาพร่างจะยังคงนำอุปกรณ์ต่อพ่วงของเพื่อนของคุณออกไปและเกิดข้อผิดพลาดเป็นประจำ ใช่ Arduino IDE เองเมื่อเปรียบเทียบกับ ATMEL STUDIO แน่นอนว่าเป็นสิ่งดั้งเดิมมาก แต่แน่นอนว่าคำถามนี้ยังเป็นที่ถกเถียงกันอยู่ว่า นักเรียนและเด็กนักเรียนสาขามนุษยศาสตร์น่าจะสนุกสนานและง่ายขึ้นกับการวาดภาพร่าง

ในการเขียนโปรแกรม ESP8266 ฉันใช้เฟิร์มแวร์ NodeMCU และเขียนโปรแกรมใน Lua ไม่ ฉันอยากจะเขียนด้วยภาษา Java และ C แต่ไม่มีให้บริการบน ESP Lua ไม่ใช่ภาษาที่ยากต่อการนำไปใช้งานของเรา การเรียนรู้มันเป็นเรื่องง่าย และจริงๆ แล้ว ในการดาวน์โหลดโปรแกรมและแก้ไขข้อบกพร่องบน ESP ฉันจึงใช้ IDE ESPlorer ภายในประเทศ สินค้าฟรี(แต่คุณสามารถบริจาคให้กับผู้เขียนได้) ซึ่งแน่นอนว่าไม่สามารถเปรียบเทียบกับสภาพแวดล้อมที่กล่าวมาข้างต้นได้ แต่อย่างที่พวกเขาพูดกับม้าของขวัญ... แต่เพื่อที่จะใช้งาน ESPlorer และเขียนใน LUA ก่อนอื่นเราต้อง เปลี่ยนเฟิร์มแวร์พื้นฐานในชิป ESP8266 (จัดหาจากผู้ผลิต) เป็นอันใหม่ โปรแกรม NODE MCU PyFlasher จะช่วยเราในความพยายามนี้ ฉันหมายความว่ามันจะช่วย reflash มัน และเราจะสร้างเฟิร์มแวร์เองและส่งมอบให้กับคุณบนเว็บไซต์ของผู้สร้าง: NodeMCU และคุณสามารถอ่านเพิ่มเติมเกี่ยวกับกระบวนการนี้ได้

ทุกอย่างเข้าถึงได้และเข้าใจได้ดีมาก เราเพิ่มการรองรับสำหรับการดำเนินการ SPI และบิตให้กับไลบรารีพื้นฐาน (ในกรณีของเรา LUA การดำเนินการบิตมีโอเวอร์โหลดและใช้งานน้อย) คุณไม่ควรยัดไลบรารี่จำนวนมากลงในเฟิร์มแวร์ เนื่องจาก ESP8266 มีซอฟต์แวร์ที่แตกต่างกันทุกประเภท จึงมีหน่วยความจำเหลือน้อยมาก บางตัวมีขนาด 20 kB ที่เลวทรามต่ำช้า

แน่นอนคุณสามารถใช้เฟิร์มแวร์สำเร็จรูปซึ่งมีอยู่มากมายบนอินเทอร์เน็ต แต่ฉันไม่แนะนำ หากเพียงเพราะบางส่วนไม่รองรับการทำงานของบิต (และเราต้องการ) และไม่ควบคุมอัตราการถ่ายโอนข้อมูลผ่าน SPI
ดังนั้นจะถูกส่งโดยค่าเริ่มต้นที่ความเร็ว 40 MHz หารด้วยสัมประสิทธิ์เล็กน้อยดังนั้น AVR จึงไม่มีเวลาแยกแยะ

หากคุณขี้เกียจเกินไปที่จะสร้างเฟิร์มแวร์ คุณสามารถดาวน์โหลดของฉันจากคลาวด์ได้

ตอนนี้เรามีเฟิร์มแวร์แล้วและเราต้องโหลดมันลงใน ESP8266 แทนที่จะเป็นเฟิร์มแวร์พื้นฐาน สำหรับสิ่งนี้เราจำเป็นต้องมีอะแดปเตอร์ USB - UART แบบธรรมดา


เราเชื่อมต่อขา TXD กับ RXD และ RXD กับ TXD สร้างกราวด์ทั่วไป แต่อย่าใช้อย่างที่ดูเหมือนเป็นเอาต์พุตกำลังไฟ 3.3 V ที่สะดวกบนอะแดปเตอร์ ในกรณีส่วนใหญ่ ESP8266 จะระบายออกจนหมด ดังนั้นเราจึงจ่ายไฟแยกกัน จากนั้นเราเปลี่ยน ESP ไปที่โหมดการเขียนโปรแกรม (GP0 เป็นกราวด์ เผื่อมีใครลืม) และเปิด NODE MCU PyFlasher

สิ่งสำคัญคืออย่าลืมลบหน่วยความจำแฟลช (ใช่ล้างข้อมูลทั้งหมด) มิฉะนั้นอาจยังคงอยู่ในหน่วยความจำขึ้นอยู่กับเวอร์ชันของเฟิร์มแวร์หลังจากตั้งโปรแกรมแล้ว ขยะที่ไม่จำเป็นซึ่งจะทิ้งขยะลงในคอนโซลระหว่างการทำงานต่อไป ก่อนหน้านั้น ฉันใช้ซอฟต์แวร์ที่ไม่มีตัวเลือกในการลบหน่วยความจำก่อน และฉันต้องทนทุกข์ทรมานมากเพราะไม่มีอะไรทำงาน และกล่องก็เปิดออก มีเพียงความจริงเท่านั้นที่อยู่ในฟอรัมภาษาอังกฤษของผู้สร้าง NODE MCU

ได้รับแล้ว เฟิร์มแวร์ที่จำเป็นตอนนี้เราสามารถเขียนและดีบักโปรแกรมในภาษา LUA ได้แล้ว (มี MicroPython ด้วย แต่ฉันไม่ได้ใช้) โดยใช้ API ที่สะดวกมากจาก NODE MCU เราเปิดตัว ESPlorer ที่กล่าวถึงก่อนหน้านี้

นอกจากนี้เรายังกำหนดค่าให้ทำงานกับ ESP8266 ตั้งค่าพารามิเตอร์ การเชื่อมต่อแบบอนุกรม- ทุกอย่างค่อนข้างง่ายและอธิบายไว้หลายครั้งบนอินเทอร์เน็ต

ตอนนี้เราเขียนโปรแกรมใน LUA ซึ่งเราจะโหลดลงใน ESP8266:

Lua bootloader สำหรับ AVR เขียนเป็น ESP8266

ฟังก์ชั่น InstrProgrammingEnable () -- คำสั่งสำหรับ MC "เปิดใช้งานการเขียนโปรแกรม" p=0 ในขณะที่พี<31 do p=p+1 pin=8 gpio.write(pin, gpio.LOW) spi.send(1, 0xAC,0x53) read = spi.recv(1, 8) spi.send(1,0,0) gpio.write(pin, gpio.HIGH) if (string.byte(read)== 83) then print("connection established") p=33 if(p==31) then print("no connection") end end end end ฟังก์ชั่นการเขียนโปรแกรมปิดการใช้งาน () pin=2--สิ้นสุด ESET FOR MK gpio.mode(pin, gpio.INPUT) pin=8 gpio.mode(pin, gpio.INPUT) pin=5--CLK MASTER สำหรับ SPI gpio.mode(pin, gpio.mode) INPUT) pin=6--MISO MASTER สำหรับ SPI gpio.mode(pin, gpio.INPUT) pin=7--MOSI MASTER สำหรับ SPI gpio.mode(pin, gpio.INPUT) สิ้นสุด ฟังก์ชั่น ProgrammingEnable() pin=2-- รีเซ็ตสำหรับ MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.LOW) pin=2--POZITIV สำหรับ 4MSEC รีเซ็ตสำหรับ MK gpio.mode(pin, gpio.OUTPUT) gpio .write(pin, gpio.HIGH) tmr.delay(4) gpio.mode(pin, gpio.OUTPUT) gpio.write(พิน, gpio.LOW) tmr.delay(25000) สิ้นสุด ฟังก์ชั่น InstrFlashErase() pin=8 gpio.write(pin, gpio.LOW) spi.send(1,0xAC,0x80,0,0) gpio.write(pin, gpio.HIGH) tmr.delay(15000) pin=2--รีเซ็ตสำหรับ MK gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio.HIGH) tmr.delay(20000) gpio.write(pin, gpio.LOW) พิมพ์("FLASH ถูกลบ") InstrProgrammingEnable () สิ้นสุด ฟังก์ชั่น InstrStorePAGE(H, ที่อยู่, ข้อมูล) pin=8 gpio.write(pin, gpio.LOW) spi.send(1,H,0,ที่อยู่,ข้อมูล) gpio.write(pin, gpio.HIGH) tmr.delay(500) สิ้นสุด ฟังก์ชั่น InstrWriteFLASH (page_address_low, page_address_high) pin=8 gpio.write(pin, gpio.LOW) spi.send(1.0x4C,page_address_high,page_address_low,0) gpio.write(pin, gpio.HIGH) tmr.delay(5000)-- บางครั้งแฟลชไม่ได้ลงทะเบียนเมื่อ เวลาแฝงต่ำ ฟังก์ชั่นการเขียนโปรแกรม (เพย์โหลด) pin=8--CS MASTER สำหรับ SPI gpio.mode(pin, gpio.OUTPUT, gpio.PULLUP) pin=4--ไฟ LED บนต่ำ gpio.mode(pin, gpio.OUTPUT) gpio.write(pin, gpio. LOW) print(string.len(payload)) page_count = 7 -- เขียน 1 กิโลไบต์สำหรับ k =0 ,page_count ,1 do--จำนวนหน้าสำหรับ i=0 , 127, 2 do-- -1 address = i/ 2 data=payload:byte(i+1+128*k) ถ้า data == nil ดังนั้น data = 0xff end InstrStorePAGE(0x40,address,data) -- tmr.delay(100)-- ไม่เช่นนั้นจะเขียนข้อมูลไม่ทัน = เพย์โหลด:ไบต์(i+1+1+128*k) ถ้าข้อมูล == ไม่มี ดังนั้น data = 0xff สิ้นสุด InstrStorePAGE(0x48,ที่อยู่,ข้อมูล) -- tmr.delay(100) สิ้นสุด page_address_low=bit.band(k ,3 )*64 -- 3 คือไบนารี 11 page_address_high=k/4+frame1024*2 tmr.delay(1000) InstrWriteFLASH(page_address_low,page_address_high) tmr.wdclr() end pin=4--LED gpio.mode(pin, gpio.mode) เอาท์พุท) gpio.write(pin, gpio.HIGH) สิ้นสุด --บล็อกหลัก wifi.setmode(wifi.STATION) --wifi.sta.config("ชื่อเครือข่าย", "รหัสผ่าน") -- ตั้งค่า SSID และรหัสผ่านของจุดเข้าใช้งานของคุณ station_cfg=() tmr.delay(30000) station_cfg.ssid=" ชื่อเครือข่าย" tmr.delay(30000) station_cfg.pwd="password" tmr.delay(30000) wifi.sta.config(station_cfg) tmr.delay(30000) wifi.sta.connect() tmr.delay(1000000) พิมพ์ (wifi.sta.status()) print(wifi.sta.getip()) ในขณะที่ (wifi.sta.status()~=1) do if(wifi.sta.status()==5) จากนั้นแตกปลาย sv=net.createServer(net.TCP,30) tmr.delay(100) print("SERVER READY") sv:listen(4000,function(c) c:on("receive", function(c, payload) พิมพ์ (เพย์โหลด) ถ้า (เพย์โหลด =="program\r\n") จากนั้น c:send("ready\r\n") print("ready for program\r\n") spi.setup(1, spi.MASTER , spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8,320,spi.FULLDUPLEX) การเขียนโปรแกรมเปิดใช้งาน () tmr.delay(100) InstrProgrammingEnable () tmr.delay(100) InstrFlashErase() tmr.delay(100) frame1024=0- - จำนวนเฟรมที่ส่ง st=net.createServer(net.TCP,30) st:listen(4001,function(c) c:on("receive", function(c, payload) tmr.wdclr() การเขียนโปรแกรม (payload ) frame1024=frame1024+1 end) end) end) end if (payload =="data\r\n") จากนั้น c:send("ready\r\n") print("ready for data\r\n") srv = net.createServer(net.UDP) tmr.delay(1000) pin=10 gpio.write(pin, gpio.HIGH) uart.setup(0,9600,8,0,1,0) srv:listen(5000) srv :on("receive", function(srv, pl) pl=pl*1 --print(pl) uart.write(0,pl) tmr.wdclr() end) สิ้นสุด if (payload =="stop\r \ n") แล้ว if(st~=nil) แล้วก็ st:close() frame1024=0 ProgrammingDisable () print("stop program") end if(srv~=nil) แล้วก็ srv:close() print("stop data " ) สิ้นสุด สิ้นสุด สิ้นสุด) สิ้นสุด) สิ้นสุด)


โดยที่ฟังก์ชันที่เกี่ยวข้องจะทำสิ่งต่อไปนี้:

ฟังก์ชั่น InstrProgrammingEnable()– ทำให้ไมโครคอนโทรลเลอร์เข้าสู่โหมดการเขียนโปรแกรมด้วยคำสั่งพิเศษที่ส่งผ่าน SPI

ฟังก์ชั่น ProgrammingEnable()– เพียงรีเซ็ต AVR เป็นเวลา 25 มิลลิวินาทีก่อนเริ่มการเขียนโปรแกรม

ฟังก์ชั่นการเขียนโปรแกรมปิดการใช้งาน ()– หลังจากเสร็จสิ้นการเขียนโปรแกรม เราจะย้ายพิน SPI ใน ESP8266 ไปเป็นสถานะไม่ใช้งาน เพื่อไม่ให้รบกวนเราเมื่อรันโค้ดบนไมโครคอนโทรลเลอร์ (ในกรณีใช้งานที่นั่น)

ฟังก์ชั่น InstrFlashErase()– ลบหน่วยความจำแฟลชบนไมโครคอนโทรลเลอร์ก่อนเริ่มการเขียนโปรแกรม ไม่จำเป็นต้องอธิบายว่าเหตุใดจึงจำเป็น

ฟังก์ชั่น InstrStorePAGE(H, ที่อยู่, ข้อมูล)– คำสั่งนี้เขียนโปรแกรมไบต์ไปยังบัฟเฟอร์ภายในของไมโครคอนโทรลเลอร์ แต่นี่ไม่ใช่ตัวบันทึกแฟลช เนื่องจากแฟลชถูกเขียนที่นี่ทีละหน้า แต่ละหน้ามีขนาด 128 ไบต์

ฟังก์ชั่น InstrWriteFLASH (page_address_low, page_address_high)– แต่นี่เป็นการบันทึกแบบแฟลชและต้องใช้เวลา ให้ความสนใจกับการหน่วงเวลา 5,000 μs

ฟังก์ชั่นการเขียนโปรแกรม (เพย์โหลด)– ฟังก์ชั่นที่ใหญ่ที่สุดและสำคัญที่สุดที่ใช้ฟังก์ชั่นข้างต้น โดยจะใช้โปรแกรมที่ส่งเป็นชิ้นขนาด 1,024 ไบต์ แบ่งออกเป็นไบต์และสร้างที่อยู่สำหรับโปรแกรมเหล่านั้น จากนั้นส่งไปยังไมโครคอนโทรลเลอร์ในบัฟเฟอร์ภายใน และหลังจากทุกๆ 128 ไบต์ โปรแกรมจะเริ่มต้นการเขียนแฟลช จากนั้นจะใช้โค้ดอีกกิโลไบต์ถัดไปและทำซ้ำการดำเนินการ โดยธรรมชาติแล้วจะมีการชดเชยที่อยู่ เพื่อให้สามารถเขียนเพิ่มเติมได้และไม่เขียนทับ ตอนแรกฉันพยายามถ่ายโอนโปรแกรมทั้งหมด แต่เมื่อ ESP8266 เกิน 6 กิโลไบต์ หน่วยความจำที่มีอยู่ก็หมดลงและขัดข้อง หนึ่งกิโลไบต์กลายเป็นหน่วยที่สะดวกที่สุดเนื่องจากแบ่งออกเป็นส่วน ๆ อย่างเรียบร้อยและส่งผ่าน TCP อย่างสะดวก (เรายังต้องได้รับจากคอมพิวเตอร์) ไม่จำเป็นต้องใช้ขนาดที่ใหญ่กว่านี้ TCP ดังที่คุณทราบในเวอร์ชันปัจจุบันจำกัดแพ็กเก็ตที่ส่งไว้ที่ 1,500 ไบต์หรือประมาณนั้น (แต่ด้วยเหตุผลบางอย่างฉันถูกส่ง 1440 ดูเหมือนว่า)

ดูเหมือนจะไม่มีอะไรซับซ้อน แต่ต้องเอาชนะข้อผิดพลาดหลายประการ

ลงทะเบียนบนเครือข่ายไร้สาย

ขั้นแรกเราสร้างเซิร์ฟเวอร์ TCP ที่ฟังคำสั่งสามคำสั่ง:

1. “โปรแกรม” (เราจะเขียนโปรแกรม)

2. “ข้อมูล” (เราจะแลกเปลี่ยนข้อมูล)

3. “หยุด” (เราหยุดทุกอย่าง)

หากเรากำลังเขียนโปรแกรม ก่อนอื่นเราจะเริ่มต้น SPI และสร้างเซิร์ฟเวอร์ TCP อื่นที่ดึงข้อมูล (โค้ดของโปรแกรมที่เป็นเฟิร์มแวร์) ต่อกิโลไบต์ และเรียกใช้ฟังก์ชันการเขียนโปรแกรมไมโครคอนโทรลเลอร์สำหรับมัน ฉันเข้าใจว่าการสร้างเซิร์ฟเวอร์ตัวที่สองดูโง่เขลา แต่นี่เป็นสิ่งจำเป็นเนื่องจาก API ในเครื่องรองรับการสร้างซ็อกเก็ตเดียวเท่านั้น และเราจำเป็นต้องแยกคำสั่ง "โปรแกรม" และ "ข้อมูล" ด้วยข้อมูลที่ส่งจริง เพราะแยกไม่ออกด้วยตา จึงมีไบต์ และนี่คือไบต์

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

หลังจากนั้น UART จะถูกเตรียมใช้งาน และแต่ละไบต์ที่ได้รับแบบไร้สายจะถูกส่งผ่านสาย TXD ไปยังไมโครคอนโทรลเลอร์ ซึ่งจำเป็นต้องยอมรับหากโปรแกรมที่เกี่ยวข้องกระพริบที่นั่น การจัดการแลกเปลี่ยนข้อมูลไปในทิศทางอื่นไม่ใช่เรื่องยาก แต่ฉันยังไม่ได้ดำเนินการ

ตามคำสั่ง "หยุด" เซิร์ฟเวอร์ที่กล่าวถึงข้างต้น (ยกเว้นเซิร์ฟเวอร์แรก) จะปิดการเชื่อมต่อและเซิร์ฟเวอร์หลักจะเข้าสู่สถานะรอคำสั่ง "โปรแกรม" และ "ข้อมูล" อีกครั้ง

เนื่องจากอินเทอร์เฟซ SPI ถูกจำลองในซอฟต์แวร์ใน ESP8266 คุณจึงสามารถใช้พอร์ต I/O ใดๆ ที่มีอยู่สำหรับสัญญาณ CS, CLK, MISO, MOSI, RESET (สำหรับ AVR) ได้ ไม่ใช่พอร์ตที่ระบุไว้ใน Bootloader ของฉัน นอกจากนี้ปรากฎว่าโดยหลักการแล้ว CS และ MISO ก็สามารถถูกตัดออกได้ในกรณีนี้ มีการใช้พินหนึ่งอันสำหรับ LED ที่ติดตั้งอยู่ในบอร์ด ESP8266 เพื่อให้บางครั้งกะพริบและแสดงว่าโปรแกรมยังมีชีวิตอยู่

ไม่มีการตรวจสอบข้อผิดพลาดในการบันทึก (ยกเว้นคำขอแรกไปยัง AVR แต่ข้อมูลนี้จะแสดงบนคอนโซลเพียงอย่างเดียว) ไม่ได้ตั้งโปรแกรม EEPROM ไม่ได้เขียนมากกว่า 32 KB - กล่าวโดยย่อยังมี บางสิ่งบางอย่างที่จะดำเนินการ ความเร็วในการแลกเปลี่ยน SPI อยู่ที่ประมาณ 115 Kbit ทุกอย่างจะกะพริบภายในไม่กี่วินาที เหมือนกับโปรแกรมเมอร์แบบอนุกรมทั่วไปเช่น ISP500)

นำโค้ด ป้อนเครือข่ายและรหัสผ่านของคุณ คอมไพล์บน ESplorer เรียกมันว่า "init" (เพื่อเริ่มต้นใหม่เมื่อรีสตาร์ท) และส่งไปที่ ESP8266 มันควรจะทำงาน ในแง่การทำงานเป็นโปรแกรมเมอร์ไร้สายเป็นอย่างน้อย

ตอนนี้เราจะจัดการกับด้านการควบคุม - คอมพิวเตอร์ส่วนบุคคล

โดยพื้นฐานแล้ว เราจำเป็นต้องนำไฟล์รูปแบบ HEX ไปใช้ในการแปลงโปรแกรมของคุณที่เขียนในสภาพแวดล้อม ATMEL STUDIO และส่งผ่าน WI-FI ไปยังพอร์ตซ็อกเก็ตที่เรารู้จัก (ในกรณีนี้คือ 4000) ประเด็นเล็กๆ น้อยๆ ก็คือเราต้องการไฟล์ไบนารี่ BIN สำหรับการถ่ายโอน และ ATMEL STUDIO จะให้เฉพาะ HEX แก่เราเท่านั้น มีสองวิธีที่นี่ หรือแปลงเป็นรูปแบบ BIN ด้วยโปรแกรมแปลงพิเศษเช่น WinHex หรือทำเองในโปรแกรมของคุณ ยังไม่ได้ทำแต่ดูไม่ยากต้องตัดหัวข้อไปทำอย่างอื่น

ด้วยเหตุนี้ ฉันจึงเขียนโปรแกรมตัวโหลดใน JAVA (เพราะฉันไม่รู้อย่างอื่นเป็นหลัก) โดยทำงานในสภาพแวดล้อม IntelliJ IDEA ที่ยอดเยี่ยมและฟรี มันสร้างไคลเอนต์ TCP ที่ค้นหาเซิร์ฟเวอร์ที่ทำงานบน ESP8266 หากพบเขาจะติดต่อกับเขาและส่งไฟล์ที่อยู่ดังกล่าวและที่อยู่ดังกล่าวไปให้เขา รหัสอยู่ด้านล่าง

ตัวดาวน์โหลดไฟล์ JAVA ทำงานบนฝั่งพีซี

นำเข้า java.io.*; นำเข้า java.net.*; นำเข้า java.util.ArrayList; นำเข้า java.util.List; คลาสสาธารณะ Net ( โมฆะคงที่สาธารณะหลัก (String args) ( ใหม่ Http_client (4000); )) คลาส Http_client ขยาย Thread ( int port; String s; String Greetings_from_S; Http_client(int port)( this.port = port; start(); ) public void run() ( //192.168.1.113 เป็นที่อยู่ของ ESP8266 บน เครือข่ายของฉัน แต่โดยทั่วไปคุณเรียนรู้จากการสื่อสารกับเราเตอร์ // จะดีกว่าถ้าทำให้คงที่เราเตอร์สามารถลองได้ (Socket socket = new Socket("192.168.1.113", port)) ( PrintWriter pw = new PrintWriter(ใหม่ OutputStreamWriter(socket.getOutputStream( )),true); pw.println("program");// สวัสดีกับ SERVER System.out.println("program"); ​​br.readLine(); println(Greetings_from_S); if(Greetings_from_S.equals("ready")) ( ลอง ( File file = new File("d:BlinkOUT.bin"); // ที่อยู่ของไฟล์ที่อัพโหลด BufferedInputStream bis = new BufferedInputStream(new FileInputStream( ไฟล์)); ข้อมูลไบต์; bis.read(data); byte data_buffer = data.length/1024;< frames;i++) { for (int k = 0; k< (1024); k++) { data_buffer[k] = data; } sendingChunk(data_buffer); } byte data_buffer2= new byte; for (int i = 0; i < residy;i++) { data_buffer2[i] = data; } sendingChunk(data_buffer2); pw.println("stop");// System.out.println("stop program"); } catch (Exception e) { System.out.println(e); } } } catch (Exception e) { System.out.println(e); } } public void sendingChunk (byte data_buffer){ try (Socket socket = new Socket("192.168.1.113", 4001)){ BufferedOutputStream bos = new BufferedOutputStream((socket.getOutputStream())); bos.write(data_buffer); bos.flush(); System.out.println(data_buffer.length); } catch (Exception e) { System.out.println(e); } } }


int ถิ่นที่อยู่ = data.length%1024;

สำหรับ (int i = 0; i

สิ่งเดียวคือในการรันคุณจะต้องติดตั้งสภาพแวดล้อมรันไทม์ JAVA บนคอมพิวเตอร์ของคุณ แต่ฉันมักจะเปิดโดยตรงจาก IntelliJ IDEA เพราะที่นั่นคุณสามารถดูสิ่งที่เกิดขึ้นในคอนโซลได้ตลอดเวลา (แต่ที่นี่จำเป็นต้องมีสภาพแวดล้อม JAVA ด้วย) แม้ว่าแน่นอนว่า GUI จำเป็นต้องทำอย่างชาญฉลาดกว่านี้ นั่นคือหน้าต่างที่เส้นทางไปยังไฟล์ปรากฏขึ้นความสามารถในการเปลี่ยนหมายเลขพอร์ตในหน้าต่างและสิ่งที่จำเป็นอื่น ๆ และรวบรวมทั้งหมดนี้ในรูปแบบของไฟล์ปฏิบัติการ

จากนั้นอย่างที่ Koroviev เคยพูดไว้ พลเมืองทั้งหลาย กลับมาที่แขนกลของ MechArm ซึ่งได้รับการกล่าวถึงในตอนต้นกันเถอะ ขณะนี้เรามีความสามารถในการตั้งโปรแกรมจากระยะไกลแล้วควบคุมได้ มาดูโปรแกรมควบคุมฝั่งไมโครคอนโทรลเลอร์กันดีกว่า

ในกรณีนี้เราจำเป็นต้องควบคุมเซอร์โวสี่ตัว เหล่านี้คือพวกนั้น


ชุดขับดังกล่าวถูกควบคุมโดยพัลส์สี่เหลี่ยมเป็นระยะเวลา 20 มิลลิวินาที (50 เฮิรตซ์) โดยมีรอบการทำงานอยู่ที่ 2 ถึง 4 เปอร์เซ็นต์ นั่นคือ 2% เป็นการเลี้ยวที่สมบูรณ์ในทิศทางเดียว และ 4% ในอีกทิศทางหนึ่ง งานนี้มีไว้สำหรับ PWM ที่สร้างไว้ใน AVR เท่านั้น

เซอร์โวตัวหนึ่งใช้สำหรับการเคลื่อนไหวซ้าย-ขวา ประการที่สองในตัวเอง - จากตัวเอง; ที่สามขึ้นและลง; อันที่สี่คือกรงเล็บซึ่งควรบีบอัดและคลี่ออก ทุกอย่างเขียนด้วยภาษา C และคอมไพล์เป็นไฟล์ HEX ใน ATMEL STUDIO ลักษณะที่แปลกเล็กน้อยของโปรแกรมนั้นเกิดจากการที่มือถูกควบคุมในตอนแรกจากแป้นพิมพ์ที่เชื่อมต่อด้วยสายไฟเข้ากับไมโครคอนโทรลเลอร์ แต่สายไฟเป็นเรื่องของอดีตแล้ว เราจำเป็นต้องพัฒนาต่อไป

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

นี่คือโค้ดที่เราเขียนไปยัง Arduino Nano โดยใช้ ESP8266-07

โปรแกรมควบคุม MechArm สำหรับไมโครคอนโทรลเลอร์ AVRmega328P

#กำหนด F_CPU 16000000 #รวม #รวม // จำนวนเต็มมาตรฐาน #include #รวม // คณิตศาสตร์ #รวม //I/O มาตรฐาน #include #รวม #รวม // ความสามารถมาตรฐาน #define UART_BAUD_RATE 115200 // ตัวนับ T1 กำหนดช่วงเวลาเป็น 20ms #define COUNTER1_OFF TCCR1B=0b00000000 // CS02 CS01 CS00 - 000 - ปิดการใช้งาน; 001 ไม่มีตัวหาร; 010 พร้อมตัวหาร 8; 011 -64; 100 -256; 101 -1024 #define COUNTER1_ON TCCR1B=0b00000011 // counter T0 ตั้งค่าความกว้างของพัลส์ควบคุมสำหรับเซอร์โว PB0 และ PB1 #define COUNTER0_OFF TCCR0B=0b00000000 // CS02 CS01 CS00 - 000 - ปิดการใช้งาน; 001 ไม่มีตัวหาร; 010 พร้อมตัวหาร 8; 011 -64; 100 -256; 101 -1024 #define COUNTER0_ON TCCR0B=0b00000100 // counter T2 ตั้งค่าความกว้างของพัลส์ควบคุมสำหรับเซอร์โว PB2 (PD6) และ PB3 (PD7) #define COUNTER2_OFF TCCR2B=0b00000000 // CS02 CS01 CS00 - 000 - ปิดการใช้งาน; 001 ไม่มีตัวหาร; 010 พร้อมตัวหาร 8; 011 -64; 100 -256; 101 -1024 #define COUNTER2_ON TCCR2B=0b00000110 ผันผวน uint16_t period_20ms; ผันผวน uint8_t State_of_keyboard; ผันผวน uint8_t start_position ; int8_t number_servo ระเหยง่าย; ISR (USART_RX_vect) // ขัดจังหวะสำหรับ UART ( State_of_keyboard=UDR0; return; ) ISR (TIMER0_COMPA_vect) // เซอร์โวРВ0ควบคุมความกว้างพัลส์ ( PORTB &=~(1<<0); TIMSK0&=~(1<
สาระสำคัญของโปรแกรมชัดเจนจากข้อความและความคิดเห็น เราใช้ตัวนับ T1 สำหรับช่วงเวลาตัวอย่าง 20 ms และตัวนับ T0, T2 เพื่อส่งสัญญาณ PWM ไปยังสี่บรรทัดของพอร์ต I/O เนื่องจากตัวนับสองตัวนี้สามารถทำงานบนอุปกรณ์สองตัวได้
โปรแกรมจะตั้งค่าตำแหน่งเริ่มต้นของเซอร์โวโดยการโหลดรีจิสเตอร์การนับ OCR0A, OCR0B, OCR2A, OCR2B นอกจากนี้ การจำกัดค่าคงที่ยังถูกนำมาใช้ เนื่องจากเราไม่จำเป็นต้องมีช่วง 180 องศาเสมอไป ถ้าอย่างนั้นโดยการหยุดชะงักจาก UART โปรแกรมจะจับหมายเลขที่ส่งโดย ESP8266 (จาก 1 ถึง 8) และแปลเป็นคำสั่งสำหรับเซอร์โวไดรฟ์ที่เกี่ยวข้อง มีไดรฟ์สี่ตัว แต่ละไดรฟ์ทำงานในสองทิศทาง ดังนั้นจำนวนเต็มตั้งแต่ 1 ถึง 8 ก็เพียงพอแล้ว เมื่อเลือกตัวเลขแล้ว เนื้อหาของรีจิสเตอร์ตัวนับด้านบนจะเพิ่มขึ้นหรือลดลง ตามการเปลี่ยนรอบการทำงานของพัลส์ควบคุมและมุมการหมุนของเซอร์โวที่เลือก ไดรฟ์เหล่านั้นที่เราไม่ได้เลือกจะคงค่าเดิมของมุมการหมุน (เนื่องจากเนื้อหาของรีจิสเตอร์ที่เกี่ยวข้อง แม้ว่าจะอัปเดต แต่ก็ไม่เปลี่ยนแปลง) และยังคงยึดแขนกลไว้ในตำแหน่งเดิม

ตอนนี้สิ่งที่เราต้องทำคือเขียนโปรแกรมควบคุม ยกโทษให้เรื่องซ้ำซาก เพื่อควบคุมแขนกลโดยตรงจากคอมพิวเตอร์ผ่าน WI-FI
รหัสนี้เขียนด้วยภาษา JAVA เช่นกัน แต่มีการปรับปรุงเล็กน้อย มี GUI และความสามารถในการแก้ไขหมายเลขพอร์ตและที่อยู่เครือข่ายของ ESP8266

สิ่งที่เกิดขึ้นนั้นชัดเจนจากหน้าต่าง ฉันไม่ได้ให้ข้อความของโปรแกรมที่นี่ (ดูได้ที่

ฉันมีอุปกรณ์ที่สร้างด้วย Arduino uno:

    ซอฟต์แวร์ Arduino ที่ติดตั้งบน Arduino uno

    สามารถควบคุมได้โดยใช้คำสั่งอนุกรม

    สามารถควบคุมได้โดยใช้ปุ่มและเซ็นเซอร์ทางกายภาพ

    เมื่อปุ่ม/เซ็นเซอร์มีการเปลี่ยนแปลง มันจะเขียนสถานะปัจจุบันเป็นอนุกรม

    หากไม่มีการส่งข้อความภายใน 5 วินาที ข้อความซีเรียลจะส่งข้อความโดยไม่มีการเปลี่ยนแปลง

สิ่งที่คุณต้องการ:

    ใช้ ESP8266 เพื่อสร้างสะพานเชื่อมระหว่างซอฟต์แวร์ Arduino ปัจจุบันและ MQTT/เว็บ

    ฉันสามารถตั้งโปรแกรม ESP8266 เป็นเว็บเซิร์ฟเวอร์ ไคลเอนต์ MQTT ฯลฯ โดยใช้ Arduino IDE หรือ Lua ได้ (แต่ฉันชอบ Arduino IDE มากกว่าเพราะฉันสามารถใช้บางส่วนของโค้ดซ้ำเพื่อสร้าง/ตีความการสื่อสาร)

    ESP8266 จะจัดการทุกอย่างที่จำเป็นสำหรับ wifi/เว็บ/MQTT; หากไม่มีโมดูล MQTT ส่วน Arduino จะทำงานโดยอัตโนมัติ มีเพียงรีโมทคอนโทรลเท่านั้นที่จะหายไป

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

    ESP8266 อาจไม่พร้อมใช้งานในบางการติดตั้ง

ฉันพบตัวเลือกอะไรบ้าง:

    <�Литий>สม่ำเสมอ

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

ข้อดีประการหนึ่งคือไม่มีการเปลี่ยนแปลง/การทดสอบโค้ดที่จำเป็นสำหรับชิ้นส่วน Arduino

สร้าง Arduino I2C master และ ESP8266 Slave (หรือกลับกัน) และใช้การสื่อสารแบบสองทิศทาง ได้แนวคิดนี้จากการอ่านกระทู้นี้

ข้อมูลอื่นๆ เกี่ยวกับคำสั่งอนุกรม:

แพ็กเก็ตข้อมูล (คำสั่งหรือคำอธิบายสถานะ) ประกอบด้วยอักขระ 1-20 ตัว โดยมีจุดสูงสุดที่เป็นไปได้ที่ 20 แพ็กเก็ตต่อ 5 วินาที และเฉลี่ยหนึ่งแพ็กเก็ตทุกๆ 3 วินาที หากจำเป็น ฉันสามารถกำหนดให้ส่งจำนวนเต็มที่ไม่ได้ลงนาม 5 ตัวแทนอักขระตัวอักษรและตัวเลข

หากจำเป็นต้องใช้พิน I2C/อนุกรมมากกว่า ฉันสามารถอัปเกรดเป็น Arduino Mega ได้ (ดังนั้นจำนวนพินที่ว่างจึงไม่เป็นปัญหา)

มีตัวเลือกอื่นสำหรับสิ่งนี้หรือไม่? (โปรโตคอล ไลบรารีสำเร็จรูปสำหรับการสื่อสารแบบอนุกรม ฯลฯ) ฉันกำลังพยายามที่จะไม่สร้างล้อขึ้นมาใหม่

ขอบคุณสำหรับเวลาของคุณ!

3

1 คำตอบ

บทช่วยสอน I2C ส่วนใหญ่ทำให้ Arduino แต่ละตัวเป็นทาสและมาสเตอร์ แต่อันนี้ดีกว่าเพราะ Arduino แต่ละตัวเป็นมาสเตอร์หรือทาส (ไม่ใช่ทั้งสองอย่าง) และไม่จำเป็นต้องสลับ สิ่งนี้ทำให้สิ่งต่าง ๆ ง่ายขึ้น

I2C ดีกว่าอนุกรมเพราะคุณสามารถเพิ่ม Arduinos ได้มากขึ้นบนบัสเดียวกัน

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

นี่คือตัวอย่างของฉัน (เป็นเพียงการพิสูจน์แนวคิด) Arduino Slave ควบคุมพินและอุณหภูมิบางส่วน เซ็นเซอร์และตัวจับเวลา Watchdog ตามคำสั่งของ Arduino master หากสเลฟไม่ได้รับบิตทันเวลา มันจะรีเซ็ต Arduino ต้นแบบ

รหัสหลัก

#include #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 const ไบต์ SLAVE_ADDRESS = 42; LED ไบต์ const = 13; บัฟเฟอร์ถ่าน; การตั้งค่าเป็นโมฆะ () ( Serial.begin (9600); Serial.println ("Master"); Wire.begin (); pinMode (LED, OUTPUT); digitalWrite (LED, สูง); ล่าช้า (1,000); digitalWrite (LED, ต่ำ); Wire.beginTransmission(SLAVE_ADDRESS); Wire.write(CMD_PIN_ON); Wire.endTransmission(); = Wire.requestFrom(SLAVE_ADDRESS, 1); / สิ้นสุดการตั้งค่า void loop () ( Serial.println ("."); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write (CMD_SENSOR); int x = Wire.requestFrom (SLAVE_ADDRESS, 1); int) Wire.read ( ); Wire.beginTransmission(SLAVE_ADDRESS);<< 8 | Wire.read(); Serial.print("Light="); Serial.println(light); Wire.beginTransmission (SLAVE_ADDRESS); Wire.write (CMD_BEAT); Wire.endTransmission(); Wire.requestFrom(SLAVE_ADDRESS, 1); delay (5000); } //end of loop

รหัสทาส

/* Esclavo I2C รองรับคำสั่งอื่น ๆ<- 1° byte -> <- 2° byte -> <- 3° byte ->CMD_SENSOR CMD_PIN_ON n° de pin duracion en segundos CMD_PIN_OFF n° de pin CMD_LUMEN CMD_BEAT Cada commando recibe una respuesta, ya sea el valor pedido o un status. */ #include #include typedef struct ( int pin; unsigned long off; ) PIN_PGMA; /* Lista de pines que se pueden activar ผ่าน CMD_PIN_ON */ #กำหนด PIN_LUMEN A0 #กำหนด PIN_LED 2 #กำหนด PIN_RESET 3 PIN_PGMA pgma = ( (PIN_LED, 0), (PIN_RESET, 0) ); const int pgmaSize = ขนาดของ(pgma)/ขนาดของ(PIN_PGMA); #define CMD_SENSOR 1 #define CMD_PIN_ON 2 #define CMD_PIN_OFF 3 #define CMD_LUMEN 4 #define CMD_BEAT 5 #define ST_OK 0 #define ST_BAD_PIN 1 #define ST_TIME_0 2 #define ST_BAD_LEN 3 #define MY_ADDRESS 42 // Maximo Tiempo de esper a entre CMD_BEAT . Pasado // เหล่านี้เหมือนกัน, se activa และ PIN_RESET. // ใน misegundos. #define BEAT_INTERVAL 10,000 LastBeat ยาวที่ไม่ได้ลงนาม; // Largo del รีเซ็ตและตั้งค่าใหม่ #define RESET_LENGTH 250 ไบต์ cmd = 0; สถานะไบต์ = 0; อินท์เทอร์โม DO = 11; อินท์เทอร์โมซีเอส = 12; อินท์เทอร์โม CLK = 13; เทอร์โมคัปเปิล MAX6675 (thermoCLK, thermoCS, thermoDO); การตั้งค่าเป็นโมฆะ () (Serial.begin(9600); pinMode(PIN_LUMEN, INPUT); analogRead(PIN_LUMEN); for (int i = 0; i< pgmaSize; i++) { pinMode(pgma[i].pin, OUTPUT); digitalWrite(pgma[i].pin, LOW); } lastBeat = millis(); Wire.begin (MY_ADDRESS); Wire.onReceive (receiveCommand); Wire.onRequest (sendAnswer); } void loop() { unsigned long now = millis(); // Baja la linea de RESET si no ha recibido un beat ultimamente. unsigned long diff = now - lastBeat; if (diff >BEAT_INTERVAL) (resetPin(); ) // Recorre la lista de pines y apaga aquellos cuyo tiempo termino.< pgmaSize; i++) { if (pgma[i].off >สำหรับ (int i = 0; i<= now) { Serial.print("off pin="); Serial.println(pgma[i].pin); pgma[i].off = 0; digitalWrite(pgma[i].pin, LOW); } } } // called by interrupt service routine when outgoing data is requested void sendAnswer() { byte temp; int lightReading; switch (cmd) { case CMD_SENSOR: temp = thermocouple.readCelsius(); Wire.write(temp); break; case CMD_LUMEN: lightReading = analogRead(PIN_LUMEN); Wire.write(lightReading >0 && pgma[i].ปิด< 0) { status = ST_BAD_PIN; } else { pgma[i].off = 0; digitalWrite(pin, LOW); } } } int searchPin(int pin) { int i = pgmaSize - 1; while (i >> 8);< 0) { status = ST_BAD_PIN; Serial.println("bad pin"); } else { if (len == 0) { status = ST_TIME_0; Serial.println("ban len"); } else { pgma[i].off = millis() + len * 1000; digitalWrite(pin, HIGH); Serial.println("ok"); } } } }

พอร์ต COM มักใช้ในการสื่อสารระหว่างไมโครคอนโทรลเลอร์และคอมพิวเตอร์ ในบทความนี้ เราจะแสดงวิธีการส่งคำสั่งควบคุมจากคอมพิวเตอร์และส่งข้อมูลจากคอนโทรลเลอร์

การเตรียมงาน

ไมโครคอนโทรลเลอร์ส่วนใหญ่มีพอร์ต I/O หลายพอร์ต โปรโตคอล UART เหมาะสมที่สุดสำหรับการสื่อสารกับพีซี นี่คือโปรโตคอลการถ่ายโอนข้อมูลแบบอะซิงโครนัสแบบอนุกรม หากต้องการแปลงเป็นอินเทอร์เฟซ USB จะมีตัวแปลง USB-RS232 – FT232RL บนบอร์ด
หากต้องการทำตามตัวอย่างในบทความนี้ คุณจะต้องใช้บอร์ดที่เข้ากันได้กับ Arduino เท่านั้น เราใช้. ตรวจสอบให้แน่ใจว่าบอร์ดของคุณมี LED เชื่อมต่อกับพิน 13 และปุ่มรีเซ็ต

ตัวอย่างเช่น ลองโหลดโค้ดลงบนบอร์ดที่แสดงตาราง ASCII ASCII คือการเข้ารหัสเพื่อแสดงตัวเลขทศนิยม ตัวอักษรละตินและตัวอักษรประจำชาติ เครื่องหมายวรรคตอน และอักขระควบคุม

สัญลักษณ์ int = 33 ;

การตั้งค่าเป็นโมฆะ() ( Serial.begin(9600 ) ; Serial.println(" ASCII Table ~ Character Map " ) ; ) void loop() ( Serial.write(สัญลักษณ์) ; Serial.print(" , dec: " ) ; Serial . print(สัญลักษณ์) ; Serial.print( " ) ; " , bin: " ) ; ​ทำต่อ ; ) ) สัญลักษณ์+ + ;
ตัวแปรสัญลักษณ์จะเก็บรหัสสัญลักษณ์ ตารางเริ่มต้นที่ 33 และสิ้นสุดที่ 126 ดังนั้นตัวแปรสัญลักษณ์จึงถูกตั้งค่าเริ่มต้นเป็น 33 หากต้องการเริ่มการทำงานของพอร์ต UART ให้ใช้ฟังก์ชันอนุกรม.begin()
- พารามิเตอร์เดียวของมันคือความเร็ว ความเร็วจะต้องได้รับการตกลงกันในด้านการส่งและรับล่วงหน้า เนื่องจากโปรโตคอลการรับส่งข้อมูลเป็นแบบอะซิงโครนัส ในตัวอย่างที่กำลังพิจารณา ความเร็วคือ 9600bps

  1. มีการใช้ฟังก์ชันสามฟังก์ชันในการเขียนค่าไปยังพอร์ต:อนุกรม.write()
  2. – เขียนข้อมูลไปยังพอร์ตในรูปแบบไบนารีอนุกรม.พิมพ์() อาจมีความหมายได้หลายอย่าง แต่ทั้งหมดนี้มีไว้เพื่อแสดงข้อมูลในรูปแบบที่มนุษย์สามารถอ่านได้ ตัวอย่างเช่น หากข้อมูลที่ระบุเป็นพารามิเตอร์ที่จะถ่ายโอนถูกเน้นด้วยเครื่องหมายคำพูด โปรแกรมเทอร์มินัลจะเอาต์พุตโดยไม่มีการเปลี่ยนแปลง หากคุณต้องการแสดงค่าในระบบตัวเลขเฉพาะ คุณต้องเพิ่มคำบริการ: BIN - ไบนารี, OCT - ฐานแปด, DEC - ทศนิยม, HEX - เลขฐานสิบหก ตัวอย่างเช่น,.
  3. อนุกรมพิมพ์(25,HEX)อนุกรม.println() – เขียนข้อมูลไปยังพอร์ตในรูปแบบไบนารีทำสิ่งเดียวกันกับ

ในการตรวจสอบการทำงานของโปรแกรมจำเป็นต้องให้คอมพิวเตอร์มีโปรแกรมเทอร์มินัลที่รับข้อมูลจากพอร์ต COM Arduino IDE มีสิ่งนี้ในตัวอยู่แล้ว หากต้องการเรียก ให้เลือก Tools->Port Monitor จากเมนู หน้าต่างของยูทิลิตี้นี้ง่ายมาก:

ตอนนี้คลิกปุ่มรีบูต MK จะรีบูตและแสดงตาราง ASCII:

ให้ความสนใจกับโค้ดส่วนนี้:

ถ้า (สัญลักษณ์ = = 126 ) ( ในขณะที่ (จริง) ( ดำเนินการต่อ ; ) )

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

การส่งคำสั่งจากพีซี

ก่อนที่จะดำเนินการนี้ คุณต้องเข้าใจวิธีการทำงานของพอร์ต COM ก่อน
ประการแรก การแลกเปลี่ยนทั้งหมดเกิดขึ้นผ่านบัฟเฟอร์หน่วยความจำ นั่นคือเมื่อคุณส่งบางสิ่งจากพีซีไปยังอุปกรณ์ ข้อมูลจะถูกวางไว้ในส่วนหน่วยความจำพิเศษบางส่วน ทันทีที่อุปกรณ์พร้อม อุปกรณ์จะอ่านข้อมูลจากบัฟเฟอร์ ฟังก์ชั่นนี้ช่วยให้คุณตรวจสอบสถานะบัฟเฟอร์ได้ Serial.ใช้ได้()- ฟังก์ชันนี้ส่งคืนจำนวนไบต์ในบัฟเฟอร์ หากต้องการลบไบต์เหล่านี้ คุณต้องใช้ฟังก์ชัน อนุกรม.อ่าน()- ลองดูว่าฟังก์ชันเหล่านี้ทำงานอย่างไรโดยใช้ตัวอย่าง:

ค่า int = 0 ;

การตั้งค่าเป็นโมฆะ() ( Serial.begin(9600 ) ; ) void loop() ( if (Serial.available() > 0 ) ( val = Serial.read() ; Serial.print(" ฉันได้รับ: " ) ; Serial. เขียน(วาล) ; เมื่อโค้ดถูกโหลดลงในหน่วยความจำของไมโครคอนโทรลเลอร์แล้ว ให้เปิดมอนิเตอร์พอร์ต COM พิมพ์อักขระหนึ่งตัวแล้วกด Enter ในช่องข้อมูลที่ได้รับคุณจะเห็น:“ฉันได้รับ: X” ที่ไหนแทนเอ็กซ์
จะเป็นตัวละครที่คุณป้อน โปรแกรมจะหมุนวนอย่างไม่มีที่สิ้นสุดในวงหลัก ในขณะที่เขียนไบต์ไปยังพอร์ต ฟังก์ชัน Serial.available() จะใช้ค่า 1 นั่นคือตรงตามเงื่อนไข Serial.available() > 0 อนุกรม.อ่าน()- ฟังก์ชั่นถัดไป
การใช้มอนิเตอร์พอร์ต COM ในตัวของ Arduino IDE มีข้อจำกัดบางประการ เมื่อส่งข้อมูลจากบอร์ดไปยังพอร์ต COM สามารถจัดระเบียบเอาต์พุตในรูปแบบใดก็ได้ และเมื่อส่งจากพีซีไปยังบอร์ดอักขระจะถูกส่งตามตาราง ASCII ซึ่งหมายความว่าเมื่อคุณป้อนอักขระ "1", "00110001" จะถูกส่งผ่านพอร์ต COM ในรูปแบบไบนารี (นั่นคือ "49" ในรูปแบบทศนิยม)
มาเปลี่ยนโค้ดกันสักหน่อยแล้วตรวจสอบคำสั่งนี้:

ค่า int = 0 ;

การตั้งค่าเป็นโมฆะ() ( Serial.begin(9600 ) ; ) void loop() ( if (Serial.available() > 0 ) ( val = Serial.read() ; Serial.print(" ฉันได้รับ: " ) ; Serial. println(วาล, BIN);

หลังจากดาวน์โหลดในมอนิเตอร์พอร์ตเมื่อส่ง "1" คุณจะเห็นคำตอบ: "ฉันได้รับ: 110001" คุณสามารถเปลี่ยนรูปแบบเอาต์พุตและดูว่าบอร์ดยอมรับอะไรกับอักขระอื่นๆ

ควบคุมอุปกรณ์ผ่านพอร์ต COM

แน่นอนว่าการใช้คำสั่งจากพีซีทำให้คุณสามารถควบคุมฟังก์ชันต่างๆ ของไมโครคอนโทรลเลอร์ได้ ดาวน์โหลดโปรแกรมที่ควบคุมการทำงานของ LED:

ค่า int = 0 ;
การตั้งค่าเป็นโมฆะ() ( Serial.begin(9600 ) ; ) void loop() ( if (Serial.available() > 0 ) ( val = Serial.read() ; if (val= = "H" ) digitalWrite(13 , สูง); ถ้า (val= = "L" ) digitalWrite(13 , LOW) )