AVR-Xuất xung với tần số và độ rộng theo ý muốn

Mô tả dự án: 

Tiếp tục chuỗi bài: Điều khiển pin bằng ngôn ngữ chính thống. 

Bài viết này sẽ giúp bạn tạo một xung PWM có tần số và độ rộng xung theo ý muốn. 

Bài 3: Sử dụng thanh ghi như một bộ định thời và đếm sự kiện (timer/counter+interrupt)

Chủ đề này đã được bạn NTP_PRO viết rất kĩ, hãy tìm hiểu về nó nhé.

Link: http://arduino.vn/bai-viet/411-timercounter-tren-avrarduino

Nếu thấy chưa rõ phần nào hãy chủ động search goocle nha.

Tương lai sẽ có các bài viết với ví dụ minh họa về ngắt, các bạn hãy ủng hộ nhé ^^.

Bài 4: Chính là tiêu đề của bài viết này “Tạo xung theo ý muốn”

1: Làm sao để tạo xung?

Yêu cầu: Tạo xung vuông với tần số khoảng 1khz, độ rộng xung là 10%.

 
void setup()
{
    pinMode(13, OUTPUT);
}
void loop()
{
    digitalWrite(13, HIGH);
    delayMicroseconds(100);
    digitalWrite(13, LOW);
    delayMicroseconds(900);
}

 

 
void setup()
{
    analogWrite(5, 25);
    // 25/256=10%
}
void loop()
{
}

 

Về bản chất hàm analogWrite

  • Không cần khai báo pin.
  • Tần số mặc định trên pin 5,6 là 976 Hz (uno r3), trên pin 3, 11 là 976 Hz (Leonardo).
  • Tần số mặc định trên các pin còn lại là 490 hz.
  • Nó truy cập trực tiếp lên các thanh ghi nên không ảnh hưởng đến tốc độ sử lý . (bạn sẽ biết điều đó ngay bây giờ).

Chạy mô phỏng trên proteus

void setup()
{
    pinMode(13, OUTPUT);
    analogWrite(5, 25);
}

void loop()
{
    digitalWrite(13, HIGH);
    delayMicroseconds(100);
    digitalWrite(13, LOW);
    delayMicroseconds(900);
}

 

So sánh
DigitalWrite/port
AnalogWrite
Ưu điểm
Có tính ổn định cao.
Có thể tùy chỉnh tần số và độ rộng bằng delay.
Điều khiển chính xác, tần số cao,
Hoạt động độc lập và song song với các tiến trình.
Nhược điểm
Tần số thấp.
Ảnh hưởng tới tốc độ sử lý 1 luồng.
Phụ thuộc delay.
Tần số cố định là 976 hz (490 hz).

2: Truy cập thanh ghi điều khiển để thay đổi tần số

2.1: Cách tạo ra xung PWM.

Cấp một xung nhịp P_clock vào bộ đếm Counter, Xung P_clock được lấy ra từ bộ chia tần số hệ thống F_clock. Mỗi một xung P_clock sẽ làm bộ đếm Counter tăng thêm một giá trị, khi giá trị đạt max (tràn số) thì counter lại được đặt về 0 (Fast PWM) hoặc lại đếm lùi về 0 (Phase correct), quá trình này sẽ được lặp đi lặp lại .

Tiếp đến, bộ so sánh sẽ kiểm tra giá trị của bộ đếm Counter với một giá trị đặt trước Value, giá trị lấy ra từ bộ so sánh cũng chính là dạng xung PWM có tần số P_clock, độ rộng xung là tỷ số của Value với Counter.

 

2.2: Truy cập cài đặt các thanh ghi

Trên AVR 168/328, Việc tạo xung được hỗ trợ bởi 3 timer là TIMER 0 (8 bit), TIMER 1 (16 bit), TIMER 2 (8 bit). Mỗi Timer bao gồm 2 thanh ghi dữ liệu A-B, Bằng cách truy cập và thay đổi thông số của các thanh ghi, chúng ta sẽ cài đặt pin ra, bộ chia tần, đặt ngắt Value, lựa chọn kiểu Counter (xung răng cưa/ tam giác), kiểu so sánh, đặt ngắt tràn cho Counter…

AVR là mình gọi tắt của con Atmega - cái con vi điều khiển của con arduino đó các bạn

