Chapter 9 Interrupts Timers and Tasks
ปํญหาไม่ได้อยู่ที่ปัญหา
แต่อยู่ที่ทัศนคติของมึงในการเข้าถึงปัญหา- รุกกี้
Timer and Interrupts
MCU ต้องทำพวกนี้ได้
- วัดเวลา
- สร้าง time-based event (อาจจะเกิดครั้งเดียว หรือหลายครั้ง)
- ตอบสนองด้วยความรวดเร็ว
Tasks : Event-Triggered and Time-Triggered
Event-Triggered
เกิดเมื่อมี event ภายนอกมากระตุ้น
Time-Triggered
เกิดแบบ periodic ซึ่งถูกกำหนดโดย MCU
Polling
เอาง่ายๆ ก็คือต้องคอยไปอ่านสถานะของอุปกรณ์อยู่เรื่อยๆ
ทำไมเป็นปัญหา
1. ระหว่าง Poll ก็ทำอะไรไม่ได้
2. ความสำคัญของแต่ละอันเท่ากัน
Interrupt
เอาง่ายๆคือ interrupt สามารถหยุด CPU ได้เมื่อเกิด event
Simple Interrupt on the mbed
บอร์ด mbed ใช้ pin ได้ตั้งแต่ 5 - 30 เป็น Interrupt ยกเว้น 19,20
| Function | Usage |
|---|---|
InterruptIn(pin) |
สร้าง Object ของ Interrupt |
rise(ISR) |
ให้ Interrupt trigger ที่ขอบขาขี้น พร้อม Attach Interrupt Service Routine (ISR) (ก็คือฟังชั่นที่จะให้มันทำตอนเกิด event นั่นแหละ) |
fall(ISR) |
เหมือน rise แต่เป็นสัญญาณขาลง |
mode |
คือใช้ทำไรไม่เข้าใจ |
ตัวอย่างโค้ด
#include "mbed.h"
InterruptIn button(p5); //สร้าง object + กำหนด pin
DigitalOut led(LED1);
DigitalOut flash(LED4);
void ISR1() { // ฟังชันที่ทำตอนเกิด interrupt
led = !led;
}
int main() {
button.rise(&ISR1); // attach the address of the ISR
//function to the interrupt rising edge
while(1) { //continuous loop, ready to be interrupted
flash = !flash;
wait(0.25);
}
}
Deeper into interrupt (ข้อดี Interrupt)
- Prioritized บาง event สำคัญกว่าอันอื่นๆได้
- Masked เปิดปิดได้ เผื่อไปรบกวนอันที่สำคัญกว่า
- Nested ทำๆอยู่โดนแทรกจากอันที่สพคัญกว่าได้
- Location can be selected เลือกได้ว่าจะเอาไปไว้ใน memory ส่วนไหน
Delay between event occur and response is called latancy ถ้า Interrupt รอ processor ตอบ เขาเรียกว่า Pending
Testing interrupt latency
เอาง่ายๆโปรแกรมนี้จะวัดว่า Latency เยอะมั้ยโดยวัดว่า กว่า LED จะเป็น 1 ห่างจาก input squarewave เยอะมั้ย ในขณะที่กระพริบ LED ใน int main()
#include "mbed.h"
InterruptIn squarewave(p5); //Connect input square wave here
DigitalOut led(p6);
DigitalOut flash(LED4);
void pulse() { //ISR sets external led high for fixed duration
led = 1;
wait(0.01);
led = 0;
}
int main() {
squarewave.rise(&pulse); // attach the address of the pulse function to
// the rising edge
while(1) { // interrupt will occur within this endless loop
flash = !flash;
wait(0.25);
}
}
Interrupt from analog Inputs
ใช้ Comparator ครับสัญญาณขา \(V_+\) เกิน \(V_-\) Output ก็เป็น High ครับจบ😜
\(V_- = V_{sup} * \frac{R_2}{R_1+R_2}\)
The Digital Counter
ใช้ Flip-Flop เป็น Counter โดยนับได้เยอะแค่ไหนก็ขึ้นกับจำนวนบิตเช่น 8 bit ก็จะนับได้ตั้งแต่ 0-255 (\(0-(2^8-1)\)) และก็ถ้าต่อสัญญาณ Input เข้าไปที่ Clock มันก็จะนับ Clock ออกมาเป็น binary
สามารถอ่านได้, Preload ได้, จะ Reset เป็น 0 ก็ได้
Counting and Timing
ถ้า Clock Source ของ Counter มีความถี่คงที่ Counter นั้นก็จะกลายเป็น Timer Ex. ถ้าจะให้เข้าใจง่ายๆ ถ้ามี Clock ความถี่ 1MHz (อันบน) ทุก Clock Cycle ที่ผ่านไปจะทำให้ค่าใน Counter เพิ่มไป 1 ซึ่งไอค่า Counter เนี้ยสามารถใช้เป็นตัวนับเวลาได้ โดย Counter แต่ละเลขก็จะมีระยะเวลา 1uS (1/1MHz) เช่น ถ้า Counter มีค่าเท่ากับ 2000 ก็แปลว่ามีการนับมาแล้ว 2000uS
และพอ Counter มันนับไปจนสุดค่าของมัน (aka Overflow) ก็จะทำให้เกิด Interrupt ขึ้นแล้วก็จะ Reset ค่ากลับเป็น 0
คุณสมบัตินี้ใช้เอามากำหนด event ที่ต้องเกิดแบบ synchronize กันได้
MBED Timer
MBED มี Timers
- Timer General Purpose 4 ตัว
- Repetitive Interrupt Timer
- System Tick Timer
Timer ใช้กับ Simple Timing application
Timeout ใช้เรียกตอนหมดเวลาที่กำหนดไว้ (แบบ non-blocking)
Ticker ใช้เรียกฟังชั่นทุกครั้งที่ถึงเวลาที่กำหนด
Timer ทำได้ดังนี้
| Function | Usage |
|---|---|
start |
Start Timer |
stop |
Stop Timer |
reset |
Reset timer to 0 |
read |
get passed time in seconds |
read_ms |
get passed time in milliseconds |
read_us |
get passed time in microseconds |
Simple timer application
โค้ดนี้ก็ Start Timer -> ปริ้น Hello World และ Stop Timer
เพื่อวัดเวลาในการส่งข้อมูล(มั้ง)
#include "mbed.h"
Timer t; // define Timer with name “t”
Serial pc(USBTX, USBRX);
int main() {
t.start(); //start the timer
pc.printf("Hello World!\n");
t.stop(); //stop the timer
//print to pc
pc.printf("The time taken was %f seconds\n", t.read());
}
mbed Timeout
ฟังชันจะถูกเรียกใช้ตามเวลาที่กำหนด
| Function | Usage |
|---|---|
attach(ISR,seconds) |
Attach function และจำนวนวินาที ที่จะเรียกตอนเกิด timeout |
attach(ISR,seconds) |
Attach member?? function และจำนวนวินาที ที่จะเรียกตอนเกิด timeout |
attach_us(ISR,seconds) |
Attach function และจำนวน microseconds ที่จะเรียกตอนเกิด timeout |
attach_us(ISR,seconds) |
Attach member?? function และจำนวน microseconds ที่จะเรียกตอนเกิด timeout |
detach(ISR) |
Detach the function |
#include "mbed.h"
Timeout Response; //create a Timeout, and name it "Response"
DigitalIn button (p5);
DigitalOut led1(LED1); //blinks in time with main while(1) loop
DigitalOut led2(LED2); //set high fixed period after button press
DigitalOut led3(LED3); //goes high when button is pressed
void blink() { //this function is called at the end of the Timeout
led2 = 1;
wait(0.5);
led2=0;
}
int main() {
while(1) {
if(button==1){
Response.attach(&blink,2.0); //attach blink function to Response
//Timeout, to occur after 2 seconds
led3=1; //shows button has been pressed
}
else {
led3=0;
}
led1=!led1;
wait(0.2);
}
}
mbed Ticker
ฟังชันจะถูกเรียกใช้ตามเวลาที่กำหนด
| Function | Usage |
|---|---|
attach(ISR,seconds) |
Attach function และจำนวนวินาที ที่จะให้ ticker เมื่อถึงเวลา |
attach(ISR,seconds) |
Attach member?? function และจำนวนวินาที ที่จะให้ ticker เมื่อถึงเวลา |
attach_us(ISR,seconds) |
Attach function และจำนวน microseconds ที่จะให้ ticker เมื่อถึงเวลา |
attach_us(ISR,seconds) |
Attach member?? function และจำนวน microseconds ที่จะให้ ticker เมื่อถึงเวลา |
detach(ISR) |
Detach the function |
#include "mbed.h"
void led_switch(void); // Prototype function
Ticker time_up; //define a Ticker, with name “time_up”
DigitalOut myled(LED1);
void led_switch(){ //the function that Ticker will call
myled=!myled;
}
int main(){
time_up.attach(&led_switch, 0.2); //initialises the ticker
while(1){ //sit in a loop doing nothing, waiting for
//Ticker interrupt
}
}
Real Time Clock
RTC (Real time clock) เอาง่ายๆ คือนาฬิกาที่กินไฟน้อยมาก
ใช้ Clock ความถี่ 32kHz
| Function | Usage |
|---|---|
Time |
Get Current Time |
set_time |
Set Current Time |
mktime |
converts converts the time structure into a calender time value |
localtime |
Converts a timestamp to a tm structure |
ctime |
Converts a timestamp to a human-readable string |
strftime |
Converts a tm structure to a custom format human-readable string |
#include "mbed.h"
InterruptIn button(p18); // Interrupt on digital pushbutton input p18
DigitalOut led1(LED1); // digital out to LED1
Timer debounce; // define debounce timer
void toggle(void); // function prototype
int main() {
debounce.start();
button.rise(&toggle); // attach the address of the toggle
} // function to the rising edge
void toggle() {
if (debounce.read_ms()>10) // only allow toggle if debounce timer
led1=!led1; // has passed 10 ms
debounce.reset(); // restart timer when the toggle is performed
}
Realtime Operating System (RTOS)
มี OS ช่วยในการจัดสรรทรัพยากร แบ่งทรัพยากรกัน รันโค้ดพร้อมกัน เรียกว่าเป็น Task หรือ Threads โดย RTOS ทำ 2 อย่างหลักๆ
- Decides which Program run for how long
- Provide Commu and Sync between tasks
- Control overall resource
RTOS Scheduling
RTOS ยังมี Scheduler เอาไว้กำหนดว่า Task ไหนรัน และรันนานแค่ไหน
Ex. Round Robin Scheduler sync activity to clock tick แต่ Round robin จะ Switch ทุก Clock Tick ไม่ว่า Task แต่ละอันจะเป็นไง ก็เลยไม่มี Task Prioritization (แต่ scheduler อันอื่นอาจจะมีนะ)