Ta đã biết ưu điểm của bộ TIMER 1 là cho phép đếm với độ phân giải 16bit. Cùng với đó là khả năng tùy chỉnh ngắt tràn (TOP_value).
Đề bài
Tạo xung chu kì 5ms, với độ rộng xung cao thay đổi được trong khoảng 1000us => 2000 us.
Code tạo xung trên pin ~9 theo đề bài
unsigned int Gia_tri_moi; void setup() { TCCR1A = 0; TCCR1B = 0; // RESET lại 2 thanh ghi DDRB |= (1 << PB1); // Đầu ra PB1 là OUTPUT ( pin 9) TCCR1A |= (1 << WGM11); TCCR1B |= (1 << WGM12) | (1 << WGM13); // chọn Fast PWM, chế độ chọn TOP_value tự do ICR1 TCCR1A |= (1 << COM1A1); // So sánh thường( none-inverting) TCCR1B |= (1 << CS11); // P_clock=16mhz/8=2mhz // mỗi P_clock bằng 1/2mhz= 0.5 us OCR1A = 2000; Gia_tri_moi = OCR1A; // Value=2000 , tương đương xung có độ rộng 2000*0.5us=1000us (1ms) // Value=4000, tương đương xung có độ rộng 4000*0.5us=2000us (2ms) ICR1 = 40000; // xung răng cưa tràn sau 40000 P_clock, tương đương (20ms) } void loop() { set(2000); // 0 độ } void set(unsigned int x) { if (Gia_tri_moi != x) { OCR1A = x; Gia_tri_moi = OCR1A; } else { return; // thoát ngay } // x : 2000 – 4000 //Độ rộng: 1ms – 2 ms }

Test servo
Giữ nguyên code trên, sửa hàm loop thành:
void loop() { set(2000); // 0 độ delay(1000); set(4000); // 180 độ delay(1000); }
Kết quả
Servo chỉ lệch góc trong khoảng 0 đến 90 độ !!!!!!!!!!!!!!!!!!!
Code sai ??!!!
Đến đây, mình đã bối rối khi làm đúng lý thuyết mà nó lại không như lý thuyết tí nào .
Lý thuyết nói: Xung có độ rộng 1ms => lệch 0, xung rộng 2ms => lệch 180. Xung có tần số 50 hz. (xung PPM cần độ dài tối thiểu 20ms để (có thể) ghép tối đa 10 servo).
Tất nhiên mình đã đáp ứng đúng tiêu chí trên.
Sự thật đằng sau!
Đã vậy thì mình sẽ kiểm tra xung của thư viện điều khiển Servo (servo.h) xem có sự sai khác gì không.
#include <Servo.h> Servo s9, s10; // tạo 2 Object void setup() { // pin ra ~9, ~10 s9.attach(9); s10.attach(10); // xuất xung s9.write(0); // 0 độ s10.write(180); //180 độ } void loop() { }

Kết quả
F_pwm=50hz.
Độ rộng xung: 530us (0.53ms) tương ứng góc lệch 0.
Độ rộng xung : 2410us (2.41ms) tương ứng góc lệc 180.
Đó, thực tế đó.!
Sửa lại độ rộng xung
unsigned int Gia_tri_moi; void setup() { TCCR1A = 0; TCCR1B = 0; // RESET lại 2 thanh ghi DDRB |= (1 << PB1); // Đầu ra PB1 là OUTPUT ( pin 9) TCCR1A |= (1 << WGM11); TCCR1B |= (1 << WGM12) | (1 << WGM13); // chọn Fast PWM, chế độ chọn TOP_value tự do ICR1 TCCR1A |= (1 << COM1A1); // So sánh thường( none-inverting) TCCR1B |= (1 << CS11); // P_clock=16mhz/8=2mhz // mỗi P_clock bằng 1/2mhz= 0.5 us OCR1A = 1060; Gia_tri_moi = OCR1A; // Value=1060 , tương đương xung có độ rộng 1060*0.5us=530us (0.53ms) // Value=4820, tương đương xung có độ rộng 4820*0.5us=2410us (2,41ms) ICR1 = 40000; // xung răng cưa tràn sau 40000 P_clock, tương đương (20ms) } void set(unsigned int x) { if (Gia_tri_moi != x) { OCR1A = x; Gia_tri_moi = OCR1A; } else { return; // thoát ngay } // x : 1060 – 4820 //Độ rộng: 0.53ms – 2.41 ms } void loop() { set(1060); // 0 độ delay(1000); set(4820); // 180 độ delay(1000); }
OK, thành công òi.