Trên AVR 328, Chúng ta có 6 pin hỗ trợ xuất xung.

 

Một vài thuật ngữ

Lấy ví dụ trên TIMER 1:

  • TCCR_1_A(Timer/Counter_1 _Control Register_ A)
  • TCCR_1_B(Timer/Counter_1 _Control Register _B)
  • TCNT_1(Timer/Counter Register )
  • ICR_1(Input Capture Register) 
  • OCR_1_A/B(Output Compare Register)

2.3 Đầu ra phụ thuộc vào kiểu so sánh “inverted” hay "none-inverted":

Ví dụ chọn kiểu đếm răng cưa (FAST PWM), kiểu so sánh thường ”none-inverted”. Tín hiệu ra là HIGH khi Value lớn hơn Counter, là LOW khi Value nhỏ hơn Counter. Khi chọn là “inverted”, tín hiệu đầu ra sẽ bị đảo lại so với trường hợp trên.

 

Kiểu đếm Counter tam giác cũng như vậy.

Tần số xung phụ thuộc vào xung nhịp P_clock (sau bộ chia tần) và dạng đếm counter.

Như đã biết, mỗi  P_clock thì counter tăng lên 1, nếu bộ đếm có cỡ là 8 bit thì cần 256 xung để đếm từ BOTTOM lên TOP (đếm răng cưa). Nếu chọn kiểu tam giác, khi Counter đạt TOP nó sẽ tiếp tục đếm lùi, khi đó nó cần 256*2 xung P_clock để đi hết một chu kỳ đếm.

Khi đó công thức tổng quát để tính tần số PWM là :

F_pwm =P_clock  /  (Top_value+1).    Fast Pwm.

Hoặc

F_pwm=P_clock  / (2*( Top_value+1)) .   Phase Cerrect Pwm.

Với P_clock =F_clock  / Prescaller.

Ví dụ

Chọn kiểu Fast Pwm, tần số thạch anh F_clock=16mhz, sử dụng bộ đếm timer 0 (8 bit = 1 byte) tương đương TOP_value=255+1. Giảm tầm số Counter xuống còn P_clock = 16mhz/64=250kHz. (Prescller=64).

Khi đó tần số của xung ra:

F_pwm=250khz/256=976.562 Hz.

Cũng như trên, nhưng chọn kiểu Phase Cerrect Pwm, tần số xung ra F_pwm=488.28 Hz.

1: TIMER 0 (8 BIT)

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR0A
COM0A1
COM0A0 
COM0B1
COM0B0
-
 -
 WGM01
WGM00 

Timer/Counter Control Register 0 A

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR0B
FOC0A
FOC0B
-
-
WGM02
 CS02
 CS01
CS00 

Timer/Counter Control Register 0 B

Timer/ counter 0 hỗ trợ 2 đầu ra là OC0A  OC0B tương ứng với (PD 5- pin ~5) (PD6 –pin  ~6).

Chọn kiểu so sánh (thường / đảo)

Cài cho PD5

COM0A1
COM0A0
 DESCRIPTION
0
 OC0A disabled
0
 WGM02 = 0: Normal Port Operation, OC0A Disconnected  WGM02 = 1: Toggle OC0A on Compare Match
1
 None-inverted mode (HIGH at bottom, LOW on Match)
1
 Inverted mode (LOW at bottom, HIGH on Match)

Applies only to PWM modes

Cài cho PD6

COM0B1
COM0B0
 DESCRIPTION
0
 OC0B disabled
0
 Reserved
1
 None-inverted mode (HIGH at bottom, LOW on Match)
1
 Inverted mode (LOW at bottom, HIGH on Match)

Applies only to PWM modes

Cài bộ chia tần số

 CS12
 CS11 
 CS10 
 DESCRIPTION
0
Chọn để không kích hoạt TIMER này
0
 No Prescaling =F_Clock
0
 F_Clock / 8
0
 F_Clock / 64
1
 F_Clock / 256
1
 F_Clock / 1024
1
 Không dùng F_clock, đặt một xung P_clock vào pin T1 (PD5), xung kích clock có chuyển mức trạng thái 5v->0v. (Sườn xuống -Falling)
1
 Không dùng F_clock, đặt một xung P_clock vào pin T1 (PD5), xung kích clock có chuyển mức trạng thái 0v->5v. (Sườn lên-Rasing)

