Atmega328P Datasheet 18. I/O Ports 1

Started by tha, August 25, 2019, 09:42:42 AM

Previous topic - Next topic

tha

เราลองมาทำกดปุ่มสวิทช์แล้วปล่อย ไฟจะวิ่งไปทีละดวง ใช้ PB0 เป็นอินพุทสวิทช์พร้อม internal pull-up ไม่ต้องใช้ตัวต้านทาน pull-up ภายนอก ส่วนไฟ LED ก็ใช้ PD0-7 มีท่านใดบอกมาอีกเนี้ย ก็ค่อนข้างที่จะไวเลย ช่วยกันคิดนะ ขอบคุณ

มีโปรแกรมตัวอย่าง
http://www.mediafire.com/file/1yz1ksgpt14n6hv/Switch_2.rar/file

มีแท๊บเล็ตแล้วก็มีภาพมายืนยัน ว่าทำงานได้จริง ไม่ได้หลอก  ;D

https://www.youtube.com/v/nqGyP_bubmQ

ปล. มือใหม่เพิ่งจะถ่าย มีอะไรต้องปรับปรุงบ้างก็บอกมานะ

tha

ลองทำอีกตัวอย่างนะ ใช้สวิทช์สองตัว PB0 เปิด PB1 ปิด พร้อม internal pull-up ไม่ต้องใช้ตัวต้านทาน pull-up ภายนอก เปิดปิดไฟ LED 8 ดวง ดูยังไม่สมบูรณ์ดี ก็ลองเอาไปโมกันนะครับ

มีโปรแกรมตัวอย่าง
http://www.mediafire.com/file/o3dlx9jc739eww9/Switch_3.rar/file

https://www.youtube.com/v/45P_Pft-1Ck

ปล. ชักจะคล่องแล้วกับการโพสต์ลงยูทูบ วันนี้พอก่อนนะ หรือจะเอาตัวอย่างอะไรก็บอกมาครับ

tha

ไหนๆก็ว่ากันถึง switch แล้วนะ ใครเจอปัญหาการ debounce บ้าง ลองเสิร์จหาในเน็ตเจออันนี้น่าสนใจ แต่ดูออกจะยากหน่อย มีง่ายกว่านี้ไหม เอามาลงกันหน่อย เดี๋ยวจะลองศึกษาตัวนี้ก่อนนะ ค่อนข้างยาก แต่ก็สามารถนำไปใช้ได้ถ้าเข้าใจมัน จะศึกษาตัวนี้นะวันนี้

https://www.avrfreaks.net/forum/tutsofthard-button-debouncing-software


tha

ผมเสิร์จคำว่า AVR switch debounce code ครับ อันนี้ก็ดูง่ายดี 
https://www.avrfreaks.net/forum/switch-debounce-code?page=all

Quote
// ---------- In header file ----------
#define KEY_UP         6
#define KEY_DN         7

// Pins
#define KEY_PINS       PIND

// Macros
#define KEY_DN_PRESS   (~(KEY_PINS) & (1<<KEY_DN))
#define KEY_UP_PRESS   (~(KEY_PINS) & (1<<KEY_UP))

// ---------- In main file ----------
int8_t read_keys(void) {
   if(KEY_UP_PRESS) {
      _delay_ms(10);
      while(KEY_UP_PRESS);      // Wait for key to be released
      _delay_ms(10);
      return 1;
   }
   if(KEY_DN_PRESS) {
      _delay_ms(10);
      while(KEY_DN_PRESS);
      _delay_ms(10);
      return -1;
   }
   else return 0;
}

ปล.  ท่านใดบอกมาอีกหล่ะ เอาตัวอย่างไหนดี ผมจะลองทำที่ตัวอย่างแรกก่อนนะ

tha

ได้แล้ว switch debounce สวิทช์เดียว ใส่สวิทช์ที่ PB0 ใช้ pull-up ภายใน ไม่ต้องต่อตัวต้านทาน pull-up ภายนอก หลอด LED ก็ต่อที่ PD0 เวลากดสวิทช์แล้วหลอด LED ก็จะ toggle ต้องกดสวิทช์ค้างไว้ วนถึง 4 รอบๆละ 10ms ครับ

http://www.mediafire.com/file/da6q49ww6mqlsme/Switch_Debounce_1.rar/file

