Xoá màn hình

Một phần của tài liệu Lập trình 8051 siêu chi tiết (Trang 99)

Hàm này chỉ đơn giản là gửi lệnh clear màn hình lcd (xem thêm trong bảng lệnh của LCD). void lcd_clear() { lcd_write_cmd(0x01); lcd_goto_xy(0, 0); } 15.8.4 Thiết lập vị trí con trỏ

Hàm này thiết lập vị trí bắt đầu xuất dữ liệu trên màn hình LCD 2 hàng 16 cột. Để hiện thực hàm này ta phải tính được địa chỉ tương ứng với toạ độ (row,col) và dùng lệnh SET DDRAM ADDRESS (bit 7 của lệnh này bằng 1).

char lcd_goto_xy(unsigned char row, unsigned char col) { unsigned char addr = 0x00;

if(col >= 20 || row >= 4) return FALSE; if(row < 2) {

addr = (row * 0x40) + col; addr = 0x80 | (addr & 0x7F);

} else {

addr = (row * 0x40) + col; addr = 0x94 | (addr & 0x7F); } lcd_write_cmd(addr); current_row = row; current_col = col; return TRUE; } 15.8.5 In kí tự ra màn hình

Hàm này nhận thông số là 1 kí tự và hiển thị kí tự đó ra màn hình LCD. Việc hiện thực hàm này khá đơn giản, ta chỉ cần kéo chân RS xuống 0 là LCD sẽ hiểu các bit D7- D4 là dữ liệu.

void lcd_print_char(unsigned char dat) {

lcd_wait_busy(); //find next position

if(current_row == 0 && current_col == 16) lcd_goto_xy(1,0);

if(current_row == 1 && current_col ==16) lcd_goto_xy(0,0);

RS(DAT); //RS = 0 lcd_write_4bits(dat); lcd_write_4bits(dat << 4);

current_col ++; //update new position

}

Từ những hàm cơ bản này, bạn có thể hiện thực thêm các hàm để xuất 1 string hay 1 giá trị số ra màn hình LCD. Code chi tiết có thể xem thêm trong thư mục Bài 15.

BKIT HARDWARE CLUB www.bkit4u.com 101

Bài 16 : Giao tiếp I2C – DS1307

Mục đích:

Nắm vững giao tiếp I2C

Yêu cầu:

Xây dựng ứng dụng giao tiếp với DS1307 để lấy dữ liệu ngày tháng năm, giờ phút giây.

16.1 Các đặc điểm của DS1307

Real time clock đếm giờ, phút, giây, tháng, ngày của

tháng, ngày của tuần, năm kể cả năm nhuận (đến năm 2100). 56 byte Ram để lưu trữ dữ liệu, nhưng dữ liệu không bị

mất khi tắt nguồn.

Sử dụng 2 dây tín hiệu để truyền dữ liệu theo giao thức

I2C.

Có thể lập trình được để xuất tín hiệu xung vuông.

Tự động phát hiện ra nguồn cung cấp bị lỗi (ngắt nguồn) và chuyển qua

mạch bảo vệ sử dùng nguồn pin dự trữ. (adsbygoogle = window.adsbygoogle || []).push({});

16.2 Nguyên lý hoạt động

DS1307 hoạt động như một slaver trên bus dữ liệu nối tiếp. Để truy xuất

nội dung ta phải thiết lập một điều kiện Start và cung cấp mã nhận dạng của IC

(Device Identification Code) theo sau bởi thanh ghi địa chỉ. Các thanh ghi theo sau

được truy xuất tuần tự cho đến khi gặp tín hiệu Stop.

Khi VCC = 1.25Vbat thì DS1307 sẽ kết thúc việc truy xuất và reset lại bộ đếm địa chỉ. Các Input sẽ không được nhận ra tại thời điểm này để ngăn ngừa một

số lượng lớn dữ liệu được ghi tới DS1307 từ hệ thống bên ngoài. Khi VCC < Vbat thì ic này sẽ chuyển sang mode sử dụng pin dự trữ. Khi nguồn chính được bật lên thì IC này sẽ chuyển từ dùng nguồn pin sang dùng nguồn chính. Hình sau mô tả

16.3 Các tín hiệu Input và Output

VCC, GND : Nguồn DC được cung cấp cho IC qua những chân này. Khi gắn vào nguồn 5V thì IC này có thể đọc ghi bình thường. Nhưng khi nguồn giảm

xuống còn 3V thì việc đọc ghi sẽ không được phép. Tuy nhiên, các chức năng của

timer vẫn tiếp tục với nguồn cung cấp thấp. Khi Vcc giảm xuống dưới VBAT thì