CS bits

Chọn kiểu Counter (răng cưa/ tam giác)

 MODE
WGM02
WGM01
WGM00
 TOP
 DESCRIPTION
0
0
 
 Normal 
1
0
 0xFF
 PWM Phase Corrected
2
0
 OCRA
 CTC
3
0
 0xFF
 Fast PWM 
4
1
0
0
 -
 Reserved 
5
0
 OCR0A 
 PWM Phase Corrected 
6
 - 
 Reserved
7
 OCR0A 
 Fast PWM 

Waveform Generator Mode bits

<pin 6> <PD6> <pin 5><PD5>

void setup(){

  //B1:
TCCR0A=0;TCCR0B=0;
  // reset lại 2 thanh ghi
  //B2:
    DDRD |= (1 << PD6);
    // pin 6 là output
  //B3:
 
    TCCR0A |= (1 << WGM01) | (1 << WGM00);
    // chọn Fast Mode
    TCCR0A |= (1 << COM0A1);
    // đầu ra kiểu thường (none-inverting)
    TCCR0B |= (1 << CS01);
    //prescaler = 8, P_clock=16mhz/8=2mhz
    // Tần số xung F_pwm=2 mhz/256=7812,5 hz
   
    OCR0A = 128;
    // Value=128
    // Độ rộng xung= 128/256=50%
}
void loop(){
 
}
void setup(){
  //B1:
  TCCR0A=0;TCCR0B=0;
  // reset lại 2 thanh ghi
  //B2:
    DDRD |= (1 << PD5);
    // pin 5 là output
  //B3:
 
    TCCR0A |= (1 << WGM01) | (1 << WGM00);
    // chọn Fast Mode     TCCR0A |= (1 << COM0B1);
    // đầu ra kiểu thường (none-inverting)
    TCCR0B |= (1 << CS02)|(1 << CS00);
    //prescaler = 1024, P_clock=16mhz/1024=15,625 khz
    // Tần số xung F_pwm=15,625 khz/256=61,0351 hz
   
    OCR0B = 25;
    // Value=25
    // Độ rộng xung= 25/256=10%
}
 
void loop(){
 
}

Kết quả:

F=7813 Hz.

Độ rộng xung = 50%.

Chu kỳ xung: 0,129 ms.

Kết quả:

F=61 Hz

Độ rộng xung: 10%

Chu kỳ xung: 16,20ms

CODE Tương đương

<pin 6> <PD6>
<pin 5><PD5>
void setup()
{

    TCCR0B = 0;
    // reset lại thanh ghi
    TCCR0B |= (1 << CS01);
    analogWrite(6, 128);
    // pin 6 là output, Value=128
}
void loop()
{
}
void setup()
{

    TCCR0B = 0;
    // reset lại  thanh ghi
    TCCR0B |= (1 << CS02) | (1 << CS00);
    analogWrite(5, 25);
    // pin5, value=25
}
void loop()
{
}

 

Cảnh báo devil: Việc thay đổi tần số xung nhịp trên TIMER 0  sẽ gây ảnh hưởng đến các hàm delay(), delayMicroseconds(), millis(), micros(); , để an toàn hơn bạn hãy giữ nguyên và dùng hàm analogWrite là đủ rồi

TIMER 1 (16 BIT)

Timer/Counter1 có 2 đầu ra là OC1A OC1B tương ứng với pin ~9 pin ~10 trên arduino.

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR1A
COM1A1
COM1A0
COM1B1
COM1B0
-
 -
 WGM11
WGM10 

Timer/Counter Control Register 1 A

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR1B
ICNC1
ICES1
-
WGM13
WGM12
 CS12
 CS11
CS10 

Timer/Counter Control Register 1 B

Kiểu so sánh

COM1A1, COM1B1
COM1A0, COM1B0
   DESCRIPTION
0
 Normal port operation, OC1A/OC1B disconnected.
0
 Mode 9,11,14,15 only: Enable OCR1A only (OC1B disconnected)
1
 None-inverted mode (HIGH at bottom, LOW on Match)
1
 Inverted mode (LOW at bottom, HIGH on Match)

Applies only to PWM modes

Bộ chia tần

 CS12
 CS11 
 CS10 
 DESCRIPTION
0
Chọn để không kích hoạt TIMER này
0
 No Prescaling= F_Clock.
