Atmega328P Datasheet 15. SCRST - System Control and Reset

Started by tha, January 05, 2018, 08:19:38 AM

Previous topic - Next topic

tha

ขออธิบายหน่อย บางท่านอาจจะไม่ทราบ ว่าทำแบบนี้หมายถึงอะไร
อย่างการกลับบิทแล้ว AND อย่างนี้

QuoteDDRD &= ~(1<<DDD3);           // port D3 is input

ซึ่งที่เรา include ไฟล์ io.h ไว้ในไฟล์ wdt.c ของเราใช่ไหม เพราะตอนเราสร้าง new project ใน AVR Studio 4.17 เราระบุเลือกเบอร์ ATmega328p เอาไว้ใช่ไหม ทำให้ไฟล์ io.h จะลิ้งค์ไปสู่ไฟล์ iom328p.h คราวนี้เราก็มาดูที่ไฟล์ iom328p.h ว่ามีอะไรบ้าง (ไฟล์จะอยู่ใน C:\WinAVR-20100110\avr\include\avr)

Quote
#define DDRD _SFR_IO8(0x0A)
#define DDD0 0
#define DDD1 1
#define DDD2 2
#define DDD3 3
#define DDD4 4
#define DDD5 5
#define DDD6 6
#define DDD7 7

ก็จะมีการ define เอาไว้ อย่างเช่น DDRD ก็จะเป็น special function register IO ตำแหน่งอยู่ที่แอดเดรส 0x0A ใช่ไหม
อย่าง DDD3 ก็ถูก define ไว้ว่ามีค่าเท่ากับ 3

คราวนี้เราก็มาดูตรงนี้ก่อนนะ (1<<DDD3) หมายถึงเรา shift left ข้อมูล "1" ของข้อมูลชั่วคราว 8 บิท ไป 3 ตำแหน่ง เพราะ DDD3 = 3 ก็จะได้ข้อมูล 8 บิทชั่วคราวเป็น 0b00001000

คราวนี้ต่อไปก็ทำกลับบิท ~(1<<DDD3) ก็จะทำการกลับบิทข้อมูลชั่วคราว 8 บิทจาก 0b00001000 ก็จะได้เป็น 0b11110111

คราวนี้มา &(AND) กับรีจีสเตอร์ DDRD &= ~(1<<DDD3); ก็จะมีความหมายว่า DDRD = DDRD & 0b11110111

ก็จะหมายถึงว่าเอาข้อมูลในรีจีสเตอร์ DDRD 8 บิทมา AND กับข้อมูลชั่วคราว 0b11110111
ก็จะหมายถึงว่าให้ข้อมูลในรีจีสเตอร์ DDRD อยู่คงเดิม ให้เฉพาะบิทที่ 3 กลายเป็น 0 เพียงบิทเดียว

ส่วนการ OR กันอย่างนี้ ก็จะคล้ายๆกัน ลองทำความเข้าใจดู ว่าให้บิทไหนในรีจีสเตอร์ WDTCSR เป็น "1" บ้าง ส่วนบิทอื่นจะคงเดิม ดูตำแหน่งบิทของรีจีสเตอร์นั้น ในดาต้าชีทประกอบเอานะ

QuoteWDTCSR |= (1<<WDCE) | (1<<WDE);

ส่วนการ = ก็จะไม่เหมือนการ OR เพราะจะทำให้บิทที่แสดงนั้นเป็น "1" ส่วนบิทอื่นในรีจีสเตอร์จะกลายเป็น "0" หมด

QuoteWDTCSR = (1<<WDE) | (1<<WDP2) | (1<<WDP1)| (1<<WDP0);

ลองทำความเข้าใจดูนะ ไม่เข้าใจก็สอบถามมาได้ครับ

tha

Bit 4 – WDCE: Watchdog Change Enable
เมื่อบิทนี้ถูกใช้ในการทำงานตามลำดับเวลา (timed sequences) สำหรับเปลี่ยนบิท WDE และบิท prescaler bits เพื่อที่จะเคลียร์บิท WDE และ/หรือเปลี่ยนบิท prescaler bits บิท WDCE ต้องถูกเซท เมื่อถูกเขียนให้เป็น "1" แล้ว hardware จะเคลียร์ WDCE หลังจาก 4 clock cycle

