Pico W โครงการ #1 ทดลองประดิษฐ์ Pico Echo Sounder จากทรานสดิวเซอร์ Airmar DT800

ผมว่างเว้นจากไม่ได้จับบอร์ดไมโครคอนโทรลเลอร์ไปพักใหญ่หลายปี เมื่อสิบกว่าปีที่แล้วเคยจับ Arduino เขียนโค้ดด้วยภาษาซี ก็สนุกดีได้ความรู้พอสมควร มาในปัจจุบันเป็นยุคของไอโอที (iOT : Internet of Thing) เป็นยุคของอินเทอร์เน็ตของสิ่งของที่ไม่ใช่อินเทอร์เน็ตของมนุษย์

สร้าง Echo sounder จากทรานสดิวเซอร์ Airmar DT800

มีโอกาสมาจับบอร์ด Raspberry Pi Pico W เพราะต้องการเอาทรานสดิวเซอร์ Airmar DT800 ที่ผมซื้อมาเพื่อจะทำเรือรีโมทแต่โครงการล้มไปก่อน อาจจะมารื้อฟื้นอีกทีก็ได้ ในตัวทรานสดิวเซอร์ Airmar DT800 ข้างในฝังด้วยชิปวงจรที่แปลงค่าความลึกที่อ่านได้จากทรานสดิวเซอร์ แล้วส่งความลึกมาตามสายข้อมูล RS485 แล้วมีสายไฟฟ้า DC 12V สองเส้นไปเลี้ยงวงจรด้วย ตอนซื้อตอนนั้นราคาประมาณเก้าพันกว่าบาท ปัจจุบันราคาอยู่ที่ประมาณหกพันถึงเจ็ดพันบาท

สเป็คของ Airmar DT800

คุณสมบัติของทรานสดิวเซอร์ ทำงานที่ความถี่ 200 Khz หยั่งที่ความลึกได้ตั้งแต่ 0.5 เมตร ถึง 100 เมตร ส่วน Accuracy ความลึก ผู้ผลิตไม่ให้ข้อมูลไว้ ใช้ไฟฟ้ากระแสตรง 10-25V ส่งข้อมูล NMEA 0183 ความลึกออกมาตามสายข้อมูลด้วยด้วย $SDDBT, $SDDPT และอุณหภูมิด้วย $YXMTW ผ่านทางสายข้อมูลยาวประมาณ 10 เมตร ด้วยอนุกรมแบบซีเรียล RS485 ตามสเป็คของ RS485 แล้วสามารถส่งข้อมูลได้ถึง 1 กิโลเมตร (บางตำราบอกว่าถึง 3 กม.)

จุดประสงค์ของโครงการ

ความต้องการคือต้องการแสดงผลความลึกที่ส่งมาตามสาย RS485 ดักจับข้อมูลแล้วแสดงผลความลึกบนจอ LCD ขนาดเล็กๆ ในขณะเดียวกันก็สามารถจัดเก็บไฟล์ลง SD Card ได้แบบเรียลไทม์ และความต้องการต่อไปคือเอาข้อมูลความลึกส่งออกไปยัง serial port ผ่านหัวต่อ DB9 หากต้องการนำข้อมูลเข้าคอมพิวเตอร์โปรแกรมต่างๆเช่น Hypack, HydroPro หรือ Hydromagic

ความต้องการอีกอย่างที่ต้องการคืออัพโหลดข้อมูลเข้าคลาวด์แบบ Thingspeak แต่ดูราคาแล้วคงไม่ไหว ส่วนที่พอจะทำได้คือส่งข้อมูลไฟล์จาก SD card เข้า Web hosting ที่ผมมีอยู่แล้ว

บอร์ดไมโครคอนโทรลเลอร์ Raspberry PI Pico W