0
 F_Clock / 8
0
 F_Clock / 64
1
 F_Clock / 256
1
 F_Clock / 1024
1
 Không dùng F_clock, đặt một xung P_clock vào pin T1 (PD5), xung kích clock có chuyển mức trạng thái 5v->0v. (Sườn xuống -Falling)
1
 Không dùng F_clock, đặt một xung P_clock vào pin T1 (PD5), xung kích clock có chuyển mức trạng thái 0v->5v. (Sườn lên-Rasing)

CS bits

Kiểu counter

 MODE
WGM13
WGM12
WGM11
WGM10
 DESCRIPTION
 TOP
0
0
 Normal 
 0xFFFF
1
0
 PWM, Phase Corrected, 8bit
 0x00FF
2
0
 PWM, Phase Corrected, 9bit
 0x01FF
3
0
0
 PWM, Phase Corrected, 10bit 
0x03FF
5
 Fast PWM, 8bit 
0x00FF 
6
 Fast PWM, 9bit 
0x01FF 
7
1
 Fast PWM, 10bit 
0x03FF 
8
 PWM, Phase and Frequency Corrected 
ICR1 
9
 PWM, Phase and Frequency Corrected 
OCR1A 
10
 PWM, Phase Correct 
ICR1 
11
 PWM, Phase Correct 
 OCR1A
14
 Fast PWM 
ICR1 
15
1
 Fast PWM
OCR1A 

Waveform Generator Mode bits (Abbreviated)

Ưu điểm của timer 1 so với timer 0 là nó độ phân giải cao hơn, bộ đếm Counter 0 sẽ bị tràn sau 256 xung P_clock, còn Counter 1 sẽ tràn sau 512 xung Clock (9 bit) hoặc 1024 xung (10 bit), hoặc 65536 xung (16 bit).  Điều này giúp ta xuất xung PWM có rộng xung cực kỳ chính xác.

Ưu điểm nữa của Timer 1 là nó cho phép thay đổi giá trị TOP, ví dụ bạn có thể cài đặt ngưỡng tràn là 500 xung P_clock ( thay vì mặc định là 512 xung). Khi đó độ phân giải mặc định là 16 bit.

Còn lại cách dùng thì vẫn như cũ.

PB1 – pin 9
PB2-pin10
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)
    ICR1 = 65535;
    // xung răng cưa tràn sau 65535 P_clock
    OCR1A =16838;
    // Value=16838 -> độ rộng 25 %
    TCCR1B |= (1 << CS10)|(1 << CS11);
    // F_clock/64=16mhz/64=250 khz
    //F_pwm=250khz/65536=3.81469 hz
}
void loop(){
}
void setup(){
   TCCR1A=0; TCCR1B=0;
   // RESET lại 2 thanh ghi
  DDRB |= (1 << PB2);
  // Đầu ra PB2 là OUTPUT ( pin 10)
 
    TCCR1A |= (1 << WGM11);
    TCCR1B |= (1 << WGM12)|(1 << WGM13);
    // chọn Fast PWM chế độ chọn TOP_value tự do  ICR1
    TCCR1A |= (1 << COM1B1);
    // So sánh thường( none-inverting)
    ICR1 = 30000;
    // xung răng cưa tràn sau 30000 P_clock
    OCR1B = 15000;
    // Value=15000 -> độ rộng 50 %
    TCCR1B |= (1 << CS10);
    // F_clock/1=16mhz
    //F_pwm=16mhz/30001=533.315 hz
}
void loop(){
}

Kết quả:

F_pwm=3.814hz

Độ rộng xung: 25 %

Chu kỳ xung: 262,50 ms.

Kết quả:

F_Pwm=533.315 hz

Độ rộng: 50 %

Chu kỳ: 1.87 ms.

Như vậy việc sử dụng TIMER 1 -16 BIT cũng rất dễ dàng.

TIMER 2 (8 BIT)

Timer/Counter 2 phụ trách 2 đầu ra OC2A OC2B, tương ứng pin ~11 (PB3) và ~3 (PD3).

Timer 0 – 8 bit.

Timer 1 – 16  bit + khả năng thay đổi TOP value

Timer 2 thì lại có thể chia tần ở PRESCALER= 32 hoặc 128. Đó là ưu điểm của timer 2.

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR2A
COM2A1
COM2A0 
COM2B1
COM2B0
-
 -
 WGM21
