ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer
ในบทความนี้จะโบกมือลาให้กับการนับลูปที่ยาวและน่าเบื่อ เราปล่อยให้ตัวจับเวลาภายในทำหน้าที่ในการนับให้เป็นอิสระจากการดำเนินการของโปรแกรม
ความรู้เบื้องต้นเกี่ยวกับฮาร์ดแวร์จับเวลา
ตัวจับเวลาในตัว (exact: timer/counter, TC0) เป็นส่วนประกอบฮาร์ดแวร์ภายในที่ใช้บ่อยที่สุด ในฐานะที่เป็นองค์ประกอบที่หลากหลายจึงมีโหมดต่างๆมากมายขึ้นอยู่กับความต้องการของเรา เราจะใช้ตัวจับเวลาในการอธิบายในภายหลังดังนั้นในการอธิบายครั้งต่อไปเราจะใช้ตัวจับเวลานี้ในโหมดต่างๆเพื่อควบคุม LED
อุปกรณ์ AVR ที่แตกต่างกันมีตัวนับจำนวนที่แตกต่างกัน สิ่งเหล่านี้มีชื่อว่า TC0, TC1 เป็นต้นเนื่องจากบางครั้งตัวจับเวลาสามารถเชื่อมต่อกับ port pins ได้ชื่อขาเหล่านั้นอ้างถึงหมายเลข TC โดย ATtiny13 มีตัวจับเวลาเพียงตัวเดียว แต่มีการใส่ศูนย์ในชื่อแม้ว่าจะไม่จำเป็นในกรณีนั้นก็ตาม
ตัวจับเวลา
TCNT ตัวจับเวลาใน AVR มีความกว้าง 8 หรือ 16 บิต พวกเขานับขึ้นหรือลงในบางโหมด โดย 8 บิตจะนับจากทศนิยม 0 ถึง 255 และ 16 บิตตั้งแต่ 0 ถึง 65,535 ถ้าเกินขีดจำกัด สูงสุด จะกลับเริ่มต้นใหม่อีกครั้งที่ศูนย์ และสถานะการนับที่แท้จริงโดยการอ่านพอร์ต TCNT (8 บิต) หรือพอร์ต TCNTH และ TCNTL (16 บิต) สามารถเขียนได้เช่นกันและตัวจับเวลาจะนับจากสถานะที่เปลี่ยนแปลงนี
แหล่งกำเนิดพัลส์ของตัวจับเวลา
มีแหล่งที่มาที่แตกต่างกัน 7 แหล่งเพื่อเชื่อมต่อตัวจับเวลาด้วยพัลส์ (และ 8 แหล่งเพื่อปิดการจับเวลา / การนับ) 3 บิตในพอร์ตควบคุมตัวจับเวลา B, TCCRB ควบคุมแหล่งที่มาที่ใช้ ทั้ง 3 บิตควบคุมมัลติเพล็กเซอร์ที่มีอินพุต 8 ตัวและควบคุมสัญญาณนาฬิกาจับเวลา
แหล่งที่มาที่แตกต่างกัน 8 แหล่ง ได้แก่ :
# | Bin | Mode | Clock source |
---|---|---|---|
0 | 000 | Off | No signal, counting off |
1 | 001 | Timer | Controller clock |
2 | 010 | Timer | Controller clock divided by 8 |
3 | 011 | Timer | Controller clock divided by 64 |
4 | 100 | Timer | Controller clock divided by 512 |
5 | 101 | Timer | Controller clock divided by 1,024 |
6 | 110 | Counter | external pin T, falling edge |
7 | 111 | Counter | external pin T, rising edge |
ตัวจับเวลาเริ่มต้นด้วยนาฬิกาควบคุมเป็นแหล่งสัญญาณ
ldi R16,1 ; R16 to 1
out TCCR0B,R16 ; to control port B
ตัวจับเวลาหยุดลง คำสั่ง “OUT” เขียนทั้ง 8 บิตไปยังพอร์ต
ldi R16,0 ; R16 to zero
out TCCR0B,R16 ; to control port B
จับเวลาและเปรียบเทียบ
เปรียบเทียบเวลาและการนับทั้งหมดจะมีความรู้สึก จำกัด ก็ต่อเมื่อเราอ่าน TCNT แบบวนซ้ำและตอบสนองต่อค่าบางค่า สำหรับงานนี้ตัวจับเวลามีตัวเปรียบเทียบสองตัว สิ่งเหล่านี้เปรียบเทียบสถานะปัจจุบันของ TCNT กับค่าโปรแกรมใน OCRA และ OCRB หากค่า TCNT ตรงกับฟังก์ชันฮาร์ดแวร์บางอย่างเหล่านั้นสามารถตั้งโปรแกรมได้หรือตัวควบคุมสามารถขัดจังหวะได้
ตัวจับเวลาในโหมด CTC
CTC การใช้ตัวเปรียบเทียบที่ชัดเจนคือการใช้การเปรียบเทียบเพื่อเริ่มจับเวลา / ตัวนับใหม่ โหมดการนับนี้เรียกว่า “clear timer on Compare” หรือ CTC ด้วยความละเอียดของตัวจับเวลา / ตัวนับตามความยาวที่ต้องการ (ต่ำกว่าแปด / สิบหกบิตแน่นอน)
โปรดทราบว่าการจับคู่การเปรียบเทียบจะรีเซ็ตตัวนับ a) หากการแข่งขันเกิดขึ้นและ b) ชีพจรการนับถัดไปเกิดขึ้น เพื่อให้แน่ใจว่าระยะเวลานั้นแน่นอนและไม่ขึ้นอยู่กับความเร็วของการรับรู้การจับคู่เปรียบเทียบ ในตัวอย่างการลงทะเบียนเปรียบเทียบถูกตั้งค่าเป็น 9 โดยที่ CTC จะรีเซ็ตด้วยการนับสิบ (พัลส์ 0 ถึง 9 = 10 พัลส์)
CTC เป็นไปได้กับตัวจับเวลาทั้งหมดที่ใช้การจับคู่เปรียบเทียบ A เปรียบเทียบการจับคู่ B จากนั้นสามารถใช้เพื่อวัตถุประสงค์อื่นได้ อุปกรณ์ AVR บางรุ่นมีพอร์ตเพิ่มเติมที่สามารถใช้เป็นการเปรียบเทียบการจับคู่สำหรับ CTC โดยปล่อยให้เปรียบเทียบการจับคู่ A และ B เพื่อวัตถุประสงค์อื่น
การจัดการตัวจับเวลาของขาเอาต์พุต
การใช้พอร์ตการจับคู่เปรียบเทียบบ่อยครั้งที่สองคือการตั้งค่าหรือล้างพอร์ตพิน ด้วยการที่ตัวจับเวลา / ตัวนับสามารถสร้างพัลส์ไฟฟ้าบนขาพอร์ตของระยะเวลาที่ต้องการและการจับคู่เปรียบเทียบจะปรากฏให้เห็นด้านนอก สำหรับ ATtiny13 สามารถตั้งโปรแกรมพินพอร์ต PB0 เพื่อติดตามการเปรียบเทียบการจับคู่ A (ชื่อพินของพอร์ตหากตั้งโปรแกรมด้วยวิธีนั้น: OC0A), PB1 เชื่อมต่อเพื่อเปรียบเทียบการจับคู่ B (OC0B) ในการเปิดใช้งานการเปรียบเทียบการจับคู่ต้องกำหนดค่า PB0 เป็นเอาต์พุต (เช่นด้วย sbi DDRB, DDB0) และเพื่อเลือกโหมดพินที่มีบิตควบคุมสองตัว:
COM0A1 COM0B1 | COM0AO COM0B0 | Function OC0A/OC0B |
---|---|---|
0 | 0 | No change on port pin |
0 | 1 | Port pin changes its polarity at Compare Match (Toggle) |
1 | 0 | Port pin clears at Compare Match |
1 | 1 | Port pin sets at Compare Match |
โปรดทราบว่าสิ่งนี้ใช้สำหรับโหมดจับเวลา / การนับปกติ ในโหมดอื่นบิตควบคุมมีความหมายต่างกัน
ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer
รายการอุปกรณ์
- 1. ATtiny13 ATTINY13A-PU 8-bit AVR
- 2. Jumper (M2M) cable 20cm Male to Male
- 3. USBasp USBisp AVR Programmer
- 4. VAR 10Pin to 6Pin Adapter Converter
- 5. Breadboard 700 Points SYB-120
- 6. หลอดไฟ LED 5mm สีแดง
- 7. รีซิสเตอร์ 220 OHM 1/4W 5%
- 8. Jumper (M2M) cable 10cm Male to Male
ขั้นตอนการทํางาน
1 : โปรแกรมแรก เปิดไฟ LED
โปรแกรมแรกของ การใช้งานไมโครคอนโทรลเลอร์ ซึ่งเป็นหนึ่งในโปรแกรมที่ง่ายที่สุดเท่าที่จะเป็นไปได้ในการเขียนภาษาโปรแกรมต่างๆ เพราะฉะนั้นโดยธรรมเนียมปฏิบัติแล้ว มักจะใช้ในการตรวจสอบว่าเขียนภาษาโปรแกรมได้ถูกต้องหรือระบบมีการประมวลผลที่ถูกต้อง และมักถูกใช้เป็นตัวอย่างที่ง่ายที่สุดในการแสดงผลลัพธ์ของการเขียนโปรแกรม โดยทำตามตามขั้นตอนลิงค์ด้านล่าง
2 : จับเวลาพร้อมการทำงานมาตรฐาน
โหมดที่ง่ายที่สุดในการตั้งโปรแกรมไฟกะพริบคือการปล่อยให้ตัวจับเวลานับเป็น 255 พร้อมกับพรีสเกลเลอร์สูงสุดที่มี (1,024) เพื่อเปรียบเทียบกับ 255 และสลับขาเอาต์พุต OC0A ด้วยเหตุนี้ความถี่การกะพริบที่
1,200,000 / 1,024 / 256/2 = 2.29 cs / s
ผลลัพธ์ : LED กระพริบเร็วกว่าที่ควรจะเป็น แต่อยู่ในช่วงที่มองเห็นได้แล้ว แต่เรียบง่าย
โค้ด Timer to blink a LED
ขั้นแรกจะเปลี่ยน PB0 เป็นเอาต์พุต จากนั้นเขียน 255 ไปยังพอร์ต Compare A กำหนดขาเอาต์พุตไปที่โหมด Toggle และเริ่มจับเวลาด้วยค่า Prescaler เป็น 1,024
; ---------- Registers ----------------
.def rmp = R16 ; Multi purpose register
;
; ---------- Timing -------------------
; Internal RC-Oscillator = 9,600,000 Hz
; Clock prescaler CLKPR = 8
; Internal contr. clock = 1,200,000 Hz
; TC0 precaler = 1,024
; TC0 tick = 1,171.875 cs/s
; TC0 cycle = 256
; TC0 single cycle = 4.578 cs/s
; TC0 toggle frequency = 2.289 cs/s
;
; ---------- Start --------------------
; PB0 as output
sbi DDRB,DDB0 ; PB0 as output
; Select Compare Match
ldi rmp,0xFF ; Match at 255
out OCR0A,rmp ; to Compare Match A
; toggle PB0 at Compare Match
ldi rmp,1<<COM0A0 ; Toggle Mode
out TCCR0A,rmp ; to control port A
; Start timer
ldi rmp,(1<<CS02)|(1<<CS00) ; prescaler 1024
out TCCR0B,rmp ; to control port B
Loop:
rjmp Loop
คำสั่ง OUTเขียนแปดบิตในรีจิสเตอร์ไปยังพอร์ตที่กำหนด
ตามลำดับการเริ่มต้นไม่จำเป็นต้องใช้คอนโทรลเลอร์อีกต่อไปสำหรับการควบคุม เขาถูกส่งไปยังลูปไม่ จำกัด (โปรดจำไว้ว่า: ตัวควบคุมไม่สามารถทำอะไรได้) โปรดทราบว่านี่เป็นวิธีการแก้ปัญหาที่หรูหรากว่าการนับลูปซึ่งคุณจะเห็นได้ว่ามันสั้นกว่ามาก และคลายตัวควบคุมจากการควบคุมทำให้ง่ายต่อการเพิ่มงานเพิ่มเติมโดยขัดจังหวะการทำงาน Timing
คุณสมบัติพิเศษอย่างหนึ่งที่ต้องเรียนรู้ที่นี่ เราจำเป็นต้องใช้มันตั้งแต่ตอนนี้ในซอร์สโค้ดแต่ละอันดังนั้นเราควรเรียนรู้สิ่งนี้ ด้วยการกำหนด “ldi rmp, 1 << COM0A0” บิตพอร์ต COM0A0 ในพอร์ต TCCR0A จะต้องถูกตั้งค่าเป็นหนึ่ง COM0A0 เป็นบิต 6 ในพอร์ตนี้ เราสามารถกำหนดสิ่งนี้สำหรับเช่น “ldi rmp, 0b01000000” (0b ถูกเพิ่มเพื่อบ่งบอก ว่าค่าต่อไปนี้เป็นเลขฐานสอง) การอ่านโค้ดว่าไบนารี 01000000 หมายถึงอะไรและเราจะต้องดูรายชื่อพอร์ตในฐานข้อมูลอุปกรณ์อีกครั้ง ดังนั้นการกำหนด “ldi rmp, 1 << COM0A0” จึงสะดวกและเข้าใใจง่ายกว่ามาก การกำหนดหมายถึง:
- หาไบนารี 1 นั่นคือ 0b00000001
- เลื่อนไปทางซ้ายหกครั้ง (COM0A0 หมายถึง 6) << หมายถึง “เลื่อนไปทางซ้าย” โดยการใส่ศูนย์ไปทางขวา
- การเปลี่ยนแปลงนี้นำไปสู่ 0b01000000 ในที่สุด
จำเป็นอย่างยิ่งที่จะต้องเข้าใจว่าการเปลี่ยน shifting จะกระทำในระหว่างการ Assembling เท่านั้นไม่ใช่ภายในตัวควบคุม คำสั่ง shift ของคอนโทรลเลอร์คือ “LSL” (Logical Shift Left) และมีรีจิสเตอร์เป็นพารามิเตอร์ที่จะเลื่อนไปทางซ้ายหนึ่งครั้ง ดังนั้นอย่าสับสนระหว่างการคำนวณแอสเซมเบลอร์ภายในกับสิ่งที่คอนโทรลเลอร์ทำ
ในทำนองเดียวกันในบรรทัดต้นทาง “ldi rmp, (1 << CS02) | (1 << CS00)” จะใช้การดำเนินการ shift-left ในกรณีนี้ผลลัพธ์สองรายการของการดำเนินการกะสองครั้งคือ ORED (“|”) ดังนั้นสองบิตภายในรีจิสเตอร์จึงถูกตั้งค่าพร้อมกัน CS02 คือ 2 ในขณะที่ CS00 เป็นศูนย์ ดังนั้น 0b00000100 (1 << CS02) และ 0b00000001 (1 << CS00) จึงเป็นบิตหรือเพื่อให้ได้ 0b00000101 ในที่สุดค่านี้จะถูกเขียนไปยัง register rmp แอสเซมเบลอร์ภายในหรือต้องไม่สับสนกับคำสั่ง OR ที่ OR สองรีจิสเตอร์และเขียนผลลัพธ์ไปยังอันแรก | ทำในระหว่างขั้นตอนการ assembly เท่านั้น
อักขระ << และ | เป็นตัวดำเนินการทางคณิตศาสตร์ของแอสเซมเบลอร์ซึ่งมีตัวดำเนินการต่อไปเช่น +, -, * และ / ทั้งหมดนี้เป็นคำสั่งของแอสเซมเบลอร์ โดยที่ตัวควบคุมไม่ทราบ
credit : http://www.avr-asm-tutorial.net/avr_en/micro_beginner/4_Led_Timer/4_Led_Timer.html
<<< #3 Blink ไฟกระพริบ LED บทความก่อนหน้า | บทความต่อไป #5 ปรับความสว่าง LED ด้วย PWM >>>