->> หมวดหมู่และหัวข้อบทความ << คลิ๊ก
บันทึกช่วยจำ และความเข้าใจส่วนตัว ATmega328P
--กำลังศึกษาอยู่ครับ มันเป็นแค่บันทึกช่วยจำส่วนตัวครับ ผมสนใจอะไรก็จะบันทึกลงไป อาจไม่มีประโยชน์อะไรแก่ผู้อ่าน และไม่ได้ครอบคลุมทั้งหมด แค่ผมอยากจะขอรื้อฟื้นความจำหน่อยแต่ก่อนเล่นแต่ AT89LP4052 (MCS-51) สัก8-9ปีที่แล้ว ตอนนั้นเขียนด้วยภาษา ASM ด้วย ตอนนี้สนใจตัวนี้ ก็เลยอ่านซะหน่อย เผื่อเอามาประยุกต์ใช้งานส่วนตัวได้ เพราะมีเห็นลงบอร์ดจากเมืองจีนแล้วถูกมากๆ ไม่ได้เอามาขายนะครับ หาซื้อได้ตามร้านทั่วไปที่ลงบอร์ดแล้วที่ฮิตๆกันที่เรียกว่า Arduino UNO อะไรนี่แหละ แก่แล้วขอรื้อฟื้นความจำนิดนุง--
ถ้าท่านผู้อ่านไม่มีพื้นความรู้ทางด้านไมโครคอนโทรลเลอร์เลย แนะนำให้หาหนังสืออ่านก่อนนะครับ โดยเฉพาะพื้นฐานเรื่องสถาปัตยกรรมของไมโครโปรเซสเซอร์ เรื่องดิจิตอล จากนั้นก็ต้องพอมีพื้นฐานการเขียนโปรแกรมอีก(อันนี้พอดีได้พื้นฐานจากการเรียนที่ลาดกระบังไม่ว่าอยู่ภาคไหนเขาก็บังคับเรียนหมด) การเรียนแบบซื้อวงจรมาต่อเล่นเลยแล้วค่อยๆหาทางแก้ไปมันเป็นการเรียนแบบไม่มีพื้นฐานความรู้จะต่อยอดก็ยากครับสุดท้ายก็ต้องกลับไปเรียนใหม่อยู่ดี แต่เดิมผมศึกษา MCS-51 กว่าจะเข้าใจ1MCUอ่านหนังสือไม่ต่ำกว่า5-6เล่ม อ่านดาต้าชีทภาษาอังกฤษของMCUที่เราสนใจก็ต้องอ่านหมดแทบทุกบรรทัด (พอดีผมจบทางด้านเครื่องกล ไม่ใช่ภาคคอมพิวเตอร์หรืออีเล็กทรอนิกส์) แล้วก็ต้องหาบอร์ดมาทดลองเล่นดูของผมเริ่มที่ของ [?site]ETT ครับ เมื่อไม่เข้าใจก็เขียนคำถามไว้เองแล้วก็ต้องไปค้นเองมาตอบเอาเองนะครับ
-ATmega328/P หาอ่านได้ที่ เว็บไซต์ผู้ผลิตครับ ATmega328P Atmel page
ซึ่งข้อความหรือรูปภาพหรือการระบุหน้าอ้างอิงส่วนใหญ่อยู่ใน [?pdf ]Atmega328/P ถ้าเป็นpdf อย่างอื่นก็จะระบุชื่ออื่นนะครับ
Feature
.
ระบบภายใน ATmega328P ภาพตัดจาก pdf ของผู้ผลิต
.
pin ชนิด 28ขา หรือขาแต่ละขา สั่งหรือรับอะไรได้บ้าง ของ ATmega328p ตัดมาจาก pdf ของผู้ผลิต
.
pinชนิด32ขา มีขา ADC เพิ่มมาให้ใช้อีก2ขา(ADC6-7)รวมกันเป็น 8ขาที่รับแปลงอนาล็อกได้ รู้สึกว่ามีบางเจ้าขายบอร์ดรุ่น32ขาจากจีนถูกมาก ถือว่าได้เปรียบครับอันนี้ ภาพขา ATmega328P ตัดจากpdf ของผู้ผลิต
.
สถาปัตยกรรมทางการอ่านเขียนคิดคำนวนและการชี้ข้อมูล มีรีจิสเตอร์ที่สามารถดำเนินการทางคณิตศาสตร์ได้ทันทีถึง 32ตัว*8บิท ในที่นี้มี 6ตัว เข้าใจว่าเป็น R26-31 เป็น รีจิสเตอร์ 16บิท 3ชุด สำหรับเป็นตัวชี้อ้างอิงที่อยู่ข้อมูลโปรแกรมแบบอินไดเร็ค แต่ละที่อยู่ของคำสั่งในโปรแกรมโดยคำสั่งที่บรรจุอยู่ในโปรแกรมเมมโมรี่แบบแฟลชส่วนใหญ่ใช้อย่างน้อย2byte หรือ 16บิท ถึง4byte หรือ32บิท
เมื่อเกิดการอินเตอรัพหรือขัดจังหวะโปรแกรมเช่นมีการเรียกโปแกรมอื่นซ้อนเข้ามาค่าตัวชี้ที่อยู่โปรแกรมหรือpc จะถูกเก็บเข้า SP หรือ stack pointer ในSRAMเอาไว้ก่อนกระโดดไปที่อื่น จำนวนโปรแกรมที่เรียกซ้อนได้ถูกจำกัดตามขนาดแรมที่จองพื้นที่เอาไว้ เหมือนกับMCUทั่วไป
.
ลองสำรวจพื้นที่แรมที่ให้มา พบว่า
--รีจิสเตอร์ที่ใช้ในการคำนวนทางคณิตศาสตร์ได้ทันที 32ตัว ใช้คำสั่งภาษาเครื่องจะสั้นกว่าปรกติคือไม่เกิน2ไบท์*8 ส่วนใหญ่ เรียกรีจิสเตอร์เหล่านี้ว่า General purpose working register ซึ่งเมื่อดำเนินการทางคณิตสาตร์ใดๆบนรีจิสเตอร์เหล่านี้ จะมีสถานะบิทพิเศษที่บอกผลการดำเนินการให้ทราบในกรณีต่างๆเช่น มีตัวทด overflow
--รีจิสเตอร์ 64 I/O อันนี้มันI/Oข้างในหรือเปล่า? สามารถเรียกใช้งานแบบไดเร็ก แต่มีข้อสงสัย IN/OUT อีก 32 ตัวต่างหากหรือเปล่า? เพราะaddrคนละที่กัน ภาษาอังกิดบอกว่า 64 addresses for CPU peripheral functions as Control Registers, SPI, and other I/O functions. รวมความแล้วเป็นรีจิสเตอร์ที่เรียกใช้งานได้โดยตรง 0x20-0x5F เช่นกัน
รีจิสเตอร์ 160 I/O Ext ข้างนอกมันหมายความว่าไงหว่า? this device has Extended I/O space from 0x60 - 0xFF in SRAM where only the ST/STS/STD and LD/LDS/LDD instructions can be used. คงหมายความว่าMCUสามารถต่อ เรียกI/Oข้างนอกเพิ่มได้ 160ตำแหน่ง แต่ก็ยังไม่เข้าใจอยู่ดีว่าใช้อะไร?? แต่ต้องใช้คำสั่งพิเศษในการอ้างอิงและย้ายข้อมูลแบบอินไดเร็กแอดเดรส
LD Rd, X Load Indirect Rd ← (X)
คำสั่งการโหลดข้อมูลที่ใช้รีจิสเตอร์ 16bitคือ R26,R27
ชี้ข้อมูลที่ตำแหน่ง(X) นำข้อมูลมาเก็บไว้ที่ Rd คือ R1-R25 เป็นต้น
การนำข้อมูลI/O ที่คำนวนแล้วส่งออกไป ก็อาศัยคำสั่งเช่น
ST X, Rr Store Indirect (X) ← Rr
ก็ต้องอาศัยรีจิสเตอร์พ็อตเตอร์ X หรือ Y,Z แล้วแต่คำสั่งที่
ใส่ลงไป ในการชี้ตำแหน่งปลายทางที่เก็บข้อมูล
ส่วนอินเทอนัลSRAM 2048byte วิธีการอ้างอิงที่อยู่คงใช้คำสั่งอ้างอิงที่อยู่แบบอินไดเรค เช่นคำสั่ง ST/STS/STD and LD/LDS/LDD เข้าใจว่างั้นนะ
ในอินเทอนัลแรม ยังต้องกันพื้นที่สำหรับ Stack Pointer ซึ่งมันเป็นพื้นที่ความจำชั่วคราวที่เก็บทั้งข้อมูลหรือที่อยู่เมื่อถูกเรียกโปรแกรมย่อย การเรียกโปรแกรมย่อยตัวชี้ข้อมูลจะใส่เข้าไปใหม่หรือถูกกระโดดซึ่งก่อนกระโดดตำแหน่งของข้อมูลเดิมจะถูกเก็บไว้ในบริเวณที่เรียกว่าสแตกพ็อยเตอร์ ซึ่งเขากำหนดมาว่าตำแหน่งเริ่มต้นควรเก็บในแรมในที่อยู่ที่ตำแหน่งสูงๆ เช่น0x08FF?อย่างงี้เปล่าหว่า?ยังไม่แน่ใจตรงนี้นะว่าตำแหน่งสูงๆหมายถึงตำแหน่งไหน? เมื่อถูกเรียกด้วยคำสั่ง CALL ที่อยู่เดิมจะถูกดันไปเก็บหรือพุชเข้าไปที่ตำแหน่งดังกล่าว ซึ่งที่อยู่เดิมจะถูกใส่ลงในstack ดังกล่าวและลดค่าตำแหน่งของstack ลงไปเรื่อยๆ เมื่อเข้าไปในโปรแกรมย่อย (ข้อมูลที่อยู่ในรีจิสเตอร์ที่ใช้ประจำเดิมในเส้นทางเดิมก็สามารถเก็บลงสแต็กได้เช่นกัน แต่ต้องเรียกคืนตามลำดับให้ถูกชนิดใส่ลงไปก่อนก็เรียกคืนก่อนเป็นต้น) เมื่อโปรแกรมย่อยเสร็จจะถูกคำสั่ง RET หรือกระโดดกลับไปตำแหน่งที่เคยมา ก็นำที่อยู่ในstackคืนกับเข้าพ๊อยเตอร์ เรียกว่าป๊อปและกระบวนการป๊อปเกิดขึ้นตำแหน่งสแต็กจะถูกเพิ่มไปสองค่า
การใช้คำสั่ง PUSH Rr หมายถึงให้เก็บข้อมูลขนาด8บิทจาก Rr เช่นR1 ลงไปใน stack ตำแหน่งสแต็กจะลดลง1ค่าเอง พอจะเรียกคืนก็เรียก POP Rd ก็เรียกคืนข้อมูลในสแต็กและตำแหน่งสแต็กจะเพิ่มขึ้นหนึ่งค่าเป็นต้น
.
ต่อไปเป็น Program memory หรือที่เก็บโปรแกรมแบบแฟลชที่มีขนาด 32k*8 แต่เนื่องจากชุดคำสั่ง1คำมีจำนวนเวิร์ด(word,คำสั่ง)อย่างน้อย1เวิร์ด(MCU Atmega328p อ่านคำสั่งทีละ16บิท หรือ2byte*8bit จึงถือว่ามันกินหรืออ่านคำสั่ง1คำมีจำนวนบิท8บิท ซึ่งพวกตระกูล51อ่านทีละ8บิท คำนิยามเรื่องเวิร์ดในที่นี้คือ 1 เวิร์ดคือ2byte*8bit หรือ16บิท) ฉะนั้นผู้ผลิตMCUตัวนี้จึงออกแบบการอ้างอิงที่อยู่โปรแกรมเป็นแบบ 16K*16 แทน จึงอ้างอิงที่อยู่ได้16,384 ตำแหน่ง แต่ละตำแหน่งจะเก็บข้อมูล1เวิร์ด,16bitแทน ซึ่งเอาไว้เก็บโปรแกรมหรือเก็บข้อมูลก็ได้ พบว่าส่วนหนึ่งถูกกันเอาไว้ใช้งานเกี่ยวกับระบบบูทภายในของMCU เอง ฉะนั้นแล้วตัวชี้ตำแหน่งโปรแกรม หรือ PC หรือโปรแกรมเค้าเตอร์ จึงใช้งานได้ 14 bit หรืออ้างอิงตำแหน่งได้เพียง 16,384 ตำแหน่งดังที่กล่าวไปแล้ว (เข้าใจว่าแต่ละค่าที่อยู่ในPC ปรกติจะใช้รีจีสเตอร์ที่ทำหน้าที่เหมือนกับรีจิสเตอร์Z และจะมีบิทต่ำสุดลงท้ายด้วย0เท่านั้น ซึ่งMCUจะอ้างอิงที่อยู่PCในลักษณะอิงบิทเพจและอิงบิทเวิร์ด32เวิร์ดในแต่ละหน้าซึ่งการทำงานจริงๆไม่ได้อธิบายอย่างชัดเจน แต่การโปรแกรมด้วยคำสั่งSPM อธิบายชัดเจนว่าใช้รีจิสเตอร์Zในการส่งตำแหน่งที่ต้องการเขียน โดยอนุมาน) ฉะนั้นแล้วการอ้างอิงของที่อยู่ของPC จึงไม่ใช่ 32K*8 แต่เป็นในลักษณะ16k*16bit
แต่การดึงเอาข้อมูล8บิทจากที่เก็บโปรแกรมแบบแฟลชมาใช้(เช่น ชุดข้อมูลอาเรย์ของ7-seg หรือสัญลักษณ์แปลกๆ) จะต้องอ้างอิงแบบอินไดเรกและที่อยู่ในที่เก็บโปรแกรมยังมีขนาดใช้งานเป็น 32k*8 เหมือนเดิม ใช้ชุดคำสั่งพวก LPM โดยต้องกำหนดตำแหน่งในR30(ZL) และR31(ZH) หรือ Z 16บิทรีจิสเตอร์ก่อน แล้วจึงเรียกคำสั่งดังกล่าว
LPM Load Program Memory R0 ← (Z)
ข้อมูลใดๆขนาด1byte 8bit จะถูกเก็บเข้าR0 ผ่านการชี้ข้อมูลของโดยอ้อมของZ ซึ่ง Z จะมีการชี้ตำแหน่งของบิทต่ำสุดZLSB เป็น0หรือ1ก็ได้ (ซึ่งถ้าเทียบZเป็นPC ต่างจากPCตรงบิทต่ำสุดต้องเป็น0อย่างเดียวเท่านั้น) ซึ่งวิธีการนี้ทำให้การชี้ตำแหน่งเพื่อโหลดเอาข้อมูลบนหน่วยความจำโปรแกรมทำได้ครอบคุมครบทุกไบท์-8บิทในหน่วยความจำโปรแกรม32K*8
เราลองมาดูคำสั่ง เก็บข้อมูลเข้าไปใน program memory พบว่ามีคำสั่ง
SPM Store Program Memory (Z) ← R1:R0
ระบุชัดเจนว่า เป็นการนำข้อมูล 16บิท ทีอยู่ใน R1:R0 เรียงต่อกันไป ไปเก็บไว้ที่Zชี้เอาไว้แบบโดยอ้อม ซึ่งเป็นการโปรแกรมหรือเขียนโปรแกรมลงในชิพ ซึ่งไม่ใช่ขั้นตอนการเรียกใช้งานโปรแกรมทั่วไป
ส่วนการรันข้อมูลตามปรกติก็เริ่มจากตำแหน่งข้อมูลโปแกรมPC= 0x0000H เพิ่มค่าไปเรื่อยๆแบบเป็นเลขคู่เท่านั้น(เมื่อเทียบกับเลขฐานสิบ) การจะกระโดดข้ามไปมาไปตำแหน่งอื่นก็จะกระโดดตามเงื่อนไขใดๆก็ได้ ดูที่คำสั่งเกี่ยวกับ Branch Instructions ท้ายเพจนี้
.
ข้อที่น่าสนใจต่อไปคือ มี EEPROM ขนาด 1KB ซึ่งเราหรือCPU นั้นจะติดต่อทำงานกับEEPROM อย่างไรกันแน่
เขาบอกเอาไว้ก่อนว่าต้องสนใจ 3 รีจิสเตอร์สำคัญ
1 EEPROM Address Registers, รีจิสเตอร์ที่อยู่อีอีพรอม
2 EEPROM Data Register, รีจิสเตอร์ข้อมูลอีอีพรอม
3 EEPROM Control Register รีจิสเตอร์ควบคุมอีอีพรอม
การเข้าถึงการอ่านเขียน EEPROM (หน้า36) จะทำในรีจิสเตอร์ ในบริเวณแรม ส่วนI/O registers ทำไงหว่า?
ข้องาน
กำลังอ่านอยู่ครับแล้วค่อยมาเขียนต่อ
tttt
Register Summary
ตารางข้างล่างแสดงชื่อรีจิสเตอร์และที่อยู่อ้างอิง ATmega328P
1 ตำแหน่ง 00H-1FH (R1-R31)เป็นรีจิสเตอร์ที่อ้างอิงได้โดยตรง
2 เฉพาะตำแหน่ง 20H-3FH หรือ32 I/0ใน 64 I/O สามารถอ้างอิงแบบบิท(หน้า37)ได้โดยตรงถ้าเข้าใจไม่ผิดนะอ่านแล้วก็งงเองอีก?? คือ32ใน64ตัวไบท์ต่ำ ที่เขียนว่า IN/OUT 0x0000-0x001F น่าจะหมายถึง32ตำแหน่งแรก ในโซนI/O 64ไบท์ อ่านไงก็เข้าใจว่างี้นะ ผ่านคำสั่งแบบบิท การให้0หรือ1โดยตรง เช่น
SBI P,b Set Bit in I/O Register I/O(P,b) ← 1
CBI P,b Clear Bit in I/O Register I/O(P,b) ← 0
สองคำสั่งล่างยังไม่ค่อยเข้าใจเท่าไหร่? แต่เป็นคำสั่งประเภทตรวจสอบบิทแล้วกระโดดหรือไม่
SBIC A, b Skip if Bit in I/O Register Cleared
if (I/O(A,b)=0) PC ← PC + 2(or 3) else PC+1
SBIS A, b Skip if Bit in I/O Register is Set
if (I/O(A,b)=1) PC ← PC + 2(or 3) else PC+1
3 ตำแหน่ง 20H-5FH หรือทั้งหมดใน64 I/O อ้างอิงตำแหน่งโดยตรงได้
4 รีจิสเตอร์ 60H-C7H อยู่ใน 160 I/O extension เวลานำมาใช้งานต้องอ้างอิงที่อยู่แบบอินไดเรค เด๋วอ่านอีกทียิ่งอ่านยิ่งงง??
C0H | UCSR0A | UCSR0B | UCSR0C | UBRR0L | UBRR0H | UDR0 | - | C7H | |
B8H | TWBR | TWSR | TWAR | TWDR | TWCR | TWAMR | BFH | ||
B0H | TCCR2A | TCCR2B | TCNT2 | OCR2A | OCR2B | ASSR | B7H | ||
A8H | AFH | ||||||||
A0H | A7H | ||||||||
98H | R | E | S | E | R | V | E | 9FH | |
90H | 97H | ||||||||
88H | OCR1AL | OCR1AH | OCR1BL | OCR1BH | 8FH | ||||
80H | TCCR1A | TCCR1B | TCCR1C | TCNT1L | TCNT1H | ICR1L | ICR1H | 87H | |
78H | ADCL | ADCH | ADCSRA | ADCSRB | ADMUX | DIDR0 | DIDR1 | 7FH | |
70H | TIMSK2 | 77H | |||||||
68H | PCICR | EICRA | PCMSK0 | PCMSK1 | PCMSK2 | TIMSK0 | TIMSK1 | 6FH | |
60H | WDTCSR | CLKPR | PRR | OSCCAL | 67H | ||||
^ 60H to FFH-----I/O extend ,no bit access ,no IN OUT // LD.. ST.. ok | |||||||||
58H | SPL | SPH | SREG | 5FH | |||||
50H | ACSR | DWDR | SMCR | MCUSR | MCUCR | SPMCSR | 57H | ||
48H | OCR0B | GPIOR1 | GPIOR2 | SPCR0 | SPSR0 | SPDR0 | 4FH | ||
40H | EEDR | EEARL | EEARH | GTCCR | TCCR0A | TCCR0B | TCNT0 | OCR0A | 47H |
^ -----I/O no bit access but IN OUT ok // LD.. ST.. ok | |||||||||
38H | PCIFR | EIFR | EIMSK | GPIOR0 | EECR | 3FH | |||
30H | TIFR0 | TIFR1 | TIFR2 | 37H | |||||
28H | PORTC | PIND | DDRD | PORTD | 2FH | ||||
20H | - | - | - | PINB | DDRB | PORTB | PINC | DDRC | 27H |
^ -----I/O bit access & IN,OUT with I/O space addr or name // LD.. ST.. ok | |||||||||
18H | R24 | R25 | R26(XL) | R27(XH) | R28(YL) | R29(YH) | R30(ZL) | R31(ZH) | 1FH |
10H | R16 | R | R | R | R | R | R | R23 | 17H |
08H | R8 | R | R | R | R | R | R | R15 | 0FH |
00H | R0 | R | R | R | R | R | R | R7 | 07H |
ความหมาย I/O register แต่ละไบท์และบิท
ไอโอรีจิสเตอร์ที่กล่าวถึง เป็นรีจีสเตอร์ที่เอาไว้เป็นตัวช่วยควบคุมสั่งการให้MCUทำงานตามโปรแกรมที่เราเขียนไว้ได้ตามประสงค์ ซึ่งใน ATmega328p เริ่มในที่อยู่ในSRAM 0x20-0xFF ซึ่งบางตำแหน่งไม่ได้ไม่ได้กล่าวถึงหรือสงวนจองเอาไว้ใช้ในซีพียูรุ่นอื่นๆตามสถาปัตยกรรมที่ออกแบบมาโดยเฉพาะ โดยI/O ที่อยู่ในSRAM ตั้งแต่
1. I/O SRAM address 0x20-0x5F จำนวน64ไบท์ (โดย32 ตำแหน่งแรก addr sram 0x20-0x3F สามารถใช้การติดต่อระดับบิทได้โดยใช้คำสั่ง SBI,CBI โดยมีค่าI/O space address ช่วง 0x00-0x1F เท่านั้น
ตัวอย่างเช่นรีจีสเตอร์ SREG มี sram addr=0x5F แต่มี I/O space addr=0x3F จะไม่สามารถใช้คำสั่งประเภทนี้ได้ สรุปI/O space address คือที่อยู่เชิงสัมพัทธ์สำหรับใช้ใส่ในคำสั่งเท่านั้นไม่ได้มีความหมายอย่างอื่น ) ....(และคำสั่งโหลดหรือคืนข้อมูล IN,OUT ได้โดยตรงใช้ได้ทั้งหมดทั้ง64ตำแหน่ง addr sram 0x20-0x5F จะเห็นว่า SREG ใช้คำสั่งนี้ได้) โดยการใช้คำสั่งทั้งสองประเภทต้องผ่านการให้ที่อยู่อ้างอิงโดยตรงบน I/O space address 0x00-0x3F แทน เนื่องจากชุดคำสั่งที่ออกแบบมาอย่างนั้น ถ้าต้องการติดต่อกับI/O ดังกล่าว ต้องใส่ I/O space addr โดยหาค่าได้จาก
I/O space addr = I/O sram address - 0x20
**การระบุที่อยู่ในคำสั่ง ต้องเป็นที่อยู่ใน I/O space address เท่านั้น ดูในชุดคำสั่งท้ายตารางครับ ***
2 I/O SRAM adress 0x60-0xFF จำนวน160ไบท์ที่เหลือ เป็น extended I/O เวลาติดต่อใช้งานต้องติดต่อแบบโดยอ้อมหรืออินไดเรค ผ่านตัวชี้ที่อยู่ขนาด16บิท คือ X,Y,Z ทำการโหลดข้อมูลเข้าในรีจีสเตอร์R0-R31 ด้วยคำสั่งประเภทกลุ่ม LD LDD ก่อน หรือจะโหลดโดยตรงเข้ารีจิสเตอร์คำนวนโดยใช้คำสั่ง LDS ด้วยการระบุค่าที่อยู่บน SRAM address โดยตรง ...จากนั้นทำการแก้ไขแปลงข้อมูลโดยแปลบิทตามต้องการด้วยคำสั่งอื่นๆ แล้วจึงส่งคืนกลับไปเก็บผ่านคำสั่งกลุ่มเก็บโดยตัวชี้ ST STD และเก็บโดยตรงSTS โดยการระบุที่อยู่โดยตรงบนSRAM **ที่อยู่ที่ทำการระบุในคำสั่งต้องเป็นที่อยู่ใน SRAM เท่านั้น และคำสั่งดังกล่าวสามารถใช้งานกับไบท์ทั้งหมดในSRAMด้วยที่เป็นI/Oทั้งหมด หรือไม่ก็ได้**
11121
11121
11121
11121
ต่อไปนี้ในตารางจะระบุตำแหน่งรีจีสเตอร์เป็น **SRAM Address เป็นสีน้ำตาล** ส่วน I/O Space addr ถ้ามีแสดงเป็นสีน้ำเงิน ว่าใช้คำสั่งพิเศษ IN,OUT ได้
0x5F , 0x3F , Status Register | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SREG | I | T | H | S | V | N | Z | C |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
ในส่วนสถานะของรีจิสเตอร์ทั้งหมดรวมถึงI/O เมื่อใช้งานผ่านคำสั่ง อาจมีแฟลกเกิดขึ้นดังนี้
I : Global Interrupt Enable คือถ้าเท่ากับ1 หมายถึงมีการเปิดระบบขัดจังหวะหรือรอการขัดจังหวะอยู่ เมื่อมีอินเตอรัพเกิดขึ้นMCUจะให้I=0แสดงว่าไม่รับอินเตอร์รัพอื่นๆในช่วงนี้แล้วจะโดดไปดำเนินการตามโปรแกรมย่อยทำให้จบ หลังจากRETIหรือกลับจากโปรแกรมย่อยMCUจะให้I=1 แสดงว่าพร้อมรอรับต่อไป เข้าใจว่าต้องมีการปรับค่าอินเตอร์รัพอื่นๆในบิทคอนโทรลตัวอื่น แต่global interruptก็ยังไม่ถ่องแท้ว่าหมายถึงอะไรกันแน่?เป็นการเปิดระบบรวมหรือเปล่า?
มีอินเตอรัพเกิดขึ้น MCUให้ I=0
RETI Interrupt Return PC ← STACK I=1 หลังอ่านRETI
SEI Global Interrupt Enable I=1 ใส่เอง
CLI Global Interrupt Disable I=0 ใส่เอง
T : copy storage เขาบอกว่าใช้เก็บเป็นต้นทางหรือปลายทางที่ดำเนินงานเกี่ยวกับบิท
คำสั่งที่เกี่ยงข้องกับ flag T
BST Rr, b Bit Store from Register to T
เข้าใจว่า bคือตำแหน่งบิท 0-7 ใน รีจิสเตอร์ Rr จะถูกโอนเข้าไปใน Flag T เพื่อส่งไปใช้งานต่อไป? แปลย่อว่า T ← Rr(b)
BLD Rd, b Bit load from T to Register เมื่อมีข้อมูลเก็บเข้าflag Tแล้ว เมื่อดำเนินการสั่งBLD ก็หมายถึงให้เก็บค่าแฟลกT ลงบนRdหรือรีจิสเตอร์ปลายทางที่ตำแหน่งบิทb เป็นต้น แปลโดยย่อคือ Rd(b) ← T
SET Set T in SREG T ← 1
CLT Clear T in SREG T ← 0
H : Half Carry Flag เป็นแฟลกที่เกิดขึ้นเมื่อดำเนินการเกี่ยวกับตัวเลข เช่น บวก ลบ 2's ซึ่งใช้เฉพาะเลขBCD ([?wiki]binary-coded decimal) ซึ่งนำเลขฐานสิบมาเทียบใส่ในเลขฐานสอง 2ชุด 4บิทต่ำเป็นเลขหลักหน่วย 4บิทสูงเป็นเลขหลักสิบ แต่ละบิทถ้าจะแปลงเป็นเลขฐานสิบต้องคูณด้วย8421 เรียงตามบิท เช่น
ค่า9 เลขฐานสอง= 1001 BCD= 1001
บวกอีก1 เลขฐานสอง= 1010 BCD= 0001 0000
BCD = 0001 0000 =10(เลขฐานสิบ)
ทำให้การบวกดังกล่าวมีค่าHalf carry เกิดขึ้น1ค่า จากการบวก4bit หลังนั่นเอง ผมเข้าใจว่างั้นนะ?
S : Sign Flag , S = N ㊉ V แฟลกเครื่องหมาย เกิดจากการนำflag N และ V มา exclusive or กัน (S=1เมื่อ N1V0 หรือ N0V1 อย่างใดอย่างหนึ่ง) โดยSอาจเกิดขึ้นหรือใช้ในชุดคำสั่ง บวกลบรีจีสเตอร์16บิท เช่น X,Y,Z
ADIW Rdl,K Add Immediate to Word Rdh:Rdl ← Rdh:Rdl + K
SBIW Rdl, K Subtract Immediate from Word Rdh:Rdl ← Rdh:Rdl - K
V : Two’s Complement Overflow Flag อาจเกิดขึ้นเมื่อดำเนินการคำสั่ง บวก ลบ นำมาโลจิกกัน เปรียบเทียบค่า และ การหมุนวนบิท เป็นต้น
N : Negative Flag ,หรือเกิดค่าลบ อาจเกิดขึ้นเหมือนคำสั่งในV
Z : Zero Flag , เช่น บวกลบหรือโลจิกแล้วค่าทั้งหมดเท่ากับ 0 จะเกิดZ=1 ****ข้อยกเว้น ถ้าค่าตัวตั้งเป็น0อยู่แล้ว แม้ลบด้วย0 ก็ไม่ทำให้flag z เปลี่ยนแปลง คือถ้าz=0ก็ยังคงเป็น0 แต่ถ้าเป็น1ก็ไม่เปลี่ยนแปลง*****
C: Carry Flag หมายความว่าตัวทดช่วย ส่วนใหญ่ เกิดจากคำสั่ง บวก ลบ คูณ หาร ซึ่งมีค่าส่วนเกินเกินกว่ารีจิสเตอร์มีจำนวนบิทจะแสดงได้ แฟลกCจะปรากฎ1 หรือคำสั่งบางอย่างที่ต้องอิงค่า C ก็ใช้งานได้เช่นกัน
SP Stack Pointer
SP มีขนาด11bit ประกอบด้วย SP=SPH:SPL ตัวชี้ที่อยู่ของสแต็ก ,Stack ถูกเก็บไว้บนsram ตอนรีเซทแล้วใหม่ๆต้องกำหนดที่อยู่ให้มัน ควรกำหนดเป็น SP=0x8FF (ค่า2303 บนสุดของแรม) เวลาสแต็กถูกเก็บค่าก็จะลดค่าSP ลงเรื่อยๆจากตำแหน่งสูงสุดที่เราตั้งค่าเอาไว้
0x5E , 0x3E ,Stack Pointer Register High byte | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
SPH | x | x | x | x | x | SP(10) | SP(9) | SP(8) |
access | RW | RW | RW | |||||
reset | 0 | 0 | 0 |
0x5D , 0x3D , Stack Pointer Register Low byte | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
SPL | SP(7) | SP(6) | SP(5) | SP(4) | SP(3) | SP(2) | SP(1) | SP(0) |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
EEPROM หน่วยความจำข้อมูล
EEAR คือ ที่อยู่บนEEPROM เอาอ่านหรือเขียน EEAR=EEARH:EEARL รวม10bit อ้างอิงได้ 1024 ตำแหน่ง ก่อนออกคำสั่งให้อ่านเขียนอีอีพรอมต้องใส่ที่อยู่EEARก่อน ส่วนการเขียนก็ต้องใส่ข้อมูลลงในEEDRให้เรียบร้อยก่อนสั่งเขียน และวิธีการสั่งให้เขียนหรืออ่านคือการกำหนดบิทใน EECR ซึ่งจะทำงานทันทีที่กำหนดบิทให้อ่านหรือเขียน
0x42 , 0x22 , EEPROM Address Register High | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
EEARH | x | x | x | x | x | x | EEAR9 | EEAR8 |
access | RW | RW | ||||||
reset | x | x |
0x41 , 0x21 , EEPROM Address Register Low | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
EEARL | EEAR7 | .. | .. | .. | .. | .. | .. | EEAR0 |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | x | x | x | x | x | x | x | x |
0x40 , 0x20 , EEPROM Data Register ,เก็บค่าอ่าน-เขียน | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
EEDR | EEDR7 | .. | .. | .. | .. | .. | .. | EEDR0 |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0x3F , 0x1F*bit , EEPROM Control Register | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
EECR | x | x | EEPM1 | EEPM0 | EERIE | EEMPE | EEPE | EERE |
ความ หมาย | program mode [bit5:4] 0:0 ลบ&เขียน 3.4ms 0:1 ลบ 1.8ms ลบ = 0b11111111 1:0 เขียน 1.8ms เขียน ทำให้บางบิทเป็น0 |
interrupt enable 1,รับ หลังให้ I=1 0,ไม่รับ |
master write en 1,ใส่ก่อนให้ EEPE=1 0,auto หลังเขียน |
write en 1,ใส่-เริ่ม 0,auto หลังเขียน |
read enable 1, อ่านเลย 0, auto? |
|||
reset | x | x | 0 | 0 | x | 0 |
GPIOR2 0x4B 0x2B
GPIOR1 0x4A 0x2A
GPIOR0 0x3E 0x1E* bit access
General Purpose I/O Register 0/1/2 เอาไปใช้ทำอะไรก็ได้ reset=0 ทั้งหมด
สัญญาณนาฬิกา
0x66 , Oscillator Calibration Register ปรับค่าความเที่ยงสัญญานนาฬิกาRCภายใน | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
OSCCAL | CAL7 | .. | .. | .. | .. | .. | .. | CAL0 |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | x | x | x | x | x | x | x | x |
0x61 , Clock Prescaler Register ปรับค่าตัวหารความเร็วMCU | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
CLKPR | CLKPCE | x | x | x | CLKPS3 | CLKPS2 | CLKPS1 | CLKPS0 |
ค. หมาย | ใส่ 0b10000000 แล้วใส่ CLKPS ใน4cl ,0 by HW |
CLKPS[3,2,1,0] 0000>/1 0001>/2 0010>/4 0011>/8 0100>/16 0101>/32 0110>/64 0111>/128 1000>/250 |
||||||
reset | 0 | x | x | x | x |
โหมดพลังงานและโหมดหลับ ..
ไปศึกษาเอาหน้า62 แต่ละโหมดอาจยังสามารถรับอินเตอร์รัพต่างชนิดกัน มีรายละเอียดปลีกย่อยเยอะ และปรับค่าได้ต่างๆกัน**อ่านข้ามๆ**
0x53 , 0x33 Sleep Mode Control Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
SMCR | x | x | x | x | SM2 | SM1 | SM0 | SE |
ค. หมาย | 000 Idle , 001 ADC Noise Reduction , 010 Power-down ,011 Power-save , 110 Standby , 111 Extended Standby | 1, sleep 0, ไม่หลับ ใส่เอง ถ้าตื่นก็ต้อง clr |
||||||
reset | 0 | 0 | 0 | 0 |
0x55 , 0x35 MCU Control Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
MCUCR | x | BODS | BODSE | PUD | x | x | IVSEL | IVCE |
ค.หมาย | 1,ปิดBODS ตอนหลับ ให้BODSE=1 0,byHWตื่น |
ให้1,หลังให้ BODS=1 0,ใน4cl เพื่อยืนยันการปิด? |
1,ปิดพลูอัพ ที่พอร์ท อินพุท 0,ไม่ปิด |
Interrupt Vector Select? 1,เปลี่ยนตำแหน่ง IE,reset |
IV Change Enable? 1,เพื่อใส่ IVSEL=1 4cl |
|||
reset | 0 | 0 | 0 | 0 | 0 |
0x64 , Power Reduction Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
PRR | PRTWI0 | PRTIM2 | PRTIM0 | x | PRTIM1 | PRSPI0 | PRUSART0 | PRADC |
ค.หมาย | 1,ปิดPower TWI0 |
1,ปิดPower Timer/C2? |
1,ปิดPower Timer/C0 |
1,ปิดPower Timer/C1 |
1,ปิดserial | 1,ปิดUSART | 1,ปิดADC | |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
การรีเซท ..
..
0x54 , 0x34 MCU Status Register แฟลกสั่งให้รีเซท | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
MCUSR | x | x | x | x | WDRF | BORF | EXTRF | PORF |
w/r ค.หมาย | watch dog reset flag |
Brown out reset flag |
external reset flag |
power on reset flag |
||||
reset | 0 | 0 | 0 | 0 |
wdt diagram การเกิดอินเตอรัพและการที่mcuจะรีเซทเครื่อง พบว่า มี3โหมดการทำงานที่กำหนดโดยบิท WDE(เปิดรีเซทเครื่อง) และ WDIE(เปิดอินเตอรัพ) คือ 00 ปิดwdt , 01 wdtจะฟ้องWDIFอย่างเดียว ,10 wdtรีเซทเครื่องอย่างเดียว ,11 wdtฟ้องWDIF+resetเครื่อง
เมื่อเกิดอินเตอรัพWDIF วิธีการรีเซทคือใช้คำสั่ง WDR ก็สามารถรีเซทค่าตัวนับให้เริ่มนับใหม่ได้ทันที **อ่านข้ามๆ***
0x60 , Watchdog Timer Control Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
WDTCSR | WDIF | WDIE | WDP3 | WDCE | WDE | WDP2 | WDP1 | WDP0 |
ค.หมาย | 1,เกิดIF I&WDIE=1 before 0,by hw or ให้1ซ้ำ? |
1,interrupt enable |
prescaler3 | 1,Change Ena before to ch WDE, WDP 4cl 0, hw 4cl |
1,Wdt System Reset Enable WDRF=1 before |
WDP[3210] ค่าเวลาwdtทำงาน [0000=16ms..to..1001=8s] |
||
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
INTERRUPT การขัดจังหวะ
การขัดจังหวะในMCU หมายถึงมีแฟลกบางชนิดเกิดขึ้นในขณะที่MCUทำงานประจำอยู่ทำให้เกิดเหตุการณ์ที่เรียกว่าอินเตอรัพ ซึ่งโดยปรกติเมื่อมีแฟลกอินเตอรัพชนิดใดก็จะกระโดดจากงานประจำไปทำงานขัดจังหวะหรือโปรแกรมย่อยที่เขียนเอาไว้ ซึ่งตำแหน่งเริ่มหลังรีเซท00H ส่วนโปรแกรมขัดจังหวะ เริ่มที่ที่อยู่โปรแกรมแฟลช 02H-032H ซึ่งมีอินเตอรัพประมาณ25ตำแหน่งหรือ25ชนิด (เช่น ที่อยู่โปรแกรมขนาด1เวิร์ดๆละ2ไบท์ 0CH เป็นที่อยู่ของ WDT เป็นต้น) ที่ต้องถูกจองพื้นที่เอาไว้เพื่อให้รองรับคำสั่ง jmp (ขนาด4byte) กระโดดไปโปรแกรมย่อยที่ถูกเรียกใช้ เมื่อจบโปรแกรมให้ ต้องใช้คำสั่ง RETI เพื่อคืนค่าที่อยู่ที่กำลังทำงานประจำอยู่ การเปลี่ยนตำแหน่งโผล่ของโปรแกรมขัดจังหวะสามารถทำได้ก่อนอัดโปรแกรมลงไปโดยไปเปลี่ยนบิท BOOTRST และเลือกใช้ได้ในbit IVSEL ในMCUCR หาอ่านเอาเองนะ
0x69 , External Interrupt Control Register A | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
EICRA | x | x | x | x | ISC11 | ISC10 | ISC01 | ISC00 |
access | RW | RW | RW | RW | ||||
reset | 0 | 0 | 0 | 0 |
0x3D , 0x1D*bit External Interrupt Mask Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
EMISK | x | x | x | x | x | x | INT1 | INT0 |
access | RW | RW | ||||||
reset | 0 | 0 |
0x3C , 0x1C*bit External Interrupt Flag Register | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
EIFR | x | x | x | x | x | x | INTF1 | INTF0 |
access | RW | RW | ||||||
reset | 0 | 0 |
|
เด๋วมาเขียนต่อนะครับ เรื่องI/O รีจิสเตอร์ ถ้าอ่านข้ามหัวข้อไปที่คำสั่งในการเขียนโปรแกรมด้านล่างได้เลยนะครับ อันล่างเขียนจบแล้ว
I/O Ports การกำหนดค่าports
ควรศึกษาแต่ละขาportในคู่มือว่ามีความสามารถนอกเหนือหรือใช้งานได้ที่มากกว่า input output หรือไม่
0x25 , 0x05*bit Port B data register ใส่ค่าเพื่อส่งเอ้าพุท พอร์ทB | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
PORTB | PORTB7 | ..B6 | ..B5 | ..B4 | ..B3 | ..B2 | ..B1 | PORTB0 |
ฟังก์ชั่นขา | XTAL2 TOSC2 PCINT7 |
XTAL1 TOSC1 PCINT6 |
Digital PB5 SCK PCINT5 |
/D PB4 MISO PCINT4 |
/D PB3 MOSI OC2A PCINT3 |
/D PB2 SS OC1B PCINT2 |
/D PB1 OC1A PCINT1 |
/D PB0 ICP1 CLK0 PCINT0 |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0x24 , 0x04*bit Port B data direct register กำหนดชนิดพอร์ทB input ,output | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
DDRB | DDRB7 | .. | .. | .. | .. | .. | .. | DDRB0 |
ค. หมาย | DDRBn =1 ให้ขานั้นเป็น output โดยไม่สนใจ PUD (MCUCR) ว่าปิด-เปิด pull up ที่ pinBหรือไม่ , PORTBn =1ด้วย outputจะเป็น hi source คือแต่ละขาสามารถจ่ายไฟออก5V20mA แต่ กระแสรวมกันของB0 - B5, D5 - D7, ADC6, XTAL1, XTAL2 ไม่เกิน 100mA , PORTBn= 0ด้วย outputจะเป็น hi sink คือแต่ละขาสามารถรับกระแสลงกราวด์ภายในMCU ที่5V20MA แต่ B0 - B5, D5 - D7, XTAL1, XTAL2 รวมกันไม่เกิน 100mA DDRBn =0 ให้ขานั้นเป็น input ส่วนใหญ่จะไปรับอินพุทว่ามีสัญญาณใดเข้าที่ขา PINBx ว่า=0หรือ1 เกี่ยวข้องกับ ปิด-เปิดpullupภายในที่ขาพิน โดยปิดPUD=1 (Pull up disable=1) =0,ไม่ปิด , PORTBn=0 ,PUD=0,1 เป็น Tri-state (Hi-Z) ไม่มีการจ่ายpull up ภายใน , PORTBn=1 ,PUD=0 เป็น PINBn จะถูกต่อpull upจ่ายไฟจากภายในพินถ้าpullภายนอกlow , PORTBn=1 ,PUD=1 Tri-state (Hi-Z) ไม่มีการจ่ายpull up ภายใน |
|||||||
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0x23 , 0x03*bit Port B Input Pins Address ที่เก็บสัญญาณอินพุทพอร์ทB | ||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
PINB | PINB7 | .. | .. | .. | .. | .. | .. | PINB0 |
access | Read | R only | R** | R** | R** | R** | R** | R** |
ค.หมาย | ** PINB เป็นรีจิสเตอร์ที่เกิดจากการวัดสัญญาณไฟฟ้าที่ขาไอซีจริงๆว่าเป็น0 หรือ 1 ที่เกิดขึ้นจริงๆ จึงเป็นลักษณะอินพุทหรืออ่านได้อย่างเดียว ไม่สามารถเปลี่ยนสัญญาณขาได้โดยตรง แต่มีระบบที่เรียกว่า toggle port ด้วย pinxn ซึ่งเป็นลักษณะเฉพาะที่เกิดขึ้นจากการสร้างฮาร์ดแวร์และชุดคำสั่ง เมื่อกำหนดDDRB เป็นเอ้าพุท เช่น DDRB5=1 แต่ให้ค่าในชุดคำสั่งว่า pinb5=1ในครั้งแรกจะไปสั่งportb5-->1แทน (pinb5จะอัพเดทช้ากว่า1clock) เมื่อทำการวนซ้ำที่เดิม ด้วยคำสั่ง pinb5=1 ไปเรื่อยๆ จะเกิดสภาวะ สลับค่าportb5 จาก1-->0-->1-->0-->1 สลับกันไปเรื่อยๆ *** ลองหาอ่านดูใน cpre.kmutnb.ac.th/esl/learning/index.php?article=avr-studio_asm_328p ในส่วนของ File: portb_io_toggle_v3.asm มีกราฟให้ดูด้วยตอนแรกผมงงมากเลย เมื่อกลับไปอ่าน datasheet atmega328p ก็มีระบบtoggleจริง เลยลองเขียนasmดูพบว่าเป็นจริงครับ ผมขอเขียนให้สั้นๆนะครับคำสั่งอาจต่างจากเขาแต่มีความหมายเหมือนกันครับแต่คล็อกผมช้ากว่า1c sbi ddrb , 5 ;[2c] ให้ ddrb5=1 main: sbi pinb , 5 ;[2c] ให้ pinb5=1 มีผลให้สั่ง portb5-->1 ในครั้งแรก rjmp main ;[2c] กระโดดไปที่ main portb5--> 0 ครั้งที่2 และสลับไปเรื่อยๆ |
|||||||
reset | x | x | x | x | x | x | x | x |
Status Register SREG--แฟลกสถานะรีจิสเตอร์8978 | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PORTB | I | T | H | S | V | N | Z | C |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Status Register SREG--แฟลกสถานะรีจิสเตอร์8978 | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PORTB | I | T | H | S | V | N | Z | C |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Status Register SREG--แฟลกสถานะรีจิสเตอร์8978 | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
PORTB | I | T | H | S | V | N | Z | C |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
E23EPROM หน่วยความจำข้อมูล
ไอโอรีจิสเตอร์ที่กล่าวถึง เป็นรีจีสเตอร์ที่เอาไว้เป็นตัวช่วยควบคุมสั่งการให้
Status Register SREG--แฟลกสถานะรีจิสเตอร์ | ||||||||
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SREG | I | T | H | S | V | N | Z | C |
access | RW | RW | RW | RW | RW | RW | RW | RW |
reset | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---
---
---
ชุดคำสั่ง ATmega328p
ข้อความต่อไปนี้มาจาก (Atmel-0856-AVR-Instruction-Set-Manual.pdf) ส่วนตัวอักษรสีเขียวเป็นบันทึกส่วนตัว
Status Register (SREG)
SREG Status Register
C Carry Flag
Z Zero Flag
N Negative Flag
V Two’s complement overflow indicator
S N ⊕ V, for signed tests
H Half Carry Flag
T Transfer bit used by BLD and BST instructions
I Global Interrupt Enable/Disable FlagRegisters and Operands (Atmel-0856-AVR-Instruction-Set-Manual.pdf)
ในpdf AVR ใช้เครื่องหมาย $นำหน้าตัวเลขฐาน16 ส่วนในภาษาC ใช้0xนำหน้าตัวเลขฐาน16 ส่วนผมอาจใช้ตัวอักษรHต่อท้ายเลขฐาน16 ซึ่งมีความหมายเดียวกันครับว่าหมายถึงเลขฐาน16 ถ้าไม่มีอะไรนำหน้าหรือตามหลังให้เข้าใจว่าเป็นเลขฐานสิบครับ
Rd: Destination (and source) register in the Register File
ปลายทาง (และแหล่ง) ของรีจิสเตอร์ R0-R32 ในที่อยู่sram 0x00-0x1F เช่น
****เท่าที่อ่านๆดู R0-R32 ไม่ได้ใช้ได้ทุกคำสั่งที่เขียนว่า Rd *****
ADD R2, R2 อธิบายว่า Rd ← Rd + Rd (เดิม Rd ← Rd + Rr) ซึ่งคำสั่งบวกดังกล่าว-
สามารถกระทำได้อย่างถูกต้อง โดยมีคำสั่ง16บิทรองรับจริง คือคำสั่ง 0c22Hd
Rr: Source register in the Register File (R0-R32)
R: Result after instruction is executed (หาไม่เจอว่าใช้ตรงไหน)
K: Constant data (K คือค่าคงที่ที่เป็นข้อมูลใดๆ)
k: Constant address
(k คือค่าคงที่ที่เป็นที่อยู่ ทั้งแบบรีเลทีฟค่าkไม่เหมือนกัน และที่อยู่สัมบูรณ์16บิท2ไบท์) เช่น
RJMP k ค่า k คิดเครื่องหมาย มีขนาด11บิท คือ -2048 to 2047 กระโดดเดินหน้า
หรือถอยหลังก็ได้แต่ไม่เกินนี้ ปรกติใช้การอ้างอิงที่อยู่ด้วยตัวแปร
คือกำหนดตำแหน่งที่จะให้กระโดดด้วยตัวแปรแล้วใส่คำสั่งให้กระโดด
rjmp calculate_again1 มันจะกระโดดไปที่ cal...again1
jmp k ค่า k มีขนาด 16 bit(65,536 ตำแหน่ง) ใน1คำสั่งขนาด32บิท ค่าk สามารถ
กระโดดไปที่ใดก็ได้ในโปรแกรมเมมโมรี่ แต่ในที่นี้ใช้ไม่เกิน16k ตำแหน่ง
b: Bit in the Register File or I/O Register (3-bit)
บิทที่เท่าไหร่ในR0-31 หรือใน R(I/O)ตำแหน่งออฟเซทSRAM0x20-0x5x
ซึ่ง b มีค่าระหว่าง0-7 ใส่เป็นเลข 0-7ได้เลย
s: Bit in the Status Register (3-bit)
บิทที่เท่าไหร่ 0-7 ใน SREG หรือ แฟลกสเตตัสรีจีสเตอร์
X,Y,Z: Indirect Address Register (X=R27:R26, Y=R29:R28, and Z=R31:R30)
A: I/O location address คือที่อยู่ชนิด I/O offset spaceซึ่งแต่เดิม I/O ในSRAM มีที่อยู่จริง อยู่ที่ตำแหน่ง 0x20-0x5F ซึ่งมี64ตำแหน่ง แต่เมื่อนำมาใช้ในชุดคำสั่ง IN และ ชุดคำสั่ง OUT เนื่องจากการออกแบบการเรียงตัวของคำสั่งชุดนี้ ทำให้ต้องจำกัดความเลขฐาน16 2ไบท์ในopcode IN และ OUT ใหม่ โดยค่าของ Aมีค่าอยู่ระหว่าง{0x00....0x3F} ฉะนั้นแล้วถ้าใส่ค่าที่อยู่เป็น0x5F ก็จะไม่มีในคำสั่งดังกล่าว จึงอาจกล่าวว่าเป็นเพราะภาษาเครื่องของมันจำกัดเอาไว้ จึงต้องทำให้ผู้ใช้งานงงว่าทำไมทางAtmel ต้องจำกัดความว่าที่อยู่ใน I/O offset space เริ่มที่ A{0x00...0x3F} จะถูกนำมาใช้ในคำสั่งดังกล่าว แทนที่อยู่จริงหรือที่อยู่สัมบูรณ์ใน I/O SRAM ที่เริ่มที่ 0x20-0x5Fซึ่งไม่สามารถใช้กับคำสั่งดังกล่าวได้อย่างถูกต้องครับ
q: Displacement for direct addressing (6-bit)
q คือค่าที่เคลื่อนไปจากที่อยู่เดิมไปข้างหน้าไม่เกิน63ตำแหน่ง
PC : Progam Counter
เป็นหน่วยความจำที่ทำหน้าที่จำตำแหน่ง และชี้ตำแหน่งโปรแกรมที่MCUกำลังทำงานอยู่
ในหน่วยความจำโปรแกรมแบบflash ทุกครั้งที่pc+1 มีความหมายว่า ได้อ่านข้อมูลโปรแกรม
ที่มีขนาด1เวิร์ดหรือ16bit ทำให้ที่อยู่ในโปรแกรมขนาด64K+ขึ้นทีละ2ค่า หรือ
ที่อยู่โปรแกรมถูกบวกด้วยค่า 0x0002 ทุกครั้งที่ pc+1
Stack : Stack for return address and pushed registers
กองชั้นที่สุมๆอย่างต่อเนื่องของข้อมูลบนแรม โดย
1. เป็นที่อยู่16bitที่ถูกเก็บขึ้นทุกครั้งเมื่อโปรแกรมถูกเรียกให้กระโดดเข้าโปรแกรมย่อย
แล้วรอส่งคืนaddressให้กับPCเมื่อจบโปรแกรมย่อย
2. เอาไว้เก็บ(push)ข้อมูล8บิทในรีจิสเตอร์และส่งคืนข้อมูลในรีจิสเตอร์ด้วยคำสั่งpop
SP : STACK POINTER to Stack
เป็นหน่วยความจำที่เก็บค่าตัวชี้ตำแหน่งสแตก
..
--Instruction set summary หน้า432
กลุ่ม คำสั่งกระบวนการทางคณิตศาสตร์ เช่น บวก ลบ คูณ หาร ทั้งไบท์และบิท ต้องทำในรีจีสเตอร์(หมายถึงหน่วยความจำชั่วคราวเฉพาะที่สามารถส่งต่อให้ทำการ(คำนวน)ได้)
Arithmethic and Logic Instructions | ||||
นิวโมนิก | โอเปอแรน | อธิบาย | กระบวนการ | Flag|clocks |
ADD | Rd, Rr | Add two Registers without Carry | Rd ← Rd + Rr | Z,C,N,V,H | 1 |
เช่น บวก สองรีจีสเตอร์ เช่น Rd=R2 ,Rr=R1 โดยไม่ต้องสนใจตัวทด(Carry) | R2 ← R2 + R1 (ผลลัพธ์ที่ได้เก็บที่R2) |
ถ้ามีตัวทดเพิ่มจะเก็บใน C | ||
ADC | Rd, Rr | Add two Registers with Carry | Rd ← Rd + Rr + C | Z,C,N,V,H | 1 |
ADIW | Rdl,K | Add Immediate to Word , ** d{24,26,28,30} ** K{0..63} // adiw r25:24,1 adiw ZH:ZL,63 บวกค่าคงที่ให้พ้อยเตออินได้เร็ก | Rdh:Rdl ← Rdh:Rdl + K | Z,C,N,V,S | 2 |
SUB | Rd, Rr | Subtract two Registers ลบกัน | Rd← Rd - Rr | Z,C,N,V,H | 1 |
SUBI | Rd, K | Subtract Constant from Register , **d{16..31} K{0..255} | Rd ← Rd - K | Z,C,N,V,H | 1 |
SBC | Rd, Rr | Subtract two Registers with Carry | Rd ← Rd - Rr - C | Z,C,N,V,H | 1 |
SBCI | Rd, K | Subtract Constant from Reg with Carry , **d{16..31} K{0..255} ลบค่าด้วยค่าคงที่และC | Rd ← Rd - K - C | Z,C,N,V,H | 1 |
SBIW | Rdl, K | Subtract Immediate from Word , **d{24,26,28,30} ** K{0..63} // sbiw r25:r24,1 sbiw YH:YL,63 ลบค่าคงที่ให้พ้อยเตออินได้เร็ก | Rdh:Rdl ← Rdh:Rdl - K | Z,C,N,V,S | 2 |
AND | Rd, Rr | Logical AND Registers | Rd ← Rd · Rr | Z,N,V | 1 |
ANDI | Rd, K | Logical AND Register and Constant , **d{16..31} k{0..255} | Rd ← Rd · K | Z,N,V | 1 |
OR | Rd, Rr | Logical OR Registers | Rd ← Rd v Rr | Z,N,V | 1 |
ORI | Rd, K | Logical OR Register and Constant , **d{16..31} K{0..255} | Rd ← Rd v K | Z,N,V | 1 |
EOR | Rd, Rr | Exclusive OR Registers , ** r{0..3} | Rd ← Rd ⊕ Rr | Z,N,V | 1 |
COM | Rd | One’s Complement | Rd ← 0xFF - Rd | Z,C,N,V | 1 |
NEG | Rd | Two’s Complement | Rd ← 0x00 - Rd | Z,C,N,V,H | 1 |
SBR | Rd,K | Set Bit(s) in Register , ** d{16..31} K{0..255} | Rd ← Rd v K | Z,N,V | 1 |
CBR | Rd,K | Clear Bit(s) in Register , ** d{16..31} K{0..255} | Rd ← Rd · (0xFF - K) | Z,N,V | 1 |
INC | Rd | Increment | Rd ← Rd + 1 | Z,N,V | 1 |
DEC | Rd | Decrement | Rd ← Rd - 1 | Z,N,V | 1 |
TST | Rd | Test for Zero or Minus | Rd ← Rd · Rd | Z,N,V | 1 |
CLR | Rd | Clear Register | Rd ← Rd ⊕ Rd | Z,N,V | 1 |
SER | Rd | Set Register , **d{16..31} | Rd ← 0xFF | None | 2 |
MUL | Rd, Rr | Multiply Unsigned | R1:R0 ← Rd x Rr | Z,C | 2 |
MULS | Rd, Rr | Multiply Signed , **d{16..31} **r{16..31} | R1:R0 ← Rd x Rr | Z,C | 2 |
MULSU | Rd, Rr | Multiply Signed with Unsigned , **d{16..23} **r{16..23} | R1:R0 ← Rd x Rr // (signed ← signed × unsigned) | Z,C | 2 |
FMUL | Rd, Rr | Fractional Multiply Unsigned , คูณเลขเศษส่วน ** d{16..23} r{16..23} | R1:R0 ← (Rd x Rr) << 1 | Z,C | 2 |
FMULS | Rd, Rr | Fractional Multiply Signed , ** d{16..23} r{16..23} | R1:R0 ← (Rd x Rr) << 1 | Z,C | 2 |
FMULSU | Rd, Rr | Fractional Multiply Signed with Unsigned , ** d{16..23} r{16..23} | R1:R0 ← (Rd x Rr) << 1 | Z,C | 2 |
.
กลุ่มคำสั่งกิ่งก้านสาขา เช่นการกระโดด เงื่อนไข การเปรียบเทียบ การเรียกโปรแกรมย่อย การกลับคืนที่กระโดดมา เป็นต้น
Branch Instructions | ||||
นิวโมนิก | โอเปอแรน | อธิบาย | กระบวนการ | Flag | clocks |
RJMP | k | Relative Jump , k{-2048...2047} //กระโดดโดยใช้ชื่อก็ได้ | PC ← PC + k + 1 | - | 2 |
IJMP | Indirect Jump to (Z) Z{0...65535} //เจาะจงยาก | PC ← Z | - | 2 | |
JMP | k | Direct Jump , k{0...65535} *32bit opcode // jmp subp1 กระโดดไปที่ชื่อก็ได้ | PC ← k | - | 3 |
RCALL | k | Relative Subroutine Call , k{-2048 to 2047} | PC ← PC + k + 1 | - | 3 |
ICALL | Indirect Call to (Z) | PC ← Z | - | 3 | |
CALL | k | Direct Subroutine Call , k{0...65535} *32bit opcode | PC ← k | - | 4 |
RET | Subroutine Return | PC ← STACK | - | 4 | |
RETI | Interrupt Return | PC ← STACK | I | 4 | |
CPSE | Rd,Rr | Compare, Skip if Equal |
if (Rd = Rr) PC ←PC+2 (or 3) else PC+1 | - | 123 |
^เทียบ Rd กับ Rr ถ้าเท่าให้ข้าม 1. ถ้าเท่าให้ข้ามไปอ่านคำสั่งบรรทัดถัดๆไป [..คือให้กระโดดข้ามคำสั่งบรรทัดถัดไปซึ่งอาจเป็นคำสั่งขนาด1-2เวิร์ด ทำให้ PC=PC+2(or3)..] 2. ถ้าไม่เท่าให้อ่านคำสั่งบรรทัดต่อไปจากCPSE [..PC=PC+1..] |
cpse r4,r0 ; เทียบ r4กะ r0 neg r4 ; ไม่เท่า pc+1 nop ; เท่า pc+2 cpse r4,r0 ; เทียบ r4กะ r0 call funcA ; ไม่เท่า pc+1 nop ; เท่า pc+3 |
|1 false & pc+1 (no skip) |2 true & pc+2 |3 true & pc+3 |
||
CP | Rd,Rr | Compare เปรียบเทียบกันโดยไม่เก็บค่าเพื่อเอาแฟลกมาใช้กระโดด // พวกCP CPC CPI..อาจใช้ คำสั่ง BREQ ,BRNE ,BR.. ต่อท้าย | Rd - Rr |
Z, N,V,C,H | 1 |
CPC | Rd,Rr | Compare with Carry | Rd - Rr - C | Z, N,V,C,H | 1 |
CPI | Rd,K | Compare Register with Immediate , ** d{16..31} K{0..255} | Rd - K | Z, N,V,C,H | 1 |
SBRC | Rr, b | Skip if Bit in Register Cleared , b{0..7} all bit check branch below same b ,b คือตำแหน่งบิทใน Rr , ตย:sbrc r0,7 | if (Rr(b)=0) PC ←PC+2 (or 3) else PC+1 | - | 123 |
SBRS | Rr, b | Skip if Bit in Register is Set | if (Rr(b)=0) PC ←PC+2 (or 3) else PC+1 | - | 123 |
SBIC | A, b | Skip if Bit in I/O Register Cleared , ** I/O offset space addr A{0..31}bit addressable | if (I/O(A,b)=0) PC ←PC+2 (or 3) else PC+1 | - | 123 |
SBIS | A, b | Skip if Bit in I/O Register is Set, ** I/O offset space addr A{0..31}bit addressable | if (I/O(A,b)=1) PC ←PC+2 (or 3) else PC+1 | - | 123 |
BRBS | s, k | Branch if Status Flag Set , s คือตำแหน่งบิทที่เท่าไหร่ในSREG , k ที่อยู่ในการกระโดด , s{0..7} , ** k{-64..63} ,all bit check branch below same value s and k หรือกระโดดโดยระบุชื่อก็ได้** | if (SREG(s) = 1) then PC←PC+k+1 else PC+1 | - | 12 |
BRBC | s, k | Branch if Status Flag Cleared | if (SREG(s) = 0) then PC←PC+k+1 else PC+1 | - | 12 |
BREQ | k | Branch if Equal | if (Z = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRNE | k | Branch if Not Equal | if (Z = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRCS | k | Branch if Carry Set | if (C = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRCC | k | Branch if Carry Cleared | if (C = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRSH | k | Branch if Same or Higher | if (C = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRLO | k | Branch if Lower | if (C = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRMI | k | Branch if Minus | if (N = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRPL | k | Branch if Plus | if (N = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRGE | k | Branch if Greater or Equal, Signed | if (N ⊕ V= 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRLT | k | Branch if Less Than Zero, Signed | if (N ⊕ V= 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRHS | k | Branch if Half Carry Flag Set | if (H = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRHC | k | Branch if Half Carry Flag Cleared | if (H = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRTS | k | Branch if T Flag Set | if (T = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRTC | k | Branch if T Flag Cleared | if (T = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRVS | k | Branch if Overflow Flag is Set | if (V = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRVC | k | Branch if Overflow Flag is Cleared | if (V = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
BRIE | k | Branch if Interrupt Enabled | if ( I = 1) then PC ←PC+k+1 else PC+1 | - | 12 |
BRID | k | Branch if Interrupt Disabled | if ( I = 0) then PC ←PC+k+1 else PC+1 | - | 12 |
.
กลุ่มคำสั่งการดำเนินการเกี่ยวกับบิท เช่น เซ็ทบิท เคลียร์บิท การสลับบิท การวนบิทในรีจิสเตอร์ เป็นต้น
BIT AND BIT-TEST INSTRUCTIONS | ||||
นิวโมนิก | โอเปอแรน | อธิบาย | กระบวนการ | Flag | clocks |
SBI | A, b | Set Bit in I/O Register , ** I/O offset space addr A{0..31}bit addressable b{0..7} | I/O(A,b) ← 1 | - | 2 |
CBI | A, b | Clear Bit in I/O Register , ** A{0..31} b{0..7} | I/O(A,b) ← 0 | - | 2 |
LSL | Rd | Logical Shift Left | Rd(n+1) ← Rd(n), Rd(0) ← 0 | Z,C,N,V | 1 |
LSR | Rd | Logical Shift Right | Rd(n) ← Rd(n+1), Rd(7) ← 0 | Z,C,N,V | 1 |
ROL | Rd | Rotate Left Through Carry | Rd(0)←C ,Rd(n+1)← Rd(n) ,C←Rd(7) | Z,C,N,V | 1 |
ROR | Rd | Rotate Right Through Carry | Rd(7)←C ,Rd(n)← Rd(n+1) ,C←Rd(0) | Z,C,N,V | 1 |
ASR | Rd | Arithmetic Shift Right ,หมุนบิทไปทางบิทต่ำทางขวามือ บิท0เข้าC บิท7มีค่าเท่าเดิม | Rd(n) ← Rd(n+1), n=0...6 | Z,C,N,V | 1 |
SWAP | Rd | Swap Nibbles สลับที่4บิทสูงและต่ำกัน | Rd(3...0)←Rd(7...4) , Rd(7...4)←Rd(3...0) | - | 1 |
BSET | s | Flag Set , s{0..7} sคือตำแหน่งบิทใน SREG | SREG(s) ← 1 SREG(s) | SREG(s) | 1 |
BCLR | s | Flag Clear | SREG(s) ← 0 SREG(s) | SREG(s) | 1 |
BST | Rr, b | Bit Store from Register to T , b{0..7} bคือตำแหน่งบิทในRr นำค่าดังกล่าวไปเก็บในbit T หรือ SREG(6) | T ← Rr(b) | T | 1 |
BLD | Rd, b | Bit load from T to Register ,ทำกลับกันกับ BST | Rd(b) ← T | - | 1 |
SEC | Set Carry | C ← 1 | C | 1 | |
CLC | Clear Carry | C ← 0 | C | 1 | |
SEN | Set Negative Flag | N ← 1 | N | 1 | |
CLN | Clear Negative Flag | N ← 0 | N | 1 | |
SEZ | Set Zero Flag | Z ← 1 | Z | 1 | |
CLZ | Clear Zero Flag | Z ← 0 | Z | 1 | |
SEI | Global Interrupt Enable | I ← 1 | I | 1 | |
CLI | Global Interrupt Disable | I ← 0 | I | 1 | |
SES | Set Signed Test Flag | S ← 1 | S | 1 | |
CLS | Clear Signed Test Flag | S ← 0 | S | 1 | |
SEV | Set Two’s Complement Overflow. | V ← 1 | V | 1 | |
CLV | Clear Two’s Complement Overflow | V ← 0 | V | 1 | |
SET | Set T in SREG | T ← 1 | T | 1 | |
CLT | Clear T in SREG | T ← 0 | T | 1 | |
SEH | Set Half Carry Flag in SREG | H ← 1 | H | 1 | |
CLH | Clear Half Carry Flag in SREG | H ← 0 | H | 1 |
.
กลุ่มคำสั่งการย้ายข้อมูล ระหว่างข้อมูลโปรแกรมและที่อื่นๆกับรีจิสเตอร์ การเก็บค่าที่อยู่ขณะเรียกโปรแกรมย่อย รวมถึงการย้ายข้อมูลของตัวชี้ข้อมูล(พ๊อยเตอร์16บิท มีให้เลือกใช้ถึง3 ชุดรีจีสเตอร์ คือ X,Y,Z)
DATA TRANSFER INSTRUCTIONS | ||||
นิวโมนิก | โอเปอแรน | อธิบาย | กระบวนการ | Flag | Clocks |
MOV | Rd, Rr | Move Between Registers | Rd ← Rr | - | 1 |
MOVW | Rd, Rr | Copy Register Word คัดลอกทีละ1เวิร์ด16bit **d,r{0,2,..30} // ตย. movw r17:16,r1:r0 | Rd+1:Rd ← Rr+1:Rr | - | 1 |
LDI | Rd, K | Load Immediate ใส่ค่าคงที่, ** d{16..31} K{0..255} // ldi r30, $F0 | Rd ← K | - | 1 |
LD | Rd, X | Load Indirect **LD..โหลดจาก sram | Rd ← (X) | - | 2 |
LD | Rd, X+ | Load Indirect and Post-Increment โหลดก่อนแล้วX+1 | Rd ← (X), X ← X + 1 | - | 2 |
LD | Rd, -X | Load Indirect and Pre-Decrement X-1ก่อนแล้วโหลด | X ← X - 1, Rd ← (X) | - | 2 |
LD | Rd, Y | Load Indirect | Rd ← (Y) | - | 2 |
LD | Rd, Y+ | Load Indirect and Post-Increment | Rd ← (Y), Y ← Y + 1 | - | 2 |
LD | Rd, - Y | Load Indirect and Pre-Decrement | Y ← Y - 1, Rd ← (Y) | - | 2 |
LDD | Rd,Y+q | Load Indirect with Displacement q , q{0..63} q in data trasfer is same value q , qคือค่าที่เคลื่อนไปจากที่อยู่เดิมไปด้านหน้าไม่เกิน63ตำแหน่ง | Rd ← (Y + q) | - | 2 |
LD | Rd, Z | Load Indirect | Rd ← (Z) | - | 2 |
LD | Rd, Z+ | Load Indirect and Post-Increment | Rd ← (Z), Z ← Z+1 | - | 2 |
LD | Rd, -Z | Load Indirect and Pre-Decrement | Z ← Z - 1, Rd ← (Z) | - | 2 |
LDD | Rd, Z+q | Load Indirect with Displacement | Rd ← (Z + q) | - | 2 |
LDS | Rd, k | Load Direct from SRAM , k{0...65535} *32bit opcode | Rd ← (k) | - | 2 |
ST | X, Rr | Store Indirect | (X) ← Rr | - | 2 |
ST | X+, Rr | Store Indirect and Post-Increment | (X) ← Rr, X ← X + 1 | - | 2 |
ST | - X, Rr | Store Indirect and Pre-Decrement | X ← X - 1, (X) ← Rr | - | 2 |
ST | Y, Rr | Store Indirect | (Y) ← Rr | - | 2 |
ST | Y+, Rr | Store Indirect and Post-Increment | (Y) ← Rr, Y ← Y + 1 | - | 2 |
ST | - Y, Rr | Store Indirect and Pre-Decrement | Y ← Y - 1, (Y) ← Rr | - | 2 |
STD | Y+q,Rr | Store Indirect with Displacement | (Y + q) ← Rr | - | 2 |
ST | Z, Rr | Store Indirect | (Z) ← Rr | - | 2 |
ST | Z+, Rr | Store Indirect and Post-Increment | (Z) ← Rr, Z ← Z + 1 | - | 2 |
ST | -Z, Rr | Store Indirect and Pre-Decrement | Z ← Z - 1, (Z) ← Rr | - | 2 |
STD | Z+q,Rr | Store Indirect with Displacement | (Z + q) ← Rr | - | 2 |
STS | k, Rr | Store Direct to SRAM , k{0...65535} *32bit opcode | (k) ← Rr | - | 2 |
LPM | Load Program Memory | R0 ← (Z) | - | 3 | |
LPM | Rd, Z | Load Program Memory | Rd ← (Z) | - | 3 |
LPM | Rd, Z+ | Load Program Memory and Post-Inc | Rd ← (Z), Z ← Z+1 | - | 3 |
SPM | Store Program Memory | (Z) ← R1:R0 | - | - | |
IN | Rd, A | In from I/O Location , ** I/O offset space addr A{0..63} | Rd ← I/O (A) | - | 1 |
OUT | A, Rr | Out to I/O Location , ** I/O offset space addr A{0..63} // ตย. out PORTB,R1 ใช้ชื่อรีจิสเตอร์ I/Oแทนเลยก็ได้ หรือ out $05,R1 ก็เหมือนกัน | I/O (A) ← Rr | - | 1 |
PUSH | Rr | Push Register on Stack | STACK ← Rr | - | 2 |
POP | Rd | Pop Register from Stack | Rd ← STACK | - | 2 |
.
กลุ่มคำสั่ง MCU control
MCU CONTROL INSTRUCTIONS | ||||
นิวโมนิก | โอเปอแรน | อธิบาย | กระบวนการ | Flag | Clocks |
NOP | No Operation | No Operation | - | 1 | |
SLEEP | Sleep | (see specific descr. for Sleep function) | - | 1 | |
WDR | Watchdog Reset | (see specific descr. for WDR/timer) | - | 1 | |
BREAK | Break | For On-chip Debug Only | - | N/A |
ถ้าท่านอ่านแล้วติดปัญหาว่าคำสั่งแต่ละคำสั่งใช้งานอย่างไร และแต่ละสัญลักษณ์มีความหมายว่าอย่างไร ใช้กูเกิ้ลเสิชหาคำว่า AVR Atmel OPCODE เท่าดูๆมีเนื้อหาที่น่าสนใจไปค้นคว้าต่อดังนี้
ข้อความต่อไปนี้มาจาก (AVR Assembler User Guide-pdf-Atmel) และ (www.atmel.com/webdoc/avrassembler/index.html) ซึ่งเป็นวิธีการเขียนโปรแกรมMCU ตระกูล AVR ด้วยภาษาแอสเซมบลี้ ผ่านตัวแปลภาษาที่เรียกว่า Assembler ข้อความที่เป็นสีเขียวเป็นข้อความเข้าใจส่วนตัวที่บันทึกเอาไว้
- - จะเรียกว่าข้อกำหนดทางภาษาของAssembler ที่นอกเหนือจากชุดคำสั่งเครื่อง เพื่อให้เขียนได้ง่ายขึ้นให้เป็นภาษาที่คนทำความเข้าใจได้ง่ายขึ้นอ้างอิงได้ง่ายขึ้น และตัวแปลภาษาหรือAssemblerสามารถแปลภาษาได้อย่างถูกต้องให้เป็นภาษาเครื่องล้วนๆในรูปแบบ file .hex ที่อยู่ในรูปตัวเลขฐานสิบหกล้วนๆติดกันยาวเหยียดได้ ซึ่ง Assembler แต่ละตระกูลไมโครคอนโทรลเลอร์อาจสร้างข้อกำหนดที่ไม่เหมือนกันแต่ใกล้เคียงกันแต่เขียนต่างกัน นอกจากนี้เวอชั่นหลังๆอยังมีภาษาแมคโครรวมอยู่ด้วย คล้ายๆกับ preprocessor ในภาษาC ก็ใช้ภาษา Macro language แต่ของCซับซ้อนกว่า - -
- - ของผมเวลาใช้ assembler คงใช้บน Atmel studio 7.0 - --Integer constants: ค่าคงที่ที่เป็นตัวเลข กำหนดได้4แบบ
a) Decimal (default): 10, 255 เลขโดดคือฐานสิบเป็นค่าเริ่มต้น
b) Hexadecimal (two notations): 0x0a, $ff ฐานสิบหกใช้ 0x ,$ นำหน้าเลข2ตัว
c) Binary: 0b00001010, 0b11111111 เลขฐานสองใส่ 0b นำหน้า
d) Octal (leading zero): 010, 077 เลขฐานแปดใส่ 0 นำหน้า-Assembler source แหล่งสำหรับตัวแปลภาษาหรือวิธีการเขียนให้ถูกเพื่อให้มันแปรได้ถูก สิ่งที่เขียนได้มี 4 ประเภท
แต่โดยหลักๆคือทุกบรรทัดสามารถเขียน label แล้วลงท้ายด้วย: จะไม่ผิดหลักการ
1 [label:] .directive [operands] [;Comment]
2 [label:] instruction [operands] [;Comment]
3 Comment
4 Empty line
เท่าที่ลองกำหนดค่าดู ตัวอักษรใหญ่เล็กจะมีค่าเท่ากันหมด ค่าตัวแทน หรือค่าตัวแปรก็ตาม เช่นlabel: .EQU var1=100 ; Set var1 to 100 (.EQU คือ Directive)
.equ var2=200 ; Set var2 to 200
test: rjmp test ; Infinite loop (rjmp คือ Instruction)
; Pure comment line-Assembler directives แปลแบบบ้านๆคือตัวกำกับสำหรับการแปลภาษา ซึ่งโดยทั่วไปเอาไว้ ปรับตำแหน่งของโปรแกรมเมมโมรี่(ORG ซึ่งเป็นตัวเดียวที่ขาดไม่ได้) การกำหนดแมโคร หรือการกำหนดค่าเริ่มต้นที่จำเป็น ต่อไปนี้เป็นคือชนิดของมัน --
directive ที่ใช้บ่อยๆ 1. ORG Set program origin ระบุตำแหน่งที่อยู่ของโปรแกรม(ข้อมูล)ที่กำลังจะเขียน
.ORG expression
.org 0x0000 jmp main ;กระโดดไปที่เมนเพื่อหลีกพื้นที่อินเตอรัพ
.org 0x0034
main: nop ; mainจะเริ่มที่อยู่ที่0x00342. EQU Set a symbol equal to an expression กำหนดชื่อตัวแทนและตั้งว่าเท่ากับค่าใด คล้ายๆกับกำหนดชื่อตัวแปรหรือชื่อค่าคงที่หรือชื่อตำแหน่งที่อยู่ในsramเมื่อได้ชื่อแล้วก็ให้ค่าลงไป
.EQU label = expression .EQU io_offset = 0x23
.EQU myaddr_r0 = 0x00 .equ my_page = 53. DB Define constant byte(s) กำหนดค่าชุดข้อมูลทีละ1ไบท์ที่จะจัดเก็บในแฟลชหรือeeprom เนื่องจากatmega328เก็บข้อมูลทีละ1เวิร์ดหรือ2byteควรต้องใช้.DBเก็บเป็นข้อมูลทีละ2ไบท์ถ้าหมดชุดข้อมูลได้เลขคี่มันจะก็ใส่0ลงไปแทนให้ แต่การนำออกมาจะใช้ชุดคำสั่ง LPM ซึ่งชี้ด้วยz register และดึงข้อมูลออกมาทีละ1ไบท์เหมือนเดิม โดย Zlsb=0จะชี้ไบท์ต่ำ ถ้า=1จะชี้ไบท์สูงของเวิร์ด
LABEL: .DB expressionlist
consts: .DB 0, 255, 0b01010101, -128, 0xaa
num1: .DB 0,1,2,3,4,5,6
char1: .db "a","b","c","d"
char2: .db "HELLO" ;ในกรณีที่ยาวมากๆจะใช้ \ เพื่อขึ้นบรรทัดใหม่แต่ข้อมูลยังคงติดกันไปเหมือนเดิม
lcdprint: .db 0, 1, "This is a long string", '\n', 0, 2, \
"Here is another one", '\n', 0, 3, 04. DW Define constant word(s) กำหนดค่าชุดข้อมูลทีละ1เวิร์ดที่จะจัดเก็บในแฟลชหรือeeprom วิธีการก็เหมือนDB ส่วนใหญ่ไว้เก็บค่าตัวเลขยาวๆ 5 DEF Define a symbolic name on a register กำหนดชื่อตัวแทนรีจิสเตอร์เฉพาะR0-R31เท่านั้นเพื่อให้ง่ายแก่ทำความเข้าใจในการเขียนโปรแกรม ในกรณีถ้าใช้.def เพื่อกำหนดชื่อ2ครั้งให้กับรีจิสเตอร์ตัวเดียวกันจะถูกเตือนแต่ยังแปลผ่านคือใช้งานได้ไม่มีผลกับโค๊ด วิธีแก้ให้มันไม่เตือนคือใช้ .undef
.DEF Symbol=Register .def ior=R0
.DEF temp=R16 ;แล้วนำไปใช้ ldi r16, high(RAMEND)
;ใช้แทนได้ ldi temp,high(RAMEND)6 UNDEF Undefine a register symbolic name ล้างการกำหนดชื่อตัวแทนR0-R31เพื่อป้องกันการเตือนหลังแปลภาษา เพราะบางทีเราอยากจะใช้ซ้ำรีจิสเตอร์ แต่ใช้ชื่อต่างที่กันหรือต่างฟังก์ชั่นกันเพื่อความสะดวกในการทำความเข้าใจก็ให้ undef แล้ว def ชื่อใหม่อีกที
.DEF var1 = R16
ldi var1, 0x20 ... ; ทำอะไรก็ได้กับ var1
.UNDEF var1
.DEF var2 = R16 ;แค่นี้ก็ไม่มีการเตือนว่าใช้ซ้ำกันที่เหลือก็เลือกใช้ได้ตามความจำเป็น
- SET Set a symbol to an expression
- INCLUDE Read source from another file เป็นส่วนpreprocessor เพื่อเรียกไฟล์ที่เขียนไปใน
ที่อื่นๆมาใช้งานโดยเสมือนสวมโค๊ดข้างนอกเข้าในไฟล์หลัก แต่ในไฟล์
ที่ใช้ส่วนใหญ่มักจะไม่ใช่โค๊ด แต่เป็นการกำหนดค่าตัวแทนมากกว่า
- EXIT Exit from file เมื่อไฟล์ข้างนอกถูกเรียกเหมือนเข้าไปสวมในไฟล์หลักไฟล์ข้างนอกต้องมี
คำว่า exit เพื่อให้ตัวแปลภาษาเข้าใจว่าอ่านจบแล้ว
- CSEG Code Segment บรรทัดถัดไปต่อไปนี้เป็นส่วนของโค๊ดการทำงาน(เป็นค่าเริ่มต้น)
- DSEG Data Segment ต่อไปนี้เป็นส่วนข้อมูลที่จะเก็บไว้ในsram**ไม่ได้ใช้ใช้เฉพาะตอนดีบั๊ก
- ESEG EEPROM Segment ต่อไปนี้คือส่วนข้อมูลของeeprom**ไม่แน่ใจว่าตอนอัด
โปรแกรมmcuมันอัดข้อมูลอีอีพอมด้วยหรือเปล่า
- BYTE Reserve byte to a variable จองหน่วยความจำเป็นจำนวนกี่ไบท์ในsram ใช้ได้เมื่อ
เขียนถัดจาก .DSEGเท่านั้น เท่าที่เข้าใจคือมัน**ไม่ได้ใช้จริง
- MACRO Begin macro
- ENDMACRO End macro
- ยังมีอื่นๆอีก10กว่าตัวส่วนใหญ่เกี่ยวกับภาษาแมคโคร ลิส หาอ่านได้ใน
www.atmel.com/webdoc/avrassembler/avrassembler.wb_directives.html ---function
เป็นฟังก์ชั่นอำนวยความสะดวกในการเขียนภาษา ตัวอย่าง เพื่ออำนวยความสะดวกในการให้ค่าเช่นตัวเลขทีมีค่ายาวๆมากกว่า1byte เช่น 53487 จะส่งค่าเข้าไปใน รีจิสเตอร์R30,R31 เราไม่จำเป็นต้องมานั่งแปลงเป็นเลข2ไบท์ เราอาจใช้ฟังก์ชั่นในการส่งค่าเข้าไปให้แทน เช่น low(53487) เก็บในR30 และ high(53487) เก็บใน R31 เป็นต้น หาอ่านเพิ่มเติมได้ใน www.atmel.com/webdoc/avrassembler/avrassembler.wb_expressions.html เลือกfunction
ตัวที่ใช้บ่อยๆเช่น
- LOW(expression) returns the low byte of an expression
- HIGH(expression) returns the second byte of an expression
ldi r16 , high(2303) ; เหมือนกับ ldi r16 , high(RAMEND)
out sph , r16 ;sph=0x08
ldi r16 , low(2303) ; เหมือนกับ ldi r16, 0xff
out spl , r16 ;spl=0xFF
---operator
เป็นโอเปอเรเตอร์ที่อำนวยความสะดวกในการเขียนโดยเฉพาะการให้ค่าคงที่2ตัวมากระทำการกัน ทางคณิตศาสตร์บ้าง การเปรียบเทียบค่าคงที การกระทำทางดิจิตอลกับค่าคงที่ บางทีเป็นตัวเลขฐานสิบบ้าง
ซึ่งส่วนใหญ่ไม่ค่อยมีประโยชน์มากนัก
คณิตศาสตร์และการกำหนดค่า
- Unary Minus เช่น ldi r16,-2 ; ให้ค่าลบสองซึ่งเท่ากับ 0xfe กับ r16
-2 = two's complementของสอง = ~(0000 0010)+1= 1111 1110
* Multiplication คูณ เช่น ldi r30 ,label*2 ; r30 = label*2
/ Division หารเอาค่าที่ได้เป็นจำนวนเต็ม 15/6 =2
% Modulo เอาเศษที่เหลือที่หารไม่ลงตัวคืนเป็นจำนวนเต็ม 15%6 =3
+ Addition บวก
- Subtraction ลบ
<< Shift left เช่น ldi r16, (1<<DDB5) ; กำหนดDDB bitที่5 ให้เท่ากับ1
;แต่ ldi ไม่สามารถใส่เป็นบิทได้ใส่ได้แค่ 0b00100000
เทียบเท่า ldi r16, 0b0010000 ; ซึ่งจะเห็นว่าใส่แบบข้างบนก็เท่ากัน
>> Shift right
ต่อไปนี้ให้ค่าทางตรรกะคือ ไม่1 ก็0
! Logical not เช่น ถ้าค่าหลัง! มีค่าไม่เท่ากับ1จะให้ค่า0 ถ้ามีค่า0จะให้ค่า1
< Less than น้อยกว่าจริงให้1 ถ้าไม่ใช่ให้0
<= Less than or equal > Greater than >= Greater than or equal
== Equal != Not equal && Logical And || Logical Or
ต่อไปนี้เป็นการกระทำทางโลจิก
~ Bitwise Not 1's เช่น ldi r16, (~0b0000010) ; r16=0b11111101
& Bitwise And ^ Bitwise Xor | Bitwise Or
เงื่อนไข
? Conditional operator รูปแบบ condtion? expression1 : expression2
ldi r18, a > b ? a : b ; r18 จะเท่ากับ a หรือ b ตัวใดตัวนึงที่มีค่ามากที่สุด
; ถ้าa>b จริง r16=a แต่ถ้าa ;ในความเป็นจริง a กะ b เป็นได้อย่างมากก็ค่าตัวเลขไม่ใช่ตัวแปรซึ่งไม่มีประโยชน์เท่าไหร่
ยอะ
-
คลิ๊ก> หมวดหมู่ความรู้
Email :
. . pui108108@yahoo.com
Line ID :
. . pui108diy
โทร: .. 089-797-9411
blog word press :
. . . pui108diy.com/wp/
รูป Flickr :
. . . ./photos/pui108diy/
รูป Wiki commons :
. . ./wiki/User:Pui108108
Pinterest :
. . . ./pui108108/
Youtube :
. . . ./user/p108108
หน้าที่เข้าชม | 214,168 ครั้ง |
ผู้ชมทั้งหมด | 167,913 ครั้ง |
เปิดร้าน | 17 ก.ย. 2558 |
ร้านค้าอัพเดท | 15 ก.ย. 2568 |