WGM20 

Timer/Counter Control Register 2 A

 
 7 bit
 6 bit 
 5 bit 
 4 bit 
 3 bit 
 2 bit 
 1 bit 
 0 bit 
TCCR2B
FOC2A
FOC2B
-
-
WGM22
 CS22
 CS21
CS20 

Timer/Counter Control Register 2 B

Chọn kiểu so sánh

CÀI CHO PB3 (pin ~11)

COM2A1
COM2A0
 DESCRIPTION
0
 OC2A disabled
 WGM22 = 0: Normal Port Operation, OC2A Disconnected  WGM22 = 1: Toggle OC2A on Compare Match
1
 None-inverted mode (HIGH at bottom, LOW on Match)
1
 Inverted mode (LOW at bottom, HIGH on Match)

Applies only to PWM modes

CÀI CHO PD3 (pin ~3)

COM2B1

COM2B0

 DESCRIPTION

0

 OC2B disabled

0

 Reserved

1

 None-inverted mode (HIGH at bottom, LOW on Match)

1

 Inverted mode (LOW at bottom, HIGH on Match)

Applies only to PWM modes

Bộ chia tần

 CS22

 CS21 

 CS20 

 DESCRIPTION

0

 Chọn để không kích hoạt TIMER này

0

 No Prescaling  =F_Clock

0

 F_Clock / 8

0

 F_Clock / 32

1

 F_Clock / 64

1

 F_Clock / 128

1

 F_Clock / 256

1

 F_Clock / 1024

CS bits

Chọn kiểu Counter

 MODE

WGM22

WGM21

WGM20

 TOP

 DESCRIPTION

0

0

0

0

 0xFF

 Normal 

1

0

0

1

 0xFF

 PWM Phase Corrected

2

0

1

0

 OCRA

 CTC

3

0

1

1

 0xFF

 Fast PWM 

4

1

0

0

 -

 Reserved 

5

 1 

0

1

 OCR0A 

 PWM Phase Corrected 

6

 1 

1

0

 - 

 Reserved

7

 1 

1

1

 OCR0A 

 Fast PWM 

Waveform Generator Mode bits

KHI đó , giá trị TOP_value tất nhiên là bằng 255, vì thanh đếm chỉ có 8 bit.

PD3 (pin ~3)
PB3 ( pin ~11)
void setup(){
  TCCR2A =0; TCCR2B=0;
  //reset
    DDRD |= (1 << PD3);
    // PD3 output, (pin ~3)
    TCCR2A |= (1 << COM2B1);
    // so sánh thường ( none-inverting)
    TCCR2A |= (1 << WGM21) | (1 << WGM20);
    //  PWM Mode (răng cưa)
    TCCR2B |= (1 << CS22)|(1 << CS20);
    //  prescaler= 128, P_clock=16mhz/128=125 khz
    // F_pwm=125 khz/256=488.28 hz
 
    OCR2B = 25;
    // độ rộng xung =25/256=10%
}
 
void loop(){
}
void setup(){
  TCCR2A =0; TCCR2B=0;
  //reset
    DDRB |= (1 << PB3);
    // PB3 output, (pin ~11)
    TCCR2A |= (1 << COM2A1);
    // so sánh thường ( none-inverting)
    TCCR2A |= (1 << WGM21) | (1 << WGM20);
    //  PWM Mode (răng cưa)
    TCCR2B |= (1 << CS21)|(1 << CS20);
    //  prescaler= 32, P_clock=16mhz/32=500 khz
    // F_pwm=500 khz/256=1953.215 hz
 
    OCR2A = 128;
    // độ rộng xung =128/256=50%
}
 
void loop(){
}

Kết quả:

Tần số:  488 hz

Độ rộng :10 %.

Chu kỳ: 2,03 ms

Kết quả:

Độ rộng xung 50 %.

Tần số 1953 hz

Chu kỳ: 520 ms

Các bạn hết sức chú ý: Phân biệt DDRB DDRD khi khai báo chọn PINOUT cho các chân PORT.

Mình chèn Code dạng text nhằm nhấn mạnh điều này!

Ứng dụng

1. Xuất xung 8mhz ra ngoài

Đơn giản là ta sẽ chia cho mẫu số nhỏ nhất là 1.

