You are on page 1of 35

timer/counter: dùng để đếm thời gian hay sự kiện.

ngoài ra nó còn dùng nhiều chức


năng khác. Khi tìm hiểu sâu bạn sẽ biết.
ví dụ bạn đếm sản phẩm hoặc xung encoder đưa về, khi đếm đủ thì bạn làm gí dó tùy
bạn lập trình.
Nó còn có thể ngắt, so sánh, pwm...
========================================================================
Cho bạn một ví dụ đơn giản nhé : với CPU AT90S2313 (Atmega8 không khác gì); hãy lập trình cho
Timer0 phát xung tần số do mình tự đặt ,còn Timer1 phát xung PWM

#include <90s2313.h>
#define XUNG PORTD.0 //Xung đầu ra
// Ngắt T0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
XUNG=!XUNG;
}

// Declare your global variables here

void main(void)
{
PORTB=0x00;
DDRB=0x08;
PORTD=0x00;
DDRD=0xFF; // Port D có chiều ra

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 500,000 kHz đầu vào xung 500.000khz
TCCR0=0x02;
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 500,000 kHz
// Mode: CTC top=OCR1A
// OC1 output: Toggle
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x40;
TCCR1B=0x0A;
TCNT1H=0x00;
TCNT1L=0x00;
OCR1H=0x00;
OCR1L=0xFF; // mức so sánh PWM

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization


TIMSK=0x02;

ACSR=0x80;

// Global enable interrupts


#asm("sei")

while (1)
{
// Place your code here

};
}

và sau đây là sơ đồ kết nối và dạng sóng tạo ra.


Nói chung là bạn nên kiếm sách để học qua về Timer trước khi làm tiếp vì chưa có cơ bản thì khó nói
lắm. chúc thành công. có thể lấy quyển VDK của Thầy Tống Văn On

http://dientuvietnam.net/forums/showthread.php?p=67457#post67457
File gửi kèm
===================================================================
Bài 4 AVR - Cách dùng Timer trong vi điều khiển AVR
Người gửi: bmnhy

Sử dụng bộ định thời là nhu cầu của nhiều lập trình viên. Thông thường mỗi loại vi
điều khiển đều có bộ định thời. Hôm nay VAGAM xin giới thiệu tới các bạn bài viết về
cách dùng Timer trong vi điều khiển AVR.

Đặc tính:

- Bao gồm các bộ timer 8bit 16 bit, thường có từ 3 – 4 bộ Timer


- Có các kênh PWM (từ 4 đến 8 kênh tuỳ loại )
- Bao gồm nhiều chế độ ngắt và PWM …
- Có thể là một kênh đếm riêng biệt
- Tự động xoá Timer trong chế độ so sánh(tự động nạp lại)
- Có chế độ PWM
- Tạo ra tần số
- Đếm các dự kiện ngắt ngoài
- Tạo ra các ngắt tràn và ngắt so sánh
....

Introduction

Các chế độ hoạt động của timer:

Chế Độ Thông Thường:


Đây là chế độ hoạt động đơn giản nhất của Timer .Bộ đếm sẽ liên tục đếm tăng lên cho đến khi vượt quá giá trị lớn nhất
TOP và sau đó sẽ được khởi động lại tại giá trị Bottom.Trong các hoạt động thông thường thì cờ tràn sẽ được thiết lập khi
giá trị trong Timer đạt giá trị không và không bị xoá đi.Tuy nhiên nếu mà ngắt tràn được chấp nhận thì cờ ngắt sẽ tự động bị
xoá khi ngắt được thực hiện.Giá trị trong Timer có thể được viết vào bất cứ lúc nào

Chế Độ So Sánh (CTC):


Đấy là chế độ mà giá trị trong Timer luôn được so sánh với giá trị trong thanh ghi ORC .Khi giá trị trong Timer bằng giá trị
trong thanh ghi ORC thì giá trị trong Timer sẽ bị xoá đi.Giá trị trong ORC đóng vai trò là giá trị TOP cho bộ đếm.Chế độ
này cũng cho phép tạo ra tần số so sánh ở đầu ra.Tuy nhiên trong chế độ này nếu giá trị mới ghi vào thanh ghi ORC mà nhỏ
hơn giá trị tức thời của bộ đếm thì thì 1 so sánh sẽ bị lỡ, khi đó bộ đếm sẽ đếm đến giá trị lớn nhất sau đó rơi xuống giá trị 0
trước khi so sánh tiếp theo xuất hiện.
Sơ đồ thời gian của chế độ CTC

Chế Độ Fast PWM:


Cho phép tạo ra sóng với tần số cao.Sự khác biệt cơ bản giữa Fast PWM với các loại PWM khác là nó chỉ sử dụng 1 sườn
dốc.Bộ đếm sẽ đếm từ Bottom đến Max sau đó khởi động lại từ bottom. Trong chế độ không đảo đầu ra của chân so sánh
OCx sẽ bi xoá khi có phép toán so sánh giữa TCNTx và thanh ghi ORC là bằng nhau. Và sẽ được sét lên 1 khi giá trị đạt
Bottom. Trong chế độ đảo ,đầu ra đảo sẽ được set lên 1 khi sự so sánh giữa thanh ghi ORC và giá trị trong Timer bằng nhau
và sẽ bị xoá khi giá trị đạt Bottom.Trong cả hai trường hơp này tần số của chế đô Fast PWM đều gấp đôi so với chế độ
phase correct PWM sử dụng hai sườn dốc
Với tần số cao này chế độ độ Fast PWM rất tốt cho các ứng dụng như ADC hay chỉnh lưu.Ngoài ra với tần số cao giúp làm
giảm kích thước của thiết bị ngoài như cuộn dây tụ từ đó giúp làm giảm toàn bộ chi phí cho hệ thống
Sơ đồ dưới đây mô tả chu kỳ thời gian của chế độ:

Biều đồ thời gian chế độ Fast PWM


Chế độ Phase correct PWM:
Chế độ này hoạt động dựa trên hai sườn lên xuống.Bộ đếm sẽ đếm liên tục từ giá trị BOTTOM đến giá trị MAX và sau đó
từ giá trị MAX đến giá trị BOTTOM.Trong chế độ so sánh không đảo chân so sánh (OCx) sẽ bị xóa khi giá trị TCNTx bằng
giá trị OCRx trong quá trình đếm lên và sẽ được set bằng 1 khi giá trị so sánh xuất hiện trong quá trình đếm xuống.Chế độ
so sánh đảo thì các giá trị là ngược lại.Với hoạt động hai sườn xung này thì chế độ này không tạo ra được tần số nhỏ như chế
độ một sườn xung .Nhưng do tính cân đối của hai sườn xung thì nó tốt hơn cho điều khiển động cơ
Chế độ phase correct PWM hoạt động cố định là 8 bít.Trong chế độ này bộ đếm sẽ tăng cho đến khi đạt giá trị MAX ,khi đó
nó sẽ đổi chiều đếm.Biểu đồ thời gian đây mô tả hoạt động của toàn bộ quá trình:

Từ biểu đồ thời gian ta nhận thấy việc thay đổi tần số trong hoạt động của phase correct PWM có thể thay thế bằng hai giá
trị là MAX và BOTTOM. Nó linh hoạt hơn so với chế độ Fast PWM.
Tần số có thể tính theo công thức như sau:

f=fc/N*510

Trong đó N tạo ra bởi bộ chia nó có các giá trị là:1,8,64,256 hoặc 1024

Các thanh ghi trong bộ Timer/ Counter:

Thanh ghi điều khiển - TCCRx:


Bít 3,6 –WG00-WG01: Đây là các bít chọn chế độ trong Timer.Các giá trị được mô tả trong bảng sau.

Bảng chọn chế độ Timer:

Bít 5-4 : COM00-COM01: Quy định giá trị đầu ra trong các phép so sánh
Bít 2: 0 – CS2:0 :Đây là các bít quy định xung cấp cho hoạt động của Timer.Bảng dưới đây mô tả toàn bộ các giá trị

Chọn chế độ cho xung Clock

Thanh ghi cờ ngắt-TIFR:

Bít 1-OCFx : Khi hai giá trị bằng nhau bít này được set lên bằng 1
Bít 1-TVOx : Khi bộ đếm vượt quá giá trị Top thì bít này được set bằng 1

Thanh ghi mặt nạ ngắt-TIMSK:

Bít 1 – OCIEx: khi bít này được set lên bằng 1 thì cho phép ngắt so sánh
Bít 0 –TOIEX : Khi bít này được set lên bằng 1 thì cho phép ngắt tràn
đoạn chương trình trên dùng timer1. Timer này là bộ đếm 16bit nên giá trị đếm được tối đa là FFFF. Trong phần khởi tạo
Timer ta khởi tạo xung clock cho bộ đếm là 125Khz = 125000 có nghĩa là bộ đếm sẽ đếm được 125000 giá trị trong 1 giây.
Ta làm phép tính như sau:

125000 số ----1 giây


? số----- 0,02 giây (20ms)
ta tính được trong 20ms bộ timer sẽ đếm được là: 125000x0.02= 2500 số.
Ta cần là làm sao cho timer1 đếm được 2500 số sẽ tràn có nghĩa là cần phải nạp vô nó một giá trị xác định trước
(mặc định nó sẽ đếm từ 0000>FFFF và bị tràn) giá trị này sẽ nhỏ hơn 65535(FFFF) là 2500 (9C4 Hexa) vậy ta tính được
giá trị cần nạp lại sau mỗi lần tràn là FFFF- 9C4 = F63B.

