เขียนโปรแกรม MCS-51 ขยาย Port Input แบบไม่จำกัดด้วย CD4021

ในการออกแบบให้ microcontroller รับอินพุตดิจิตอลวิธีที่ตรงไปตรงมาที่สุดคือการต่อกับ Port ของ microcontroller โดยตรง แต่ถ้าอินพุตมีจำนวนมากซัก 10-20 อินพุต เราจะทำยังไง หลายคนอาจจะใช้วิธี Scan Keyboard เอา วิธีนี้มีข้อจำกัดตรงที่แต่ละอินพุตไม่อิสระต่อกัน เพราะต่อแบบ matrix

แล้วมีวิธีที่ดีกว่านี้อีกไหม? คำตอบคือมีครับ คือใช้ Shift register รับข้อมูลแบบขนาน แล้วให้สัญญาณออกมาเป็นแบบอนุกรม (Parallet in/ Serial put) โดยใช้ IC CD4021 ภายใน IC จะประกอบไปด้วย flip-flop เมื่อเราส่ง clock ไป 1ลูก data ที่ flip-flop จะส่งไปยังตัวถัดไป ถ้าเราส่ง clock ไป 8 ลูก เราก็จะได้ data จาก 8 อินพุต

จากรูปจะเห็นว่าเอาต์พุตของ flip-flop ตัวซ้าย จะเป็นอิพุตของ flip-flop ตัวขวาไปเรื่อยๆ สำหรับ data จะอยู่ที่ขา Q6, Q7, Q8 เวลาใช้งานจริงเราต่อที่ Q8 ตัวเดียวก็พอครับ ส่วน Q6, Q7 ก็ปล่อยลอยไว้ IC CD4021 1 ตัวจะต่ออินพุตได้ 8 อินพุต แต่เราสามารถต่อ IC CD4021อนุกรมกันไปได้เรื่อยๆ โดยต่อ Q8 เข้ากับ Serial input ไปเรื่อยๆ

ทีนี้มาดูในส่วนของการเขียนโปรแกรมกัน โปรแกรมตัวอย่างจะใช้ 89S52 MCS-51 เบอร์ยอดนิยมของผม

ด้านล่างจะเป็น function อ่านค่าจาก CD4021 ที่ที่อ่านได้จะ return กลับมา

//===============================================//
//??? ??? ??? ??? ??? ??? ??? ??? ?? Read data from CD4021
//===============================================//
unsigned char read_cd4021()
{
unsigned char i,a,inport,dat;

STR = 1;
STR = 0;
a = 4;??? while(a)??? a–;
dat = 0;
for (i=0;i<8;i++)
{
inport = DAT;
dat <<= 1;
dat |= inport;

CLK = 1; ??? a = 4;??? while(a)??? a–;
CLK = 0;??? ??? a = 4;??? while(a)??? a–;

}
STR = 1;

return(dat);
}

อันนี้ main()

//———————————————————–//
// Main
//———————————————————–//
void main()
{
init();
dmsec(200);??? ??? ??? //at least 100 mS
init_lcd();
dmsec(200);??? ??? ??? //at least 100 mS

show_portval_lcd();
while(1)
{
port_present = read_cd4021();
if(port_last!=port_present)
{
port_last = port_present;
show_portval_lcd();
dmsec(200);
}
}
}

ในการทดลองนี้ผมจะต่อ LCD 16×2 แสดงผลค่าที่อ่านได้จาก port โดยใช้อินพุตเป็น DIP Switch ขนาด 8 สวิตช์ มาดูส่วนของวงจรกันต่อ

การทดลองนี้ต่อ IC CD4021 ลง Proto board ครับ ทดลองเสร็จก็ไปใช้งานอื่นๆได้ต่อสะดวกดี ต่ออุปกรณ์เสร็จแล้ว ทดลองกันเลยดีกว่า