Bit 3 – WDE: Watchdog System Reset Enable
บิท WDE ถูกครอบงำโดยบิท WDRF ใน MCUSR นี้หมายถึงว่าบิท WDE จะเซทเสมอเมื่อบิท WDRF ถูกเซท เพื่อที่จะเคลียร์ WDE บิท WDRF ต้องถูกเคลียร์ก่อน คุณสมบัตินี้ช่วยให้มั่นใจได้ว่าจะรีเซ็ตหลายครั้งในช่วงที่เกิดสภาวะความล้มเหลวและการเริ่มต้นอย่างปลอดภัยหลังจากความล้มเหลว

Bits 2:0 – WDP[2:0]: Watchdog Timer Prescaler 2, 1, and 0
บิท WDP[3:0] กำหนด Watchdog Timer prescaling เมื่อ Watchdog Timer กำลังรัน ค่า prescaling values ที่แตกต่างกันและคาบเวลา timeout ที่ตรงกัน(กับค่า prescaling values ค่านั้น)ถูกแสดงในตารางดังต่อไปนี้



ปล. ก็จบละบทนี้ อยากจะให้ทำตัวอย่างไหนก็บอกมานะ ไล่แก้ตัวอย่างของตัวเองด้วย ว่ามีตัวอย่างไหนผิดอยู่ แล้วถึงจะขึ้น Interrupt เอาตามดาต้าชีทเก่านะ ดาต้าชีทใหม่เอาเบอร์อื่นมารวมอยู่เยอะเลย

tha

ลองทำ watchdog timer interrupt mode เซทบิทยังไง ก็ลองอ่านทำความเข้าใจในดาต้าชีทดูเอานะครับ อันนี้ผมก็ลอกเอามาจากดาต้าชีทนั่นแหละ มั่วๆมาเหมือนกัน เช็คด้วยนะว่ามีผิดไหม ลองไล่บิทดูเอานะ

การทำงานของบอร์ด พอเรากดสวิทช์ PD3 ก็จะ timeout ไปทำงาน WDT Interrupt แล้วเราก็ต้อง enable interrupt ใหม่( เซทบิท WDIE ใหม่) เพราะบิท WDIE กับบิท WDIF ถูกเคลียร์ ตอนโปรแกรมเราไปทำงาน WDT interrupt ใช่ใหม อ่านดาต้าชีทดูเอานะ

http://www.mediafire.com/file/vfkb0ab8py8ikg8/wdt_2.rar/file


tha

Quote
void WDT_on(void)
{
   __disable_interrupt();
   __watchdog_reset();
   /* Start timed sequence */
   WDTCSR |= (1<<WDCE) | (1<<WDE);
   /* Set new prescaler(time-out) value = 128K cycles (~1 s) */
   WDTCSR = (1<<WDE) | (1<<WDP2) | (1<<WDP1);
   __enable_interrupt();
}

ถ้าเราเซทบิท WDCE: Watchdog Change Enable แล้ว เราต้องเปลี่ยนค่า prescaler ให้ทันภายใน 4 clock cycle ใช่ใหม พอพ้นนี้แล้วบิท WDCE จะถูกเคลียร์โดย hardware ใช่ใหม ถ้าเวลาคอมไพล์โค้ดอย่างนี้ให้เป็นภาษาแอสเซมบลี่ แล้วมันจัดเรียงย่อบีบอัดก็คงจะทัน แต่เพื่อความแน่ใจ เราก็ใช้วิธีอย่างนี้ก็ได้ คือให้มันเท่ากับอย่างนี้ก็คงใช้เวลาเพียง clock cycle เดียว

Quote
void WDT_on(void)
{
   unsigned char N;
   __disable_interrupt();
   __watchdog_reset();
   N = (1<<WDE) | (1<<WDP2) | (1<<WDP1);
   /* Start timed sequence */
   WDTCSR |= (1<<WDCE) | (1<<WDE);
   /* Set new prescaler(time-out) value = 128K cycles (~1 s) */
   WDTCSR = N;
   __enable_interrupt();
}

คือเอาค่าที่เราจะเซทมารวมเก็บไว้ที่ตัวแปร N ก่อน พอเราเซท WDCE แล้ว เราก็ให้ WDTCSR = N ไปเลย อย่างนี้ก็คงจะไซเคิลเดียว ทันนะอย่างนี้ ไม่รู้ท่านใดแนะนำมา ก็ขอขอบคุณมานะที่นี้ด้วย เอ มีโปรแกรมไหนที่ทำไม่ทันนะ ชักจะลืม โปรแกรม sleep mode พร้อมกับทำ BOD disable ใช่มั๊ย แก้ไปแล้วหรือยังไม่ได้แก้นะ แต่ไม่ได้ทำวิธีนี้ วิธีนี้ดีนะดูง่ายดี