RAM và timekeeper được chuyển qua sử dụng nguồn cung cấp tại VBAT.

VBAT : Cung cấp nguồn dữ trữ 3V. Để hoạt động ở chế độ sử dụng nguồn

Vbat thì 2.0V < Vbat < 3.5V. Khi VCC gần bằng 1.25VBAT thì chúng ta sẽ không được phép truy xuất vào RTC (Real time clock) và Ram bên trong của IC.

SCL (Serial Clock Input) : SCL được dùng để đồng bộ dữ liệu trên đường

truyền nối tiếp.

SDA (Serial Data Input/Output) : SDA là chân I/O. SDA là chân Open drain nên cần có điện trở kéo lên ở bên ngoài.

BKIT HARDWARE CLUB www.bkit4u.com 103

32khz. Chân này cũng là chân Open drain nên cũng yêu cầu có điện trở kéo lên nguồn ở bên ngoài. SQW/OUT sẽ hoạt động khi có nguồn cung cấp vào cho dù đó

là nguồn VCC hay là VBAT.

X1, X2 : Kết nối với thạch anh 32.768Khz. Mạch tạo xung bên trong được

thiết kế để hoạt động với thạch anh và tụ CL = 12.5 pF.

16.4 RTC và sơ đồ địa chỉ Ram

Sơ đồ địa chỉ của RTC và các thanh ghi Ram của DS1307 như ở hình dưới.

Các thanh ghi RTC được định địa chỉ từ 00h đến 07h. Các thanh ghi Ram được định địa chỉ tiếp theo sau đó và từ 08h đến 3fh. Trong khi truy suất nhiều byte và khi con trỏ địa chỉ chỉ tới ô 3fh, vị trí cuối của vùng nhớ Ram, thì nó sẽ quay lại địa chỉ 00h để truy xuất tiếp.

16.5 Thông tin thời gian và lịch

Thông tin thời gian và lịch được chứa trong trong các thanh ghi tương ứng. Các thanh ghi RTC như ở hình trên. Thời gian và lịch được set hoặc khởi tạo bằng cách ghi ra các byte thanh khi tương ứng. Nội dung của các thanh ghi thời gian và lịch được định dạng theo kiểu BCD. Bit 7 của thanh ghi 0 là clock halt bit (CH).

Khi bít này được set lên 1 thì mạch dao động sẽ bị ẩn không được sử dụng nữa,

khi clear xuống 0 thì mạch dao động sẽ được kích hoạt trở lại.

DS1307 có thể chạy ở chế độ 12h hay 24h. Bít thứ 6 của thanh ghi hours được định nghĩa để set xem sử dụng IC này ở chế độ nào. Khi bit này bằng 1 thì chế độ 12h được chọn. Trong chế độ 12h thì bit 5 chỉ AM/PM (PM khi bit này là 1). Trong chế độ 24h, thì bít 5 là bít thứ 2 của 10hour (20:23). (adsbygoogle = window.adsbygoogle || []).push({});

16.6 Thanh ghi điều khiển (Control Register)

Thanh ghi điều khiển của DS1307 được sử dụng để điều khiển hoạt động

của chân SQW/OUT.

Out (Output control) : Bít này điều khiển mức logic xuất ra trên chân SQW/OUT khi mà sóng vuông không được kích hoạt. Nếu SQWE = 0, thì mức

logic trên chân SQW/OUT là 1 nếu OUT = 1, và là 0 nếu OUT = 0.

SQWE (Square Wave Enabel) : Bít này khi được set lên mức 1 thì sẽ kích

hoạt mạch dao động xuất ra ngoài. Tần số của sóng vuông phụ thuộc vào giá trị ở

bít RS0 và RS1. Với sóng vuông xuất ra 1Hz thì thanh ghi clock sẽ cập nhập dữ

liệu khi có cạnh xuống của xung vuông.

RS (Rate select) : Những bit này điều khiển tần số của sóng vuông được

xuất ra trên chân SQW/OUT. Bảng sau liệt kê ra các tần số có thể được chọn bởi 2

bit RS này.

16.7 Bus dữ liệu nối tiếp.

DS1307 hỗ trợ truyền dữ liệu 2 chiều và giao thức truyền dữ liệu I2C trên 2 dây này. Thiết bị gởi dữ liệu trên bus gọi là transmitter và thiết bị nhận dữ liệu gọi

là receiver. Thiết bị điều khiển các message gọi là master. Thiết bị được điều

khiển bởi master thì gọi là slaver.

