Giới thiệu về giao tiếp vào ra I/O.- Lập trình I/O là lập trình đơn giản và cơ bản nhất, nhưng lại được sử dụng nhiều nhất, chúng ta điều khiển on/off bóng đèn, động cơ, hay 1 thiết bị n
Trang 1KHOA ĐÀO TẠO CHẤT LƯỢNG CAO
- - - - - -
MÔN HỌC: Vi điều khiển ứng dụng
Báo cáo cuối kì
GVHD: Trương Ngọc Hà SVTH: MSSV
Nguyễn Lê Anh Tuấn 20145648 Lớp:
Sáng T7 ( Tiết 4-5 )
TP.HCM 2022
Trang 2NHẬN XÉT CỦA GIÁO VIÊN
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
………
Chữ ký
Trương Ngọc Hà
Trang 3MỤC LỤC
I Chương I: Giao tiếp vào ra I/O 1
1 Giới thiệu về giao tiếp vào ra I/O 1
2 Các cấu hình chức năng I/O 2
3 Ví dụ về giao tiếp vào ra I/O 3
II Chương : Ngắt 3
1 Ngắt trên AVR 3
2 Ngắt ngoài 4
3 Ví dụ về Ngắt 5
III.Chương: Timer- Counter 6
1 Tổng quan về Timer-Counter 6
2 Ví dụ 7
2.1 Ví dụ Timer 7
2.2 Ví dụ về Counter 7
IV Chương: UART 8
1 UART là gì 8
2 Ví dụ truyền dữ liệu bằng USART 9
V Chuyển đổi ADC 10
1 Chuyển đổi ADC là gì 10
2 Chuyển đổi ADC trên AVR 10
3 Ví dụ về ADC 10
VI.Giao tiếp SPI 11
1 SPI là gì 11
2 SPI trên AVR 11
3 Sử dụng SPI trên AVR 12
4 Ví dụ về giao tiếp SPI 12
VII Analog comparator 13
1 Tổng quan về Analog comparator 13
2 Ví dụ về Analog comparator 15
Trang 4I Chương I: Giao tiếp vào ra I/O.
1 Giới thiệu về giao tiếp vào ra I/O.
- Lập trình I/O là lập trình đơn giản và cơ bản nhất, nhưng lại được
sử dụng nhiều nhất, chúng ta điều khiển on/off bóng đèn, động cơ, hay 1 thiết bị nào đó cũng là 1 dạng của điều khiển I/O
Để giảm bớt số chân ra, một số chân của AVR là các chân đa chức năng, nó phục vụ cho các thiết bị ngoại vi Ở đây khái niệm thiết bị ngoại vi không có nghĩa là 1 chip khác mua rời bên ngoài mà là các modun được tích hợp sẵn trong các chip như các modun ADC… Khi các thiết bị ngoại vi này được enable thì các chân này không được sử dụng như các chân của các cổng I/O thông thường nữa
- Các thao tác cơ bản
Nhập dữ liệu (Input)
Xuất dữ liệu (Output)
- Các thành phần chính
Các thiết bị ngoại vi
Các modun IO
- Cấu trúc cơ bản của hệ thống IO
- Các thiết bị ngoại vi
Chức năng: Chuyển đổi dữ liệu giữa bên trong và bên ngoài máy tính
Phân loại:
Thiết bị ngoại vi giao tiếp người-máy (người đọc): Bàn phím, màn hình, máy in,…
Thiết bị ngoại vi giao tiếp máy-máy (máy đọc): Đĩa cứng, CDROM, USB,…
Trang 5 Thiết bị ngoại vi truyền thông: Modem, Network, Interface Card (NIC)
- Các thành phần của thiết bị ngoại vi
Bộ chuyển đổi tín hiệu: Chuyển đổi dữ liệu giữa bên ngoài và bên trong máy tính
Bộ đệm dữ liệu: đệm dữ liệu khi truyền giữa modun IO
và thiết bị ngoại vi
Khối logic điều khiển: điều khiển hoạt động của thiết bị ngoại vi đáp ứng theo yêu cầu từ modun IO
- Chức năng của modun IO
Điều khiển và định thời
Trao đổi thông tin với CPU hoặc bộ nhớ chính
Trao đổi thông tin với thiết bị ngoại vi
Đệm giữa bên trông máy tính với thiết bị ngoại vi
Phát hiện lỗi của thiết bị ngoại vi
2 Các cấu hình chức năng I/O.
Atmega32 có 4 cổng vào ra là PORTA, PORTB, PORTC, PORTD Khi xem xét đến các cổng I/O của AVR thì ta phải xét tới 3 thanh ghi DDxn, PORTxn,PINxn
- Các bit DDxn để truy cập cho địa chỉ xuất nhập DDRx Bit DDxn trong thanh ghi DDRx dùng để điều khiển hướng dữ liệu của các chân của cổng này.Khi ghi giá trị logic ‘0’ vào bất kì bit nào của thanh ghi này thì nó sẽ trở thành lối vào,còn ghi ‘1’ vào bit đó thì nó trở thành lối ra
- Các bit PORTxn để truy cập tại địa chỉ xuất nhập PORTx Khi PORTx được ghi giá trị 1 khi các chân có cấu tạo như cổng ra thì điện trở kéo là chủ động(được nối với cổng) Ngắt điện trở kéo ra, PORTx được ghi giá trị 0 hoặc các chân có dạng như cổng ra.Các chân của cổng là 3 trạng thái khi 1 điều kiện reset là tích cực thậm chí xung đồng hồ không hoạt động
- Các bit PINxn để truy cập tại địa chỉ xuất nhập PINx PINx là các cổng chỉ để đọc,các cổng này có thể đọc trạng thái logic của PORTx.PINx không phải là thanh ghi,việc đọc PINx cho phép ta đọc giá trị logic trên các chân của PORTx.chú ý PINx không phải là thanh ghi,việc đọc PINx cho phép ta đọc giá trị logic trên các chân của PORTx
- PORTxn được ghi giá trị logic ‘1’ khi các chân của cổng có dạng như chân ra ,các chân có giá trị ‘1’.Nếu PORTxn ghi giá trị ‘0’ khi các chân của cổng có dạng như chân ra thì các chân đó có giá trị ‘0’
Trang 6- Các cổng của AVR đều có thể đọc, ghi Để thiết lập 1 cổng là cổng vào,
ra thì ta tác động tới các bit DDxn, PORTxn, PINxn Ta có thể thiết lập để từng bit làm cổng vào, ra cứ không chỉ với cổng, như vậy ta có thể xử lý tới từng bit, đây chính là điểm mạnh của các dòng Vi điều khiển 8 bit
3 Ví dụ về giao tiếp vào ra I/O.
#include <avr/io.h>
Int main()
{
DDRD |= (1 << 7) ;
PORTD |=(1<<7);
while(1) {
if ( (PIND & (1 << 4) == 0) {
PORTD |= (1<<7);
}
else {
PORTD &= ~(1 << 7);
}
}
return 0;
}
II Chương : Ngắt.
1 Ngắt trên AVR
- Ngắt là một trong 2 kỹ thuật “bắt” sự kiện cơ bản là hỏi vòng (Polling)
và ngắt Hãy tưởng tượng bạn cần thiết kế một mạch điều khiển hoàn chỉnh thực hiện rất nhiều nhiệm vụ bao gồm nhận thông tin từ người dùng qua các button hay keypad (hoặc keyboard), nhận tín hiệu từ cảm biến, xử
lí thông tin, xuất tín hiệu điều khiển, hiển thị thông tin trạng thái lên các LCD…(bạn hoàn toàn có thể làm được với AVR), rõ ràng trong các nhiệm vụ này việc nhận thông tin người dùng (start, stop, setup, change,
…) rất hiếm xảy ra (so với các nhiệm vụ khác) nhưng lại rất “khẩn cấp”, được ưu tiên hàng đầu Nếu dùng Polling nghĩa là bạn cần viết 1 đoạn chương trình chuyên thăm dò trạng thái của các button (tôi tạm gọi đoạn chương trình đó là Input()) và bạn phải chèn đoạn chương trình Input() này vào rất nhiều vị trí trong chương trình chính để tránh trường hợp bỏ sót lệnh từ người dùng, điều này thật lãng phí thời gian thực thi Giải pháp cho vấn đề này là sử dụng ngắt, bằng cách kết nối các button với đường ngắt của chip và sử dụng chương trình Input() làm trình phục vụ ngắt - isr của ngắt đó, bạn không cần phải chèn Input() trong lúc đang thực thi và vì thế không tốn thời gian cho nó, Input() chỉ được gọi khi người dùng nhấn các button Đó là ý tưởng sử dụng ngắt
Trang 7- Bảng 1 các vector ngắt và Reset trên chip Atmega
2 Ngắt ngoài
- Ngắt ngoài là cách rất hiệu quả để thực hiện giao tiếp giữa người dùng
và chip Trên chip atmega8 có 2 ngắt ngoài có tên là INT0 và INT1 tương ứng 2 chân số 4 (PD2) và số 5 (PD3) Như tôi đã đề cập trong bài AVR2, khi làm việc với các thiết bị ngoại vi của AVR, hầu như chúng ta chỉ thao tác trên các thanh ghi chức năng đặc biệt - SFR (Special Function Registers) trên vùng nhớ IO, mỗi thiết bị bao gồm một tập hợp các thanh ghi điều khiển, trạng thái, ngắt…khác nhau, điều này đồng nghĩa chúng ta phải nhớ tất cả các thanh ghi của AVR
- (MCU Control Register) là thanh ghi xác lập chế độ ngắt cho ngắt ngoài
3 Ví dụ về Ngắt.
#include <avr/io.h>
#include <avr/interrupt.h>
Trang 8#include <avr/delay.h>
volatile int8_t val=0; //khai báo 1 biến val 8 bit, có dấu và giá trị khởi tạo bằng 0
int main(void){
DDRD=0x00; //khai báo PORTD là Input để sử dụng 2 chân ngắt
PORTD=0xFF; //sử dụng điện trở nội kéo lên
DDRB=0xFF; //PORTB là Output để xuất LED 7 đoạn
MCUCR|=(1<<ISC11)|(1<<ISC01); //cả 2 ngắt là ngắt cạnh xuống GICR |=(1<<INT1)|(1<<INT0); //cho phép 2 ngắt hoạt động sei(); //set bit I cho phép ngắt toàn cục
DDRC=0xFF; //PORTC là Output
while (1){ //vòng lặp vô tận
PORTC++; //quét PORTC
_delay_loop_2(60000);
}
return 0;
}
//Trình phục vụ ngắt của INT0
ISR(INT0_vect){
val++; //nếu có ngắt INT0 xảy ra, tăng val thêm 1
if (val>9) val=0; //giới hạn không vượt quá 9 PORTB=val;
}
//Trình phục vụ ngắt của INT1
ISR(INT1_vect){
val ; //nếu có ngắt INT1 xảy ra, giảm val
đi 1
if (val<0) val=9; //giới hạn không nhỏ hơn 0
PORTB=val;
}
III Chương: Timer- Counter.
1 Tổng quan về Timer-Counter.
- Timer/Counter là các module độc lập với CPU Chức năng chính của các bộ Timer/Counter, như tên gọi của chúng, là định thì (tạo ra một khoảng thời gian, đếm thời gian…) và đếm sự kiện Trên các chip AVR,
Trang 9các bộ Timer/Counter còn có thêm chức năng tạo ra các xung điều rộng PWM (Pulse Width Modulation), ở một số dòng AVR, một số Timer/Counter còn được dùng như các bộ canh chỉnh thời gian (calibration) trong các ứng dụng thời gian thực Các bộ Timer/Counter được chia theo độ rộng thanh ghi chứa giá trị định thời hay giá trị đếm của chúng, cụ thể trên chip Atmega8 có 2 bộ Timer 8 bit (Timer/Counter0
và Timer/Counter2) và 1 bộ 16 bit (Timer/Counter1) Chế độ hoạt động
và phương pháp điều khiển của từng Timer/Counter cũng không hoàn toàn giống nhau, ví dụ ở chip Atmega8:
Timer/Counter0: là một bộ định thời, đếm đơn giản với 8 bit Gọi là đơn giản vì bộ này chỉ có 1 chế độ hoạt động (mode) so với 5 chế độ của
bộ Timer/Counter1 Chế độ hoat động của Timer/Counter0 thực chất có thể coi như 2 chế độ nhỏ (và cũng là 2 chức năng cơ bản) đó là tạo ra một khoảng thời gian và đếm sự kiện Chú ý là trên các chip AVR dòng mega sau này như Atmega16,32,64…chức năng của Timer/Counter0 được nâng lên như các bộ Timer/Counter1…
Timer/Counter1: là bộ định thời, đếm đa năng 16 bit Bộ Timer/Counter này có 5 chế độ hoạt động chính Ngoài các chức năng thông thường, Timer/Counter1 còn được dùng để tạo ra xung điều rộng PWM dùng cho các mục đích điều khiển Có thể tạo 2 tín hiệu PWM độc lập trên các chân OC1A (chân 15) và OC1B (chân 16) bằng Timer/Counter1 Các bộ Timer/Counter kiểu này được tích hợp thêm khá nhiều trong các chip AVR sau này, ví dụ Atmega128 có 2 bộ, Atmega2561 có 4 bộ…
Timer/Counter2: tuy là một module 8 bit như Timer/Counter0 nhưng Timer/Counter2 có đến 4 chế độ hoạt động như Timer/Counter1, ngoài ra nó nó còn được sử dụng như một module canh chỉnh thời gian cho các ứng dụng thời gian thực (chế độ asynchronous)
Trong phạm vi bài 4 này, tôi chủ yếu hướng dẫn cách sử dụng 4 chế
độ hoạt động của các Timer/Counter Chế độ asynchronous của Timer/Counter2 sẽ được bỏ qua vì có thể chế độ này không được sử dụng phổ biến
Trước khi khảo sát hoạt động của các Timer/Counter, chúng ta thống nhất cách gọi tắt tên gọi của các Timer/Counter là T/C, ví dụ T/C0 để chỉ Timer/Counter0…
2 Ví dụ
2.1 Ví dụ Timer
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
Trang 10int main(void){
DDRB=0xFF; //PORTB la output PORT
PORTB=0x00;
TCCR1B=(1<CS10);// CS12=0, CS11=0, CS10=1: chon Prescaler =1 // thanh ghi TCCR1B duoc dung thay vi TCCR0 cua Timer0 TCNT1=55535; //gan gia tri khoi tao cho T/C1
TIMSK=(1<<TOIE1);//cho phep ngat khi co tran o T/C1
sei(); //set bit I cho phep ngat toan cuc
while (1){ //vòng lặp vô tận
//do nothing
}
return 0;
}
//trinh phuc vu ngat tran T/C1
ISR (TIMER1_OVF_vect ){
TCNT1=55535; //gan gia tri khoi tao cho T/C1
PORTB ^=1; //doi trang thai Bit PB0
}
2.2 Ví dụ về Counter.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile usigned char val=0; //khai bao 1 bien tam val va khoi tao =0 int main(void){
DDRB=0xFF; //PORTB la output PORT
PORTB=0x00;
TCCR1B=(1<<WGM12)|(1<<CS12)|(1<<CS11); //xung nhip tu chan T1, canh xuong
OCR1A=4; //gan gia tri can so sanh
TIMSK=(1<OCIE1A);//cho phep ngat khi gia tri dem bang 4 sei(); //set bit I cho phep ngat toan cuc
while (1){ //vòng lặp vô tận
//do nothing
}
return 0;
}
//trinh phuc vu ngat compare match
ISR (TIMER1_COMPA_vect){
val++;
Trang 11if (val==10) val=0; //gioi han bien val tu 0 den 9
PORTB =val; //xuat gia tri ra PORTB
}
IV Chương: UART
1 UART là gì.
- Vi điều khiển Atmega32 có 1 module truyền thông nối tiếp USART Có
3 chân chính liên quan đến module này đó là chân xung nhịp - XCK (chân số 1), chân truyền dữ liệu – TxD (Transmitted Data) và chân nhận
dữ liệu – RxD (Reveived Data) Trong đó chân XCK chỉ được sử dụng như là chân phát hoặc nhận xung giữ nhịp trong chế độ truyền động bộ Tuy nhiên bài này chúng ta không khảo sát chế độ truyền thông đồng bộ,
vì thế bạn chỉ cần quan tâm đến 2 chân TxD và RxD Vì các chân truyền/nhận dữ liệu chỉ đảm nhiệm 1 chức năng độc lập (hoặc là truyền, hoặc là nhận), để kết nối các chip AVR với nhau (hoặc kết nối AVR với thiết bị hỗ trợ UART khác) bạn phải đấu “chéo” 2 chân này TxD của thiết bị thứ nhất kết nối với RxD của thiết bị 2 và ngược lại Module USART trên chip Atmega32 hoạt động “song công” (Full Duplex Operation), nghĩa là quá trình truyền và nhận dữ liệu có thể xảy ra đồng thời
Thanh ghi:
Cũng như các thiết bị khác trên AVR, tất cả hoạt động và tráng thái của module USART được điều khiển và quan sát thông qua các thanh ghi trong vùng nhớ I/O Có 5 thanh ghi được thiết kế riêng cho hoạt động và điều khiển của USART, đó là:
UDR: hay thanh ghi dữ liệu, là 1 thanh ghi 8 bit chứa giá trị nhận được
và phát đi của USART Thực chất thanh ghi này có thể coi như 2 thanh ghi TXB (Transmit data Buffer) và RXB (Reveive data Buffer) có chung địa chỉ Đọc UDR thu được giá trị thanh ghi đệm dữ liệu nhận, viết giá trị vào UDR tương đương đặt giá trị vào thanh ghi đệm phát, chuẩn bị để gởi
đi Chú ý trong các khung truyền sử dụng 5, 6 hoặc 7 bit dữ liệu, các bit cao của thanh ghi UDR sẽ không được sử dụng
UCSRA (USART Control and Status Register A): là 1 trong 3 thanh ghi
điều khiển hoạt động của module USART
Thanh ghi UCSRA chủ yếu chứa các bit trạng thái như bit báo quá trình nhận kết thúc (RXC), truyền kết thúc (TXC), báo thanh ghi dữ liệu trống
Trang 12(UDRE), khung truyền có lỗi (FE), dữ liệu tràn (DOR), kiểm tra parity có lỗi (PE)…
UCSRB (USART Control and Status Register B): đây là thanh ghi quan
trọng điều khiển USART Vì thế chúng ta sẽ khảo sát chi tiết từng bit của thanh ghi này
UCSRC (USART Control and Status Register C): thanh ghi này chủ yếu
quy định khung truyền và chế độ truyền Tuy nhiên, có một rắc rối nho nhỏ là thanh ghi này lại có cùng địa chỉ với thanh ghi UBRRH (thanh ghi chứa byte cao dùng để xác lập tốc độ baud), nói một cách khác 2 thanh ghi này là 1 Vì thế bit 7 trong thanh ghi này, tức bit URSEL là bit chọn thanh ghi Khi URSEL=1, thanh ghi này được chip AVR hiểu là thanh ghi điều khiển UCSRC, nhưng nếu bit URSEL=0 thì thanh ghi UBRRH sẽ được sử dụng
2 Ví dụ truyền dữ liệu bằng USART.
#include <avr/io.h>
#include <avr/delay.h>
//chuong trinh con phat du lieu
void uart_char_tx(unsigned char chr){
while (bit_is_clear(UCSRA,UDRE)) {}; //cho den khi bit UDRE=1 UDR=chr;
}
int main(void){
//set baud, 57.6k ung voi f=8Mhz, xem bang 70 trang 165, Atmega32 datasheet
UBRRH=0;
UBRRL=8;
//set khung truyen va kich hoat bo nhan du lieu
UCSRA=0x00;
UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
UCSRB=(1<<TXEN);
while(1){
for (char i=32; i<128; i++){
uart_char_tx(i); //phat du lieu
_delay_ms(100);
}
}
}
V Chuyển đổi ADC.