III. Truyền thông nối tiếp không đồng bộ với AVR (UART).
2. Sử dụng UART:.
2.2 Nhận dữ liệu.
Quá trình nhận dữ liệu chỉ xảy ra khi bit RXEN trong thanh ghi UCSRB được set bằng 1 và tất nhiên chân nhận dữ liệu RxD phải được nối với một nguồn phát (chân TxD của một chip UART khác chẳng hạn). Các thông số truyền thông như tốc độ baud và khung truyền trong bộ nhận phải được cài đặt như của bộ phát. Nếu không có lỗi
trong quá trình truyền và nhận dữ liệu, sau khi nhận dữ liệu sẽđược chứa trong thanh ghi UDR và bit RXC (Reveice Complete) trong thanh ghi UCSRA sẽ tựđộng được set lên 1. Sau khi thanh ghi UDR được đọc, bit RXC lại tựđộng reset về 0 để chuẩn bị
cho quá trình nhận dữ liệu kế tiếp. Như thế về cơ bản chúng ta có 2 cách đọc dữ liệu nhận về. Cách thứ nhất là cách hỏi vòng (polling), kiểm tra nếu bit RXC = 1 thì đọc giá trị thanh ghi UDR (và đọc cả bit RXB8 trong thanh ghi UCSRB nếu frame truyền 9 bit được dùng). Cách thứ hai là sử dụng ngắt “nhận hoàn tất” (Receive Complete Interrupt), bằng cách set bit cho pháp ngắt nhận hoàn tất, tức bit RXCIE trong thanh ghi UCSRB, và bit cho phép ngắt toàn cục (bit I, xem lại bài 3) thì một ngắt sẽ xảy ra khi dữ liệu đã được nhận và chứa trong thanh ghi UDR, chúng ta chỉ cần đọc giá trị
của thanh ghi UDR trong trình phục vụ ngắt là xong. Theo kinh nghiệm, sử dụng ngắt là phương pháp tốt nhất cho đa số các trường hợp nhận dữ liệu UART, vì chúng ta không cần quan tâm thời điểm mà dữ liệu gởi đến, tránh lãng phí thời gian dành cho việc “hỏi vòng”. Vì thế trong phần tiếp theo tôi sẽ trình bày một ví dụ minh họa quá trình nhận dữ liệu bằng phương pháp ngắt. Để phục vụ cho ví dụ này, chúng ta sẽ khảo sát một mạch mô phỏng gồm 2 chip Atmega32 nối với nhau qua các đường TxD và RxD. Chip thứ là chip phát dữ liệu, nhiệm vụ của chip này là phát chuỗi dữ liệu từ 32
đến 127 như chip Atmega32 trong ví dụ 1. Chân phát TxD của chip 1 sẽ được nối với chân nhận RxD của chip thứ 2 (chip thứ 2 được gọi là chip nhận dữ liệu). Chip thứ 2 sau khi nhận dữ liệu sẽ phát dữ liệu này ra chân TxD của chính nó để có thể hiển thị
lên thiết bịđầu cuối ảo cho chúng qua quan sát và so sánh kết quả. Bạn xem mạch
điện mô phỏng trong hình 5 để hiểu rõ hơn. Chúng ta sử dụng đoạn code trong ví dụ 1 cho chip thứ nhất vì thế chỉ cần viết đoạn code nhận và phát lại dữ liệu cho chip thứ
hai. List 2 trình bày đoạn code cho chip thứ hai..
List 2. Nhận dữ liệu USART không đồng bộ bằng phương pháp ngắt. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <avr/io.h> #include <avr/interrupt.h> #include <util/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;
}
volatile unsigned char u_Data; 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);
19 20 21 22 23 24 25 26 27 28
phep ngat sau khi nhan xong sei(); //cho phep ngat toan cuc while(1){
} }
ISR(SIG_UART_RECV){ //trinh phuc vu ngat USART hoan tat nhan u_Data=UDR;
uart_char_tx(u_Data); }
Đoạn code trong ví dụ nhận và phát dữ liệu không khác đoạn code trong ví dụ
1 là mấy. Ở dòng thứ 3 tôi include file header interrupt.h vì chúng ta sẽ sử dụng ngắt để nhận dữ liệu. Chúng ta khai báo một biến u_Data dạng 8 bit không dấu để
lưu dữ liệu nhận được, do biến này sẽđược truy cập trong trình phục vụ ngắt nên chúng ta đặt attribute volatile (dòng 9). Điểm quan trọng khi khởi động UART trong ví dụ này là dòng code 18, nếu trong ví dụ 1 chúng ta chỉ khởi động duy nhất bộ phát bằng cách set bit TXEN trong thanh ghi UCSRB (UCSRB=(1<<TXEN);) thì trong ví dụ này chúng ta set thêm 2 bit cho phép nhận RXEN và cho phép ngắt RXCIE trong thanh ghi UCSRB. Bit RXEN khởi động bộ nhận và bit RXCIE khởi
động chếđộ ngắt khi dữ liệu đã nhận trong UDR, tuy nhiên để có thể sử dụng ngắt, chúng ta cần set them bit I trong thanh ghi trạng thái bằng dòng code 20 (sei();). Phần quan trọng nhất trong đoạn code trên là trình phục ngắt nhận dữ liệu ISR. Khi dữ liệu đã được nhận đầy trong UDR, trình ngắt ISR(SIG_UART_RECV) sẽđược thực hiện, chúng ta sẽđọc giá trị vừa nhận được vào biến u_Data (dòng 26) và sau
đó phát giá trị này ra chân TxD để hiển thị lên thiết bị đầu cuối ảo bằng dòng lệnh 27.
Phần mạch điện mô phỏng được trình bày trong hình 5. Chương trình cho chip TRANSMITTER là chương trình trong ví dụ 1 và chương trình cho chip
RECEIVER là chương trình trong đoạn code trên. Bạn phải set xung clock cho cả 2 chip là 8MHz và set tốc độ baud cho thiết bị đầu cuối ảo là 56700. Nếu khi chạy mô phỏng, thiết bịđầu cuối hiển thị các ký tự ASCII của các số từ 32 đến 127 như