Bus dữ liệu được điều khiển bởi master. Bên cạnh đó nó cũng có nhiệm vụ

tạo xung clock trên đường tín hiệu SCL, điều khiển truy xuất bus, và tạo các tín

BKIT HARDWARE CLUB www.bkit4u.com 105

Các trạng thái của bus:

Bus không bận : khi cả 2 đường giữ tín hiệu ở mức high.

Bắt đầu truyền dữ liệu (start condition) : Thay đổi trạng thái trên đường dữ

liệu từ High xuống Low, trong khi đường clock ổn định ở mức high được định

nghĩa là một tín hiệu Start.

Kết thúc truyền dữ liệu (stop condition) : Thay đổi trạng thái trên đường dữ

liệu từ Low lên High, trong khi đường clock ổn định ở mức high thì được định

nghĩa là một tín hiệu Stop.

Dữ liệu hợp lệ : Trạng thái của đường dữ liệu biểu diễn dữ liệu hợp lệ khi

theo sau bởi tín hiệu START, đường dữ liệu ổn định trong khoảng thời gian mà tín hiệu clock ở mức High. Dữ liệu trên đường dữ liệu phải được thay đổi trong

khoảng thời gian mà tín hiệu clock ở mức Low. (adsbygoogle = window.adsbygoogle || []).push({});

Mỗi khi truyền dữ liệu điều được bắt đầu bởi một tín hiệu Start và kết thúc

việc truyền bằng một tín hiệu Stop. Số byte dữ liệu truyền giữa 2 tín hiệu Start và Stop là không hạn chế và được xác định bởi master. Thông tin được truyền và mỗi

lần truyền receiver gởi thêm ack ở bít thứ 9. Để cho biết là đã nhận xong một byte

dữ liệu.

16.8 Giao thức I2C và RTC DS1307

16.8.1 Kết nối phần cứng

Gạt switch 1 và 2 lên ON để kích hoạt P1 và P3. SDA được nối với P1.0.

SCL được nối với P1.1.

16.8.2 Start và Stop truyền dữ liệu

Việc truyền dữ liệu được bắt đầu bởi một tín hiệu Start và kết thúc việc

truyền bằng một tín hiệu Stop. Số byte dữ liệu truyền giữa 2 tín hiệu Start và Stop là không hạn chế và được xác định bởi master.

Dựa vào giản đồ trên ta hiện thực hàm để Start I2C như sau : void start_I2C() { SCL = 1; SDA = 1; nop();nop(); SDA = 0; SCL = 0; nop();nop(); }

Tốc độ clock chuẩn của giao thức I2C là 100KHz. Khi truyền ở tốc độ cao có thể hoạt động ở clock 1MHz. Tuy nhiên bạn nên delay vài uS để đảm bảo tính đúng đắn của dữ liệu.

Giản đồ xung cho điều kiện Stop như sau

Hàm để Stop I2C được hiện thực như sau:

void stop_I2C() { SCL = 1; SDA = 0; nop();nop(); SDA = 1; }

BKIT HARDWARE CLUB www.bkit4u.com 107

16.8.3 Truyền 1 byte dữ liệu

Khi truyền 1 byte dữ liệu, bit có trọng số cao nhất (bit 7) sẽ được truyền trước. Khi bit cuối cùng (bit 0) được truyền, sẽ có thêm bit ACK báo hiệu kết thúc 1 byte dữ liệu.

Truyền từ master xuống slave:

Ở chế độ này, master sẽ gửi 8 bit dữ liệu, sau khi nhận xong 8 bit này, slave sẽ tự động gửi lại 1 bit ACK và master phải tạo ra thêm 1 clock để nhận bit ACK này.

//write I2C

void write_I2C(unsigned char data2send) {

int i;

for (i=0;i<8;i++) {

SDA = (data2send & 0x80) ? 1:0; SCL=1; nop(); SCL=0; data2send<<=1; nop(); }

//clock to receive ACK from slave SCL = 1;

nop();nop(); SCL = 0; }

Truyền từ slave lên master

Ở chế độ này, master sẽ nhận vào 8 bit dữ liệu, và sau khi nhận xong, master phải gửi 1 bit ACK xuống slave. Trong quá trình đọc 1 chuỗi byte từ slave, master gửi bit ACK. Đối với byte cuối cùng, master sẽ gửi bit NO ACK và sau đó gửi tín hiệu stop. Hàm đọc 1 byte sau đây có tham số là ACK_Bit, dùng để phân biệt ACK và NACK. (adsbygoogle = window.adsbygoogle || []).push({});