คุณสมบัติของบอร์ด Raspberry Pi Pico W ที่ผมคัดลอกมาจากอินเทอร์เน็ตดังนี้ “เป็นบอร์ด Raspberry Pi ในซีรีย์ Pico ที่เพิ่มการเชื่อมต่อเครือข่ายแบบไร้สายผ่านทาง Wireless LAN 2.4 GHz 802.11n โดยยังคงใช้ RP2040 เป็น Dual ARM Cortex-M0+ ความเร็วสัญญาณนาฬิกาสูงสุดที่ 133 MHz มี SRAM ขนาด 264 KB และมี Flash Memory ขนาด 2 MB มี GPIO จำนวนรวม 26 ขา (digital-only 23 / analog 3) รองรับ SPI I2C ADC UART ทำงานที่ระดับแรงดัน 3.3 โวลต์”

เป็นบอร์ดไมโครคอนโทรลเลอร์ราคาถูกมาก ประมาณสามร้อยบาทต้นๆ ถ้าซื้อบอร์ดโคลนจากจีนราคาประมาณสองร้อยบาทแต่เสี่ยงกับใช้ไม่ได้ สามารถโปรแกรมได้ด้วยไมโครไพทอน (โปรแกรมด้วยภาษาซีก็ได้)

หน้าที่ของบอร์ดไมโครคอนโทรลเลอร์คือเป็นบอร์ดที่สามารถโปรแกรมให้มันควบคุมอุปกรณ์อื่นๆได้ ตัวบอร์ดเองมี CPU มีหน่วยความจำ (Memory) มีช่องทางติดต่ออุปกรณ์ภายนอก (Port) ไว้สำหรับนำข้อมูลเข้าและออก ช่องทางเดินสัญญานข้อมูล (BUS) และวงจรกำเนิดสัญญานนาฬิกาเป็นการกำหนดความถี่สูงหรือต่ำ ถ้าสูงก็ทำให้ไมโครคอนโทรลเลอร์ทำงานได้เร็วขึ้น

Echo sounder แบบเชิงพานิชย์ในลักษณะคล้ายกัน

สำหรับโครงการต้นแบบเป็น Echo sounder ยี่ห้อ Ohmex Sonarmite เขาใช้ทรานสดิวเซอร์ของ Airmar รุ่น P66 ที่เขาใช้เฟิร์มแวร์ที่สามารถเข้าไปตั้งค่าให้ทรานสดิวเซอร์ได้ แต่ตัว Echo sounder ไม่มีหน้าจอแสดงความลึกแต่ส่งข้อมูลความลึกเข้าคอมพิวเตอร์ได้อย่างเดียว

หลักการทำงานของ Pico Echo Sounder

ไดอะแกรมที่สร้างจากโปรแกรม Fritzing ที่ผมซื้อประมาณสามร้อยกว่าบาท เริ่มจาก Airmar DT800 ส่งความลึกในรูปแบบ NMEA Depth $SDDPT และ $SDDBT ส่วนข้อมูลอุณหภูมิ $YXMTW จะทิ้งไปไม่นำมาใช้งาน ข้อมูลความลึกจะถูกส่งเข้าบอร์ด RS485 (ชิป Max485) ที่ทำหน้าที่แปลงสัญญานข้อมูลให้กับบอร์ดพิโค ในรูปแบบโปรโตคอล UART แล้วโปรแกรมบนบอร์ดพิโค จะทำการแยกข้อมูลสตริงความลึกออกมา เมื่อได้ความลึกจะส่งไปแสดงผลที่จอ LCD ผ่านโปรโตคอลแบบ I2C ในขณะเดียวกันโปรแกรมบนบอร์ดจะคำนวณหาเวลาขณะนั้นแล้วบันทึกข้อมูลความลึกและเวลาลง SD Card ผ่านโปรโตคอล SPI และโปรแกรมบนบอร์ดพิโคจะทำการสร้างสตริงข้อมูล $SDDBT ที่มีการแปลงความลึกจากหน่วยฟุตเป็นหน่วยเมตร เพื่อให้ข้อมูลมี accuracy เพิ่มขึ้นและส่งข้อมูลผ่านโปรโตคอล UART ไปออกบอร์ด RS323 (ชิป Max3232) สามารถเอาไปเข้าคอมพิวเตอร์ได้

