Fig.1 STC8G1k08A SOP8 body. |
หลังจากได้ลองเล่น 8051 มาสักระยะ ก็รู้สึกดีกับ 8051 ตอนลองใช้งานรับส่งข้อมูลผ่าน RS485 protocol นี่ไม่ขึ้น error เลย เทียบกับ Arduino มันก็มี error บ้าง ต้องปรับต้องจูนเหมือนกัน (จริงๆ มันก็อยู่ที่โค้ดอ่ะนะ เขียนไม่ดีมันก็ error สิ ก็ลองทั้งสองด้วยทักษะที่มี แล้วก็เทียบด้วยความรู้สึก)
ติดความสะดวกในการใช้งานไลบรารี่ของ Arduino จะหันมาใช้ 8051 มันต้องใช้เวลาทำความเข้าใจ ซึ่งก็ยากแก่การเข้าใจพอดู พอทำไม่ได้ก็จะเกิดอาการเบื่อหน่าย หนีไม่พ้นต้องอ่านคู่มือที่เป็นภาษาอังกฤษ
ตอนเล่น Arduino ไม่ค่อยเฉียดไปยุ่งกับ interrupt เท่าไหร่ ใช้มากหน่อยก็ตอนที่ใช้ save mode ,wdt แต่พอหันมาลองเล่น 8051 มันต่างกัน ต้องยุ่งกับ interrupt บ่อยขึ้น ก็กลายเป็นเรื่องปกติ
วันนี้ได้ลองเอา mcu STC8G1K08A มาต่อเข้ากับ HMI แล้วสั่งงานจาก HMI ลองทำเป็น DO ชิพรุ่นนี้มี GPIO 6 ขา แต่ต้องเสียขาไปทำ Rx, Tx และ MAX485 Flow control เหลือใช้งานสุดท้ายแค่ 3 ขาเอง Series STC8G นี้มีเกือบทุก package ยกเว้น DIP40 รุ่นนี้น่าใช้รองจาก STC8H แต่ก็น่าใช้มากกว่า Series STC8F เพราะมี uart 2 (จะมีใน package 16 ขาขึ้นไป ) มี timer 3 และมี ADC
Fig.2 Pinout and wiring for HMI connected. |
การติดต่อกับ HMI จะใช้ RS485 protocol ซึ่งมันต้องจัดการกับ uart และถ้าใช้ interrupt แทน polling ก็ต้องจัดการกับ interrupt ด้วย
จะใช้ uart ต้องเลือก mode แล้วก็ต้องเลือกว่าจะใช้ timer ไหนเป็นตัวกำหนด baudrate
8051 uart เมื่อมีการรับข้อมูลทางขา Rx จะมี flag register RI คอยบอกว่าการรับเสร็จสิ้นหรือยัง ส่วนการส่งข้อมูลทางขา Tx จะมี register TI ทำหน้าที่บอกสถานะการส่ง
เมื่อรับข้อมูล 1 byte เสร็จแล้ว flag RI จะถูกเซตหรือว่ามี logic 1 ซึ่งต้องถูกรีเซตด้วย software ก็ใช้คำสั่ง RI = 0 เพื่อรอรับข้อมูลถัดไป เช่นเดียวกันฝั่่งการส่งข้อมูล TI ก็คล้ายกันนี้
Fig.3 STC8G1K08A DIP8 body that STC not recommended to use (refer to manual STC8G-En.pdf version date update 2022/3/9 on page 15). |
Fig.4 Test communicating. |
MCU 8G1K08A แบบ 8 ขานี้ ถึงแม้จะไม่มี Enhanced PWM แต๋ก็ยังมี PCA อยู่ 3 ชุด คือ CCP0,CCP1,CCP2 เอาไว้ใช้ทำ software timer รวมถึงยังเอาไว้ทำ hi speed output ได้ด้วย ถ้าใช้ PCA ในการทำ PWM โดยมันมี 3 ขา สำหรับ CCP0, CCP1 และ CCP2 ตามรูป
Fig.5 CCPn pin. |
จะใช้ CCAPM0 ในการทำตัวจับเวลา มีรีจิสเตอร์ที่เกี่ยวข้องตามนี้
CCAPM0, CCON, CMOD, CL, CH, CCAP0L, CCAP0H, CCF0 และ CR
เมื่อเริ่มต้นจับเวลา ต้องทำการกำหนดค่าเปรียบเทียบให้กับ CCAP0L, CCAP0H เมื่อ mcu ทำงานแต่ละรอบจะเก็บค่าไว้ใน CH, CL จนมันเท่ากันกับตัวเปรียบเทียบ เมื่อนั้นจะเกิดการ interrupt ขึ้น จากนั้นเราก็กำหนดค่าให้กับตัวเปรียบเทียบอีก เป็นแบบนี้วนๆ ไป เราต้องรู้ว่าแต่ละรอบของ machine cycle นั้นกินเวลาเท่าใด มันคือ 12T หมายถึง 1 machine cycle และก็ใช้สัญญาณนาฬิกา 12 ลูก
เนื่องจากเป็นระบบ 12T มันก็ใช้ความถี่ FOSC / 12 ตัวอย่างเช่น ระบบกำหนดสัญญาณที่ 18.432MHz
18,432,000 Hz / 12 = 1,536,000 Hz
คาบเวลาดังกล่าว มันเป็นส่วนกลับของความถี่ นั่นคือ
1 / 1,536,000 = 0.65104us
0.65104us คือ เวลาที่ใช้ทำงาน 1 cycle (12 clock pulse)
แล้ว 1ms มันต้องทำงานกี่รอบกัน?
1 รอบการทำงานใช้เวลา 0.65104us
ทำ x รอบ จะได้เวลา 1ms (1ms มันเท่ากับ 1000us)
x/1 = 1000us / 0.65104us
x = 1536 รอบ
สรุปว่าต้องให้ mcu ทำงาน 1536 รอบจะใช้เวเลา 1ms
ค่า 1536 (600H) นี้จะต้องถูกกำหนดให้กับรีจิสเตอร์ CCAP0L, CCAP0H ในกรณีที่ต้องการจับเวลา 1ms
และต้องเข้าใจว่า ว่าเป็น 16bit timer นั่นหมายถึงจำนวนรอบการทำงานไม่เกิน 65535
ส่วนการกำหนดค่าทำดังนี้
CCAP0L = 0x600;
CCAP0H = 0x600>>8;
Arduino จะมีความถี่ของ PWM ราวๆ 490Hz นั่นคือมันจะมีคาบเวลาของ 1 pulse อยู่ที่ 1/490 = 2.04 ms ( 1 ลูกคลื่นใช้เวลา 2.04 มิลลิวินาที)
ถ้าเราทำ PWM โดยที่ 1 ลูกคลื่นมีคาบเวลา 1ms จะได้ว่า PWM นั้นมีความถี่ 1/0.001s = 1000Hz
การสั่งให้ขา P32 เป็น analog output (โดยการทำ PWM) ทำประมาณนี้
void main(){
CCON = 0x00;
CMOD = 0x00;
CL = 0x00;
CH = 0x00;
CCAPM0 = 0x4d; //ใช้โมดูล 0 และเป็น hi speed output
t = 768; // 1536 / 2
CCAP0L = t;
CCAP0H = t>>8;
t += 768;
CR = 1; //start capture
EA = 1; //enable global interrupt
while();
}
ถ้าไม่ทำไรเพิ่ม เราก็จะได้ PWM 50%duty เราก็ควรจัดการปรับเวลาของการเกิด logic 1 , logic 0 เพื่อให้ได้ %duty ตามต้องการ จะต้องทำใน interrupt service routine (ISR)
เราก็ดูว่าเมื่อไหร่ที่มันมี logic 0 เราก็ให้เป็น logic 0 นานเท่าที่เราต้องการ
และที่สำคัญคือ ผลรวมของเวลาที่เป็น logic 0 และ logic 1 เมื่อรวมกันต้องได้ 1ms (ตามตัวอย่างได้ 1536) เพราะจะได้ความที่ 1000Hz
void pca_isr() interrupt 7 {
CCF0 = 0; //clear flag
if(P32 == 0)
{
t += 1536*0.05; // (1536*0.05 = 77) มันจะเป็น logic 0 เท่ากับ 5/100 ms
CCAP0L = t;
CCAP0H = t>>8;
} else
{
t += 1536*0.95; // (1536*0.95 = 1459) มันจะเป็น logic 1 เท่ากับ 95/100 ms
CCAP0L = t;
CCAP0H = t>>8;
}
}
Fig.6 PCA making PWM on P32 |
เราตั้งเวลาตอนมันเป็น logic 0 ให้มีค่า 5% ของ 1ms (จำนวน 77 รอบ) จากนั้นพอ mcu ทำงานครบ 77 รอบ จะเกิด interrupt อีกครั้ง เนื่องจากมันอยู่ในโหมด hi speed output (CCAPM0 = 0x4d) รอบนี้มันจะมี logic 1 ซึ่งเราได้กำหนดให้มันต้องทำงานอีก 1459 รอบ เมื่อครบแล้วก็เกิด interrupt รอบใหม่อีก พร้อมกับมี logic 0 วนๆ ไป
โปรดสังเกตุว่ามันเกิด interrupt 2 ครั้ง ในช่วงเวลา 1 ms ถ้าเราเอาตัวแปรนับจำนวนมาใส่ใน ISR เราก็ได้ timer 1ms ไว้ใช้งาน
ไม่มีความคิดเห็น:
แสดงความคิดเห็น