ในตอนสวิตช์ไม่สับลง GND ก็แสดงค่า 255 อันนี้ถูกต้องครับ ต่อมาสับสวิตช์ 1 และ 2 ไปที่ GND ถ้าเทียบเป็นเลขฐาน 2 จะได้ 11111100 = 252 สังเกตุว่าเท่ากับที่หน้าจอ LCD แสดงผล เป็นอันว่าอ่านค่าได้ถูกต้อง

Download

datasheet CD4021

source code CD4021(zip)

Watchdog Timer สำหรับ 89S52 ใน Keil

ถ้าพูดถึงไมโครคอนโทรลเลอร์ตระกูล MCS-51 ที่ผมชอบใช้ ก็เป็นเบอร์ 89S52 เนื่องจากมีราคาที่ถูกมาก และที่ถูกอกถูกใจคือผมไม่ต้องถอด IC มา burn เหมือนแต่ก่อนแล้ว ผมต่อสายจาก parallel port มา burn IC ได้เลย (ISP Programming) สะดวกกว่า ICD2 ของ Microchip เสียอีก

เอาละมาเข้าเรื่องกันดีกว่า มันมีอยู่งานนึงที่ผมใช้ 89S52 แต่มันเป็นงานที่ทำตลอด 24 ชั่วโมง ฉะนั้นมันแฮงค์ไม่ได้เลย ผมจำได้ว่า 89S52 มันมี Watchdog Timer ในตัวด้วย เลยไม่รอช้าเปิด datasheet มาดู เค้าบอกว่าอย่างนี้

การที่จะ Enable ให้ Watchdog ทำงานนั้นให้เขียนข้อมูล 0x1E และ 0xE1 ลงไปใน register WDTRST ต้องเขียนต่อกันเลยนะถึงจะใช้ได้ ส่วน Watchdog Timer ตัวนี้เป็น Counter 13 บิตแล้วจะนับขึ้นทุก machine cycle แล้วถ้าปล่อยให้นับได้ถึง 8191 (0x1FFF) เมื่อไหร่ละก็ จะเกิดการรีเซต ฉะนั้นเราต้องเขียนโปรแกรมไปคอยเคลียร์ไม่ให้ Watchdog Timer มันนับไปถึงค่า Overflow 8191

การเคลียร์ Watchdog Timer ก็ทำเหมือนกับ enable นะแหล่ะ ก็เขียนข้อมูล 0x1E และ 0xE1 ลงไปใน register WDTRST ถ้าอยากรู้ว่า 8191machine cycle นี่นานขนาดไหนมาลองคำนวนเล่นๆกันดีกว่า

ตัวอย่าง สมมุติว่าใช้ XTAL 11.0592 MHz แล้ว clock 12 ลูกจะได้ 1 machine cycle

T = (8191*12)/(11059200) = 8.887 mS ฉะนั้นเราต้องไปเคลียร์ Watchdog Timer ทุกๆ 8.8 mS เป็นอย่างน้อย หรือใครจะเคลียร์ทุกๆ 1 mS ก็ยิ่งดี ส่วนตัวเลข 8191 นี่เค้ากำหนดมาตายตัว เราไม่สามารถ scale ได้

ลองดู code ที่จะนำไปใช้กับ Compiler keil ดู

อันดับแรกเราก็ต้องประกาศ sfr (Speacial Function Register) ก่อนเพราะใน AT89X52.h ไม่ได้ประกาศ register WDTRST มาให้

sfr WDTRST = 0xa6;
sfr AUXR = 0x8e;

จากนั้นก็ Enable และ เคลียร์ด้วย Sub void kickdog()

void kickdog()??????????????????????????????? //every 8191 Machine Cycle
{ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //~8 ms
WDTRST = 0x1e;
WDTRST = 0xe1;
}

จากนั้นเราก็หาที่วาง void kickdog() ใน function ต่างๆ (แนะนำว่าควรวางใน loop while(1) )? เพียงเท่านี้ 89S52 ของเราก็ทำงานได้นานแสนนาน โดยที่ไม่แฮงค์ (ถึงแฮงค์ก็รีเซตตัวเองขึ้นใหม่ได้)

การทดลองที่ 7 เขียนโปรแกรม Interface กับ DigitalPot

MCP4011

MCP4011