พื้นฐานการสื่อสารแบบอนุกรม

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

  • แบบซิงโครนัส (Synchronous) เป็นการสื่อสารที่ใช้สายสัญญาณข้อมูลอย่างน้อย 1 เส้น และมีสายอีก 1 เส้นกำหนดจังหวะ (clock) การรับข้อมูล ข้อดีของการสื่อสารแบบนี้คือการรับส่งข้อมูลมีความผิดพลาดน้อยหรือไม่มีความผิดพลาดเลย โดยโปรโตคอลที่ทำงานแบบซิงโคนัสได้แก่ I2C และ SPI
  • แบบอะซิงโครนัส (Asynchronous) เป็นการสื่อสาร Full Duplex รับและส่งข้อมูลบิตได้สองทิศทางพร้อมกันและไม่อาศัยสัญญานนาฬิกา (clock) การส่งข้อมูลทำได้ที่ละหนึ่งไบต์ (แปดบิต) โดยอาศัยสัญญาณจากบิตเริ่มต้น และบิตสิ้นสุดในการบอกจังหวะการรับส่งข้อมูล โปรโตคอลที่ทำงานแบบอะซิงโคนัสคือ UART โดยใช้สายสัญญานเพียงสองเส้นสำหรับขาข้อมูลสำหรับส่งและรับ ได้แก่ Tx และ Rx

ต่อไปมาทำความเข้าใจกับโปรโตคอลสามประเภทที่กล่าวไปแล้วคือ I2C, SPI และ UART

UART (Universal Asynchronous Receiver and Transmitter) เป็นการสื่อสารอนุกรมแบบอะซิงโคนัส ใช้ขาสัญญาน 2 ขาคือ Tx กับ Rx ละเพื่อให้สามารถส่งข้อมูลได้ไกลจึงมีการนำมาตรฐานRS232 และ RS485 มาใช้ร่วมด้วย

I2C (Inter-Integrated Circuit)เป็นการสื่อสารแบบอนุกรม สามารถส่งข้อมูลแบบ half-duplex ได้ ใช้ช่อง 2 สายคือ Serial Data (SDA) สำหรับรับส่งข้อมูล และ Serial Clock (SCL) สำหรับส่งสัญญาณ clock โดยมีตัว Master จะเป็นตัวกำหนดค่าความถี่ clock ส่งไปยัง slave ตัวอื่นๆ ผ่านทางสาย SCL และข้อมูลการสื่อสารระหว่าง Master และ Slave จะถูกส่งผ่านทางสาย SDA

SPI (Serial peripheral interface)เป็นการสื่อสารแบบอนุกรมที่สามารถส่งข้อมูลแบบ full-duplex โดยที่การทำงานในรูปแบบที่ให้อุปกรณ์ตัวหนึ่งทำหน้าที่เป็น Master ในขณะที่อีกตัวหนึ่งทำหน้าที่เป็น Slave ซึ่ง Master และ Slave สามารถส่งข้อมูลไปกลับหากันได้ การสื่อสารแบบ SPI ไม่มีการกำหนดแอดเดรส แต่ Master จะเป็นตัวควบคุมการส่งข้อมูลโดยเป็นกำหนดการเรียกใช้งานขา SS ที่ต้องการสื่อสาร ซึ่งขึ้นอยู่กับผู้ใช้งานเป็นคนกำหนดเอง

การสื่อสารแบบอนุกรมในบอร์ด Pico Echo sounder

เมื่อมองในภาพรวมของโครงการ ชุดวงจร Pico Echo sounder จะใช้การสื่อสารแบบอนุกรมทั้งสามรูปแบบคือ

  • UART ใช้สำหรับนำข้อมูลความลึกผ่าน RS485 to TTL เข้าบอร์ด Pico และนำความลึกที่ผ่านการปรับแต่งให้ละเอียดจากบอร์ด Pico ออกไปยัง RS322 เพื่อออกไปยังคอมพิวเตอร์
  • การสื่อสารแบบ SPI ใช้กับ SD Card
  • การสื่อสารแบบ I2C ใช้กับจอ LCD ขนาด 16×02 พิกเซล