Kĩ thuật này chỉ áp dụng cho TIMER1 vì nó có thể thay đổi tràn TOP_value.

Có nghĩa chỉ có 2 pin ~9 và ~10 mới có khả năng này

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)
    ICR1 = 1;
    // xung răng cưa tràn sau 1 P_clock
    OCR1A = 0;
    // xuất mọi lúc
    TCCR1B |= (1 << CS10);
    // F_clock=16mhz, P_clock=16/1=16mhz.
    //F_pwm=16mhz/(ICR1+1)=8mhz
}

void loop()
{
}

2. Xuất xung 16mhz ra ngoài

Theo công thức ngay ở đầu bài viết:

F_pwm P_clock  /  (Top_value+1).   

Để F_pwm=16mhz, thì TOP_value=0,P_clock=16mhz.

Điều này là không thể, bởi vì OCR1A (value) nhỏ nhất =0, khi đó nếu  ICR1 (TOP_value) cho bằng 0 thì nó sẽ không đếm được sự kiện.

3. Điều khiển SERVO với góc siêu chính xác

Thư viện SERVO.h mà chúng ta đang dùng có số góc điều khiển SERVO là số nguyên.(0->180) độ.

Vậy bạn có muốn điều khiển nó nhích 0.5 độ không ?  Hãy đón đọc bài tiếp theo nhé. yes

4. Hàm AnalogWrite!

Tới đây việc tự xây dựng một hàm AnalogWrite sẽ không còn khó nữa. Hiểu lầm lớn nhất của beginner khi sử dụng AnalogWrite  là đã “đánh đồng” cả 3 bộ TIMER là như nhau, khiến ta không khai thác được nhiều ưu điểm của từng TIMER.

Dưới đây là mã nguồn cho hàm analogWrite:

http://http://garretlab.web.fc2.com/en/arduino/inside/arduino/wiring_analog.c/analogWrite.html

Chế độ COUNTER tam giác (PHASE CERRECT PWM.)

Từ đầu đến giờ mình không sử dụng chế độ này, mà chỉ nói đến counter răng cưa. (FAST PWM)

Đó là vì hai chế độ này gần như tương đồng với nhau, PHASE CERRECT chỉ khác ở chỗ : Chu kì đếm tăng lên gấp 2 , tức là tần số P_clock của PHASE CERRECT nhỏ hơn 2 lần so với FAST PWM

Sử dụng 2 đầu ra cùng lúc.

Các ví dụ trên là sử dụng độc lập các đầu ra của timer, tinh ý sẽ thấy, ta luôn phải reset lại 2 thanh ghi trước khi muốn đặt lại bằng phép hợp (toán tử “ |”). Lý do reset vì nó đã được với các thông số  mặc định trước đó.  Tiếp nữa là tần số trên  hai đầu ra là luôn bằng nhau ( chung một Counter, chung tần số P_clock).

TIMER 0:

void setup(){
  ////////////////////////////////////////////////////
  TCCR0A=0;TCCR0B=0;
  // reset lại 2 thanh ghi
  //B2: 
    DDRD |= (1 << PD6);
    DDRD |= (1 << PD5);
    // pin 6, 5 là output
  //B3:

    TCCR0A |= (1 << WGM01) | (1 << WGM00);
    // chọn Fast Mode
    TCCR0B |= (1 << CS01);
    //prescaler = 8, P_clock=16mhz/8=2mhz
    // Tần số xung F_pwm=2 mhz/256=7812,5 hz

    ///////////////////////////////////////////////////////
    TCCR0A |= (1 << COM0A1);
    // đầu ra kiểu thường cho PD6 (none-inverting)
    TCCR0A |= (1 << COM0B1);
    // đầu ra kiểu thường cho PD5 (none-inverting)

    OCR0A = 128; //(chân PD6 ) Độ rộng xung= 128/256=50%
    OCR0B = 64;// (chân PD5) Độ rộng xung 64/256=25%
   
   
}


void loop(){

}

 

 

 

 

TIMER 1:

void setup(){
  /////////////////////////////////////////////////
   TCCR1A=0; TCCR1B=0;
   // RESET lại 2 thanh ghi
  DDRB |= (1 << PB1)|(1 << PB2);
  // Đầu ra PB1 và PB2 là OUTPUT ( pin ~9, ~10)

    TCCR1A |= (1 << WGM11);
    TCCR1B |= (1 << WGM12)|(1 << WGM13);
    // chọn Fast PWM, chế độ chọn TOP_value tự do  ICR1 

    ICR1 = 10000;
    // xung răng cưa tràn sau 10001 P_clock
    TCCR1B |= (1 << CS10)|(1 << CS11);
    // F_clock/64=16mhz/64=250 khz
    //F_pwm=250khz/10001=25hz
///////////////////////////////////////////////////
    
    TCCR1A |= (1 << COM1A1);
    // So sánh thường cho PB1 ( none-inverting)
    TCCR1A |= (1 << COM1B1);
    // So sánh thường cho PB2 ( none-inverting) 
    OCR1A =1000;//(PB1) Value=1000 -> độ rộng 10%
    OCR1B = 5000; //(PB2) Value=5000 -> độ rộng 50 %

}

void loop(){

  
}

 

 

TIMER 2:

void setup(){

  ////////////////////////////////////////////////////////
  TCCR2A =0; TCCR2B=0;
  //reset
    DDRD |= (1 << PD3);// PD3 output, (pin ~3)
    DDRB |= (1 << PB3);// PB3 output, (pin ~11)

    TCCR2A |= (1 << WGM21) | (1 << WGM20);
    //  PWM Mode (răng cưa)
    TCCR2B |= (1 << CS22)|(1 << CS20);
    //  prescaler= 128, P_clock=16mhz/128=125 khz
    // F_pwm=125 khz/256=488.28 hz
//////////////////////////////////////////////////
    TCCR2A |= (1 << COM2B1);// so sánh thường (PD3) (pin 3) ( none-inverting)
    TCCR2A |= (1 << COM2A1);// so sánh thường (PB3) (pin 11) ( none-inverting)

    OCR2B = 25; // (PD3) (pin 3)độ rộng xung =25/256=10%
    OCR2A = 128;//(PB3) (pin 11) độ rộng 50%

}

void loop(){
}

 

\

Kết

Tất cả các code trên đều được mình kiểm tra & chạy thử, mô phỏng thành công. Yêu cầu bạn thông thạo các phép toán BIT (BIT MATH).

Bài viết có thể chưa đủ với bạn, dưới đây là các trang web được mình sưu tầm về phần PWM+TIMER.

VIDEO HƯỚNG DẪN dùng Proteus để đo tần số.

Chúng ta lại vượt qua một chướng ngại vật nữa! ^^

Việc đào sâu về phần cứng sẽ giúp ta sử dụng arduino với một hiệu suất cao nhất, điều mà những cải tiến phần mềm sẽ không thể với tới được.

Chúc bạn sớm có những ứng dụng từ bài viết này .

<Đừng quên đón đọc bài tiếp theo về điều khiển SERVO siêu chuẩn nhé..> laugh

Tác giả THÁI SƠN.

lên
29 thành viên đã đánh giá bài viết này hữu ích.
Các dự án được truyền cảm hứng

Select any filter and click on Apply to see results

Các bài viết cùng tác giả

Giới thiệu cách sử dụng module GPS NEO 6 và NEO 7 của hãng Ublox

Hôm nay mình sẽ giới thiệu module GPS NEO 6 và NEO 7, rất cần thiết cho các dự án định vị vị trí và chuyển động, tốc độ cập nhật rất nhanh, trả về tọa độ rất chính xác, kết nối và sử dụng rất đơn giản là những ưu điểm của loại module này.

lên
18 thành viên đã đánh giá bài viết này hữu ích.

AVR-OSCILLOSCOPE - Tự làm Máy hiện sóng điện tử trên nền ARDUINO với giá chưa đến 300 nghìn

Ở phiên bản này, máy hiện sóng AVR-OSCILLOSCOPE của mình có thể được hiển thị lên 2 lcd thông dụng là NOKIA5110 hoặc lcd ST7565 Homephone .

Đây là thiết bị hiện sóng đa năng, mạnh mẽ và vô cùng gọn nhẹ. Các bạn hoàn toàn tự làm nó ngay lại công xưởng chế tạo tại nhà của mình với giá thành cực rẻ (chưa đến 300k - tính luôn Arduino Uno). 

lên
29 thành viên đã đánh giá bài viết này hữu ích.