#include

unsigned char count=0;

interrupt [TIM1_OVF] void timer1_ovf_isr(void) //ngat xay ra sau 20ms


{
TCNT1H=0xF6; //giá trị nạp lại TCNT1L=0x3B;
// goi ham can xu li sau 20mscount++;
if (count>10)
{
count=0;
//goi ham can xu li sau 2s }
}

voidmain(void)
{
//Timer/Counter1initialization
//Clocksource:SystemClock
//Clockvalue:125.000 kHz
// Mode: Normal top=FFFFh
//OC1A output:Discon.
//OC1Boutput: Discon.
//Noise Canceler: Off
// InputCaptureon Falling Edge
// Timer1Overflow Interrupt: On
// Input Capture Interrupt: Off
//Compare A Match Interrupt:Off
//Compare B Match Interrupt: OffTCCR1A=0x00;
TCCR1B=0x03;
TCNT1H=0xF6;
TCNT1L=0x3B;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
#asm("sei") //bat co cho phep ngat toan cuc neu khong thi khong co ngat xay ra
while (1)
{
..........................
};
}
===========================================================================

Co hai khai niem ve bo dinh thoai va counter.

1. Trong AVR tuy theo cac loai ma cac bo dinh thoi khac nhau, co bo dinh thoi 8 bit, co bo dinh thoi 16
bit. Bo dinh thoi nay dua tren co so cua clock ma ban su dung de dem, tan so cua bo dinh thoi hoan
toan co the biet duoc tuy theo gia tri cua xung clock ban dung. Ta co the dung voi tan so cua xung
clock, hoac clk/2, clk/4 .........
Khi bo dinh thoi tran (over flow) no se tro ve 0. binh thuong gia tri tran defalut la gia tri maximum cua
bo dinh thoi, tuy nhien ta co the thiet lap gia tri tran cho bo dinh thoi. Neu su dung Codevision avr,
ban co the thiet lap gia tri nay trong Codewizard khi khoi tao chuong trinh.

2. Couter: ve ban chat thi counter cung khong khac so voi bo dinh thoi lam. Tuy nhien ve dinh nghia
thi counter la mot bo dem, nghia la no dem gia tri cua mot su kien nao do. Nhu vay ve nguyen tac thi
counter co the co tan so khac nhau!!
Neu ban su dung timer giong nhu mot bo dem, thi ban phai de y khi bo dinh thoi bi tran, phai co viec
xu ly de cho counter ko bi reset.

ta co the xay dung bo dem thoi gian su dung bo dinh thoi trong AVR, truoc tien ta phai xac dinh tan so
ca abo dinh thoi, gia tri tran cua bo dinh thoi de sao cho khi no tran thi thoi gian tu diem xuat phat den
luc tran la 0.1 giay chang han (vi du the), bang viec dem so lan tran (vi du 10 lan) ban co duoc 1 giay,
tu do ban se dem duoc phut va gio tuong ung dua tren viec tran cua bo dinh thoi.

=============================================================================

Timer bắt đầu đếm khi bạn cấp clock cho nó.
Tức là ngay sau câu lệnh set bit CS00, CS01, CS02 của thanh ghi TCCR

===============================================================

Ban co the dung ngat Input Capture Interrupt (ICP) cua timer1 de lam viec dem tan so. Tren atmega
co mot Pin ICP, ban tim xem voi atmega8535 no la chan nao. Noi chan ICP nay voi tien hieu ma ban
can dem.

Chu y:
- kich hoat ngat ICP
- xac dinh dem suon len hay suon xuong

Sử dụng codevision la tốt nhất. chỉ cần khai báo là xong!


Khai báo Timerx làm bộ đếm ngoài
khai báo sườn lên hay xuống
trong đó có các ngắt ví dụ như tràn TOV so sánh với A,B...
bạn viết với codevision rất tiện
Atemega8 có thể dùng với cả dao động trong lẫn dao động ngoài. Nguồn dao động bạn co thể xem
trong datasheet (page 24).

Nếu dùng dao động trong, bạn nên để ý:


- Set Fusebit
- Khi nạp chương trình, bạn vẫn cần mot dao động ngoài để nap. ( một dạng như là kích hoạt dao
động nội)
- gia trị lớn nhất có thể là 8 MHz với Atmega8
=======================================================================

Đặc tính:

- Bao gồm các bộ timer 8bit 16 bit, thường có từ 3 – 4 bộ Timer


- Có các kênh PWM (từ 4 đến 8 kênh tuỳ loại )
- Bao gồm nhiều chế độ ngắt và PWM …
- Có thể là một kênh đếm riêng biệt
- Tự động xoá Timer trong chế độ so sánh(tự động nạp lại)
- Có chế độ PWM
- Tạo ra tần số
- Đếm các dự kiện ngắt ngoài
- Tạo ra các ngắt tràn và ngắt so sánh
....

==========================================
Introduction

--Các chế độ hoạt động của timer:--

--Chế Độ Thông Thường:--


Đây là chế độ hoạt động đơn giản nhất của Timer .Bộ đếm sẽ liên tục đếm tăng lên cho đến khi
vượt quá giá trị lớn nhất TOP và sau đó sẽ được khởi động lại tại giá trị Bottom.Trong các hoạt
động thông thường thì cờ tràn sẽ được thiết lập khi giá trị trong Timer đạt giá trị không và không
bị xoá đi.Tuy nhiên nếu mà ngắt tràn được chấp nhận thì cờ ngắt sẽ tự động bị xoá khi ngắt được
thực hiện.Giá trị trong Timer có thể được viết vào bất cứ lúc nào

--Chế Độ So Sánh (CTC): --


Đấy là chế độ mà giá trị trong Timer luôn được so sánh với giá trị trong thanh ghi ORC .Khi giá trị
trong Timer bằng giá trị trong thanh ghi ORC thì giá trị trong Timer sẽ bị xoá đi.Giá trị trong ORC
đóng vai trò là giá trị TOP cho bộ đếm.Chế độ này cũng cho phép tạo ra tần số so sánh ở đầu
ra.Tuy nhiên trong chế độ này nếu giá trị mới ghi vào thanh ghi ORC mà nhỏ hơn giá trị tức thời
của bộ đếm thì thì 1 so sánh sẽ bị lỡ, khi đó bộ đếm sẽ đếm đến giá trị lớn nhất sau đó rơi xuống
giá trị 0 trước khi so sánh tiếp theo xuất hiện.
///Sơ đồ thời gian của chế độ CTC///

--Chế Độ Fast PWM: --


Cho phép tạo ra sóng với tần số cao.Sự khác biệt cơ bản giữa Fast PWM với các loại PWM khác là
nó chỉ sử dụng 1 sườn dốc.Bộ đếm sẽ đếm từ Bottom đến Max sau đó khởi động lại từ bottom.
Trong chế độ không đảo đầu ra của chân so sánh OCx sẽ bi xoá khi có phép toán so sánh giữa
TCNTx và thanh ghi ORC là bằng nhau. Và sẽ được sét lên 1 khi giá trị đạt Bottom. Trong chế độ
đảo ,đầu ra đảo sẽ được set lên 1 khi sự so sánh giữa thanh ghi ORC và giá trị trong Timer bằng
nhau và sẽ bị xoá khi giá trị đạt Bottom.Trong cả hai trường hơp này tần số của chế đô Fast PWM
đều gấp đôi so với chế độ phase correct PWM sử dụng hai sườn dốc
Với tần số cao này chế độ độ Fast PWM rất tốt cho các ứng dụng như ADC hay chỉnh lưu.Ngoài ra
với tần số cao giúp làm giảm kích thước của thiết bị ngoài như cuộn dây tụ từ đó giúp làm giảm
toàn bộ chi phí cho hệ thống
Sơ đồ dưới đây mô tả chu kỳ thời gian của chế độ:

--Biều đồ thời gian chế độ Fast PWM --

-- Chế độ Phase correct PWM: --


Chế độ này hoạt động dựa trên hai sườn lên xuống.Bộ đếm sẽ đếm liên tục từ giá trị BOTTOM đến
giá trị MAX và sau đó từ giá trị MAX đến giá trị BOTTOM.Trong chế độ so sánh không đảo chân so
sánh (OCx) sẽ bị xóa khi giá trị TCNTx bằng giá trị OCRx trong quá trình đếm lên và sẽ được set
bằng 1 khi giá trị so sánh xuất hiện trong quá trình đếm xuống.Chế độ so sánh đảo thì các giá trị
là ngược lại.Với hoạt động hai sườn xung này thì chế độ này không tạo ra được tần số nhỏ như chế
độ một sườn xung .Nhưng do tính cân đối của hai sườn xung thì nó tốt hơn cho điều khiển động cơ
Chế độ phase correct PWM hoạt động cố định là 8 bít.Trong chế độ này bộ đếm sẽ tăng cho đến
khi đạt giá trị MAX ,khi đó nó sẽ đổi chiều đếm.Biểu đồ thời gian đây mô tả hoạt động của toàn bộ
quá trình:

Từ biểu đồ thời gian ta nhận thấy việc thay đổi tần số trong hoạt động của phase correct PWM có
thể thay thế bằng hai giá trị là MAX và BOTTOM. Nó linh hoạt hơn so với chế độ Fast PWM.
Tần số có thể tính theo công thức như sau:

f=fc/N*510

Trong đó N tạo ra bởi bộ chia nó có các giá trị là:1,8,64,256 hoặc 1024

--Các thanh ghi trong bộ Timer/ Counter:--

-- Thanh ghi điều khiển - TCCRx:--


Bít 3,6 –WG00-WG01: Đây là các bít chọn chế độ trong Timer.Các giá trị được mô tả trong bảng
sau.

-- Bảng chọn chế độ Timer:--

Bít 5-4 : COM00-COM01: Quy định giá trị đầu ra trong các phép so sánh
Bít 2: 0 – CS2:0 :Đây là các bít quy định xung cấp cho hoạt động của Timer.Bảng dưới đây mô tả
toàn bộ các giá trị

--Chọn chế độ cho xung Clock--

--Thanh ghi cờ ngắt-TIFR:--

Bít 1-OCFx : Khi hai giá trị bằng nhau bít này được set lên bằng 1
Bít 1-TVOx : Khi bộ đếm vượt quá giá trị Top thì bít này được set bằng 1

--Thanh ghi mặt nạ ngắt-TIMSK:--

Bít 1 – OCIEx: khi bít này được set lên bằng 1 thì cho phép ngắt so sánh
Bít 0 –TOIEX : Khi bít này được set lên bằng 1 thì cho phép ngắt tràn
===========================
đoạn chương trình trên dùng timer1. Timer này là bộ đếm 16bit nên giá trị đếm được tối đa là
FFFF. Trong phần khởi tạo Timer ta khởi tạo xung clock cho bộ đếm là 125Khz = 125000 có nghĩa
là bộ đếm sẽ đếm được 125000 giá trị trong 1 giây. Ta làm phép tính như sau:

125000 số --------------------1 giây


? số----------------------- 0,02 giây (20ms)
ta tính được trong 20ms bộ timer sẽ đếm được là: 125000x0.02= 2500 số.
Ta cần là làm sao cho timer1 đếm được 2500 số sẽ tràn có nghĩa là cần phải nạp vô nó một giá trị
xác định trước (mặc định nó sẽ đếm từ 0000-->FFFF và bị tràn) giá trị này sẽ nhỏ hơn 65535(FFFF)
là 2500 (9C4 Hexa) vậy ta tính được giá trị cần nạp lại sau mỗi lần tràn là FFFF- 9C4 = F63B.

#include <mega8.h>

unsigned char count=0;

interrupt [TIM1_OVF] void timer1_ovf_isr(void) //ngat xay ra sau 20ms


{
TCNT1H=0xF6; //giá trị nạp lại TCNT1L=0x3B;
// goi ham can xu li sau 20mscount++;
if (count>10)
{
count=0;
//goi ham can xu li sau 2s }
}

void main(void)
{
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125.000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: OffTCCR1A=0x00;
TCCR1B=0x03;
TCNT1H=0xF6;
TCNT1L=0x3B;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
#asm("sei") //bat co cho phep ngat toan cuc neu khong thi khong co ngat xay ra
while (1)
{
..........................
};
}

Sau đây xin giới thiệu mọi người cách điều khiển động cơ PWM(Pulse Width Modulator) bằng AVR .
c ó khá nhiều loại mạch cầu trong bài viết này mình giới thiệu mọi người cầu IRF – RELAY. Ưu điểm
là rẻ , đơn giản chỉ cần băm xung 1 kênh . Tuy nhiên nó có nhược điểm rất lớn là khả năng , tần số
đảo chiều thấp.
Sơ đồ mạch điện :

Với sơ đồ như trên chân đk IRF được nối trực tiếp với chân PORTD.5 hay chân OC1A .
Với Atmega 16L có 4 kênh băm xung nếu các bạn xem datasheet sẽ thấy timer 0 và timer 2 chỉ có
1 bộ PWM 8 bit và có đầu ra ở chân OC0 và OC2 trong khi đó timer1 có 2 bộ băm xung 16 bit và
có đầu ra là OC1A và OC1B .Tuỳ loại avr mà số kênh PWM nhiều hay ít khác nhau .Atmega88 có
tới 6 kênh băm xung , Atmega128 có tới 8 kênh băm xung.
Với cách mắc như sơ đồ để động cơ chạy ta cho giá trị ra ở portD.5 là logic 0 , hay trong phần
chọn Out A : inverted

Trong tiện ích codeWizardAVR ta chọn như sau :

Chọn chế độ Phase Correct 8 bit , khi đó để điều khiển tốc độ của động cơ ta chỉ cần đổi các giá trị
trong thanh ghi OCR1AL từ 0 -> 255 .
#include <mega16.h>

// Declare your global variables here


#define V_DC OCR1AL
#define RELAY PORTD.6
void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization


// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=1 State5=1 State4=T State3=T State2=T State1=T State0=T
PORTD=0x60;
DDRD=0x60;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 3.906 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x05;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 500.000
// Mode: Ph. correct PWM top=00FFh
// OC1A output: Inverted
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xC1;
TCCR1B=0x02; //bam xung voi tan so gan 1KHz
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization


TIMSK=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// Global enable interrupts


#asm("sei")
while (1)
{
// Place your code here
V_DC=0;
delay_ms(10);
RELAY=1;
V_DC=255;//quay thuan toi da
delay_ms(2000);
V_DC=0;
delay_ms(10); //khi dao chieu ban phai tat IRF neu khong se hong relay
RELAY=0; //dao chieu dong co
V_DC=125; // Chay 50% toc do toi da
Delay_ms(5000);
};
}

Hiện tại em đang thử xuất xung PWM đk động cơ DC qua chân PD7 của con Atmega 8535.Thạch anh
em xài là 11,0592MHz. Nhưng em mới vừa chuyển qua AVR nên ko bít cơ chế xuất xung PWM của AVR
như thế nào(đọc tiếng Anh tệ quá nên vẫn chưa hiểu rõ lắm ).Qua bên diendandientu.com thì thấy
có mấy bác nói về việc này,nhưng em đọc code vẫn thắc mắc không bít có phải OCR2 là quy định cái
duty cycle của PWM ko nữa,còn cái TCNT2 dùng làm gì nhỉ ?Các anh gúp em với !CẢm ơn anh trc
nghen!

OC2 (PD7) là tín hiệu đầu ra của khối PWM trong Atmega8535. Tín hiệu này làm việc với bộ định thời
Timer2.

Bạn phải khởi tạo bộ định thời timer 2 trước tiên bằng cách thiết lập thanh ghi TCCR2 (3 bit: CS20,
CS21, CS22). Giá trị của 3 bit này xác định tần số làm việc của Timer2.

Sau đó bạn phải thiết lập PD7 là đầu ra của PWM thông qua thanh ghi TCCR2 (bit WGM20 = 1, WGM21
= 1: fast PWM)

Xác định chế độ đầu ra là Non-inverted PWM: thônng qua các bít sau trong TCCR2 (COM2.1 =1,
COM2.0 = 0 )

Như vậy đầu ra đã sẵn sàng. Để thay đổi độ rông xung, bạn chỉ cần thay đổi giá tri của thanh ghi
OCR2. Chú y là giá trị này phải nhỏ hon 256 vì chế độ làm việc ở trường hợp này là PWM 8 bit. Nói
cách khác OCR2 quy định cái duty cycle của PWM.

Nếu làm việc với fast PWM, giá trị TCNT2 nên đặt bằng 0. Nếu làm việc ở chế độ so sánh thì OCR2 sẽ
so sánh với giá trị TCNT2 để tạo ra đầu ra.

Vi dụ :

Code:
interrupt [USART1_RXC] void usart1_rx_isr(void)
{
data=UDR1;
if(data == 'a')
{
count +=5;
if(count >=30000)
count = 30000;
}
else if(data == 'd')
{
count -=5;
if(count <=0)
count = 0;
}
}
void main(void)
{
char receive_char;
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
while (1)
{
OCR1AH = count>>8;
OCR1AL = count;
};
}

Ví dụ trên tôi viết cho atmega8, nên co lẽ ko chạy dc với 8535, tuy nhiên về nội dung thi như nhau. độ
rộng xung thay đổi khi ân kí tư 'a' hoac 'd' tu bàn phím, bạn có thể nhìn thấy sự thay đổi nếu dùng
động cơ hoặc oscilloscope

Anh jindo_vn nói thật rõ ràng!EM cám ơn anh nhiều lắm!


Anh cho em hỏi thêm cái này nghen,em đọc trong datasheet của Atmega8535 thấy nó bảo : trong chế
độ Phase correct PWM,ở Non-inverting Compare output mode, OC2 sẽ clear khi có compare match giữa
TCNT2 và OCR2(khi đếm lên) và set khi có compare match giữa TCNT2 và OCR2 (khi đếm xuống),nó
có cả cái diagram,nhưng trên diagram em không hiểu từ period 1 chuyển qua period 2 tại sao OC2 lại
bị clear. Những mũi tên từ cái OCR2 update lại không phải tại thời điểm OC2 thay đổi trạng thái??
Em mới tập tành về VXL nên khả năng đọc mấy cái diagram này không tốt lắm,anh giúp giùm em nhé
! Thanks anh nhiều nhiều!!!!

Đồng ý với bạn là cái diagram đó thiếu, trên giản đồ thời gian cua TCNT, nhung chỗ có gạch ngang
phải là những chỗ OCR2 update.

Điều khác biệt cua Phase corect PWM la ở chỗ TCNT đếm đến giá trị MAX rồi nó sẽ đếm ngược mà ko
quay trở lại giá trị MIN như ở fast PWM. Chính vì vạy mới nảy sinh ra việc clear hay set khi đếm ngược
và đếm xuôi.

====================
PWM sử dụng bộ định thời trong AVR kết hợp với một bộ so sánh để tạo đầu ra PWM.

giả sử bộ định timer đếm từ 0 -> 255


giả sủ giá trị đặt để so sánh là 128, giá trị này quan hệ tuyến tính với độ rộng cua xung PWM

khi timer đếm tu 0 -> 128, đẩu ra cua PWM ơ mức cao
128 -> 255 đầu ra cua PWM ở mức thấp

Vi vặy nếu thay đổi giá trị đặt, độ rộng của tin hiệu PWM ở mức cao và mức thấp sẽ thay đổi.

Đo là nguyen tắc hoạt động cua PWM, tất nhiên là còn nhiều chế độ PWM khác, tuy nhiên cơ bản là
vậy.

Ở đây là thiếu hay sai?Thiếu cái jì?.Nguyên tắc vầy là sai.Mọi người xem lại đi.
Bạn nào có thể giải đáp 1 số thắc mắc của mình với:
+Điểm khác Phase and frequency correct PWM so với chế độ phase correct PWM mode là thời gian
thanh ghi OCR1x được updated bởi thanh ghi đệm OCR1x.(mình dịch ra là vậy)Mình chưa hiểu rõ ý
này?
+bạn nào có thể nói rõ hơn về hoạt động đồng bộ của Timer2 được ko?ứng dụng khi nào?
Mình mới bắt đầu dịch datasheet.bạn nào biết chỉ giáo nhé
Hy vọg 4rum này sẽ sôi động hơn.
Mình mới biết sơ qua như datasheet nói: phase correct PWM mode dùng cho đk động cơ vì nó đối
xứng, còn fast PWM thì phù hợp cho tính toán mạnh, chp DAC và lọc, cũng làm cho các thiết bị vật lý
kích thước nhỏ hơn.
Chỉ là lý thuyết datasheet.Bạn Jinđo_vn có thể nói rõ hơn thực tế dùng các chế độ đó như thế nào ko?
hay dùng chế độ nào nhất?nếu có thế cho đoạn code tham khảo thì càng tốt.thanks

tổng quan về DAC :Khi nói tới DAC có lẽ trongchungs ta khong ai là không nghĩ tới đó là chip DAC !!!
Hê hê hê (ví như có lần tôi tranh luận với Fallear bên dientuvietnam.net khi tôi nói tới DAC thì F chụp
đầu tôi là con chip DAC hô hô - !!! )Thực chất đối với tôi và quan điểm của tôi DAC xét về mặt toán
học đây là một phét biến đổi từ không gian số học rời rạc sang không gian tương tự. Và để thực hiện
phép biến đổi này chúng ta có 2 kĩ thuật gần đúng đó là kĩ thuật DAC và kĩ thuật PMW (mà tôi
biết).Xét về mặt toán học mà nói thì hai phương pháp này đều là phuêong pháp xấp xỉ xong với độ
chính xác khác nhau.(như vậy khi nói tới DAC chúng ta hãy nghĩ tới khâu DAC đừng nghĩ ngay tới chip
DAC-PMW cũng có thể coi là DAC)
Phương pháp DAC có độ chính xác tiệm cận cao và thưong f được sử dung trong các hệ xử lý tín
hiệu.Phương pháp PMW có sai số tiệm cận lớn hơn và nó phù họp trong cacmachj công suất .
AVR có trang bị các bộ PMW với số lượng và số bít khác nhau.Để tạo một chip DAC từ bộ PMW thì
chúng ta có thể mắc nối tiếp chúng với một mạch lọc thông thấp LC (có thể thông qua một transistor
đệm hoặc 1 con IRF) nhưng độ chính xác không cao.
Để điều khiển các bộ PMW chúng ta cũng làm các bước sau:
bước 1: Khởi tạo trạn thái cho bộ PMW bao gồm các thông số điều khiển,các thông số dữ liệu
,,,,,,,,buồn ngủ quá !!!!!!!!!!!!! mai viết tiếp !!!

Lập trình đa nhiệm cho vi điều khiển

Cái này trước đây tớ viết cho DTVN hôm nay Copy lại sang đây !!!
Lập trình đa nhiệm cho hệ thống nhúng khác với lập trình có cấu trúc và lập trình tuyến tính là.Chúng
không thực hiện một khối lệnh một cách liên tục (hàm) mà khối lệnh đó được chia nhỏ và thức hiện
sen kẽ với các đoạn lệnh trong các khối lệnh khác.Về cấu trúc chương trình thì lập trình đa nhiệm
không có một chương trình chính (hay hàm main trong C) mà chúng chia thành các task.Các task này
được đặt trong bộ nhớ ,và có một câu hoỉ được đặt ra là vậy thì các task này sẽ hoạt động như thế nào
?Đúng vậy chúng phải có một chương trình để điều khiển chúng và có tên rất quen thuộc là
Kernel.Kernet có nhiệm vụ quản lý sự hoạt động của các task bao gồm các công việc : Phân hạch thời
gian,quản lý tài nguyên …

Như vậy để có thể xây dựng được một hệ thống đa nhiệm trên VĐK thì các bạn cần có những yêu cầu
gì về phần cứng và phần mềm?

Về phần cứng:
Một điều không thể thiết đó là một bộ timer tích hợp trong VĐK.Nó có nhiệm vụ tạo đơn vị thời gian.
(Có nghĩa là một chu kì hoạt động của hệ thống được chia nhỏ thành các đơn vị thời gian).Bộ nhớ
chương trình đủ lớn để chứa các mã lệnh .Ngoài mã lệnh của các task cong mã lệnh của Kernel .Bộ nhớ
RAM cũng là một vấn đề rất hạn chế của VĐK vì mỗi lần chuyển ngữ cảnh thì toàn bộ ngữ cảnh của
một Task được lưu vào một ngăn xếp trong RAM.Chúng ta có càng nhiều task thì cần cành nhiều
ngăng xếp kiểu này (Các bạn đừng nhầm ngăn xếp này với ngăn xếp cứng nhé ! đây là ngăng xếp do
phần mềm chúng ta phải tạo ra)Cụ thể chúng là bao nhiêu thì tùy vào các ứng dụng mà các bạn mới
có thể xác định được.
Về phần mềm:
Các bạn hiện gời có hai công cụ để lập trình cho VĐK đó là ngôn ngữ bậc thấp (Assembly) và ngôn ngữ
bậc cao (C ,basic…,nhưng tôi chỉ dùng C) và ở hai ngôn ngữ này các bạn đều có thể lập trình đa nhiệm
cho VĐK được.
Với Assembly đây là ngôn ngữ mà các bạn có thể làm mọi chuyên được với VĐK nhưng thực sự nó chỉ
dành cho những người quá chuyên nghiệp.Để lập trình đa nhiệm cho VĐK bằng ngôn ngữ này thì các
bạn phải bắt đẩu từ con số 0 !!! bạn phải xây dụng toàn bộ Kernel cho ứng dụng của bạn và nó chỉ phù
hợp với các ứng dụng rất nhỏ (Đối với tôi và không giám nói tới các cao nhân).Nếu bạn nào đam mê có
thể đọc quyển sách :”Real time system and programming languages” Có gần như tất cả các thuật toán
tối ưu để các bạn có thể xây dựng Kernel. Song thế mạnh của Assembly là bạn có thể xác định được
chính xác thời gian mà một task của bạn thực hiện và tất nhiên điều đó đồng nghĩa với việc hệ thống
của các bạn sẽ tố ưu.(Thế mạnh của Assembly mà).
Với C và các ngôn ngữ bậc cao khác thì sao nhỉ ?bạn đã được cung cấp một Kernel rồi và vấn đề của
các bạn là sử dụng chúng mà thôi .Nếu như phần mềm các bạn sử dụng mà chưa có thì các bạn vào
các trang Web của bản hãng để mua về !!!(Vấn đề là mất tiền) tôi xin thí dụ như để viết cho 8051 Keil
C có một nhân đó là RTX51.Với AVR là ….Trời tôi quên mất rồi vì hôm trước chỉ xem trên Web thôi họ
không cho free nên không có (!!! Bác nào có thì share cho em nhé)
Vấn đề sd nhân RTX51 thì cũng không có gì khó cả .Các bạn có thể xem phần hướng dẫn của Keil C là
có hết.Tôi xin tóm tắt đôi chut :
Các cú pháp của chương trình C thì hoàn toàn không có gì khác cả chỉ có khác về mặt cấu trúc.Các bạn
không cần hàm “main” mà thay vào đó là hàm khởi tạo các task
Ví dụ :
void init (void) _task_ 0 { /* sau khi Reset chương trình sẽ chạy từ đây */
os_create_task (1); /* Bắt đầu task 0 hoạt động */
os_create_task (2); /* task 1 hoạt động */
os_create_task (3); /* */
os_delete_task (0); /*dừng khởi tạo các task */
}
Các bạn sẽ nói chaẻng khác gì các chương trình C khác cả nhưn sự thật là cúng sẽ được thực hiện
“đồng thời” và thời điểm mỗi task bắt đầu là khác nhau mà thôi.
Và các bạn khai báo các task “như”(theo nghĩa hình thức) các chương trình con mà các bạn cần thực
hiện.
Ví dụ:
void readADC (void) _task_ 1
{

// nội dung

}
….Vậy Task này có mã hiệu là 1 và là tham số cho hàm
os_create_task (má hiệu của task muốn khởi tạo.);
Sau đay tôi xin gửi tới các bạn một chương trình mẫu của Keil C rất hay và cụ thể để các bạn tham
khảo:

Lập trình đa nhiệm cho VĐK dùng Assembly


Chào các bạn !

Hôm trước tôi đã nói sơ về lập trình đa nhiệm cho VĐK và hướng dẫn chó các bạn dùng Keil C .Hôm
nay tôi sẽ hướng dẫn cho các bạn các sử dụng Asembly (vì nó không mất tiền , và có tư duy trong
sáng để các bạn hiểu hơn về lập trình đa nhiệm cho VĐK) .

Do tôi không có nhiều thời gian và cũng không thể nói hết tất cả được với các bạn nên tôi chỉ có thể
giới thiệu cho các bạn những gì trung nhất và một ví dụ cụ thể đơn giản nhất và phần còn lại đi sâu thì
các bạn phải tự tìm hiểu từ các tài liệu tôi đã giới thiệu ở bài viết trước cho các bạn.
Vậy để lập trình đa nhiệm được cho VĐK bằng Assembly thì bạn cần những gì ?Trước hết bạn phải là
người đã lập trình thành thạo Assembly cho VĐK (đây là điều khiên quyết).Bạn hiểu sâu sắc về cấu
trúc phần cứng mà VĐK của bạn sử dụng. Cụ thể là :Bạn cần nắm được cách mà ngăn xếp của bạn
hoạt động như thế nào.Làm thế nào để bạn có thể quản lý được ngăn xếp và bộ nhớ một cách hợp lý.

Các khái niệm cơ bản các bạn cần nắm được:

1.Ngữ cảnh:Là trạng thái tại một thời điểm nào đó của hệ thống bao gồm giá trị của các thanh ghi
chung,thanh ghi tích lũy và thanh ghi trạng thái cùng thanh ghi chương trình(con trỏ chương trình PC)

2.Chuyển ngữ cảnh :Là hoạt động chuyển quyền sử dụng CPU từ task này sang task khác,Nó bao gồm
các công việc:Lưu ngữ cảnh đang thực hiện(Lư PC,PSW,B,A,Rn,DPTR với 8051 và các thanh ghi tương
tự với AVR…)và khôi phục trạng thái của ngữ cảnh mới(Khôi phục các thanh ghi trên).

3.Task:Với Assembly thì task hoàn toàn là một đoạn mã lệnh đơn thuần và khác với cách nhìn của các
phương pháp lập trình trước của các bạn.Task gồm tên task và kết thúc của một task là một lệnh nhảy
vô điều kiện trở về đầu chương trình.

Ví dụ:

ReadADC:

;ReadADC là tên của task và chính xác hơn nó là một nhãn.

;đọang mã lệnh

Ljmp ReadADC

;lệnh nhả về đầu của task kết thúc một chu kỳ của task

4.Tài nguyên: Tài nguyên bao gồm các thiết bị ngoại vi như bộ nhớ ,các Port,ADC ,DAC(Được ghép
thêm)…

5.Ưu tiên: Là phương thức mà ta gán cho các task các quyền ưu tiên sử dụng CUP và tài nguyên.

Bài viết này tôi không tham vọng nói được hết những gì mà các nhà kinh điển đã viết và những gì tôi
ngộ được.Tôi chỉ có thể hướng dẫn các bạn cách thiết kế cho một chương trình đa nhiệm đơn giản
không có tranh chấp tài nguyên ,không có ưu tiên (các task bình đẳng).

Chúng ta sẽ bắt đầu với một ví dụ nhé:

Lập trình cho 8051 với hai công việc là đọc cổng P1 và đưa dữ liệu ra cổng P2

Như vậy với tư duy lập trình cấu trúc hoặc lập trình tuyến tính thì các bạn sẽ lấy dữ liệu từ ADC (cổng
P1) sau đó sẽ chuyển ra cổng P2(DAC).

Với tư duy lập trình đa nhiệm các bạn có thể thiết kế 2 task với task1 lấy dữ liệu và task2 chuyển dữ
liệu ra cổng P2 (Ở đây tôi lấy ví dụ đơn giản cho các bạn dễ hiểu còn nếu bài toán thế này thì tất nhiên
là dùng phương pháp lập trình tuyến tính thì hiệu quả hơn)
Cấu trúc của chương trình hoàn toàn như một chương trình Assembly bình thường.

Chúng ta sẽ sử dung timer 0 để là xung nhịp chia thời gian đơn vị.Và mỗi lần ngắt của timer là một lần
chuyển ngữ cảnh (chuyển giữa các task).Như vậy chúng ta có 2 task đồng nghĩa với 2 vùng nhớ làm
ngăn xếp để lưu trạng thái(ngũ cảnh).Một vùng để lưu dữ liệu dùng chung cho các task.Và các vùng
nhớ này bạn caanf chú ý và bảo vệ không được phá hủy trong các task đặc biệt là các ngăn xếp vì điều
đó sẽ làm hỏng toàn bộ chương trình hay cụ thể là CPU sẽ chạy loạn xạ các lệnh lên (Đây cũng là điểm
yếu của Assembly-bạn phải tự quản lý tất cả).

Bước 1:Thiết kế Kernel hay viết chương trình cho ngắt timer 0(hoặc timer nào đó mà bạn chọn)Kernel
này là một nhân cơ bản nhất chỉ có hai nhiệm vụ:Định thời và chuyển các ngữ cảnh.Phần định thời ở
đây ta sẽ chọn thời gian là sau 10uS sẽ ngắt một lần (chuyển ngữ cảnh)như vậy ta chọn timer0 chế độ
tự load và giá trị các thanh ghi sẽ được thiết lập ở chương trình khi khởi tạo.Để chuyển ngữ cảnh và
khôi phục ngữ cảnh bạn cần có một biến để nhận ra task đang thực hiện để quyết định chuyển sang
một task nào đó khác.

Int_Timer0:

;Lưu ngữ cảnh đang thực hiện

Push psw

Push acc

Push b

Push dpl

Push dph

Push r7

Push r5

Push r4

Push r3

Push r2

Push r1

Push r0

Mov a,cpc

Cjne a,#2 exits

Mov stack2,sp;lưu gữ ngăn xếp

Sjmp exits
Mov stack1,sp

Exits:

;Lưu xong ngữ cảnh

;Xác định task để trả lại ngữ cảnh

Mov a,cpc

;cpc là biến trạng thái lư giữ tên của task đabg chạy (0,1,2,3…)

Cjne a,#0 task0_run

Mov cpc,#2 ;tăng con trỏ trạng thái lên 2 để báo task 2 đang ;chạy

;đây là lần chạy đầu tiên của task1 ngay sau khi khởi động

Mov psw,#0

Mov a,0

Mov dptr,#task2

Mov sp,stack2

;với stack2 là một ô nhớ lưu vị trí khởi tạo đầu của ngăn xếp ;cho task2 và được khởi tạo khi bắt đầu
chạy

Push dpl

Push dph

;Lưu vị trí của task2

Sjmp exit

task0_run: Cjne a,#1,task2_run

;nếu cpc =1 thì task1 đang chạy

;khôi phục lại task2

Mov sp,Stack2 ;trở lại ngăn xếp của task2 ở đây thì stack2 lại là ;đỉnh ngăn xếp rồi

Pop r0

Pop r1

Pop r2

Pop r3
Pop r4

Pop r5

Pop r6

Pop r7

Pop dph

Pop dpl

Pop b

Pop acc

Pop psw

Inc pcp;tăng con trỏ chương trình lên 2 (task2 chiếm CPU)

Sjmp exit

;đây là trường hợp cpc=2

;task2 đang chiếm CPU thì bị ngắt

;khôi phục lại task1

Mov sp,stack1

Pop r0

Pop r1

Pop r2

Pop r3

Pop r4

Pop r5

Pop r6

Pop r7

Pop dph

Pop dpl

Pop b

Pop acc
Pop psw

Mov cpc,#1

;task1 chạy

Exit:

Reti

Chương trình mẫu (để các bạn tham khảo vì lâu rồi không viết cho 8051 đôi chút cũng s
Stack1 equ 07FH ;bien trang thai

Stack2 equ 07EH ;bien trang thai

Cpc equ 07DH ;bien trang thai

GenralR equ 07EH ;bien du lieu dung chung

Org 00h

Ljmp start

Org 00BH

Ljmp int_timer0 ;ngat int0

Org 0030H

Start:

;đoạn khởi tạo chương trình

Mov psw,#00

;cấm các ngắt

;thiết lập timer 1 chế độ tự load và tính toán sao cho sau 10uS thì ngắt ;một lần phần này các bạn tự
viết.

Mov Stack1,#0h

Mov Stack2,#03Fh

Mov SP,#02Fh

Mov cpc,#0 ;khởi tạo con trỏ task

;cho phép ngắt


Task1:

;Lấy dữ liệu từ ADC (P1) đưa vào thanh ghi GenaralR

Ljmp task1 ;kết thúc task

Task2:

;lấy dữ liệu từ thanh ghi GenaralR dưa ra DAC qua Port P2

Ljmp task2;Kết thúc task 2

Int_timer0:

;nội dung như trên

;Hết chương trình.

Chú ý rất quan trọng:Nếu như trong các task các bạn muốn sử dụng ngăn xếp thì cács bạn cần phải
sửa lại Kernel cho phù hợp.(điều này giành cho các bạn)và đặc biệt các biến trạng thái thì các bạn
không được thay đổi trong các task.Để đặt mức ưu tiên và SD chung tài nguyên thì các bạn cần có các
biến trạng thái tương ứng để lưu trạng thái đã bị chiếm của tài nguyên và mức ưu tiên của các task.(Ở
đây chưa tính đến thời gian tới hạn của một task ).Các thuật toán các bạn đọc tại cuốn sách mà bài
viết trước tôi đã nói tới.

AVR hay các vi điều khiển khác thì nguyên tắc tương tự (Trừ PIC có ngăn xếp riêng thì hơi khác.Mong
bạn nào viết nhiều cho PIC thì cùng chia sẻ với anh em.)

các bác cho em hỏi chế độ input capture trong avr hoạt động như thế nào vậy, nó được ứng dụng làm
gì thế. BÁc nào biết chỉ em phát

input capture là tên của một chân l\lối vào (input pin) của AVR, chân này nối với khối input capture,
chức năng của khối này là : Khi có sự kiện (rising,falling,level) ở chân input capture thì giá trị của
thanh ghi bộ định thời (1,2...) sẽ được cập nhật (coppy) vào thanh ghi input capture register. Chức
năng này dùng để đo khoảng thời gian giữa các sự kiện. Để ý là khi xảy ra sự kiện input capture thì sẽ
tạo ra 1 ngắt,nếu ngắt input capture được cho phép. Như vậy chức năng input capture có liên quan
mật thiết tới bộ định thời, nên bạn cần tìm hiểu bộ định thời.

chức năng này dùng để bạn đo độ rộng xung . Dung khá nhiều trong giao tiếp hồng ngoại

Xung được đưa trực tiếp vào chân ICP. Giả sử đặt ICP làm việc ở chế độ gọi ngắt khi có rising edge thì
trong hàm ngăt sẽ có một biến counter dùng để đếm số lần có xung sườn lên đưa vào pin ICP. Như
vậy mỗi lần có xung thì giá trị counter sẽ tăng lên 1.

Chú ý: - counter bi tràn.


- Nếu xung được tạo ra bởi các sự kiện bấm nút thì vấn đề lọc các xung
nhiễu cần được xử lý trước khi đưa vào ICP

Vì ICP nó làm việc cùng với các bộ định thời nên khi có ngắt ICP, bạn có thể ghi lại thời điểm xảy ra
ngắt. Từ đó có thể ứng dụng làm các applications khác nhau. Chẳng hạn đo tần số, đo vận tốc, đo gia
tốc. vv....
Khi đo độ rộng xung, chú ý là trong chương trình ngắt nên đọc giá trị của ICR sớm nhất có thể nếu
không sẽ bị các giá trị capture lần sau ghi đè lên, sau đó là đổi sườn cature. Cuối cùng làm gì thì làm

không phải nó lưu khoảng thời gian đâu bạn ạ. Cứ mỗi một lần có sự thay đổi mức ở trên chân
inputcapture thì nó copy giá trị của timer vào trong thanh ghi (hình như là ICR). mình dựa vào các giá
trị đó và tần số đếm của timer để mình tính toán thời gian thôi. Chúc thành công

bạn có thể nói rõ hơn dc ko?


có phải nó có khả năng bắt giá trị thời gian và lưu giá trị đó vào thanh ghi ICR như bạn nói đó.
nhưng nếu khoảng thời gian mình bắt là thuộc vào 2 chu kì liên tiếp của Timer thì tính sao đây ?
bạn có thể post cho mình code ví dụ dc ko? mình đang rất cần.

Trong trường hợp mà khoảng thời gian mình bắt rơi vào 2 chu kỳ liên tiếp của timer thì khi đó bạn sẽ
sử dụng ngắt tràn timer. Mỗi một lần tràn giá trị đếm bạn lưu vào một cái gì đó, để biết được là nó
tràn mấy lần. Như vậy là thoải mái rồi đúng không. ???

chào các pác.


em mới nhập môn AVR không lâu và chọn Atmega8 làm điểm xuất phát. Trong quá trình học tập trên
diễn đàn em đã học được nhiều từ các anh đi trước. Nhưng em vần thấy trong Box này vẫn thiếu cái
Thread gì đó.

Nếu nhìn ngay bên anh em PIC thì chúng ta có thể thấy ngay họ có những Thread rất hay,các Thread
đó đánh đúng vào 1 vấn đề gì đó của con VĐK mà mình đang sở hữu như: ADC, UART, PWM, Timer ...
nên em dám mở luồng này vì em thấy có 1 số điểm như sau:
1. Để các bạn vào đây cùng thảo luận về 1 vấn đề gì đó mà chúng ta quan tâm để chúng ta học tập và
trao đổi kĩ về 1 vấn đề gì đó và luồng này chúng ra sẽ thảo luận về Timer của AVR.
2. Thuận tiện trong quá trình quản lí của MOD để những câu hỏi của chúng ta không phải trùng lặp lại
hay ở đâu đó có những câu hỏi tương tự.
3. Tập trung giải quyết các vấn đề liên quan, các vướng mắc...

Với những gì mình đã nói ở trên mình muốn đưa ra 1 số câu hỏi mở màn như sau mong anh em giúp
đỡ và cũng là cho các bạn mới học AVR có những cái nhìn tổng quan hơn khi tiếp xúc với bất kì 1 loại
AVR nào dù nó là Atmega hay bất kì loại nào ...
1. Các chế độ hoạt động của các Timer0,1,2 ?
2. các chế độ PWM trong Timer1,2 ???cách sử dụng các Mode trong các ứng dụng thực tế ...
3. Chế độ InputCapature, ứng dụng?
4. Timer định thời như thế nào? Tần số? Khi nào bộ định thời làm việc như 1 bộ đếm, nó đếm như thế
nào?

Mình hỏi vậy không là phải hỏi cho mình mà là vấn đề chung cho những ai mới học AVR.
Hy vọng Topic này sẽ được nhiều người ủng hộ.
Rất mong các cao thủ như Sphinx, NVT2, QD... hạ sơn giảng giải giúp cho chúng em được thỏa lòng
với "nàng tiên AVR" xinh đẹp.

mình bắt đầu từ đâu đây chú hùng. Cái timer này thì mình cũng biết đc vài đường cơ bản.
-Timer nào thì cũng có hai chức năng là đếm xung và đếm thời gian. Việc mà bạn chọn đếm xugn hay
đếm thời gian thì vào trong thanh ghi TCCRn (n là chỉ số của timer -- timer 0 thì n=0), giá trị đếm
được thì được ghi vào thanh ghi TCNTn (Lưu ý là nếu thanh ghi TCNTn được ghi giá trị nào đó !=0
trước khi khởi động thì sau khi khởi động T/C (timer/counter) sẽ bắt đầu đếm từ giá trị đó lên. Sau khi
tràn thì lại đếm từ 0). Có vài bít trong thanh ghi này qui định, nếu là đếm thời gian thì đem tần số
thạch anh chia cho bao nhiêu để dc tần số đếm. Còn với đếm xung thì bạn đưa xung vào chân Tn, đặt
cấu hình là chân vào bằng phần mềm. Sau đó dùng mấy cái bít trên xác định xem đếm sườn lên hay
xuống. Thế là xong.
-Việc ngắt timer hay counter được cho phép qua thanh ghi TIMSK (thanh ghi dùng riêng cho bộ định
thời và bộ đếm).Cái này để xem bít nào cho phép thì bạn phải vào datasheet của từng con AVR thì mới
rõ. Đây mình chỉ nói chung chung vậy thôi. Dĩ nhiên là lúc này bít I ở trong thanh ghi SREG được cho
phép đấy nhé.
-Đó là hai mấy thứ cơ bản mà cái timer và counter nào cũng có. Ở AVR thì timer còn có thêm vài chức
năng nữa mình xin nói thêm một tí về nó:
+ Về cái PWM để điều khiển động cơ thì timer vẫn đếm như bình thường. Có điều khi nó đếm nó vác
cái giá trị của TCNTn ra đem so sánh với cái giá trị đặt ở tại thanh ghi OCRn để quyết định độ rộng
xung ở chân đầu ra (chân đầu ra ở đây được cấu hình cứng ở trên chip và bạn phải tra datasheet. hình
như nó có tên là OC..gì đó). Có hai chế độ của PWM là FAST và phase correct. Ở cái FAST thì nếu mà
giá trị TCNTn<OCRn sẽ cho đầu ra là 0 hoặc 1 tùy chọn ở phần mềm. Còn khi TCNTn>OCRn sẽ cho
đầu ra ngược lại 1 hoặc 0. Như vậy thì trong một chu kì đếm của timer thì trong khoảng thời gian
timer đếm từ 0-->OCRn thì đầu ra là mức i, còn từ OCR--tràn thì đầu ra là mức đảo của i, vậy là có
một chú PWM. Đối với chế độ Phase..thì các bạn về tam khảo thêm nhé. nói ở đây dài lắm, còn nếu
bạn nào muốn thì mail cho mình cũng dc. Trong chế độ này thì ngắt sẽ xảy ra khi đc cho phép và tại
các thời điểm timer tràn và hoặc có thể ngắt tại thời điểm TCNTn=OCRn cũng được.
+Nếu như bạn có một ứng dụng nào đó muốn timer đếm từ 0 đến một giá trị nào đó thì bị reset về 0
(giá trị này dĩ nhiên có thể khác giá trị tràn) thì có thể sử dụng chế độ CTC mode. Bạn đặt giá trị reset
vào cái thằng ICR sau đó thì timer đếm từ 0 đến ICR thì về 0 luôn. VÀ nếu như bạn cho phép ngắt thì
tại đây sẽ có một ngắt cho bạn ứng dụng.
+ 2 chế độ ở trên có thể kết hợp với nhau để có được một bộ pwm rất linh hoạt. tùy theo nhu cầu của
bạn.
+ Về cái input capture thì nó làm việc cũng đơn giản thôi. Tai cái chân ICP, nếu được cho phép thì mỗi
lần có sự thay đổi sườn xung ở trên ICP thì nó làm công việc là copy thằng TCNTn vào ICRn, chỉ có vậy
thôi. Dĩ nhiên nó cũng có ngắt cho bạn lập trình dễ dàng hơn. Ví dụ bạn định đo độ rộng xugn dương
chẳng hạn. Bạn bắt tại sườn lên một phát, lưu giá trị lại. Bắt tại sườn xuống ngay sau đó. Sau đó lấy
giá trị mới trừ đi cái cũ và sử lý thêm cái ngắt tràn timer nữa. Tiếp đến nhân giá trị thu đc với tần số
timer là xong. Được ngay cái độ rộng xung....
+ Watch dog thì nó làm đơn giản hơn. Nếu vì một lý do gì đó mà chíp bị rơi vào vòng lặp vô hạn không
thể tiếp tục công việc của mình được (kiểu như là bị treo ấy) thì lúc này WDog sẽ làm việc. Nó sẽ kiểm
tra khi chíp bị treo, nó sẽ tính ra một khoảng thời gian nào đó mà ko thoát ra dc thì nó sẽ tự độgn
reset chip. Cái duy nhất bạn phải làm là chọn xem sau bao lâu thì reset thôi. Vào datasheet xem thanh
ghi nào qui định thời gian này nếu bạn lập trình dùng ASM. Còn codevision thì cứ tick vào phát là xong.
chả cần biết nó tên tuổi gì.
+ Trong bộ timer và conter của nó có nhiều chế độ lắm, nói ra đây không hết được đâu. Bạn nào có
vấn đề gì ở chỗ nào thì hỏi trực tiếp. Anh em ở đây giải quyết cho.
-------------------------------
Em nói chắc sẽ có nhiều chỗ sai lắm. Mong mọi người góp ý làm sửa chữa làm cho luồng này tốt hơn.

Để em nói qua một chút về Timer vậy


Uhm hum nay vừa đọc lại xem cái timer của AVR, cái Timer0 là timer 8-bit, nói chung theo datasheet
nó được sử dụng vào các ứng dụng là bộ đếm, bộ tạo dao động, đếm sự kiện ngoài.
Timer0 gồm 4 thanh ghi là TCCR0, TCNT0, TIMSK, TIFR.
TCCR0 - thanh ghi cho phép lựa chọn nguồn clock của Timer, thông qua việc đặt cho các bit của nó là
CS00, CS01, CS02. Cụ thể đặt như thế nào thì đọc thêm Datasheet sẽ biết. Nếu là sử dụng
Timer/Counter0 như một Timer thì trong CodeVision có phần Clock Value trong tab Timers-Timer0 nó
đặt sẵn cho rùi , phần Clock Source chọn là System clock, ko phải lo config Timer0 nữa cứ chọn là
xong. Hoặc nếu làm bộ Counter thì chọn Clock Source là T0 pin Falling Edge (sườn xuống) hoặc T0 pin
Raising Edge (sườn lên) để làm bộ Counter với sự kiện ngoài.
TCNT0 - thanh ghi cho phép đọc và ghi giá trị của Timer0, nó là thanh ghi 8-bit.
TIMSK - bit 0 TOIE0 là bit cho phép tràn Timer0, khi bit này đc set là 1 và bit I trong SREG dc set thì
lúc đó ngắt Tràn Timer0 mới được thực hiện.
TIFR - bit 0 TOV0 đc set khi xảy ra tràn Timer/Counter0.

Nói chung là phần Timer/Counter0 thì Codevision đã config hộ mình gần hết, chỉ việc viết code của
mình làm tác vụ gì vào phần interrupt của nó thôi.

Bạn chèn đoạn code sau vào nhé :

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 4000.000 kHz // dùng thạch anh 4MHz, PWM tốc độ cao nhất
// Mode: Fast PWM top=FFh // chon chế độ fast PWM 8bit
// OC0 output: Inverted PWM // lối ra đảo !
TCCR0=0x79;
TCNT0=0x00;
OCR0=0x00;

DDRB.3=1 // Portb3 là lối ra PWM

//Để tạo ra điện áp lối ra PWM theo ý muốn, bạn đặt giá trị cho OCR0

OCR0=0x7f ; //qua bộ lọc RC tạo ra điện áp Vcc/2 .

//Nếu lối ra đảo, nếu OCR0=0xff -> V tạo ra là 0V, ngược lại OCR0=0x0 V tạo ra là Vcc.Bạn có thể
chọn lối ra không đảo( trong Wizard của CV hoặc nếu dùng ASM thì xem lại trong datasheet để set các
bit WGM00,WGM01,COM00,COM01)

Chúc thành công !

Trước tiên bạn phải khởi tao timer0 (vd ta dung Timer0 de dieu che xung) sang chế độ PWM
Bạn mo datasheet xem thanh ghi dieu khien timer0 la TCCR0 gom co 8 bit sau
bit 7 : FOCO
bit 6 : WGM01
bit 5 : COM00
bit 4 : COM01
bit 3 : WGM00
bit 2 den bit0 : la cac bit chon tan so hoat dong cho timer0
+de chon che do hoat dong cho timer0 ban dung 2 bit WGM00 va WGM01
+để chọn kiểu thay đổi mức ( cao sang thap -hay - thap sang cao) o chan dieu che OC0 ban dung 2 bit
COM00va COM01
time0 se so sanh lien tuc thanh ghi gia tri timer0 (TCNTO) voi thanh ghi OCCR0 .
khi timer dem len bang OCR0 thi se xay ra sự đổi mức logic o chan OC0 (chan ngo ra cua xung duoc
dieu che boi timer0)
do vay muon dieu che xung tai chan OC0 ban phai lam la :
--thiet lập chân port tuong ung voi chan OC0 la ngo ra
--dat gia tri cho thanh ghi OCCR0
--thiet lap timer0 sang che độ dieu chế xung (Fast hoac PhaseCorrect,xem datasheet)
--ket noi chan OC0 voi mach dieu khien (chang han dieu khien do sang toi cua 1 con led)
the la xong, ban lam thu di nhe .

Có vài điều cơ bản về chức năng Compare trong AVR như sau:

Q: Thế nào là chức năng Compare?


A: Đây là một trong những chức năng thường thấy và gắn liền với các timer của các vi điều khiển, bên
cạnh chức năng Capture. Nguyên lý hoạt động là: giá trị đếm của timer sẽ liên tục được so sánh với
một giá trị đặt trước, khi hai giá trị này bằng nhau (chính là sự kiện compare match) thì sẽ có thể thực
hiện một tác động nào đó (ngắt, set/clear hoặc đảo chân OCx tương ứng, hoặc thậm chí là không làm
gì cả...) tùy người lập trình chọn lựa. Giá trị đặt trước ấy do người lập trình ghi trong thanh ghi OCRnx
(ví dụ: OCR0A, OCR0B, OCR1A, OCR1B...)

Q:"If one or both of the COMnA1:0 bits are written to one, the OCnA output overrides the
normal port functionality of the I/O pin it is connected to." nghĩa là gì?
A: Mỗi kênh Output Compare liên quan đến một hay vài đầu ra, tên là các chân OCnx (ví dụ OC0A,
OC1A, OC1B..). Các chân này được dùng chung với các chân cổng vào ra thông thường, khi dùng cho
chức năng Compare thì không dùng làm chức năng vào ra được nữa. Khi xảy ra sự kiện compare
match thì các đầu ra OCxn này có thể thực hiện tác động nào đó (set/clear/toggle...) tùy ý người sử
dụng. Việc chọn tác động loại nào là do các bit COMnx trong thanh ghi TCCR tương ứng quy định. Với
câu tiếng Anh bạn hỏi, dịch ra có nghĩa là nếu một hoặc hai bit COMnA0 và COMnA1 được ghi giá trị 1
vào thì tác động đầu ra sẽ được chọn là set/clear hay toogle (tùy tổ hợp là 01,10 hay 11), đè lên chức
năng hoạt động vào/ra thông thường của chân cổng tương ứng (chân cổng đó không còn dùng làm
cổng vào ra được nữa).

Q: "Toggle OCnA/OCnB/OCnC on compare match." có nghĩa là gì?


A: Khi xảy ra sự kiện compare match (tạm dịch là so sánh thấy khớp), có 04 kiểu tác động mà người
lập trình có thể chọn để tác động lên chân đầu ra OCnx: set = 1, clear = 0, toogle = đảo giá trị, và
không làm gì cả (vẫn dùng làm cổng vào ra bình thường). Bạn hãy nhớ một điều rằng, các tác động
này khi đã chọn đều được thực hiện một cách hoàn toàn tự động một khi sự kiện compare match xảy
ra.

Chức năng Compare trong timer chủ yếu liên quan đến các ứng dụng về điều chế độ rộng xung PWM.
Theo ý kiến chủ quan của bản thân tôi, timer của AVR là ngoại vi phức tạp nhất trong số các ngoại vi
onchip của nó, cũng có thể nói đó là timer khó nắm bắt nhất trong các timer của các loại vi điều khiển
8 bit, với nhiều chế độ hoạt động phức tạp. Để nắm bắt được bạn cần có thời gian và sự kiên trì.

Hy vọng đã phần nào giúp được bạn.

Q: Input capture là gì thế?


A: Mỗi kênh Input Capture liên quan đến 1 chân tín hiệu đầu vào. Khi có sự kiện bên ngoài xảy ra, thể
hiện ở việc tín hiệu đưa vào chân này thay đổi mức (tức là có sườn lên hoặc sườn xuống) thì giá trị của
timer liên quan sẽ được ghi lại đúng vào thời điểm đó. Cụ thể là ghi vào thanh ghi Capture tương ứng
(tên là ICRxn, ví dụ: ICR1A...). Kiểu tích cực của sườn có thể lựa chọn được (sườn lên, sườn xuống
hoặc cả sườn lên và sườn xuống).

Q: Ứng dụng của Input Capture?


A: Có một số. Có thể kể ra như:
- đo độ rộng xung: đo thời gian giữa sườn lên và sườn xuống gần nhất.
- đo chu kỳ: đo thời gian giữa hai sườn lên hoặc hai sườn xuống liên tiếp.
- ngắt ngoài: dùng như một ngắt ngoài (vì cũng có thay đổi mức tín hiệu)
- ...

Thông thường ATMEGA nạp qua ISP bằng cách sử dụng các chân của cổng SPI là MOSI, MISO, SCK.
Tuy nhiên đến đời ATMEGA128, ko hỉu vì seo mà bác ATMEL lại sử dụng các chân RxD0, TxD0 và
SCK. Phải rất chú ý điểm này chứ hàn vào rồi là dễ toi 150k lắm đấy

Mạch nạp và sơ đồ kít bạn hãy tìm ở http://www.olimex.com/, đây là một địa chỉ được rất nhiều người
biết. Ngoài AVR các bạn có thể tìm được nhiều thông tin hữu ích khác về các dòng VDK. Link cụ thể
cho bác đây, bác cứ làm giống hệt như nó là ổn (tôi cũng đang dùng ATMEGA128):
Đây là mạch nạp, tôi đã làm một sợi giống hệt thế và đang dùng
http://www.olimex.com/dev/avr-pg1.html

Đây là mạch phát triển:


http://www.olimex.com/dev/avr-mt128.html

http://www.olimex.com/dev/avr-h128.html

Để cấu hình sử dụng thạch anh ngoài, bootloader, Watchdog, JTAG, bạn nên bật PonyProg lên, chọn
ATMEGA128 rồi nhất Ctrl-S để có bảng Configuration and Security Bits.

Lần lượt search trong Datasheet tác dụng của từng fuse một. Bạn sẽ biết cần cấu hình như thế nào.
làm thế bạn sẽ hiểu và nhớ lâu hơn là tớ trả lời trực tiếp câu hỏi của cậu . Và với các chíp ATMEGA
khác cậu có thể làm hoàn toàn tương tự.

À, mà tớ khuyên cậu nên sử dụng Bootloader của http://www.microsyl.com/, tên là Megaload. Đã được
đề cậu đến trong 1 luồng ở Box này. Hiện đã có phiên bản mới hơn.

Sử dụng Bootloader sẽ tiết kiệm được thời gian hơn, dễ dàng hơn trong việc nạp chương trình, và còn
nạp rất nhanh nữa . Bạn hoàn toàn có thể nạp qua cổng USB (dùng Laptop ko có cổng COM chẳng
hạn ) với 1 sợi cáp USB to COM hoặc USB Data Cable của điện thoại di động như DKU5 (giá chỉ 50k)
chẳng hạn.

Những j tớ nói đều đã được tớ thử qua (tớ đang dùng bootloader cho board ATMEGA128, nạp qua cáp
USB2COM, cáp được chế từ cable nạp của Samsung E400 thì phải )

- Tôi cũng đang tìm hiểu về Timer và cũng xin hỏi các bác:
Nếu tạo một timer bằng codewizard như sau:
+ Chip: Atmega8515L - Clock 8MHz
+ Timers: tab Timer0 : Clock Source = System Clock
Clock Value = 8000.0kHz
Mode: Normal Top = 0xFF
Output: Toggle on compare match
Time Value = 0h
Compare = 0h
thì nó có tạo ra xung vuông f = 4MHz ở chân OC0 (PORTB.0) không? Nếu không thì các bác cho
em biết hình thù nó ra sao nhé?
(Cái này mà có con oxilồ thì tốt quá).

Có xung vuông ra, nhưng ... không phải là xung có tần số = 4MHz.

Nào, cùng xem tần số ra là bao nhiêu nhé:


1 - Normal mode: đếm từ 0 lên 255 lại về 0, mãi như thế... Chu kỳ tràn là 256 clock. Clock là 8MHz
suy ra chu kỳ tràn là 256*125ns = 32,000ns = 32us.
2 - Output toggle on compare match: cứ khi so sánh timer và OCR0 thấy bằng nhau sẽ đảo đầu ra
chân OC0.
3 - OCR0 = 0h (hay bằng bao nhiêu đi nữa trong dải từ 0 đến 255) thì cũng chỉ so sánh khớp với timer
tại một điểm trong quá trình timer đếm từ 0 đến 255. Như vậy chu kỳ của sự kiện so sánh khớp
(compare match) bằng với chu kỳ tràn timer (vì trong mỗi chu kỳ tràn chỉ so sánh khớp có một lần).
Tuy nhiên mỗi lần khớp lại đảo trạng thái OC0 một lần, vậy phải có hai lần so sánh khớp mới tạo ra
một xung vuông hoàn chỉnh.

Tóm lại, khi ở normal mode, bất kể Compare value bằng bao nhiêu, xung vuông tạo ra có tần số bằng
1/2 tần số tràn của timer. Trong trường hợp này, timer là 8bit, clock = 8MHz ---> tần số tràn của
timer = 1/32us = 31,250Hz ---> tần số xung vuông tạo ra là 31,250/2 = 15,625Hz!

Nếu muốn tạo xung bằng timer, không nên dùng normal mode.

Tôt nhất là tạo xung = PWM. Chính xác, đỡ tốn tài nguyên xử lý của chip.

Toán tử << là toán tử dịch trái. Lệnh của các hạ đưa ra phân tích chi tiết thì là thế này:
- dịch trái bit 1 (bit = 1 chứ không phải bit 1 trong 8bit từ 0 đến 7!!!) đi int0 lần ---> kết quả thu được
là một byte có một bit = 1 (tại số thứ tự = int0). Ví dụ nếu int0 = 5 thì sẽ thu được byte có giá trị là
00100000b.
- tương tự có được byte có một bit = 1 (tại số thứ tự = int1).
- OR hai byte đó với nhau thu được một byte có 02 bit = 1 tại số thứ tự int0 và int1 (các bit có số thứ
tự khác đều bằng 0). Đó chính là giá trị người lập trình muốn đưa vào biến temp.
Tóm lại, lệnh trên có nghĩa là nạp một hằng số 8bit có giá trị bằng 1 ở các bit có cùng số thứ tự với các
bit int0, int1 vào biến temp.
Tại hạ đoán sau đó là lệnh nạp temp vào thanh ghi cho phép ngắt của AVR. Kiến trúc của AVR không
cho phép nạp trực tiếp giá trị tức thời vào các thanh ghi thuộc vùng I/O.
Giang hồ hiểm ác, bảo trọng.

Capture là một hình thức ngẳt ngoài! Trong AVR chips, có một số chân ICPs, khi có một sự kiện xảy ra
trên các chân này (chuyen tu trạng thái thấp lên cao, hoặc ngược lại) thì sẽ có một ngắt được gọi.

Ưu điểm của loại ngắt này là nó làm việc với các bộ đinh thời, chính vì vậy khi có ngắt xảy ra, các bạn
có thể biết thời điểm ngắt. Một ứng dụng quan trọng là làm decoder. Ví dụ tính toán tốc độ của động
cơ. Nếu bạn biết thời gian giữa 2 xung nhận, bạn sẽ tính được vận tốc quay của động cơ thông qua
công thức toán học đơn giản (ko nhớ là gì :-) )

Về ví dụ về phần này, tôi đang cố gắng để viết một giáo trình cơ bản cho các module trong AVR, vậy
bạn chờ thêm chút nữa nhé. Tuy nhiên nếu bạn có một bài toán cụ thể nào sử dụng ICP, bạn hãy thử
viết code trước, nếu có những vấn đề cụ thể thi có thể bàn luận tại đây.

You might also like