การต่อวงจรในเบื้องต้นบน Breadboard เพื่อทดสอบ

โปรแกรมมิ่งด้วยไมโครไพทอน

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

บอร์ดไมโครคอนโทรลเลอร์ Raspberry Pi Pico W นับว่าเป็นบอร์ดที่ราคาถูกที่สุด สามารถเขียนต่ออินเทอร์เน็ตเพราะมีวงจรไวไฟกับบลูทูธติดมาในตัว การซื้อถ้าสามารถหาของแท้ได้ อาจจะมีราคาแพงกว่าบอร์ดพวกโคลน (Clone) ทั้งหลายแต่รับประกันว่าใช้งานได้ บอร์ดโคลนที่ผมซื้อจากจีนใช้งานไม่ได้ ผมสามารถเคลมขอคืนเงินได้ โดยที่แพล็ตฟอร์มซื้อขายของออนไลน์คงเห็นว่าราคาไม่มาก ก็เลยผ่านให้แบบง่ายๆ

ไลบรารีไมโครไพทอน

สิ่งสำคัญที่ขาดไม่ได้เลยคือไลบรารี ในส่วนไลบรารีหลักๆผู้ผลิตได้ฝังมาให้ในบอร์ดแล้วเช่น machine, utime ส่วนที่ขาดได้แก่ไลบรารีติดต่ออุปกรณ์เช่นจอ LCD, sd card, wifi, bluetooth และอื่นๆมีคนเขียนไว้ใน github อยู่มากมายไม่ต้องดิ้นรนเขียนเอง เราสามารถนำไลบรารีเหล่านี้มารวม (wrap up) แล้วเขียนโค้ดเพิ่มเติมอีกนิดหน่อย ดังเช่นโครงการ Pico Echo sounder ที่ผมทำอยู่

Pico Echo Sounder ต้นแบบ

ส่วนตัวกล่อง ผมเลือกซื้อจากออนไลน์ราคาประมาณหกสิบบาท นำมาตัดเจาะด้วยสว่านเพื่อให้เปิดเป็นช่องให้ LCD รวมถึงช่องข้อมูลเข้าจาก RS485 และช่องข้อมูลออก RS232 และอีกช่องคือช่องสาย USB รอยตัดดูไม่ดีนัก ถ้าจะทำกันจริงๆให้สวยงามต้องปริ๊นท์จาก 3D printer น่าจะดีที่สุด

ทดสอบอุปกรณ์อ่านความลึกบนจอ LCD

การทดสอบผมใช้ทรานสดิวเซอร์ Airmar DT800 ต่อไฟฟ้าด้วยแบตเตอรี Lipo ขนาด 4 เซลล์ 11.1 โวลท์ แต่ที่วัดได้จริงๆขณะชาร์จเสร็จคือ 13.2 V สามารถนำมาใช้ได้เพราะทรานสดิวเซอร์สามารถรับได้จาก 10V-25V นำสายข้อมูล A และ B ที่ไวริ่งไว้ต่อเป็นหัวแจ๊คขนาด 2.5มม. เข้าแจ๊คตัวผู้ ในขณะเดียวกันจะมีแจ๊คตัวเมียขนาดเดียวกันรับสัญญานแล้วนำไปจ่ายให้วงจร RS485 to TTL

ส่วนไฟเลี้ยงบอร์ดวงจรใช้ powerbank USB ต่อเข้าผ่านสาย USB จากนั้นนำทรานสดิวเซอร์ไปลงแท๊งค์น้ำนี้ที่บ้าน แล้วเฝ้าดูหน้าจอ LCD แสดงความลึก เท่าที่ดูค่าความลึกทั้งที่ระดับแท๊งค์น้ำไม่มีการเปลี่ยนแปลงแต่ค่าระดับที่อ่านได้แกว่งไปประมาณ +/- 3 ซม. ต่อจากนั้นดึงสายขึ้นลงเพื่อให้ความลึกเปลี่ยนแล้วทดสอบดูความลึกที่จอ LCD อีกครั้ง ผลก็ยังรับได้