unsigned char read_I2C(bit ACK_Bit) {

unsigned char Data=0; int i; SDA = 1; for (i=0;i<8;i++) { SCL = 1; Data<<= 1;

Data = (Data | SDA); SCL = 0;

nop(); }

if (ACK_Bit == 1)

SDA = 0; // Send ACK else

SDA = 1; // Send NO ACK nop();nop();

//clock to send (N)ACK SCL = 1; nop();nop(); SCL = 0; return Data; } 16.8.4 Giao tiếp với DS1307

Ghi dữ liệu vào DS1307

Đây là quá trình truyền dữ liệu từ master xuống slave. Khi master gửi xong 1 byte, slave sẽ gửi lại bit ACK. Quá trình giao tiếp như sau:

vMaster gửi tín hiệu Start.

vMaster gửi địa chỉ của DS1307 (1101 000) và bit R/W, trong trường hợp này là 0. Byte đầu tiên mà master gửi xuống sau khi start là D0.

vMaster gửi địa chỉ pointer dữ liệu cần ghi, chẳng hạn là 0x00 (register pointer, word address)

vMaster gửi các byte data cần ghi.

vMaster gửi tín hiện stop.

Code hiện thực cho quá trình này như sau

void write_RTC(unsigned char *buff) {

start_I2C(); write_I2C(0xD0); write_I2C(0x00); write_I2C(*(buff+0));

BKIT HARDWARE CLUB www.bkit4u.com 109 write_I2C(*(buff+3)); write_I2C(*(buff+4)); write_I2C(*(buff+5)); write_I2C(*(buff+6)); stop_I2C(); }

buff là 1 mảng có 7 phần tử, tương ứng với các giá trị giây, phút, giờ, thứ, ngày, tháng và năm.

Đọc dữ liệu từ DS1307

Đây là quá trình truyền dữ liệu từ slave lên master. Như đã trình bày ở phần trước, khi gửi nhận từng byte, sẽ có bit ACK đi kèm ngoại trừ byte cuối cùng trước khi stop.

Để có thể đọc chính xác giá trị mong muốn, thông thường ta phải ghi vào thanh ghi địa con trỏ dữ liệu (register pointer). Quá trình này chính là trình truyền dữ liệu từ master xuống slave nên R/W bit sẽ là 0. Sau khi ghi dữ liệu và register pointer xong, quá trình đọc dữ liệu mới bắt đầu, và bit R/W sẽ là 1.

Từng bước đọc dữ liệu từ DS1307 như sau:

vMaster gửi tín hiệu start.

vMaster gửi địa chỉ DS1307 + R/W = 0 : 0xD0.

vMaster gửi byte ghi vào register pointer : 0x00.

vMaster gửi tín hiệu start

vMaster gửi địa chỉ DS1307 + R/W = 1 : 0xD1. (adsbygoogle = window.adsbygoogle || []).push({});

vMaster đọc các byte dữ liệu và gửi bit ACK. Byte cuối cùng trước khi stop, master gửi bit NACK.

vMaster gửi tín hiện stop.

Code hiện thực cho quá trình này như sau

void read_RTC(unsigned char * buff) {

//send address to slave and reset pointer start_I2C();

write_I2C(0xD0); //address + direction write_I2C(0x00); //pointer data

//start read operation start_I2C(); write_I2C(0xD1); *(buff+0)=read_I2C(ACK); // Second *(buff+1)=read_I2C(ACK); // Minute *(buff+2)=read_I2C(ACK); // hour *(buff+3)=read_I2C(ACK); // Day

*(buff+4)=read_I2C(ACK); // date *(buff+5)=read_I2C(ACK); // month *(buff+6)=read_I2C(NO_ACK); // year stop_I2C();

}

Hàm main() dưới đây minh hoạ cho việc sử dụng các hàm trong module RTC DS1307: void main() { P1 = P3 = 0x00; RTC_ARR[0] = 0x12; //second = 12 RTC_ARR[1] = 0x55; // minute = 55

RTC_ARR[2] = 0x05; // hour = 05 ,24-hour mode(bit 6=0) RTC_ARR[3] = 0x01; // Day = 1 or sunday

RTC_ARR[4] = 0x01; // Date = 01 RTC_ARR[5] = 0x08; // month = August RTC_ARR[6] = 0x05; // year = 05 or 2005 write_RTC(&RTC_ARR[0]); // Set RTC

while(1) {

read_RTC(&RTC_ARR[0]); //read 7 bytes RTC P3=RTC_ARR[0]; //out second to P3

delay();; // delay about 1 second }

Một phần của tài liệu Lập trình 8051 siêu chi tiết (Trang 99)