มาดูตรงไหนยากบ้าง ตรงนี้จะงงหน่อย ก็ไม่มีอะไร ก็อาน PINB มาทั้ง 8 บิท ถ้าเรากดสวิทช์ PB0 อยู่ ค่าที่ได้ของ PINB0 ก็จะเป็น "0" คราวนี้พอกลับบิท ค่าที่ได้ก็จะเป็น "1" คราวนี้ก็มา AND กับ "1" shift left ไป PB0 (PB0 มีค่าเท่าไหร่ก็ไปดูที่ไฟล์ iom328p.h ใช่ไหม ตำแหน่งที่อยู่ผมก็จะบอกไว้ในโปรแกรมแล้ว) "1" กับ "1" AND กัน ก็ได้เท่ากับ "1" เมื่อสวิทช์ถูกกด ก็ไม่เท่ากับ "0" ก็ไม่เท่ากับ "0" ทางด้านขวา ก็ถูกก็เป็น "1" current_state ก็จะเป็น "1' เมื่อสวิทช์ถูกกดใช่ไหม
Quote
   // Check if button is high or low for the moment
   uint8_t current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;

Quote
// Variable to tell main that the button is pressed (and debounced).
// Main will clear it after a detected button press.
volatile uint8_t button_down;
เจอข้อผิดพลาดของตัวเองแล้ว เพราะไม่ได้เล่นมานานเลยลืม global variable มันต้องประกาศตัวแปรเป็น volatile ใช่ไหม มันถึงจะเห็นได้ทั้งโปรแกรมย่อยทั้งเมนโปรแกรม คือบีบอัด(project->configuration options->optimization = -Os) ก็จะเห็นตัวแปรอยู่ได้ทั้งเมนโปรแกรมทั้งโปรแกรมย่อย ก็สามารถทำงานได้

Quote
static inline void debounce(void)
ส่วนโปรแกรมย่อย static inline void นี้ไม่รู้ว่าทำใมต้องประกาศแบบนี้ ท่านใดทราบช่วยอธิบายหน่อย
ส่วนตัวแปร static ก็เป็นตัวแปรที่จะเก็บค่าไว้ ถึงแม้ออกจากโปรแกรมย่อยไปแล้วก็ตาม

ปล. โปรแกรมที่ผ่านมา ก็ถือว่าผิดบานเลย ที่ไม่ประกาศตัวแปร global variable ให้เป็น volatile แล้วก็ถึงจะบีบอัดได้  (project->configuration options->optimization = -Os) code size ก็จะลดลงมาเยอะเลย ไปลองแก้ที่ผ่านๆมากันนะ ข้าน้อยลืมจริงๆ  :'(

tha

ลองเสิร์จ "avr switch debounce code" กับ "bit_is_clear avr example" ก็ได้ตัวอย่างนี้มา เดี๋ยวจะลองทำตามตัวอย่างนะ
https://www.micahcarrick.com/avr-tutorial-switch-debounce.html
http://mlab.taik.fi/paja/?p=422

tha

ไม่ได้อ่านหรอก  ;D ดูผ่านๆเอาก็พอจะเดาได้ เขียนอย่างนี้มันกิน flash เยอะเหมือนกัน กับแค่สวิทช์เดียวกับ led หลอดเดียว กินตั้ง 3926 byte นี้ขนาด optimze แล้ว มีตัวอย่างให้ดูครับ

http://www.mediafire.com/file/ffuhcz3fnircfb3/switch_debounce_2.rar/file

_BV(bit) ก็ไปดูที่ๆเขา define ไว้แล้วใน sfr_defs.h ก็ included ใน io.h ตอนที่เรา include avr/io.h. ที่หัวโปรแกรม ก็จะอยู่ใน C:\WinAVR-20100110\avr\include\avr ลองไล่เช็คดูครับ (bit_is_clear() ก็อยู่ใน sfr_defs.h เหมือนกัน

Quote
#define _BV(bit) (1 << (bit))

Quote
#define bit_is_clear(sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit)))

ก็ลองทำความเข้าใจดู เดี๋ยวผมจะลองทำแบบ code ปกติที่เคยทำนะ จะดูว่า code size มันจะลดลงมั๊ย

tha

เจอปัญหา code size ใหญ่แล้ว เราไม่ต้องสร้างฟังชั่น delay_ms() เราสามารถใช้ฟังชั่น _delay_ms() ของไฟล์ delay.h ได้เลยโดยตรงได้เลย คราวนี้ code size จาก 3926 byte ก็ลดลงมาเหลือ 248 byte เอง

http://www.mediafire.com/file/t8t1ishaurxdgaj/switch_debounce_3.rar/file

fuse bit ตอนนี้เซทไว้เท่าไหร่กันแล้ว ของผม
             EXTENDED = 0xFC
             HIGH         = 0xDB
             LOW          = 0xDF
ชักจะลืมๆแล้ว พอเข้าที่แล้วก็ไม่ได้เปลี่ยนมานาน