ทดสอบต่ออุปกรณ์กับโน๊ตบุ๊คผ่านโปรแกรม Hypack

โปรแกรมด้าน Bathymetric survey ชั้นนำระดับโลกล้วนแล้วแต่สามารถอ่านสตริงความลึกในรูปแบบ NMEA depth กันได้ทั้งนั้น ตัวอย่างสตริง: $SDDBT,1330.5,f,0405.5,M,0221.6,F*2E ซึ่งสามารถอธิบายได้ดังนี้

Field#ExampleDescription
11330.5ความลึก
2fหน่วยฟุต f : feet
3405.5ความลึก
4Mหน่วยเมตร M : Meter
5221.6ความลึก F : Fathom
62Echecksum แบบ XOR ทั้งประโยค

เมื่อนำคอมพิวเตอร์โน๊ตบุ๊คเปิดโปรแกรม Hypack ทำการทดสอบต่อกับ Pico Echo sounder ด้วยการเลือกไดรเวอร์ nmea.dll ที่ไดอะล๊อกซ์เลือกความลึกแบบ $SDDBT ตั้งค่า Port ด้วยพารามิเตอร์ 4800 8-None-1 ที่คอมพิวเตอร์มี USB to serial ทำการทดสอบอ่านค่าก็ผ่านไปด้วยดี ผมเห็นสตริง $SDDBT ปรากฎขึ้นมาเป็นจังหวะตาม baud rate ที่ผมตั้งไว้ ข้อควรระวังสำหรับความลึกเป็นความลึกจากหัวทรานสดิวเซอร์ ไม่ใช่ความลึกจากผิวน้ำ ดังนั้นมันจะมีค่า draft ที่เราต้องใส่เข้าไปเพื่อให้เป็นความลึกจากผิวน้ำ

ที่ยังไม่แสดงให้ดูคือ sd card เนื่องจากผมยังไม่เปิดช่องให้สามารถเสียบ sd card ได้ เพราะวงจรเกือบทั้งหมดอยู่บน breadboard ที่ไม่มั่นคงนัก การกดอาจจะทำให้วงจร sd card ล้มได้ การจะเปิดเอา sd card ออกมาต้องเปิดฝากล่องอย่างเดียวครับ

ผมเสียดายที่ Airmar DT800 รุ่นนี้ทางผู้ผลิตไม่ได้ออก API เพื่อให้เราสามารถตั้งค่า Draft ความเร็วเสียงในน้ำได้ (Sound velocity) ดังนั้น Echo sounder ที่ทดลองประดิษฐ์นี้จึงเหมาะที่จะเอาไปใช้ในน้ำตื้น ความลึกไม่เกิน 25 เมตร และไม่ควรนำไปใช้ในงานที่ต้องการความละเอียดสูงๆ (Survey grade)

สำหรับโค้ดโปรแกรมไมโครไพทอนผมตั้งใจว่าจะเผยแพร่ ตอนนี้ได้จัดระเบียบแล้วนำไปฝาก Github ไว้ให้เข้าไปดูได้ง่ายๆ ตามลิ๊งค์นี้ https://github.com/pbroboto/Pico-Echo-Sounder/tree/main

โค้ดไมโครไพทอน

ผมแสดงโค้ด main.py ให้ดูพอเป็นเบื้องต้น ผมได้ดัดแปลงโค้ด micropygps เพื่อเพิ่มประโยค NMEA คือ PVTMA, SDDBT และ SDDPT เพื่อประมวลผลความลึกน้ำจาก echo sounder

from machine import UART
from machine import Pin, I2C, SPI
import time
import array
from micropygps import MicropyGPS
from lcd_api import LcdApi
from pico_i2c_lcd import I2cLcd
from sdcard import SDCard
import uos
import wificonfig
import network
import ntptime
from utime import gmtime, time, sleep
import rp2

