Professional Documents
Culture Documents
#include <90s2313.h>
#define XUNG PORTD.0 //Xung đầu ra
// Ngắt T0
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
XUNG=!XUNG;
}
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
ACSR=0x80;
while (1)
{
// Place your code here
};
}
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:
Introduction
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
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ị
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
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:
#include
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)
{
..........................
};
}
===========================================================================
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
Đặc tính:
==========================================
Introduction
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
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ị
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
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:
#include <mega8.h>
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
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>
// 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;
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
Đồ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.
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 !!!
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:
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ý.
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:
;đọ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).
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:
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
Sjmp exits
Mov stack1,sp
Exits:
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…)
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
Sjmp exit
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
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
Org 00h
Ljmp start
Org 00BH
Org 0030H
Start:
Mov psw,#00
;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
Task2:
Int_timer0:
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.
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
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. ???
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.
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.
// 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;
//Để tạo ra điện áp lối ra PWM theo ý muốn, bạn đặt giá trị cho OCR0
//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)
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:"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).
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ì.
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
Để 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.
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.