Fig.1 STC8F1K08S2 MCU |
เหตุจากการที่ซื้อ MCU ของ STC มาหลายอัน พอมีเวลาว่าง เอามาลองเล่นเรื่อยๆ วันนี้ถึงคิว STC8F1K08S2 TSSOP20 มี 20 pin ราคา 0.38USD (ประมาณ 13 บาท)
Fig.2 STC8F1K08's features that lack of PCA |
มี 3 timer, 2 uart, SPI,I2C แต่ไม่มี ADC, PWM,PCA,CCP ฉะนั้นก็ต้องใช้ในงานที่ไม่ต้องการ analog input ส่วน PWM หรือ analog output ก็เขียนโปรแกรมให้มันทำงานได้ โดยใช้ timer ช่วยกำหนดเวลา จะว่าไป STC8H, STC8G ดูดีกว่า เพราะมี ADC
8F1K08 series นี้ มี Flash 8kB, SRAM 1.2kB นอกนี้ยังมี EEPROM ขนาด 3kB ที่เขียนได้เป็นแสนๆ ครั้ง
เมื่อไม่มี PCA ก็ไม่มี software timer ให้ใช้ แต่ก็มี timer0,1,2 ให้ใช้ ต้องเอามาทำตัวจับเวลาสักอัน และได้เลือก timer0 มาทำหน้าที่นี้ ส่วน timer1,2 เอาไว้ใช้กับ uart1,2
นึกถึง millis() ของ arduino ที่ไว้ใช้ทำ non-blocking process แต่ท้ายที่สุด millis() ก็จะเกิด overflow ทำให้เกิดการทำงานที่ผิดพลาดได้
เมื่อใช้ timer 16bit auto reload จะไม่เกิดปัญหาแบบเดียวกันกับ millis()
1. Timer0
การใช้งาน Timer0 มีรีจิสเตอร์ที่เกี่ยวข้องตามนี้
TMOD,TCON, TL0, TH0, ET0, EA, AUXR
void Timer0_Isr() interrupt 1
{
//TF0 = 0; //hardware set and reset automatically.
P10 = !P10; //test output
}//end timer0 isr
void main()
{
TMOD = 0x00; //timer0 mode0 16bit auto reload
TL0 = 65536 - 10*18432000/(12*1000); //10ms at 18.432MHz
TH0 = (65536 - 10*18432000/(12*1000))>>8;
TR0 = 1; //start timer0
ET0 = 1; //enable timer0 interrupt
EA = 1; //enable global interrupt
while(1);
}//end main
Fig 3. captured P10 with 10ms width |
2. เอา timer0 มาช่วยทำ non-blocking
ก็นับจำนวนครั้งของ timer overflow ใน timer0_interrupt
void Timer0_Isr() interrupt 1
{
//TF0 = 0; //hardware set and reset automatically.
count++; //count every timer0 overflown
if(count%10 == 0)
t100ms = 1;
if(count%100 == 0)
t1sec = 1;
if(count == 200)
count = 0; //reset counter
}//end timer0 isr
ใน while loop ปกติ ก็ดูว่ามันมีค่าเท่ากับ 1 หรือยัง
while(1)
{
if(t100ms == 1) //do this every 100ms
{
P10 = !P10; //test timing
t100ms = 0; //clear timer , declared as bit variable
}
if(t1sec == 1) //do this every 1sec
{
P11 = !P11; //test timing
t1sec = 0; //clear timer , declared as bit variable
}
}//end while
Fig 4. Captured P10 and P11 while using timer0 for non-blocking |
Fig.5 STC8F1K08S2 working with HMI. |
พอมีตัวเวลา timer0 ก็เอามาช่วยในการทำ PWM หรือว่าเป็น analog output (นึกถึง analog.write() ของ Arduino) ก็เขียนโค้ดให้มันทำได้
ความถี่ของ PWM ที่จะทำ ก็เอาสัก 1000Hz ส่วนของ Arduino ไลบรารี่เขาทำมาให้ประมาณ 490Hz
แต่ที่ 1000Hz นั้นจะมีคาบเวลา 1ms และ %duty PWM ก็ทำการปรับให้ยอดคลื่น x ให้กว้าง-แคบ ตามต้องการ
Fig.6 PWM 's wave form. |
เรารู้ว่า ที่ความถี่ 18.432MHz ใน 12T มันต้องทำงาน 1536 รอบจึงจะใช้เวลา 1ms เมื่อเป็นอย่างนี้แล้วก็ต้องกำหนดให้ TL0, TH0 มีค่า 65536 - 1536 = 64000
64000 เป็นค่าตั้งต้นของ TL,TH และเมื่อ Timer ทำงานอีกแค่ 1536 รอบ ค่า TL,TH ก็จะล้น เมื่อล้นก็เกิด interrupt (ที่ล้นก็เพราะตัวแปรเป็นชนิด 16bit เก็บค่าได้ 65536 ค่า เมื่อเกินกว่านี้ มันไม่ใช่ 65537 แต่มันจะไปเริ่มที่ 0 ใหม่ วนๆ ไป)
กลับมาที่ค่า x มันก็แค่ใส่ค่า ที่เป็นสัดส่วน 1/100 ของ 1536 เช่น ต้องการ 75% ก็ใส่ค่า 65536 - (75/100)x1536 = 64384
ประมาณนี้
void timer0_isr() interrupt 7
{
TR0 = 0;
if(P35 == 0){
TL0 = 65536-(75/100)*1536; //64384;
TH0 = (65536-(75/100)*1536)>>8;
}else {
TL0 = 65536 - (25/100)*1536;
TH0 = (65536 - (25/100)*1536)>>8;
}
P35 = !P35; //toggle pin P3.5
TR0 = 1; //start timer0 again
count++; //general purpose timer,counter
if(count == 2000) //x2 = 1ms
{
t1sec = 1;
count = 0;
}
}
Fig. 7 Timer0 making PWM |
Fig.8 95% duty PWM and pulse from Timer0. |
ก็ไม่สะดวกเท่าไหร่ เลือกได้ ก็เลือกเอารุ่นที่มี PWM ก็จะดี ไม่ต้องวุ่นวายขนาดนี้
ไม่มีความคิดเห็น:
แสดงความคิดเห็น