def crc_calc(start_bit_, addr, datalen_, data_0, data_1, data_2, stop_bit_):
    crc = datalen_ ^ addr
    crc = crc ^ data_0
    crc = crc ^ data_1
    crc = crc ^ data_2
    crc = 255 - crc
    if crc == start_bit_ or crc == stop_bit_:
        crc = crc + 1
    return crc

def processData(nmea_sentence):
    nmea = MicropyGPS()
    for x in nmea_sentence:
        nmea.update(x)
    if (nmea.valid_sentence):
        if (nmea.gps_segments[0] == 'SDDPT'):
            #lcd.move_to(0, 0)            
            #lcd.putstr("Found $SDDPT... ")
            #lcd.move_to(0, 1)            
            #lcd.putstr(f"{nmea.depth_meter}m.")
            return (nmea.nmea_sentence, nmea.depth_meter,
                    nmea.depth_unit)            
        elif (nmea.gps_segments[0] == 'SDDBT'):
            lcd.move_to(0, 0)            
            lcd.putstr("Found $SDDBT... ")
            val_feet = float(nmea.depth_feet)
            val_meter = 0.3048 * val_feet
            nmea.depth_meter2 = "%.2f" % val_meter
            lcd.move_to(0, 1)            
            lcd.putstr(f"Depth: {nmea.depth_meter2}m.")
            return (nmea.nmea_sentence, nmea.depth_feet,
                    nmea.depth_unit1, nmea.depth_meter,
                    nmea.depth_unit2, nmea.depth_fathom,
                    nmea.depth_unit3)    

    else:
        return None
    
class RS485Serial():
    
    def __init__(self,id=1,baudrate=4800,tx=Pin(8), rx=Pin(9), ctrl_pin=Pin(12,mode=Pin.OUT),timeout=0):
        self.uart= UART(id,baudrate=baudrate,tx=tx,rx=rx,timeout=timeout)
        self.ctrl_pin = ctrl_pin
        self.char_time_ms = 10000 # baudrate 
        if self.ctrl_pin != None:
            self.ctrl_pin.value(0)
 
    def read(self, count=1):
        return self.uart.read()
        
        
    def any(self):
        return self.uart.any()
        

    def write(self, dataString):
        if self.ctrl_pin:
            self.ctrl_pin.value(1)
        self.uart.write(bytes(dataString)) #,"utf-8"))
        while not self.uart.txdone():
            machine.idle()
        if self.ctrl_pin:
            time.sleep_ms(1 + self.char_time_ms)
            self.ctrl_pin.value(0)
        #flush transmitted stuff from rcv
        nb = self.uart.any()
        self.uart.read(nb)

def calc_chksum(raw_nmea):
    # Input raw_nmea is a sentence without $ and *.
    # Initializing our first XOR value
    csum = 0 
    
    # For each char in chksumdata, XOR against the previous 
    # XOR'd char.  The final XOR of the last char will be our 
    # checksum to verify against the checksum we sliced off 
    # the NMEA sentence
    
    for c in raw_nmea:
       # XOR'ing value of csum against the next char in line
       # and storing the new XOR value in csum
       csum ^= ord(c)
    
    return hex(csum)

def build_nmea_sddbt(field_data):
    depth_feet = float(field_data[1])
    depth_meter = depth_feet * 0.3048
    str_meter = "%.2f" % depth_meter
    fdata = list(field_data)
    fdata[3] = str_meter
    #$SDDBT,1.8,f,0.5,M,0.3,F*09
    raw_nmea = ",".join(fdata)
    print(f"raw nmea: {raw_nmea}")
    csum = calc_chksum(raw_nmea)
    print(f"check sum: {csum}")
    return f"${raw_nmea}*{csum[2:].upper()}\r\n"

    
def getnow(UTC_OFFSET=+7):
    return gmtime(time() + UTC_OFFSET * 3600)

#Builtin Led
led =  Pin('LED', Pin.OUT)

#Max3232 RS323 to TTL
uart0 = UART(0, baudrate=4800, bits=8, parity=None, stop=1, tx=Pin(16), rx=Pin(17))