อาจจะมีบางงานที่คุณต้องการจะควบคุณสัญญาณ Analog ด้วย Digital I/O เช่นควบคุม Gain แต่ไม่รู้ว่าจะใช้อะไรควบคุม ลองมาดูตัวนี้ครับครับ MCP4011 Low-Cost 64-Step Volatile Digital POT มีความละเอียด 6 บิต หรือ 64 สเตป ใช้ขาสัญญาณเพียง 2 ขาในการ Interface ขา CS และ U/D

Volatile Digital Potentiometer in SOT-23 packages

64 Taps: 63 Resistors with Taps to VSS and VDD Simple Up/Down (U/D) Protocol Power-up to midscale

  • Resistance Values: 2.1Ohm, 5kOhm, 10kOhm, 50kOhm
  • Low Tempco: – Absolute (Rheostat): <150 ppm (typ.) – Ratiometric (Potentiometer): <10 ppm (typ.)
  • Low Wiper Resistance: 70? (typ.)
  • Low-Power Operation: 1mA Max Static Current
  • Wide Operating Voltage: 1.8V to 5.5V Extended Temperature Range: -40C to +125C
ตำแหน่งขา

ตำแหน่งขา

การเขียนโปรแกรมให้ POT มีค่าลดลง

void increase_pot (unsigned char nstep)
{
unsigned char a,cnt;
UD_POT = 0;
CS_POT = 0;
for (cnt = 0;cnt < nstep;cnt++){ a = 8;
while(a)
a–;
UD_POT = 1;
a = 8;
while(a)
a–;
UD_POT = 0;
}
CS_POT = 1;
}

ให้ขา U/D เป็น “0″ ก่อนแล้วจึงดึง CS ลง “0″ จากนั้นก็ส่ง pulse ไปที่ขา U/D ส่ง pulse ไป 1 ลูกค่า POT จะลดลงไป 1 Step

การเขียนโปรแกรมให้ POT มีค่าเพิ่มขึ้น

void decrease_pot (unsigned char nstep)
{
unsigned char a,cnt;
UD_POT = 1;
CS_POT = 0;
for (cnt = 0;cnt < nstep;cnt++){ a = 8;
while(a)
a–;
UD_POT = 0;
a = 8;
while(a)
a–;
UD_POT = 1;
}
CS_POT = 1;
}

ให้ขา U/D เป็น “1″ ก่อนแล้วจึงดึง CS ลง “0″ จากนั้นก็ส่ง pulse ไปที่ขา U/D ส่ง pulse ไป 1 ลูกค่า POT จะเพิ่มขึ้นไป 1 Step

การทดลอง

การทดลอง MCP4011 DigitalPot
การทดลอง MCP4011 DigitalPot

ทฤษฎีก็ว่ากันไปแล้วมาถึงการทดลอง ผมได้ลองใช้ MCP4011 เป็นตัวปรับ Gain ของ AMP LM386 โดยให้ไมโครคอนโทรลเลอร์ 89S52 รับค่าจากสวิตช์ ถ้ากดสวิตช์เพิ่มเสียง MCP4011 ก็จะเพิ่มค่า R ทำให้เสียงดังขึ้น และจะมีตัวเลขแสดง Step ของ MCP4011 ใชว์ที่จอ LCD16x2 ด้วย ในทางตรงกันข้าม ถ้ากดสวิตช์ลดเสียงก็จะลดค่า R ทำให้เสียงค่อยลง ค่าสูงสุดที่กดได้จะเป็น 64/64 และค่าต่ำสุดเท่ากับ 0/64 สำหรับตัว MCP4011 ถ้าสนใจสามารถซื้อได้ที่ บ. Electronics Source

89S52 Port Define

  • P1.1 <—> CS (MCP4011)
  • P1.2 <—> U/D (MCP4011)
  • P1.3 <—> SW UP
  • P1.4<—> SW UP

Download Code MCS51 การทดลองที่ 7 เขียนโปรแกรม Interface กับ DigitalPotentiometer ควบคุมความดังของเสียงเพลงด้วยการกดปุ่ม