ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer

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

ความรู้เบื้องต้นเกี่ยวกับฮาร์ดแวร์จับเวลา


ตัวจับเวลาในตัว (exact: timer/counter, TC0) เป็นส่วนประกอบฮาร์ดแวร์ภายในที่ใช้บ่อยที่สุด ในฐานะที่เป็นองค์ประกอบที่หลากหลายจึงมีโหมดต่างๆมากมายขึ้นอยู่กับความต้องการของเรา เราจะใช้ตัวจับเวลาในการอธิบายในภายหลังดังนั้นในการอธิบายครั้งต่อไปเราจะใช้ตัวจับเวลานี้ในโหมดต่างๆเพื่อควบคุม LED

อุปกรณ์ AVR ที่แตกต่างกันมีตัวนับจำนวนที่แตกต่างกัน สิ่งเหล่านี้มีชื่อว่า TC0, TC1 เป็นต้นเนื่องจากบางครั้งตัวจับเวลาสามารถเชื่อมต่อกับ port pins ได้ชื่อขาเหล่านั้นอ้างถึงหมายเลข TC โดย ATtiny13 มีตัวจับเวลาเพียงตัวเดียว แต่มีการใส่ศูนย์ในชื่อแม้ว่าจะไม่จำเป็นในกรณีนั้นก็ตาม


ตัวจับเวลา

ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer


TCNT ตัวจับเวลาใน AVR มีความกว้าง 8 หรือ 16 บิต พวกเขานับขึ้นหรือลงในบางโหมด โดย 8 บิตจะนับจากทศนิยม 0 ถึง 255 และ 16 บิตตั้งแต่ 0 ถึง 65,535 ถ้าเกินขีดจำกัด สูงสุด จะกลับเริ่มต้นใหม่อีกครั้งที่ศูนย์ และสถานะการนับที่แท้จริงโดยการอ่านพอร์ต TCNT (8 บิต) หรือพอร์ต TCNTH และ TCNTL (16 บิต) สามารถเขียนได้เช่นกันและตัวจับเวลาจะนับจากสถานะที่เปลี่ยนแปลงนี

แหล่งกำเนิดพัลส์ของตัวจับเวลา


มีแหล่งที่มาที่แตกต่างกัน 7 แหล่งเพื่อเชื่อมต่อตัวจับเวลาด้วยพัลส์ (และ 8 แหล่งเพื่อปิดการจับเวลา / การนับ) 3 บิตในพอร์ตควบคุมตัวจับเวลา B, TCCRB ควบคุมแหล่งที่มาที่ใช้ ทั้ง 3 บิตควบคุมมัลติเพล็กเซอร์ที่มีอินพุต 8 ตัวและควบคุมสัญญาณนาฬิกาจับเวลา

ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer


แหล่งที่มาที่แตกต่างกัน 8 แหล่ง ได้แก่ :

#BinModeClock source
0000OffNo signal, counting off
1001TimerController clock
2010TimerController clock divided by 8
3011TimerController clock divided by 64
4100TimerController clock divided by 512
5101TimerController clock divided by 1,024
6110Counterexternal pin T, falling edge
7111Counterexternal 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
00No change on port pin
01Port pin changes its polarity at Compare Match (Toggle)
10Port pin clears at Compare Match
11Port pin sets at Compare Match

โปรดทราบว่าสิ่งนี้ใช้สำหรับโหมดจับเวลา / การนับปกติ ในโหมดอื่นบิตควบคุมมีความหมายต่างกัน

ภาษาแอสเซมบลี ไฟกระพริบ ด้วย Timer



รายการอุปกรณ์


ขั้นตอนการทํางาน

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 >>>