I2C_ADDR     = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16

i2c = I2C(1, sda=Pin(6), scl=Pin(7), freq=100000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)    
sleep(1)
lcd.clear()
lcd.move_to(0,0)
lcd.putstr("Pico Echosounder")
lcd.move_to(0,1)
lcd.putstr("...")

# Connect to network
rp2.country('TH')
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

# Fill in your network name (ssid) and password here:
ssid = wificonfig.ssid
password = wificonfig.password
wlan.connect(ssid, password)
wlan.active(True)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
  if wlan.status() < 0 or wlan.status() >= 3:
    break
  max_wait -= 1
  print('waiting for connection...')
  sleep(1)
 
# Handle connection error
if wlan.status() != 3:
   raise RuntimeError('network connection failed')
else:
  print(f'Connected to {ssid}')
  status = wlan.ifconfig()
  print( 'IP = ' + status[0] )
 
#set time by sync NTP
try:
    ntptime.settime()
except:
    raise Exception("npttime.settime() failed. No network connection.")
dt = getnow()
print(f"dt: {dt}")
#now = (dt[0],dt[1],dt[2],1,dt[3],dt[4],dt[5],dt[6])
#print(f'now: {now}')

#Max485
uart1 = RS485Serial(1,ctrl_pin=Pin(12,mode=Pin.OUT),timeout=1)

#SD Card
spi = SPI(0,
          baudrate=1000000,
          polarity=0,
          phase=0,
          bits=8,
          firstbit=machine.SPI.MSB,
          sck=Pin(2),
          mosi=Pin(3),
          miso=Pin(4))
cs = Pin(1)
sd = SDCard(spi, cs)
fs = uos.VfsFat(sd)
uos.mount(sd, '/sd')
print(uos.listdir('/sd/es'))

while True:
    dt = getnow()
    d = "{0:4d}{1:02d}{2:02d}".format(dt[0],dt[1],dt[2])
        
    with open(f'/sd/es/es{d}.txt', 'a') as file:
        while uart1.any() > 0:  
            rxData1 = uart1.read()
            #uart0.write(rxData0)
            try:
                strings = rxData1.decode('utf-8')
                sentences = strings.split("\r\n")
                nmeas = list(filter(None, sentences))
            except:
                print('Error! cannaot decode UTF-8.')
            else:
                if not(nmeas is None):
                    #print(f"NMEA: {nmeas}")
                    for nmea in nmeas:
                        field_data = processData(nmea)
                        if (not (field_data is None)):
                            if (len(field_data) == 3):
                                print("Found $SDDPT NMEA...")
                                #led.on()
                                #thingspeak.WriteMultipleFields(field_data)
                                #file.write(','.join(field_data))
                                #file.write('\n')
                                #file.flush()
                                print(f"data 1: {field_data}")
                                #led.off()
                                #sleep(0.5)
                            if (len(field_data) == 7):
                                led.on()
                                print("Found $SDDBT NMEA...")
                                print(f"data 2: {field_data}")
                                new_nmea = build_nmea_sddbt(field_data)
                                print(f"new nmea: {new_nmea}")
                                uart0.write(new_nmea)
                                file.write(','.join(field_data))
                                file.write('\n')
                                file.flush()                                
                                led.off()

สำหรับโครงการที่สองเป็นการนำบอร์ด Pico W ไปต่อกับเครื่องวัดระดับน้ำ (Tide gauge) อ่านระดับน้ำแล้วยิงค่าขึ้นคลาวด์ โครงการนี้ความจริงเป็นโครงการแรกสุดแต่ติดปัญหาที่ข้อมูลสตริงความลึกจาก Tide gauge ที่ออกมาในรูปแบบ RS232 ปรากฎว่าบอร์ดวงจร Pico W ไม่ยอมอ่านสตริงนี้ยังไม่ทราบปัญหาที่แน่ชัดและกำลังแก้ปัญหานี้อยู่ โปรดติดตามบทความตอนต่อไปครับ

Leave a Reply

Your email address will not be published. Required fields are marked *