Bài giảng Vi điều khiển (Microcontroller)
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Vi điều khiển (Microcontroller)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Tài liệu đính kèm:
- bai_giang_vi_dieu_khien_microcontroller.doc
Nội dung text: Bài giảng Vi điều khiển (Microcontroller)
- VI ĐIỀU KHIỂN (MICROCONTROLLER). 1
- VI ĐIỀU KHIỂN (MICROCONTROLLER). 1. CẤU TRÚC CỦA BỘ VI ĐIỀU KHIỂN. 1.1 Giới thiệu về các bộ vi điều khiển. Bộ vi điều khiển (MCU – Micro Controller Unit) là một hệ thống vi xử lý cơ bản tích hợp trong cùng một chip, thông thường trong một MCU có một bộ vi xử lý (CPU), một dung lượng nhớ khoảng vài KB, và một số giao tiếp vào ra cơ bản thích hợp cho các ứng dụng điều khiển nhỏ. Với cấu trúc như mô tả trên, người sử dụng có thể nhanh chóng thực hiện một hệ thống phần cứng điều khiển lập trình bằng cách nối một số ít linh kiện cơ bản như thạnh anh, tụ điện, điện trở vào bộ vi điều khiển. Mặt khác do không phải thực hiện các đường mạch nối giữa các khối CPU, bộ nhớ và vào ra nên khả năng chống nhiễu của hệ thống cao thích hợp cho môi trường công nghiệp. Hiện nay các bộ vi điều khiển đã trở nên khá phổ biến trong nhiều lĩnh vực với rất nhiều hãng sản xuất như: học MCU 8051 của Atmel, họ 68HC11 của Motorola, họ Z80MCU của Zilog 1.2 Cấu trúc tổng quát của các bộ vi điều khiển. Sơ đồ khối tổng quát của một bộ vi điều khiển bao gồm các khối cơ bản như trình bày trên hình 8.1: Power Control Power monitoring store Reset Processor Input & port Reset control I/O Output pins Clock & Clocking timing RAM Hình 8.1: Sơ đồ khối tổng quát của một bộ vi điều khiển . - Khối xử lý (Processor) đóng vai trò quyết định tất cả các hoạt động của các bộ phận khác bên trong vi điều khiển. - Bộ nhớ điều khiển (Control store) thường là loại bộ nhớ ROM có dung lượng vài KB chứa các chương trình điều khiển. - Bộ nhớ RAM thường có dung lượng nhỏ sử dụng cho việc khai báo các biến trung gian, thông thường các thanh ghi của vi điều khiển cũng nằm trong phần bộ nhớ này. - Khối tạo xung nhịp và định thời (Clock & timing) đóng vai trò tạo xung nhịp định thời các hoạt động của hệ thống. Thông thường ở các bộ vi điều khiển tích hợp sẵn bộ tạo xung nhịp bên trong, tần số hoạt động của hệ thống sẽ được xác định bằng thạch anh nối vào mạch từ bên ngoài. - Khối điều khiển reset có nhiệm vụ thiết lập lại các trạng thái của hệ thống, cho phép nó bắt đầu hoạt động trở lại giống như khi mới cấp nguồn. 1
- - Khối giám sát nguồn (power monitoring) cho phép toàn bộ chip hoạt động ở chế độ chờ (standby) khi không có yêu cầu điều khiển với công suất rất nhỏ. Vì cấu trúc vi điều khiển cho phép thực hiện một hệ thống nhỏ gọn, nên nó được sử dụng nhiều trong các thiết bị điều khiển cầm tay và di động có nguồn cung cấp bằng pin, với khối giám sát nguồn vi điều khiển có thể hoạt động theo định thời hoặc chỉ khi có yêu cầu từ bên ngoài. - Các cổng vào ra (I/O): thông thường vi điều khiển có một vài cổng giao tiếp song song để giao tiếp điều khiển các thiết bị bên ngoài, đôi khi các cổng này sử dụng như các Bus (dữ liệu, địa chỉ và điều khiển) của một bộ vi xử lý thông thường, cho các hệ thống có yêu cầu mở rộng về dung lượng bộ nhớ cũng như các cổng vào ra. Ngoài các cổng vào ra song song, vi điều khiển còn có các cổng vào ra nối tiếp theo chuẩn RS232 hoặc IEEE448. Trong một số bộ vi điều khiển còn tích hợp cả các khối A/D và D/A, khi đó sẽ có cả các đường vào ra cho các khối này. 2. MÔ TẢ PHẦN CỨNG CÁC BỘ VI ĐIỀU KHIỂN HỌ MSC-51. 2.1 Giới thiệu chung. Họ IC vi điều khiển MSC-51 được phát triển, chế tạo và bán ở thị trường bởi hãng Intel. Các nhà chế tạo IC khác như Siemens của Đức, Advanced Micro Devices, Fujitsu, Philips, Atmel là các nhà cung cấp những thiết bị họ MCS-51 được cấp giấy phép bảng quyền thứ 2. 8051 là bộ vi điều khiển đầu tiên được thương mại hoá trên thị trường, sau đó nhiều thế hệ khác trong họ ra đời, các đặc tính khác nhau của một số bộ vi điều khiển trong họ này được mô tả trong bảng sau: Loại Bộ nhớ chương trình Bộ nhớ dữ liệu Số timer 8051 4K ROM 128 byte 2 8031 0K ROM 128 byte 2 8751 4K EPROM 128 byte 2 8052 8K ROM 256byte 3 8032 0K ROM 256byte 3 8752 8K EPROM 256byte 3 8951 4K EEROM 256 byte 2 892051 2K EEROM 128 byte 0 2.2 Tổng quát về phần cứng 8051. Sơ đồ khối và chức năng các khối. Các bộ vi điều khiển 8051, 8031, 8751, 8951 trong họ MSC – 51 có chung một số đặc tính như: - 4 KB bộ nhớ loại ROM để ghi các chương trình điều khiển. - 128 byte RAM. - 4 cổng vào ra 8 bit. - 2 bộ định thời (timer) 16 bit. - Một cổng giao tiếp nối tiếp chuẩn RS 232. 1
- - Có thể quản lý được 64 KB bộ nhớ mở rộng cho chương trình và 64 KB bộ nhớ mở rộng cho dữ liệu. - Một bộ xử lý các phép toán logic có thể thao tác trên từng bit. - 210 bit RAM nội được địa chỉ hoá. - Bộ nhân/chia 4 s. Cấu trúc kết nối phần cứng của các bộ vi điều khiển trong họ gần tương tự như nhau, một số khác biệt giữa chúng cũng được biểu diễn trên sơ đồ khối hình 8.2. INT1 INT0 T2EX Timer 2 (8032/52) Timer 1 128 byte ROM TIMER 2 T2 Timer 0 RAM 0K – 8031/32 (8032, 8052) Serial Port (8032, 8052) 4K – 8051/8951 TIMER 1 T1 8K – 8052/8752 INTERRUPT OTHER 128 Byte T0 CONTROL REGISTER RAM TIMER 0 CPU BUS I/O SERIAL Oscillator CONTROL PORTS PORT EA ALE RST PSEN P0 P2 P1 P3 TxD RxD Address/data Hình 8.2: Sơ đồ khối vi điều khiển MCS – 51. Khối xử lý trung tâm (CPU) nhận tín hiệu xung nhịp từ bộ dao động, tần số ra của bộ tạo dao động sẽ tuỳ thuộc vào tần số thạch anh bên ngoài. Hầu hết các bộ vi điều khiển trong họ đều có ít nhất 128 byte RAM bên trong. Các thanh ghi thông thường nằm trong phần RAM. Ngoài 8031/32 các vi điều khiển còn lại đều có bộ nhớ ROM lưu trữ chương trình điều khiển. Bộ nhớ ROM này có thể là Mask-ROM chỉ lập trình được bởi nhà sản xuất, có thể là EPROM hoặc EEROM có thể lập trình lại nhiều lần bởi người sử dụng. Các bộ định thời lập trình được có thể đếm theo xung cung cấp từ bên ngoài hoặc xung chuẩn từ bộ tạo dao động, có bộ đếm này có ứng dụng rất phổ biến trong điều khiển tự động. Bộ điều khiển Bus cung cấp các tín hiệu điều khiển giao tiếp với bên ngoài, và kiểm soát hoạt động của các cổng vào ra dữ liệu song song. Hai trong bốn cổng vào ra song song (P0 và P2) có thể sử dụng làm các Bus địa chỉ và dữ liệu trong chế độ giao tiếp bộ nhớ 1
- ngoài. Cổng vào ra nối tiếp có hai đường truyền và nhận dữ liệu nối tiếp với các thiết bị khác. Bộ điều khiển ngắt tích hợp trong chip cho phép nhận hai yêu cầu ngắt cung cấp thẳng từ bên ngoài, hoặc từ cổng nối tiếp và các bộ định thời bên trong. Các tín hiệu của 8051. 8051/8951 đều có 40 chân tín hiệu giống nhau. Ngoài các chân nhận các nguồn nuôi và các linh kiện tạo dao động, các chân còn lại hoạt động giống như các đường vào ra. Tuy nhiên, trong đó có 24 chân có hai công dụng, mỗi đường này có thể hoạt động như đường xuất nhập, hoặc như đường điều khiển, hoặc là một đường trong của BUS dữ liệu và BUS địa chỉ. Các cổng vào ra song song thường có cấu trúc cài. Các thiết kế của 8051 có thể ở hai chế độ: chế độ tối thiểu, hoặc chế độ mở rộng bộ nhớ hoặc các thành phần khác. Mỗi cổng 8 đường có thể hoạt động giống như một đơn vị giao tiếp với các thiết bị vào ra song song như: máy in, các bộ biến đổi A/D, D/A , hoặc mỗi đường có thể điều khiển một cách độc lập để có thể giao tiếp với các thiết bị chỉ yêu cầu một bit như: các công tắc, các LED, các solenoid, đóng mở động cơ . Việc giao tiếp theo từng bit, có thể điều khiển bằng các lệnh thao tác bit là một điểm mạnh của các bộ vi điều khiển so với các bộ vi xử lý thông thường. Cổng 0: Cổng 0 (các chân 32–39) là một cổng hai chức năng. Trong các thiết kế tối thiểu (không dùng bộ nhớ mở rộng), nó có chức năng như các đường I/O. Đối với các thiết kế mở rộng về bộ nhớ, nó là Bus đa hợp giữa BUS địa chỉ và BUS dữ liệu. Cổng 1: Cổng 1 (các chân 1–8) là một cổng vào ra thông thường. Các đường trong cổng được ký hiệu P1.0, P1.1, P1.2,. Cổng1 không có chức năng khác, vì vậy chúng chỉ được dùng cho giao tiếp với các thiết bị ngoài. Cổng 2: Cổng 2 (các chân 21–28): là một cổng có công dụng kép, nó được dùng như các đường vào ra, hoặc là byte cao của BUS địa chỉ đối với các thiết kế dùng bộ nhớ mở rộng. Cổng 3: Cổng 3 (các chân 10–17): là một cổng công dụng kép. Các đường của cổng này có nhiều chức năng. Ngoài công dụng như các đường vào ra thông thường, chúng còn có các công dụng khác như biểu diễn ở bảng sau: Bit Tên Địa chỉ bit Chức năng P3.0 RxD B0H Nhận dữ liệu cho cổng nối tiếp. P3.1 TxD B1H Truyền dữ liệu cho cổng nối tiếp. P3.2 INT0 B2H Nhận tín hiệu yêu cầu ngắt (0) từ bên ngoài. P3.3 INT1 B3H Nhận tín hiệu yêu cầu ngắt (1) từ bên ngoài. P3.4 T0 B4H Ngõ vào bên ngoài cho Timer 0. P3.5 T1 B5H Ngõ vào bên ngoài cho Timer 1. P3.6 WR B6H Tín hiệu điều khiển ghi cho bộ nhớ bên ngoài. P3.7 RD B7H Tín hiệu điều khiển đọc cho bộ nhớ bên ngoài. 8051 có 4 tín hiệu điều khiển. 1
- PSEN (Program Store Enable): PSEN (chân 29) là tín hiệu ngõ ra, nó là tín hiệu điều khiển để cho phép bộ nhớ chương trình mở rộng, trong hệ thống tín hiệu này thường được nối đến chân OE (Output Enable) của một EPROM, để cho phép đọc các byte mã lệnh. PSEN sẽ ở mức thấp trong thời gian lấy mã lệnh. Các mã nhị phân của chương trình, được đọc từ EPROM qua BUS dữ liệu đưa vào thanh ghi lệnh của 8051 để giải mã. Khi thi hành chương trình trong ROM nội (8051), PSEN sẽ ở mức không tích cực (mức cao). ALE (Address Latch Enable): Tín hiệu ra ALE (chân 30), có chức năng tương tự như trong các vi xử lý 8085, 8088, 8086, nó được dùng cho việc tách kênh các Bus đa hợp (địa chỉ và dữ liệu). Trong cấu hình bộ nhớ mở rộng (tín hiệu EA = 1), cổng 0 vừa là BUS dữ liệu vừa là byte thấp của BUS địa chỉ, ALE được sử dụng để chốt địa chỉ vào một bộ cài bên ngoài trong chu kỳ xung nhịp đầu tiên của chu kỳ truy cập bộ nhớ. Sau đó, các đường cổng 0 dùng để xuất hoặc nhập dữ liệu trong thời gian còn lại của chu kỳ truy cập bộ nhớ. Tín hiệu ALE có tần số bằng 1/6 lần tần số dao động trên chip, nó có thể được dùng làm nguồn xung nhịp cho các phần khác của hệ thống. Nếu xung nhịp trên 8051 là 12 MHz, thì ALE có tần số 2 MHz, chỉ ngoại trừ khi thi hành lệnh MOVX, một xung ALE sẽ bị mất. Chân này cũng được làm ngõ vào cho xung lập trình cho EPROM trong 8051. EA (External Access): Tín hiệu vào EA (chân 31) thường được nối lên mức cao (+5V) hoặc mức thấp (GND). Nếu ở mức cao, 8051 thi hành chương trình từ ROM nội trong khoảng địa chỉ thấp (4K). Nếu ở mức thấp, chương trình chỉ được thi hành từ bộ nhớ mở rộng. Khi dùng 8031, EA luôn được nối mức thấp vì không có bộ nhớ chương trình trong chip. Nếu EA được nối mức thấp, bộ nhớ bên trong chương trình 8051 sẽ bị cấm, và chương trình thi hành từ EPROM mở rộng. EA còn được dùng làm ngõ vào cấp điện áp 21V khi lập trình cho EPROM trong 8051. RST (Reset): Ngõ vào RST (chân 9) là ngõ reset của 8051. Khi tín hiệu này được đưa lên mức cao (trong ít nhất 2 chu kỳ máy), các thanh ghi bên trong 8051 được nạp những giá trị thích hợp để khởi động hệ thống. Các ngõ vào bộ dao động trên chip (X1, X2): Như trong sơ đồ khối, 8051 có một bộ dao động trong chip. Nó thường được nối với một thạch anh giữa hai chân 18 và 19 cùng với các tụ điện. Với 8051 tần số thạch anh thông thường là 12 MHz. Các chân nguồn: 8051 hoạt động với nguồn đơn +5V. V CC được nối vào chân 40 và VSS (GND) được nối vào chân 20. Tổ chức bộ nhớ của 8051. Các hệ thống vi xử lý thường thực hiện việc phân biệt các vùng nhớ riêng cho dữ liệu và chương trình, vì vậy trong máy tính thông thường chương trình và dữ liệu sẽ được nạp từ đĩa vào các vùng nhớ khác nhau của RAM hệ thống. Các bộ vi điều khiển thực hiện việc quản lý bộ nhớ theo một cách khác. 8051 không có đĩa để lưu trữ các chương trình, nó có dung lượng nhớ giới hạn ngay bên trong chip. Dung lượng nhớ này sẽ được sử dụng riêng rẽ cho chương trình và dữ liệu. Tuy nhiên chúng có thể được mở rộng bên ngoài lên đến tối đa 64 Kbytes bộ nhớ chương trình và 64 Kbytes bộ nhớ dữ liệu. Bộ nhớ RAM trên chip được sử dụng cho rất nhiều mục đích như: phần lưu trữ đa dụng, phần lưu trữ địa chỉ hoá từng bit, các thanh ghi đa năng và các thanh ghi chức năng đặc 1
- biệt. Có hai đặc tính nổi bật trong vi điều khiển là: Các thanh ghi và các cổng vào ra được bản đồ hoá trong bộ nhớ RAM, chúng có thể truy cập giống như các ô nhớ bất kỳ khác. Ngăn xếp cũng nằm ở bộ nhớ RAM bên trong chip, mà không ở RAM ngoài như các hệ thống vi xử lý thông thường Mô tả về bộ nhớ RAM trong chip của 8051. RAM bên trong 8051 mô tả trên hình 8.3 bao gồm: 4 tập thanh có địa chỉ 00H tới 1FH, mỗi tập có 8 thanh ghi được ký hiệu từ R0 tới R7, việc đổi qua các tập thanh ghi khác nhau được thực hiện bằng hai bit của thanh ghi trạng thái. Vùng nhớ địa chỉ hoá theo bit có địa chỉ từ 20H tới 2FH, việc truy cập các bit này theo các địa chỉ từ 00 tới 7FH. Vùng nhớ đa dụng từ 30H tới 7FH. Và các thanh ghi chức năng đặc biệt từ 80H tới FFH, một số thanh ghi trong vùng này cũng được địa chỉ hoá theo bit. RAM đa dụng: Ngoài 80 byte RAM đa dụng chiếm các địa chỉ từ 30H–7FH, 32 byte dưới cùng từ 00H đến 1FH cũng có thể được dùng với mục đích tương tự (mặc dù các địa chỉ này đã có mục đích khác). Mọi địa chỉ trong vùng RAM đa dụng đều có thể truy xuất với chế độ địa chỉ trực tiếp hoặc gián tiếp. Ví dụ, để đọc nội dung ở địa chỉ 5FH của RAM nội vào thanh ghi tích lũy, có thể dùng lệnh sau: MOV A, 5FH Lệnh này di chuyển 1 byte dữ liệu dùng định vị địa chỉ trực tiếp để xác định “địa chỉ nguồn” (5FH). Đích nhận dữ liệu là thanh ghi tích lũy A. RAM nội cũng có thể được truy xuất bằng định vị địa chỉ gián tiếp qua R0 hay R1. Ví dụ, hai lệnh sau thi hành cùng nhiệm vụ như lệnh ở trên: MOV R0, #5FH MOV A, @R0 Lệnh đầu dùng địa chỉ tức thời để di chuyển giá trị 5FH vào thanh ghi R0, và lệnh thứ hai dùng địa chỉ trực tiếp để di chuyển dữ liệu “được trỏ bởi R0” vào thanh ghi tích lũy A. RAM địa chỉ hoá từng bit: 8051 chứa 210 bit được địa chỉ hoá, trong đó 128 bit là ở các địa chỉ byte 20H đến 2FH, và phần còn lại là trong các thanh ghi chức năng đặc biệt. Ý tưởng truy xuất từng bit riêng rẽ bằng phần mềm là một đặc tính tiện lợi của vi điều khiển nói chung. Các bit có thể được đặt, xóa, AND, OR, bằng một lệnh. Đa số các vi xử lý đòi hỏi một chuỗi lệnh đọc-sửa-ghi để đạt được hiệu quả tương tự. Ngoài ra, các cổng vào ra cũng được địa chỉ hoá từng bit, làm đơn giản phần mềm xuất nhập từng bit. Có 128 bit được địa chỉ hoá đa dụng ở các byte 20H đến 2FH. Các địa chỉ này được truy xuất như các byte hoặc như các bit phụ thuộc vào lệnh được dùng. Ví dụ, để lập bit 67H, ta dùng lệnh sau: Chú ý rằng “địa chỉ bit 67H” là bit có trọng số lớn nhất (MSB) ở “địa chỉ byte 2CH”. Lệnh trên sẽ không tác động đến các bit khác ở địa chỉ này. Ở các vi xử lý công việc tương tự sẽ phải thi hành như sau: MOV A, 2CH ; đọc cả byte ORL A, #10000000B ; set MSB MOV 2CH,A ; ghi lại cả byte SETB 67H 1
- FF 7F F0 F7 F6 F5 F4 F3 F2 F1 F0 B General Purpose E0 E7 E6 E5 E4 E3 E2 E1 E0 Acc RAM D0 D7 D6 D5 D4 D3 D2 - D0 PSW 30 B8 BC BB BA B9 B8 IP 2F 7F 7E 7D 7C 7B 7A 79 78 77 76 75 74 73 72 71 70 B7 B6 B5 B4 B3 B2 B1 B0 P3 6F 6E 6D 6C 6B 6A 69 68 B0 67 66 65 64 63 62 61 60 AF AE ADAC ABAA A9 A8 IE 5F 5E 5D 5C 5B 5A 59 58 A8 57 56 55 54 53 52 51 50 A7 A6 A5 A4 A3 A2 A1 A0 P2 4F 4E 4D 6C 4B 4A 49 48 A0 47 46 45 44 43 42 41 40 Not bit addressable SBUF 3F 3E 3D 3C 3B 3A 39 68 99 9F 9E 9D 9C 9B 9A 99 98 SCON 37 36 35 34 33 36 31 30 98 2F 2E 2D 2C 2B 2A2 29 28 97 96 95 94 93 92 91 90 P1 27 26 25 24 23 22 21 20 90 1F 1E 1D 1C 1B 1A 19 18 Not bit addressable TH1 17 16 15 14 13 12 11 10 8D Not bit addressable TH0 0F 0E 0D 0C 0B 0A 09 08 8C 8B Not bit addressable TL1 20 07 06 05 04 03 02 01 00 8A Not bit addressable TL0 1F Bank 3 89 Not bit addressable TMOD 18 88 8F 8E 8D 8C 8B 8A 89 88 TCON 17 Bank 2 87 Not bit addressable PCON 10 0F Bank 1 83 Not bit addressable DPH 08 82 Not bit addressable DPL 07 Bank 0 (default) 81 Not bit addressable SP Các tập thanh ghi (register banks): 32 byte80 thấp87 của86 bộ85 nhớ84 83 nội82 là81 dành80 choP0 các tập thanh ghi. Tập lệnh00 của 8051 cho phép truy cập 8 thanh ghi (R0 đến R7), và theo mặc định (sau khi reset hệ thống) các Hìnhthanh 8.3: ghi Vùng này ở nhớ các RAM địa chỉ trong 00H–07H. chip của Lệnh 8051 sau đây sẽ đọc nội dung ở địa chỉ 05H của RAM vào thanh ghi tích lũy: MOV A, R5 Đây là lệnh 1 byte dùng định vị địa chỉ trực tiếp thanh ghi. Tất nhiên, công việc trên cũng̣ có thể thực hiện bằng lệnh 2 byte dùng định vị địa chỉ trực tiếp nằm trong byte thứ hai: MOV A, 05H Các lệnh dùng các định vị trực tiếp thanh ghi (R0 đến R7) sẽ ngắn hơn và nhanh hơn các lệnh tương ứng nhưng dùng định vị địa chỉ trực tiếp. Các dữ liệu được sử dụng thường xuyên trong chương trình, nên dùng một trong các thanh ghi này. 1
- Tập thanh ghi có thể chuyển đổi, bằng cách thay đổi các bit chọn tập thanh ghi trong từ trạng thái (PSW). Giả sử rằng tập thanh ghi thứ 3 được chọn, thì lệnh sau sẽ ghi nội dung của thanh ghi tích lũy vào địa chỉ 18H: MOV R0, A Ý tưởng dùng “các tập thanh ghi” cho phép “chuyển hướng” chương trình nhanh và hiệu quả, từng phần của chương trình sẽ có một bộ thanh ghi riêng không phụ thuộc vào các phần khác. Các thanh ghi chức năng đặc biệt: Các thanh ghi nội của trong hầu hết các vi xử lý được truy xuất ngầm định trong tập lệnh. Ví dụ lệnh “INC A” sẽ tăng nội dung của thanh ghi tích lũy A lên 1. Tác động này được ngầm định trong mã lệnh. Các thanh ghi trong 8051 là một phần của RAM nội. Vì vậy mỗi thanh ghi sẽ có một địa chỉ (ngoại trừ thanh ghi đếm chương trình và thanh ghi lệnh vì các thanh ghi này hiếm khi bị truy cập trực tiếp, nên chúng không được đặt trong RAM nội). Đây là lý do giải thích tại sao 8051 có nhiều thanh ghi. Cũng như R0 đến R7, 21 thanh ghi chức năng đặc biệt (SFR: Special Function Register) của 8051 nằm trong RAM nội từ địa chỉ 80H đến FFH. Chú ý rằng hầu hết 128 địa chỉ từ 80H đến FFH không được đặt tên. Chỉ có 21 địa chỉ SFR là được định nghĩa. Ngoài thanh ghi tích lũy (A) có thể được truy xuất ngầm bằng định vị ngầm định, đa số các SFR được truy xuất bằng định vị địa chỉ trực tiếp. Một số SFR có thể được địa chỉ hoá theo bit hoặc theo byte. Người lập trình phải chú ý khi truy xuất theo bit và theo byte. Ví dụ lệnh: SETB 0E0H Sẽ lập bit 0 trong thanh ghi tích lũy, các bit khác không đổi. Có thể thấy rằng E0H đồng thời là địa chỉ byte của thanh ghi tích lũy, và là địa chỉ bit của bit có trọng số nhỏ nhất trong thanh ghi tích lũy. Nhưng vì lệnh SETB chỉ tác động trên bit, nên địa chỉ bit sẽ tác động trong lệnh. Từ trạng thái chương trình (PSW: Program Status Word): nằm ở địa chỉ D0H chứa các bit trạng thái như trong bảng sau: BIT Tên Địa chỉ Chức năng PSW.7 CY D7 Cờ nhớ. PSW.6 AC D6 Cờ nhớ phụ. PSW.5 F0 D5 Cờ Zero. PSW.4 RS1 D4 Chọn tập thanh ghi. PSW.3 RS0 D3 Chọn tập thanh ghi. PSW.2 OV D2 Cờ tràn. PSW.1 - D1 Dự phòng. PSW.0 P D0 Cờ chẵn lẻ. * Cờ nhớ (CY): Thông thường được dùng cho các lệnh số học: nó sẽ được lập nếu có một số nhớ sinh ra bởi phép cộng hoặc có một số mượn bởi phép trừ. Ví dụ, nếu thanh ghi tích lũy chứa FFH thì lệnh: 1
- ADD A, #1 sẽ trả về thanh ghi tích lũy kết quả 00H và lập cờ nhớ trong PSW. Cờ nhớ cũng có thể xem như một thanh ghi 1 bit cho các lệnh xử lý bit. Ví dụ, lệnh sau sẽ AND bit 25H với cờ nhớ và đặt kết quả nằm trong cờ nhớ: ANL C, 25H * Cờ nhớ phụ: Khi cộng các số BCD, cờ nhớ phụ (AC) được lập nếu kết quả của 4 bit thấp trong khoảng 0AH đến 0FH. Nếu các giá trị được cộng là số BCD, thì sau lệnh cộng cần hiệu chỉnh thập phân bằng lệnh DAA, để các kết quả lớn hơn 9 trở về tầm từ 0 9. * Cờ Zero (F0): là1 bit cờ được sử dụng trong nhiều chức năng, nó được lập bằng 1 khi kết quả các phép tính bằng 0. * Các bit chọn tập thanh ghi (RS0 và RS1): xác định tập thanh ghi được tích cực. Chúng được xóa sau khi reset hệ thống và được thay đổi bằng phần mềm nếu cần. Ví dụ, ba lệnh sau cho phép truy cập tập thanh ghi thứ 3, và di chuyển nội dung của thanh ghi R7 (địa chỉ byte 1FH) đến thanh ghi tích lũy: SETB RS1 SETB RS0 MOV A, R7 Khi chương trình được hợp dịch, các địa chỉ bit đúng được thay thế cho các ký hiệu “RS1” và “RS0”. Tức là, lệnh SETB RS1 hoàn toàn giống như lệnh SETB 0D4H. * Cờ tràn (OV): được lập sau một lệnh cộng hoặc trừ nếu xảy ra tràn số học. Khi các số có dấu được cộng hoặc trừ với nhau, phần mềm có thể kiểm tra bit này để xác định dải kết quả thích hợp. Khi cộng các số không dấu thì không cần xét tới OV. Các kết quả lớn hơn +127 hoặc nhỏ hơn -128 sẽ lập OV. Ví dụ, phép cộng sau bị tràn và bit OV được lập: 0FH + 7FH = 8EH tức là 15 +127 = 142. Kết quả là một số có dấu 8EH được xem như -116, không phải là kết quả đúng (142), vì vậy bit OV được lập, khi kiểm tra cờ OV chúng ta có thể hiệu chỉnh lại kết quả cho thích hợp. Thanh ghi B: nằm ở địa chỉ F0H được dùng cùng với thanh ghi tích lũy A trong các lệnh nhân và chia. Lệnh MUL AB, sẽ nhân các giá trị không dấu 8 bit trong A và B, rồi trả về kết quả 16 bit trong A (byte thấp) và B (byte cao). Lệnh DIV AB sẽ chia A cho B, rồi trả về kết quả nguyên trong A và phần dư trong B. Thanh ghi B cũng có thể được xem như một thanh ghi đa dụng. Nó được địa chỉ hoá theo bit (F0H đến F7H). Con trỏ ngăn xếp (SP): là một thanh ghi 8 bit có địa chỉ 81H. Nó chứa địa chỉ của byte dữ liệu hiện hành trên đỉnh của ngăn xếp. Các lệnh trên ngăn xếp bao gồm: cất dữ liệu vào ngăn xếp và lấy dữ liệu ra khỏi ngăn xếp. Lệnh cất dữ liệu vào ngăn xếp sẽ làm tăng SP, và lệnh lấy dữ liệu ra khỏi ngăn xếp sẽ giảm SP. Ngăn xếp của 8051 được giữ trong RAM nội, và được giới hạn các địa chỉ có thể truy xuất bằng địa chỉ gián tiếp. Chúng là128 byte đầu của 8051. Lệnh sau sẽ khởi động lại SP để đỉnh ngăn xếp bắt đầu tại 60H: MOV SP, #5FH Sau lệnh trên ngăn xếp của 8051 bị giới hạn trong 32 byte, vì địa chỉ cao nhất của RAM trên chip là 7FH. Giá trị 5FH được dùng vì SP sẽ tăng lên 60H trước khi cất byte dữ liệu đầu tiên. 1
- Khi người sử dụng không khởi động lại con trỏ ngăn xếp, thì SP lấy giá trị mặc định là 07H khi reset hệ thống, và kết quả là ngăn đầu tiên để cất dữ liệu có địa chỉ là 08H. Khi đó các tập thanh ghi 1 (có thể cả 2 và 3) sẽ không dùng được vì vùng RAM này đã được sử dụng làm ngăn xếp. Ngăn xếp được truy xuất trực tiếp bằng các lệnh PUSH và POP để lưu trữ tạm thời và lấy lại dữ liệu, hoặc được truy xuất ngầm bằng các lệnh gọi chương trình con (ACALL, LCALL) hay các lệnh trở về (RET, RETI) để cất và lấy lại bộ đếm chương trình. Thanh ghi con trỏ dữ liệu (DPTR – data pointer register): được dùng để truy xuất bộ nhớ ngoài, nó là một thanh ghi 16 bit có địa chỉ 82H (DPL: byte thấp) và 83H (DPH: byte cao). Ba lệnh sau sẽ ghi 55H vào RAM ngoài ở địa chỉ 1000H: MOV A, #55H MOV DPTR, #1000H MOVX @DPTR, A Lệnh đầu tiên dùng định vị tức thời để nạp dữ liệu 55H vào thanh ghi A. Lệnh thứ hai cũng dùng định vị tức thời, lần này để nạp dữ liệu 16 bit (1000H) vào con trỏ dữ liệu. Lệnh thứ ba dùng định vị gián tiếp để di chuyển dữ liệu trong A (55H) đến RAM ngoài có địa chỉ chứa trong DPTR (1000H). Các thanh ghi cổng vào ra: Các cổng của 8051 bao gồm cổng 0 ở địa chỉ 80H, cổng 1 ở địa chỉ 90H, cổng 2 ở địa chỉ A0H và cổng 3 ở địa chỉ B0H. Tất cả các cổng đều được địa chỉ hoá từng bit. Điều đó cung cấp một khả năng giao tiếp thuận lợi theo bit. Ví dụ nếu một động cơ được nối qua một cuộn dây có transistor lái đến bit 7 của Cổng 1, nó có thể được bật và tắt bằng một lệnh: SETB P1.7 ; bật motor CLR P1.7 ; tắt motor Dấu chấm trong lệnh để xác định một bit trong cổng. Trình hợp dịch sẽ thực hiện việc chuyển đổi ra địa chỉ tương ứng của bit đó, ví dụ hai lệnh sau thực hiện cùng một công việc: CLR P1.7 CLR 97H Xét một ví dụ khác, giao tiếp đến một thiết bị với một bit trạng thái gọi là BUSY, được lập khi thiết bị đang bận và được xóa khi thiết bị đã sẵn sàng. Nếu BUSY được nối tới P1.5, vòng lặp sau sẽ được dùng để chờ thiết bị trở lại trạng thái sẵn sàng: WAIT: JB P1.5, WAIT Lệnh này có nghĩa là “nếu bit P1.5 được lập thì nhảy tới nhãn WAIT”. Nói cách khác “quay trở lại và kiểm tra lần nữa”. Các thanh ghi của bộ định thời (timer): 8051 có hai bộ định thời/đếm 16 bit được dùng cho việc định thời hoặc đếm sự kiện. Timer 0 có địa chỉ 8AH (TL0: byte thấp) và 8CH (TH0: byte cao). Timer 1 có địa chỉ 8BH (TL1: byte thấp) và 8DH (TH1: byte cao). Việc thiết lập hoạt động các timer được thực hiện bằng cách nạp các giá trị thích hợp cho thanh ghi chế độ Timer (TMOD - Timer Mode) ở địa chỉ 89H, và thanh ghi điều khiển timer (TCON – Timer Control) ở địa chỉ 88H. Chỉ có TCON được địa chỉ hoá từng bit. Các thanh ghi cổng nối tiếp: 8051 có một cổng nối tiếp trong chip dành cho việc trao đổi thông tin với các thiết bị nối tiếp như máy tính, modem hoặc với các IC khác có giao tiếp 1
- nối tiếp (các bộ chuyển đổi A/D, các thanh ghi dịch ). Một thanh ghi gọi là bộ đệm dữ liệu nối tiếp (SBUF) ở địa chỉ 99H sẽ giữ cả hai dữ liệu truyền và nhận. Khi truyền dữ liệu thì ghi lên SBUF, khi nhận dữ liệu thì đọc SBUF. Các chế độ hoạt động khác nhau được lập trình qua thanh ghi điều khiển cổng nối tiếp (SCON) được địa chỉ hoá từng bit có địa chỉ 98H. Các thanh ghi ngắt: 8051 có cấu trúc điều khiển ngắt, cho phép 5 nguồn yêu cầu ngắt, với 2 mức ưu tiên. Các ngắt bị cấm sau khi reset hệ thống, và sẽ được cho phép bằng việc ghi dữ liệu vào thanh ghi cho phép ngắt (IE) ở địa chỉ A8H. Cả hai thanh ghi được địa chỉ hoá từng bit. Thanh ghi điều khiển công suất: Thanh ghi điều khiển công suất (PCON) ở địa chỉ 87H bao gồm nhiều bit điều khiển. Ý nghĩa của chúng được tóm tắt trong bảng sau: BIT Tên ký hiệu Chức năng 7 SMOD Khi lập cho phép tăng gấp đôi tốc độ baud cổng nối tiếp. Không định nghĩa. 6 - Không định nghĩa. 5 - Không định nghĩa. 4 - Cờ đa dụng 1. 3 GF1 Cờ đa dụng 0. 2 GF0 Khi lập cho phép 8051 hoạt động trong chế độ giảm 1 PD nguồn (Power down). Khi lập cho phép 8051 hoạt động trong chế độ rỗi (Idle). 0 IDL Trong chế độ rỗi CPU sẽ không thực hiện một lệnh nào khác. Lệnh lập bit IDL là lệnh cuối cùng mà CPU thực hiện trước khi chuyển qua chế độ rỗi. Trong chế độ rỗi nguồn xung nhịp bên trong sẽ bị cắt không cung cấp tới CPU, nhưng vẫn cung cấp tới bộ điều khiển ngắt, các bộ định thời và cổng nối tiếp. Trạng thái hiện tại của CPU và các thanh ghi sẽ được giữ nguyên, các cổng vào ra cũng được duy trì mức logic hiện tại. ALE và PSEN được giữ ở mức cao. Chế độ rỗi sẽ kết thúc khi có yêu cầu ngắt (được cho phép), bit IDL sẽ được xoá. Tương tự như chế độ rỗi, lệnh lập bit PD sẽ là lệnh cuối cùng mà CPU thực hiện trước khi chuyển qua chế độ giảm nguồn. Trong chế độ giảm nguồn, bộ dao động tạo xung nhịp sẽ ngưng hoạt động, điều này làm tất cả các khối chức năng bên trong ngưng hoạt động. Nội dung của Ram nội sẽ được giữ nguyên, mức logic của các cổng cũng được giữ nguyên và ALE và PSEN sẽ được giữ ở mức thấp. Chế độ này chỉ được thoát khỏi khi reset hệ thống. Trong chế độ giảm nguồn, nguồn cung cấp Vcc có thể giảm xuống 2V. Chú ý không được giảm nguồn xuống 2V trước khi chuyển qua chế độ giảm nguồn, và phải phục hồi lại Vcc = 5V sau 10 chu kỳ xung nhịp trước khi tín hiệu RST quay về mức thấp trở lại. Giao tiếp với bộ nhớ ngoài. 8051 có khả năng mở rộng thêm 64K bộ nhớ chương trình và 64K bộ nhớ dữ liệu bên ngoài. Do đó có thể dùng thêm ROM và RAM nếu cần. Cũng có thể sử dụng chức năng 1
- mở rộng dung lượng bộ nhớ, để tăng thêm dung lượng cổng vào ra, lúc này các cổng vào ra sẽ được truy cập giống như các ô nhớ mở rộng. Khi sử dụng bộ nhớ ngoài, cổng 0 không còn là một cổng vào ra nữa. Nó được ghép kênh giữa phần thấp của BUS địa chỉ (A0–A7), và BUS dữ liệu (D0–D7). Tín hiệu ALE sẽ tác động mức cao khi bắt đầu mỗi chu kỳ truy cập bộ nhớ để chốt byte thấp của địa chỉ. Cổng 2 thông thường được dùng cho byte cao của BUS địa chỉ. Trong nửa đầu của mỗi chu kỳ truy cập bộ nhớ, byte thấp của địa chỉ được cấp ra cổng 0 và được chốt bằng xung ALE. Có thể sử dụng một IC chốt 74HC373 (hoặc tương đương) để giữ byte địa chỉ thấp trong phần còn lại của chu kỳ truy cập bộ nhớ. Trong nửa sau của chu kỳ bộ nhớ cổng 0 được dùng như BUS dữ liệu, chiều truyền dữ liệu trên nó sẽ tùy theo lệnh. Truy xuất bộ nhớ chương trình ngoài: Bộ nhớ chương trình ngoài là một bộ nhớ ROM được cho phép bởi tín hiệu PSEN. Hình 8.4 mô tả một ví dụ về cách nối một EPROM vào 8051: 8051 D – D Port 0 0 7 D Q A – A EA 0 7 ALE G EPROM 74HC373 Port 2 A8 – A15 PSEN OE Một chu kỳ máy củaHình 8051 8.4: gồm Truy 12 cập chu bộ kỳ nhớ xung chương nhịp. trình Nếu bên ngõ ngoài. vào bộ dao động nội là thạch anh 12 MHz thì một chu kỳ máy kéo dài 1 s. Trong một chu kỳ máy sẽ có hai xung ALE, và hai byte được đọc từ bộ nhớ chương trình (nếu lệnh hiện hành là lệnh 1 byte thì byte thứ hai sẽ được loại bỏ). Giản đồ thời gian của một lần lấy lệnh được trình bày trên hình 8.5: S1 S2 S3 S4 S5 S6 S1 CK P1 P2 P1 P2 P1 P2 P1 P2 P1 P2 P1 P2 P1 P2 ALE PSEN Port 2 PCH (Program counter high byte) PCH Port 0 1 PCL Opcode PCL Byte 2 Hình 8.5: Giản đồ thời gian truy cập bộ nhớ chương trình ngoài.
- Truy xuất bộ nhớ dữ liệu ngoài: Bộ nhớ dữ liệu ngoài là một bộ nhớ RAM được cho phép ghi/đọc bằng các tín hiệu WR và RD (P3.6 và P3.7). Việc truy xuất bộ nhớ dữ liệu ngoài có thể thực hiện với lệnh MOVX dùng con trỏ dữ liệu (DPTR), hoặc R0 và R1 xem như thanh ghi địa chỉ. S1 S2 S3 S4 S5 S6 S1 S2 S3 S4 S5 S6 ALE PSEN RD Port 2 PCH DPH (Data pointer high byte) Port 0 PCL Opcode DPL Data in Kết nối BUS địaHình chỉ và 8.6: BUS Giản dữ đồ liệu thời giữa gian RAM truy vàcập 8051 bộ nhớ cũng dữ giống liệu ngoài. như EPROM, do đó cũng có thể mở rộng bộ nhớ RAM lên đến 64Kbyte. Tín hiệu yêu cầu đọc RD của 8051 được nối tới chân cho phép xuất (OE) của RAM, và tín hiệu yêu cầu ghi WR được nối tới chân cho phép ghi (WR) của RAM. 8051 D – D Port 0 0 7 D Q A – A EA 0 7 ALE G EPROM 74HC373 P2.0 A8 P2.1 A9 RD OE WR WE PSEN NC CS Giản đồ thời gianHình cho 8.7: lệnh Truy đọc cập bộ bộnhớ nhớ dữ ngoàiliệu ngoài theo biểucấu trúc diễn trang. trên hình 8.6 cho lệnh đọc (MOVX A, @DPTR). 1
- Giản đồ thời gian cho lệnh ghi (MOVX @DPTR, A) cũng tương tự chỉ khác đường WR sẽ thay vào đường RD và dữ liệu được xuất ra trên cổng 0, trong chu kỳ ghi RD giữ mức cao. Bằng các định vị địa chỉ gián tiếp thanh ghi sử dụng R0 và R1, cũng có thể truy cập bộ nhớ ngoài theo cấu hình phân trang. Trong chế độ này cổng 2 được truy cập giống như một cổng vào ra thông thường. Cổng 0 vẫn được sử dụng làm Bus đa hợp (cung cấp 8 bit địa chỉ trong nửa chu kỳ đầu, sau đó sử dụng làm Bus dữ liệu). Như vậy các địa chỉ cung cấp từ cổng 0 cho phép truy cập 256 byte nhớ mỗi trang, việc chọn trang có thể sử dụng các bit một cổng khác. Hình 8.7 mô tả sơ đồ ghép nối 8051 với dung lượng RAM 1KB truy cập theo cách phân trang, với các trang được chọn bằng P2.0 và P2.1. Khi các bit P2.0 và P2.1 được thiết lập để chọn một trong 4 trang, thì lệnh MOVX sẽ đọc hoặc ghi dữ liệu trong trang đó. Ví dụ với sơ đồ hình 8.7, nếu P2.0 = P2.1 = 0 thì các lệnh sau sẽ đọc dữ liệu trong ô nhớ 0050H của RAM vào thanh ghi chứa: MOV R0,#50H MOVX A,@R0 D0 –D7 D0 –D7 PSEN RD OE OE WR WE A0 –A12 A0 –A12 A0 –A12 A0 –A12 CS CS CS CS A15 CS CS C 0 A14 B 1 A13 A 2 3 VCC Chọn mạch cho các G1 bộ nhớ khác G2A G2B 7 Hình 8.8: Giải mã địa chỉ trong hệ thống có nhiều bộ nhớ ngoài. Để đọc được địa chỉ 3FFH của RAM thì hai bit chọn trang cần được lập lên 1, Các lệnh sau có thể sử dụng: SETB P2.0 SETB P2.1 MOV R0,#0FFH 1
- MOV A,@R0. Giải mã địa chỉ: Nếu cần sử dụng nhiều EPROM và/hoặc nhiều RAM bên ngoài, thì cần phải giải mã địa chỉ. Mạch giải mã cũng tương tự như các hệ vi xử lý khác. Ví dụ trên hình 8.8 mô tả một hệ thống với nhiều bộ nhớ EPROM 2764 (8 KB) cho chương trình, và nhiều bộ nhớ RAM 6264 (8KB) cho dữ liệu. Bộ nhớ ngoài sử dụng chung cho chương trình và dữ liệu: Vì bộ nhớ chương trình là ROM, nên nảy sinh một vấn đề bất tiện khi phát triển phần mềm cho 8051. Đó là làm cách nào phần mềm có thể sửa đổi chương trình và ghi trở lại khi nó được chứa trong bộ nhớ “chỉ đọc”. Cách giải quyết là sử dụng chung một vùng nhớ RAM cho cả chương trình và dữ liệu. Điều này có thể thực hiện bằng cách nối đường OE của RAM vào một mạch logic AND của PSEN và RD như mô tả trên hình 8.9. Lúc này một chương trình có thể được nạp vào RAM bằng cách ghi RAḾ như bộ nhớ dữ liệu, và thực hiện bằng cách truy xuất RAḾ như bộ nhớ chương trình. RAM WR RD Psen Hình 8.9: Sử dụng bộ nhớ ngoài chung cho chương trình và dữ liệu. Hoạt động reset. 8051 được reset bằng cách giữ chân RST ở mức cao ít nhất trong hai chu kỳ máy và trả nó về mức thấp. Sau khi reset thanh ghi đếm chương trình được đặt lại 0000H. Khi RST trở lại mức thấp, việc thi hành chương trình luôn bắt đầu ở địa chỉ đầu tiên trong bộ nhớ chương trình (địa chỉ 0000H). Nội dung của RAM nội không bị thay đổi bởi lệnh Reset. 2.2.1 Hoạt động của bộ định thời (timer). Giới thiệu. Bộ định thời bên trong vi điều khiển là một bộ đếm được tạo thành từ một chuỗi các flip- flop nối tiếp với nhau, mỗi flip-flop là một bộ chia 2. Ngõ vào của Timer là nguồn xung nhịp. Ngõ ra của tầng cuối làm xung nhịp cho flip-flop báo tràn của timer (còn gọi là cờ của timer), cờ sẽ được kiểm tra bằng phần mềm để tạo ra ngắt. Giá trị nhị phân trong các flip-flop của timer thay đổi như trong một bộ đếm nhị phân, nó sử dụng cho việc đếm số xung nhịp (hoặc các sự kiện) từ thời điểm timer được khởi động. Ví dụ timer 16 bit sẽ đếm lên từ 0000H đến FFFFH. Cờ báo tràn sẽ lên 1 khi số đếm tràn từ FFFFH đến 0000H. 8051 có hai timer 16 bit, mỗi timer có bốn chế độ làm việc. Các timer được sử dụng để: định khoảng thời gian, đếm sự kiện hoặc tạo tốc độ baud cho cổng nối tiếp trong 8051. Trong các ứng dụng định khoảng thời gian, các timer được lập trình đếm trong một khoảng nhất định và lập cờ tràn để thông báo. Cờ sẽ được chương trình kiểm tra, để định thời thực hiện một tác động như: kiểm tra trạng thái của các ngõ vào hoặc tác động các ngõ ra. Một số ứng dụng khác có thể sử dụng timer tạo xung nhịp để đo khoảng thời giữa hai sự kiện (ví dụ: đo độ rộng xung). 1
- Đếm sự kiện dùng để xác định số lần xảy ra của một sự kiện. Một “sự kiện” có thể là tác động ngoài nào đó làm chuyển trạng thái ở một ngõ vào của 8051. Các timer cũng có thể cung cấp xung nhịp xác định tốc độ baud cho cổng nối tiếp trong 8051. Việc truy xuất các timer của 8051 sử dụng sáu thanh ghi chức năng đặc biệt trong bảng sau: SFR Chức năng Địa chỉ Địa chỉ theo bit TCON Điều khiển 88H Có TMOD Chế độ 89H Không TL0 Byte thấp của timer 0 8AH Không TL1 Byte thấp của timer 1 8BH Không TH0 Byte cao của timer 0 8CH Không TH1 Byte cao của timer 1 8DH Không Thanh ghi chế độ của timer (TMOD). Thanh ghi TMOD chứa hai nhóm 4 bit dùng để đặt chế độ làm việc cho Timer 0 và Timer 1 như mô tả trong bảng sau: BIT Tên Timer Chức năng 7 GATE 1 Khi =1 timer chỉ chạy khi INT1 ở mức cao. 6 C/T 1 1: đếm sự kiện bên ngoài; 0: định khoảng thời gian 5 M1 1 bit định chế độ cho timer 1. 4 M0 1 bit định chế độ cho timer 1. 3 GATE 0 Bit cổng cho timer 0 2 C/T 0 Bit chọn counter/timer cho timer 0 1 M1 0 bit định chế độ cho timer 0. 0 M0 0 bit định chế độ cho timer 0. Bốn chế độ của mỗi timer sẽ được chọn tuỳ theo giá trị khởi động cho các bit M1 và M0 tương ứng của nó như mô tả trong bảng sau: M1 M0 Chế độ Chức năng 0 0 0 Chế độ định thời 13 bit. 0 1 1 Chế độ định thời 16 bit. 1 0 2 Chế độ tự động nạp lại 8 bit. 1 1 3 Chế độ định thời tách biệt: Timer 0: TL0 là bộ định thời 8 bit điều khiển bởi chế độ của timer 0. TH0 tương tự nhưng được điều khiển bởi chế độ của timer 1. Timer 1: ngưng hoạt động. Thanh ghi TMOD không được địa chỉ hoá theo bit vì không cần thiết. Thông thường giá trị của nó được nạp một lần khi bắt đầu chương trình, để khởi động chế độ của các timer. 1
- Sau đó các timer có thể cho bắt đầu hoạt động hoặc ngưng lại bằng cách truy cập các thanh ghi đặc biệt khác của timer. Thanh ghi điều khiển timer (TCON). Thanh ghi TCON chứa các bit trạng thái và các bit điều khiển cho Timer 0 và Timer 1 như mô tả trong bảng sau: BIT Tên Địa chỉ Chức năng 7 TF1 8FH Cờ báo tràn của timer 1, được lập bởi phần cứng khi xảy ra tràn; được xoá bằng phần mềm hoặc phần cứng khi phục vụ chương trình ngắt. 6 TR1 8EH Bit điều khiển chạy của timer 1. Được lập xoá bằng phần mềm để điều khiển timer1 on/off. 5 TF0 8DH Cờ báo tràn cho timer 0. 4 TR0 8CH Bit điều khiển chạy cho timer 0. 3 IE1 8BH Cho phép ngắt INT1: được lập bằng phần cứng khi có cạnh xuống ở ngõ vào INT1; được xoá bằng phần mềm hoặc phần cứng khi phụ vụ ngắt. 2 IT1 8AH Chọn kiểu tác động ngắt INT1: được lập xoá bằng phần mềm để chọn kiểu tác động ngắt bằng cạnh xuống hoặc bằng mức thấp. 1 IE0 89H Cho phép ngắt INT0. 0 IT0 88H Chọn kiểu ngắt cho INT0. Bốn bit thấp của TCON không sử dụng cho các timer, chúng được sử dụng để phát hiện và khởi động kiểu tác động cho các ngắt bên ngoài. Các chế độ timer và cờ báo tràn. Các timer 0 và 1 có các chế độ hoạt động tương đương nhau, nên trong phần này chỉ số ‘x’ được sử dụng để chỉ thị cho một timer bất kỳ. Ví dụ THx có thể chỉ thị cho TH0 hoặc TH1. Timer TLx THx TFx Clock (5 bit) (8 bit) a) Mode 0 Timer TLx THx TFx Clock (5 bit) (8 bit) Timer TLx TFx Clock (8 bit) Nạp lại THx (5 bit) c) Mode 2 Timer TLx THx 1 Clock (5 bit) (8 bit) Timer TL0 TF0 Clock (8 bit) Timer TH0 TF1 Clock (8 bit) d) Mode 3 Hình 8.10: Các chế động hoạt động của các timer
- Chế độ 0 (mode 0) - chế độ timer 13 bit: Chế độ này được thực hiện tương thích với 8048 (bộ vi điều khiển có trước 8051). Hoạt động của chế độ này biểu diễn trên hình 8.10a. 5 bit thấp của TLx cùng với THx sẽ tạo thành bộ định thời 13 bit, 3 bit cao của TLx không sử dụng. Chế độ 1 – chế độ timer 16 bit: Chế độ này tương tự như chế độ 0, ngoại trừ việc các timer hoạt động đầy đủ 16 bit (hình 8.10b). Khi nhận được xung nhịp bộ đếm sẽ đếm lên từ 0000H, và cờ tràn sẽ báo khi bộ đếm chuyển trạng thái từ FFFFH về 0000H, sau đó bộ đếm vẫn tiếp tục đếm. Cờ báo tràn là bit TFx trong TCON có thể đọc hoặc ghi bằng phần mềm. Chú ý MSB bộ đếm là bit 7 của THx và LSB là bit 0 của TLx. Các thanh ghi timer (TLx/THx) có thể được đọc hoặc ghi bất cứ lúc nào bằng phần mềm. Chế độ 2 - chế độ tự động nạp lại 8 bit: trong chế độ này TLx hoạt động như một timer 8 bit, còn THx vẫn giữ nguyên giá trị cần nạp lại. Khi số đếm tràn từ FFH đến 00H, không những cờ timer được lập mà giá trị trong THx đồng thời được nạp vào TLx, việc đếm được thực hiện liên tục từ giá trị trong THx lên đến FFH xuống 00H và nạp lại. Chế độ này rất thông dụng vì sự tràn timer xảy ra trong những khoảng thời gian nhất định và tuần hoàn một khi đã khởi động TMOD và THx. Chế độ 3 - chế độ timer tách biệt: trong chế độ này timer 0 tách thành hai timer 8 bit. (TL0 và TH0), TL0 có cờ báo tràn là TF0 và TH0 có cờ báo tràn là TF1. Timer 1 không hoạt động ở chế độ 3, nhưng có thể được khởi động bằng cách chuyển sang chế độ khác. Giới hạn duy nhất là cờ báo tràn TF1 không còn bị tác động khi timer 1 bị tràn vì nó đã được nối tới TH0. Khi timer 0 ở chế độ 3, có thể cho timer 1 chạy và ngưng bằng cách chuyển nó ra ngoài và vào chế độ 3. Nó vẫn có thể được sử dụng bởi cổng nối tiếp để tạo tốc độ baud, hoặc nó có thể được sử dụng cho các ứng dụng khác khi không cần ngắt (vì nó không còn được nối với TF1). Nguồn tạo xung nhịp. Có thể sử dụng hai nguồn tạo xung nhịp cung cấp cho các timer. Chúng được chọn bằng cách ghi vào bit C/T (counter/timer) trong TMOD. Một nguồn tạo xung nhịp dùng cho định khoảng thời gian, cái khác cho đếm sự kiện. Định khoảng thời gian (interval timing): Nếu C/T = 0, hoạt động timer liên tục được chọn và timer được dùng cho việc định khoảng thời gian. Lúc đó, timer lấy xung nhịp từ bộ dao động trong chip. Xung nhịp ngõ ra bộ tạo dao động được giảm tần số bằng bộ chia 1
- 12 trước khi cấp vào timer để thích hợp cho phần lớn các ứng dụng. Như vậy với thạch anh 12 MHz, thì tốc độ xung nhịp cung cấp cho timer sẽ là1 MHz. Báo tràn timer xảy ra sau một số (cố định) xung nhịp, tuỳ thuộc vào giá trị ban đầu được nạp vào các thanh ghi timer TLx/THx. Đếm sự kiện (Event counting): Nếu C/T = 1, timer lấy xung nhịp từ nguồn bên ngoài. Trong hầu hết các ứng dụng, nguồn bên ngoài này cung cấp cho timer một xung khi xảy ra một “sự kiện” – timer dùng đếm sự kiện. Số sự kiện được xác định bằng phần mềm bằng cách đọc các thanh ghi TLx/THx, vì giá trị 16 bit trong các thanh ghi này tăng thêm 1 cho mỗi sự kiện. Nguồn xung nhịp ngoài được cung cấp bằng các chân cổng 3. Bit 4 của cổng 3 (P3.4) dùng làm ngõ vào tạo xung nhịp bên ngoài cho Timer 0 và được gọi là “T0”, còn P3.5 hay “T1” là ngõ vào tạo xung nhịp cho Timer 1. Trong các ứng dụng đếm, các thanh ghi timer được tăng thêm 1 tương ứng với sự chuyển trạng thái logic từ 1 xuống 0 ở ngõ vào bên ngoài (Tx). Ngõ vào bên ngoài được lấy mẫu trong S5P2 của mọi chu kỳ máy. Như vậy, khi ngõ vào cao trong một chu kỳ và thấp trong một chu kỳ kế thì số đếm được tăng thêm 1. Giá trị mới xuất hiện trong các thanh ghi trong S3P1 của chu kỳ theo sau chu kỳ phát hiện sự chuyển trạng thái. Do đó cần 2 chu kỳ máy (2 s) để ghi nhận một sự chuyển trạng thái1 sang 0, tần số ngoài tối đa là 500 KHz (giả sử hệ thống hoạt động ở 12 MHz). Bộ tạo dao động nội 12 Timer Clock Tx C/T Hình 8.11: Sơ đồ cung cấp xung nhịp cho timer Cho chạy, dừng và điều khiển các timer. Hình 8.10 mô tả các cấu hình khác nhau cho các thanh ghi TLx, THx và TFx của timer. Hai nguồn xung nhịp có thể cung cấp cho timer như trên hình 8.11. Phương pháp đơn giản nhất để bắt đầu (cho chạy) và dừng các timer là dùng các bit điều khiển chạy (TRx) trong TCON. TRx bị xóa sau khi reset hệ thống, như vậy các timer theo mặc định là bị cấm (bị dừng) sau khi reset. TRx được đặt lên 1 bằng phần mềm để cho các timer chạy. Vì TRx ở trong thanh ghi TCON có địa chỉ theo bit, nên việc cho chạy và dừng timer có thể thực hiện dễ dàng trong chương trình. Ví dụ, cho timer 0 chạy bằng lệnh: SETB TR0 Và dừng bằng lệnh: CLR TR0 1
- Trình hợp dịch sẽ thực hiện việc chuyển đổi ký hiệu cần thiết từ “TR0” sang địa chỉ bit tương ứng của nó. Lệnh SETB TR0 sẽ giống như SETB 8CH. Một cách khác để điều khiển các timer là dùng bit GATE trong TMOD và ngõ vào bên ngoài INTx. Đặt GATE = 1 cho phép timer sẽ được điều khiển bằng INTx. Việc này hữu dụng cho việc đo độ rộng xung. Ví dụ để đo mức cao của xung ngõ vào INT0: Khởi động Timer 0 ở chế độ 2 (chế độ timer 16 bit), với TL0/TH0 = 0000H, GATE = 1 và TR0 = 1. Khi INT0 ở mức cao, timer được “mở cổng” cấp xung nhịp 1 MHz (nếu 8051 hoạt động ở tần số 12 MHz). Khi INT0 xuống thấp, timer bị “đóng cổng” và thời khoảng của xung tính bằng s là số đếm được trong TL0/TH0. (Có thể lập trình INT0 để tạo ra một ngắt khi nó xuống thấp). Hình 8.12 minh họa Timer 1 hoạt động ở chế độ 1 như một timer 16 bit. Sơ đồ chỉ các khả năng điều khiển việc cấp nguồn tạo xung nhịp cho timer. Bộ tạo dao động 12 TL1 TH1 TF1 T1 C/T TR1 Gate INT1 Hình 8.12: Sơ đồ điều khiển hoạt động của Timer 1 trong chế độ 1 Khởi động và truy xuất các thanh ghi timer. Thông thường các thanh ghi được khởi động một lần ở đầu chương trình để đặt chế độ làm việc cần thiết. Sau đó trong thân chương trình, các timer được cho chạy, dừng, các bit cờ được kiểm tra và xóa, các thanh ghi timer được đọc và cập nhật , theo yêu cầu của các ứng dụng. TMOD là thanh ghi đầu tiên được khởi động, vì nó đặt chế độ hoạt động cho timer. Ví dụ các lệnh sau khởi động Timer 1 ở chế độ 1 có xung nhịp cung cấp từ bộ dao động nội cho việc định khoảng thời gian: MOV TMOD, #00010000B Lệnh trên đặt M1 = 0 và M0 = 1 cho chế độ 1, C/T = 0 và GATE = 0 cho xung nhịp nội, và xóa các bit chế độ của timer 0. Timer thật sự không bắt đầu định thời cho đến khi bit điều khiển chạy TR1 được đặt lên 1. 1
- Nếu cần số đếm ban đầu, các thanh ghi timer TL1/TH1 cũng phải được khởi động. Vì các timer đếm lên và đặt cờ báo tràn khi có sự chuyển tiếp FFFFH sang 0000H. Một khoảng 100 s có thể được định thời bằng cách khởi động trị cho TL1/TH1 là FF9CH: MOV TL1, #9CH MOV TH1, #0FFH Sau đó cho chạy timer bằng cách đặt bit điều khiển chạy bằng lệnh: SETB TR1 Cờ báo tràn được tự động đặt lên 1 sau 100 s. Phần mềm có thể đợi trong 100 s bằng cách dùng lệnh rẽ nhánh có điều kiện nhảy đến chính nó, trong khi cờ báo tràn chưa được đặt lên 1: WAIT: JNB TF1, WAIT Khi timer tràn, cần dừng timer và xóa cờ báo tràn trong phần mềm có thể dùng các lệnh như: CLR TR1 CLR TF1. Đọc timer đang chạy: Trong một số ứng dụng cần đọc giá trị trong các thanh ghi timer khi nó đang chạy. Vì phải đọc hai thanh ghi timer, “sai pha” có thể xảy ra nếu byte thấp tràn vào byte cao giữa hai lần đọc. Giá trị có thể đọc được không đúng. Giải pháp là đọc byte cao trước, kế đó đọc byte thấp rồi đọc byte cao lại một lần nữa. Nếu byte cao đã thay đổi thì lặp lại các hoạt động đọc. Các lệnh dưới đây đọc nội dung của các thanh ghi timer TL1/TH1 vào các thanh ghi R6/R7: AGAIN: MOV A, TH1 MOV R6, TL1 CJNZ A, TH1, AGAIN MOV R7, A 2.2.2 Hoạt động cổng nối tiếp. Giới thiệu. 8051 có một cổng nối tiếp trong chip có thể hoạt động ở nhiều chế độ, trên một dải tần số rộng. Chức năng chủ yếu của cổng nối tiếp là thực hiện chuyển đổi song song sang nối tiếp đối với dữ liệu xuất, và chuyển đổi nối tiếp sang song song với dữ liệu nhập. Việc truy xuất phần cứng qua cổng nối tiếp được thực hiện bằng các chân TXD và RXD. Các chân này là hai bit của cổng 3, P3.1 (TXD) và P3.0 (RXD). Cổng nối tiếp cho phép hoạt động song công (full duplex), và bộ đệm thu (receiver buffering) cho phép một ký tự sẽ đã thu giữ trong bộ đệm, trong khi ký tự thứ hai được nhận. Nếu CPU đọc ký tự thứ nhất trước khi ký tự thứ hai được thu đầy đủ, thì dữ liệu sẽ không bị mất. Hai thanh ghi chức năng đặc biệt cho phép phần mềm truy xuất đến cổng nối tiếp là: SBUF và SCON. Bộ đệm cổng nối tiếp (SBUF) có địa chỉ 99H thực chất bao gồm hai bộ đệm. Dữ liệu ghi vào SBUF sẽ được truyền ra thiết bị bên ngoài, và đọc SBUF để truy xuất dữ liệu thu được. Đây là hai thanh ghi riêng biệt (một thanh ghi chỉ ghi để phát và một thanh ghi chỉ đọc để thu). Thanh ghi điều khiển cổng nối tiếp (SCON) có địa chỉ 98H là thanh ghi địa chỉ hoá theo bit, nó chứa các bit trạng thái và các bit điều khiển. Các bit điều khiển cho phép thiết lập các chế độ hoạt động cho cổng nối tiếp, và các bit trạng thái chỉ thị việc kết thúc phát 1
- hoặc thu ký tự. Các bit trạng thái có thể được kiểm tra bằng phần mềm hoặc có thể được lập trình để tạo ngắt. Tần số làm việc của cổng nối tiếp, còn gọi là tốc độ baud có thể cố định (lấy từ bộ dao động trên chip). Khi muốn tốc độ baud thay đổi, cần lập trình Timer 1. Thanh ghi điều khiển cổng nối tiếp. Chế độ hoạt động của cổng nối tiếp được thiết lập bằng cách ghi dữ liệu vào thanh ghi điều khiển cổng nối tiếp (SCON). Ý nghĩa các bit của SCON được mô tả trong bảng sau: Bit Ký hiệu Địa chỉ Chức năng 7 SM0 9FH Bit chọn chế độ. 6 SM1 9EH Bit chọn chế độ. 5 SM2 9DH Bit chọn chế độ, cho phép truyền thông tin trong chế độ đa xử lý trong chế độ 2 và 3; RI sẽ không tác động nếu nhận được bit thứ 9 bằng 0. 4 REN 9CH Cần được lập để cho phép nhận dữ liệu. 3 TB8 9BH Khi được lập bit thứ 9 sẽ được truyền trong chế độ 3; bit này có thể lập xoá bằng phần mềm. 2 RB8 9AH Khi được lập, bit thứ 9 sẽ được nhận. 1 TI 99H Được lập khi kết thúc truyền 1 byte dữ liệu, bit này có thể xoá bằng phần mềm. 0 RI 98H Được lập khi nhận xong một byte dữ liệu, có thể xoá bằng phần mềm. Các chế độ truyền cổng nối tiếp với thiết bị bên ngoài được định nghĩa bằng các bit SM1 và SM0 như mô tả trong bảng sau: SM0 SM1 Chế độ Chức năng Tốc độ baud 0 0 0 Thanh ghi dịch. Cố định (tần số dao động/12). 0 1 1 8bit UART Thay đổi (theo giá trị của timer). 1 0 2 9bit UART Cố định (tần số dao động/12 hoặc 64. 1 1 3 9bit UART Thay đổi (theo giá trị của timer). Trước khi sử dụng cổng nối tiếp, phải khởi động SCON để chọn chế độ thích hợp. Ví dụ, lệnh: MOV SCON, #01010010B Sẽ khởi động cổng nối tiếp ở chế độ 1 (SM0/SM1 = 0/1), cho phép bộ thu (REN=1) và đặt cờ ngắt phát (TI=1) để chỉ bộ phát sẵn sàng hoạt động. Các chế độ hoạt động. Cổng nối tiếp có 4 chế độ hoạt động, có thể chọn được bằng cách viết các số 1 hay 0 vào các bit SM0 và SM1 trong SCON. Có ba chế độ cho phép truyền đồng bộ (UART), trong chế độ này, mỗi ký tự được thu (nhận) hoặc phát đều nằm trong một khung có một bit start và 1 bit stop. Ở chế độ 0, cổng nối tiếp hoạt động như một thanh ghi dịch thông thường. 1
- Một chu kỳ máy S1 S2 S3 S4 S5 S6 P1 P2 P1 P2 P1 P2 P1 P2 P1 P2 P1 P2 Osc ALE Data out S3P1 Shift clock S6P1 ALE Data out D0 D1 D2 D3 D4 D5 D6 D7 RXD Shift clock TXD a) Định thời phát nối tiếp trong chế độ 0 ALE Data in D0 D1 D2 D3 D4 D5 D6 D7 RXD Shift clock TXD b) Định thời nhận nối tiếp trong chế độ 0 Hình 8.13: Định thời thu phát dữ liệu trên cổng nối tiếp ở chế độ 0 Chế độ 0: (Thanh ghi dịch 8 bit): Chế độ 0 được chọn bằng cách ghi các bit 0 vào SM1 và SM0 của SCON. Trong chế độ này, cổng nối tiếp hoạt động giống như một thanh ghi dịch 1
- 8 bit. Dữ liệu nối tiếp vào và ra qua RXD và TXD theo xung nhịp. 8 bit được phát hoặc thu với bit đầu tiên là LSB. Tốc độ baud cố định ở 1/12 tần số dao động trên chip. Việc phát được khởi động bằng một lệnh ghi dữ liệu vào SBUF. Dữ liệu được dịch ra ngoài trên đường RXD (P3.0), với các xung nhịp dịch được gửi ra đường TXD (P3.1). Mỗi bit được phát đi (trên RXD) trong một chu kỳ máy. Trong mỗi chu kỳ máy, tín hiệu xung nhịp dịch xuống thấp ở S3P1 và trở về mức cao ở S6P1. Định thời dữ liệu phát biểu diễn trên hình 8.13a. Việc thu được khởi động khi bit cho phép bộ thu (REN) là 1, và bit ngắt thu (RI) là 0. Qui tắc chung là lập REN khi bắt đầu chương trình để khởi động cổng nối tiếp, rồi xóa RI để bắt đầu nhận dữ liệu. Khi RI bị xóa, các xung nhịp được đưa ra đường TXD khi bắt đầu chu kỳ máy kế tiếp, và dữ liệu được đưa ra đường RXD theo xung nhịp. Mỗi bit dữ liệu được nhận vào cổng nối tiếp ở cạnh lên của xung nhịp trên đường TXD như biểu diễn trên hình 8.13b. Một ứng dụng của chế độ thanh ghi dịch là mở rộng khả năng xuất dữ liệu của 8051. IC thanh ghi dịch nối tiếp ra song song có thể được nối vào các đường TXD và RXD của 8051 để cung cấp thêm 8 đường ra như trên hình 8.14. Có thể nối nối tiếp thêm các thanh ghi dịch để mở rộng thêm nhiều cổng vào ra khác nữa. 8051 Thanh ghi dịch RXD CLOCK TXD DATA Hình 8.14: Tăng thêm cổng vào ra song song sử dụng cổng nối tiếp ở chế độ 0 Chế độ 1 (Truyền bất đồng bộ 8 bit với tốc độ baud thay đổi được): Ở chế độ 1, cổng nối tiếp của 8051 làm việc như một bộ truyền nhận nối tiếp bất đồng bộ (UART-Universal Asynchronous Receiver/Transmitter) 8 bit với tốc độ baud thay đổi được. UART thực hiện thu phát dữ liệu nối tiếp với mỗi ký tự dữ liệu đi trước là bit start ở mức thấp, theo sau là bit stop ở mức cao. ngoài ra có thể chèn thêm bit kiểm tra chẵn lẻ giữa bit dữ liệu cuối cùng và bit stop. Trong chế độ 1, mỗi ký tự dữ liệu bao gồm 10 bit được phát trên TXD hoặc thu trên RXD bao gồm: 1 bit start (luôn là 0), 8 bit dữ liệu (LSB đầu tiên) và1 bit stop (luôn là 1). Khi thu, bit stop được đưa vào RB8 trong SCON. Trong 8051 chế độ baud được đặt bằng tốc độ báo tràn của Timer 1. Tạo xung nhịp và đồng bộ hoá các thanh ghi dịch của cổng nối tiếp trong các chế độ 1, 2 và 3 được thiết lập bằng bộ đếm 4 bit (chia cho 16), ngõ ra của bộ đếm cung cấp xung nhịp xác định tốc độ baud. Ngõ vào của bộ đếm này được chọn qua phần mềm. Việc truyền dữ liệu (phát) được khởi động bằng cách ghi vào SBUF, nhưng quá trình phát dữ liệu sẽ vẫn chưa thật sự bắt đầu cho đến khi vòng quay kế tiếp của bộ đếm chia cho 16 cung cấp tốc độ baud cho cổng nối tiếp. Dữ liệu được dịch ra ngoài trên đường 1
- TXD bắt đầu bằng bit start, theo sau là 8 bit dữ liệu và sau cùng là bit stop. Độ rộng (theo thời gian của mỗi bit) là nghịch đảo của tốc độ baud được lập trình trong timer. Cờ ngắt phát (TI) được đặt lên 1 khi bit stop xuất hiện trên TXD. Việc thu dữ liệu được khởi động khi có sự chuyển trạng thái từ 1 xuống 0 trên đường RXD. Bộ chia 16 tức thời được xóa để đồng bộ số đếm với luồng bit đến (bit kế tiếp sẽ đến ở vòng đếm 16 kế tiếp ). Luồng bit đến được lấy mẫu giữa các vòng đếm16. Bộ thu sẽ kiểm tra lại bit start ở lần đếm sau khi có chuyển trạng thái từ 1 xuống 0 đầu tiên trên RXD. Nếu ở thời điểm này RXD không còn giữ trạng thái 0, thì bộ thu sẽ xem như tín hiệu start không hợp lệ (do nhiễu chứ không phải do một ký tự hợp lệ). Bộ thu được reset và quay về trạng thái nghỉ (idle), đợi sự chuyển trạng thái từ 1 xuống 0 kế tiếp. Khi đã phát hiện được bit start hợp lệ, các bit của ký tự sẽ tiếp tục được thu. Bit start được bỏ qua và 8 bit dữ liệu được đưa vào thanh ghi dịch cổng nối tiếp. Khi tất cả 8 bit dữ liệu đã được nhận, các bước tiếp theo sẽ xảy ra: 1. Bit thứ 9 (bit stop) được nạp vào RB8 trong SCON. 2. SBUF được nạp với 8 bit dữ liệu. 3. Cờ ngắt bộ thu (RI) được lập lên 1. Tuy nhiên, các bước trên chỉ xảy ra nếu đã có những điều kiện sau: 1. RI = 0. 2. SM2 = 1 và bit stop thu được là 1, hoặc SM2 = 0. Yêu cầu RI = 0 để bảo đảm là chương trình đã đọc ký tự trước (và RI được xóa). Điều kiện thứ hai chỉ áp dụng trong chế độ truyền thông đa xử lý. Điều đó hàm ý là “không đặt RI lên 1 trong chế độ truyền thông đa xử lý khi bit dữ liệu thứ 9 là 0). Chế độ 2 (UART 9 bit với tốc độ baud cố định): Khi SM1 = 1 và SM0 = 0, cổng nối tiếp làm việc ở chế độ 2, như một UART 9 bit có tốc độ baud cố định. 11 bit sẽ được phát hoặc thu: 1 bit start, 8 bit dữ liệu, bit dữ liệu thứ 9 có thể lập trình được và 1 bit stop. Khi phát, bit thứ 9 là bất cứ gì đã được đưa vào TB8 trong SCON (có thể là bit parity). Khi thu, bit thứ 9 thu được sẽ ở trong RB8. Tốc độ baud ở chế độ 2 là 1/32 hoặc 1/16 tần số dao động trên chip. Chế độ 3 (UART 9 bit với tốc độ baud thay đổi được): Chế độ này giống như chế độ 2 ngoại trừ tốc độ baud có thể lập trình được trong timer. Thật ra, các chế độ 1, 2 và 3 rất giống nhau. Khác biệt giữa chúng là ở tốc độ baud (cố định trong chế độ 2, thay đổi trong các chế độ 1 và 3) và ở số bit dữ liệu (8 trong chế độ 1, 9 trong các chế độ 2 và 3). Khởi động và truy xuất các thanh ghi cổng nối tiếp. Cho phép thu: bit cho phép bộ thu (REN = Receiver Enable) trong SCON phải được lập lên 1 bằng phần mềm để cho phép thu các ký tự. Thông thường việc này được thực hiện ở đầu chương trình khi khởi động cổng nối tiếp, timer, Có thể thực hiện việc này theo hai cách. Lệnh: SETB REN Sẽ lập REN lên 1, hoặc lệnh: MOV SCON, #xxx1xxxxB Sẽ lập REN lên 1 và lập hoặc xóa các bit khác trong SCON tuỳ theo các yêu cầu khác nhau (Các x phải là 0 hoặc 1 để khởi động các chế độ hoạt động). 1
- Bit dữ liệu thứ 9: bit dữ liệu thứ 9 cần phát trong các chế độ 2 và 3 phải được nạp vào trong TB8 bằng phần mềm. Khi thu bit dữ liệu dữ liệu thứ 9 được nạp vào RB8. Phần mềm có thể yêu cầu hoặc không yêu cầu bit dữ liệu thứ 9, tuỳ thuộc vào đặc tính kỹ thuật của thiết bị nối tiếp sử dụng. Bit dữ liệu thứ 9 cũng đóng một vai trò quan trọng trong truyền thông tin đa xử lý. Thêm 1 bit parity: Bit dữ liệu thứ 9 thường sử dụng để thêm parity vào ký tự truyền nhận. Bit P trong từ trạng thái chương trình (PSW) được lập lên 1 hoặc bị xóa về 0 sau mỗi chu kỳ máy để thiết lập kiểm tra chẵn lẻ cho 8 bit trong thanh ghi tích lũy. Ví dụ, khi cần truyền 8 bit dữ liệu cộng thêm kiểm tra chẵn, có thể sử dụng các lệnh sau: MOV C, P ; nạp bit parity vào cờ C MOV TB8, C ; nó trở thành bit dữ liệu thứ 9 MOV SBUF, A ; Chuyển 8 bit từ ACC vào SBUF. Nếu cần parity lẻ thì sửa các lệnh lại như sau: MOV C, P ; Nạp bit parity chẵn vào cờ C CPL C ; Chuyển sang parity lẻ MOV TB8, C MOV SBUF, A Dĩ nhiên, việc sử dụng parity không bị giới hạn ở các chế độ 2 và 3. Ở chế độ 1, 8 bit dữ liệu được truyền đi có thể bao gồm 7 bit dữ liệu cộng thêm bit parity. Để truyền mã ASCII 7 bit với parity chẵn ở bit 8, có thể sử dụng các lệnh sau: CLR ACC.7 ; xóa MSB, parity chẵn ở trong P MOV C, P ; chuyển vào cờ nhớ C MOV ACC.7, C ; Đặt parity chẵn vào MSB MOV SBUF, A ; Gửi ký tự đi với 7 bit dữ liệu cộng parity chẵn. Các cờ ngắt: Hai cờ ngắt thu và phát (RI và TI) trong SCON đóng một vai trò quan trọng trong truyền thông tin nối tiếp dùng 8051. Cả hai bit được lập lên 1 bằng phần cứng, nhưng phải được xóa bằng phần mềm. Ví dụ, thường RI được đặt lên 1 khi kết thúc việc thu một ký tự và báo “bộ đệm đã có dữ liệu”. Điều kiện này có thể được kiểm tra trong phần mềm, hoặc có thể được lập trình để gây ra một ngắt. Nếu phần mềm muốn nhận một ký tự từ thiết bị được nối vào cổng, nó phải đợi cho đến khi RI được lập lên 1, rồi xóa RI và đọc ký tự từ SBUF. Đoạn chương trình như sau: WAIT: JNB RI, WAIT ; Kiểm tra RI cho đến khi nó = 1 CLR RI ; Xóa RI MOV A, SBUF ; Đọc ký tự TI được lập lên 1 khi bit cuối của ký tự được phát và báo “bộ đệm phát trống”. Nếu phần mềm muốn gửi một ký tự đến một thiết bị được nối vào cổng nối tiếp, trước hết nó phải kiểm tra xem cổng nối tiếp sẵn sàng chưa. Nói cách khác, nếu ký tự trước đã được ghi tới bộ đệm truyền để gửi đi, thì phải đợi cho đến khi việc truyền ký tự này hoàn tất, mới được gửi ký tự kế tiếp. Các lệnh sau sẽ truyền ký tự trong thanh ghi tích lũy: WAIT: JNB TI, WAIT ; Kiểm tra TI cho đến khi nó bằng 1 CLR TI ; Xóa TI MOV SBUF, A ; Gửi ký tự đi. 1
- Các đoạn chương trình trên là một phần của các hàm nhập và xuất ký tự chuẩn. Truyền thông tin trong hệ thống đa xử lý. Các chế độ 2 và 3 cung cấp khả năng truyền dữ liệu trong hệ thống đa xử lý. Trong các chế độ này bit dữ liệu thứ 9 khi thu sẽ được nạp vào RB8. Cổng nối tiếp có thể lập trình để sau khi đã nhận được bit stop, thì ngắt cổng nối tiếp chỉ tích cực khi RB8 = 1. Đặc tính hoạt động này có thể thiết lập bằng cách lập bit SM2 trong SCON. Một ví dụ cho việc ứng dụng chế độ hoạt động này mô tả trên hình 8.15. 32 đường vào ra 32 đường vào ra P0 P1 P2 P3 P0 P1 P2 P3 Matter 8051 8051 Slave 1 8051 Slave 2 TXD RXD RXD Hình 8.15: Truyền thông tin nối tiếp trong hệ thống đa xử lý. Khi 8051 chủ (matter) muốn truyền một khối dữ liệu tới 8051 tới (slaver) nào đó, trước tiên nó gửi ra ngoài một byte địa chỉ xác định 8051 tớ cần nhận dữ liệu. Byte địa chỉ sẽ khác với các byte dữ liệu khác là có bit thứ 9 là 1. Tất cả các 8051 tớ được ngắt và nhận lấy byte địa chỉ này, nhưng chỉ có 8051 tớ nào có địa chỉ đúng mới xoá bit SM2 của nó đi để chuẩn bị nhận dữ liệu từ 8051 chủ, còn tất cả các 8051 tớ khác sẽ lập SM2 và bỏ qua các byte dữ liệu kế tiếp. Các 8051 tớ sẽ được ngắt trở lại khi có byte địa chỉ tiếp theo được gửi đến. Sơ đồ này có thể mở rộng để các 8051 tớ có thể truyền dữ liệu tới 8051 chủ. Khi này không được sử dụng bit dữ liệu thứ 9, nếu không một 8051 tớ khác có thể tình cờ được chọn. SM2 không bị tác động trong chế độ 0, và trong chế độ 1 nó có thể sử dụng để kiểm tra sự hợp lệ của stop bit. Trong chế độ 1, khi nhận nếu SM2 =1, ngắt nhận sẽ không tích cực khi không có stop bit hợp lệ. Tốc độ baud cổng nối tiếp. Như đã giới thiệu, tốc độ baud cổng nối tiếp là cố định ở các chế độ 0 và 2. Trong chế độ 0, nó luôn là tần số dao động trên chip được chia cho 12. Thông thường thạch anh ấn định tần số dao động trên chip của 8051, nhưng cũng có thể sử dụng nguồn xung nhịp khác. Giả sử với tần số dao động danh định là 12MHz, thì tốc độ baud chế độ 0 sẽ là 1 MHz (hình 5.16a). Dao động Tốc độ trên chip 12 baud a) chế độ 0 64 SMOD = 0 Dao động Tốc độ trên chip baud 1 32 SMOD = 1 b) chế độ 2 32 SMOD = 0 Dao động Tốc độ trên chip baud 16 SMOD = 1 c) chế độ 1 và 3 Hình 8.16: Nguồn cung cấp xung nhịp xác định tốc độ baud cho cổng nối tiếp
- Sau khi reset hệ thống, tốc độ baud được mặc định là trong chế độ 2, nó chính là tần số bộ dao động chia cho 64. Tốc độ baud còn được quyết định bởi một bit trong thanh ghi điều khiển nguồn cung cấp (PCON). Bit 7 của PCON là bit SMOD. Nếu lập bit SMOD lên 1 sẽ làm gấp đôi tốc độ baud trong các chế độ 1, 2 và 3. Trong chế độ 2, tốc độ baud mặc định là 1/64 tần số dao động khi bit SMOD=0, nó sẽ được nhân đôi lên thành 1/32 tần số dao động khi SMOD=1 (hình 8.16b). Vì PCON không được định địa chỉ theo bit, nên để lập bit SMOD lên 1 cần thực hiện các lệnh sau: MOV A, PCON ; Lấy giá trị hiện thời của PCON SETB ACC.7; Đặt bit 7 (SMOD) lên 1 MOV PCON, A ; Ghi giá trị ngược về PCON. Tốc độ baud trong các chế độ 1 và 3 được xác định bằng tốc độ tràn của Timer 1. Vì timer hoạt động ở tần số tương đối cao, tốc độ baud cho cổng nối tiếp sẽ bằng tốc độ tràn timer được chia thêm cho 32 khi SMOD = 0 (chia16 nếu SMOD = 1). Sử dụng Timer 1 làm xung nhịp tốc độ baud: cách thông dụng để tạo tốc độ baud là khởi động TMOD với chế độ 8 bit tự động nạp lại (chế độ 2), và nạp giá trị thích hợp vào TH1, để cho tốc độ tràn đúng với tốc độ baud mong muốn. TMOD được khởi động như sau: MOV TMOD, #0010xxxxB Các bit x là 1 hoặc 0 tương ứng cho timer. Cũng có thể đạt được các tốc độ baud thấp bằng cách sử dụng timer chế độ 2 với TMOD = 0001xxxxB. Tuy nhiên, khi đó chương trình phần mềm sẽ phức tạp thêm, vì các thanh ghi TH1/TL1 phải được khởi động lại sau mỗi lần tràn. Việc này có thể thực hiện trong chương trình phục vụ ngắt. Một cách khác là cấp xung nhịp cho Timer 1 từ ngoài dùng T1 (P3.5). Và tốc độ baud luôn là tốc độ tràn của Timer 1 được chia cho 32 (hoặc cho 16, nếu SMOD = 1). Công thức xác định tốc độ baud trong các chế độ 1 và 3 là: Tốc độ baud = Tốc độ tràn của Timer 1 32. 1
- Ví dụ, muốn làm việc với tốc độ baud là 1200 baud, thì tốc độ tràn của Timer 1 phải là: 1200 32 = 38.4 KHz. Nếu dùng thạch anh 12 MHz, Timer 1 được cấp xung nhịp 1 MHz hay 1000 KHz. Vì tốc độ tràn của Timer 1 là 38.4 KHz và timer được cấp xung nhịp 1000 KHz, thì cần tràn sau 1000 38.4 = 26.04 xung nhịp (làm tròn là 26). Vì timer đếm lên và tràn xảy ra khi có sự thay đổi từ FFH xuống 00H ở số đếm. Như vậy giá trị đúng cần nạp vào TH1 là –26. Cách dễ nhất để nạp giá trị vào TH1 là: MOV TH1, # –26 Trình hợp dịch sẽ thực hiện chuyển đổi cần thiết cho lệnh. Trong trường hợp này –26 được chuyển thành 0E6H. Như vậy, lệnh trên hoàn toàn giống với lệnh: MOV TH1, # 0E6H Do việc làm tròn nên có sai số nhỏ trong tốc độ baud. Tổng quát thì cho phép dung sai 5% trong truyền thông bất đồng bộ (start/stop). Có thể có được tốc độ baud chính xác nếu dùng thạch anh 11.059 MHz. Bảng sau đây tóm tắt các giá trị nạp vào TH1 cho các tốc độ baud thông dụng nhất, dùng thạch anh 12 MHZ hoặc 11.059 MHz: Tốc độ Tần số thạch anh SMOD Giá trị nạp cho Tốc độ baud Sai số baud TH1 thực sự 9600 12 MHz 1 -7 (F9H) 8923 7% 2400 12 MHz 0 -13 (F3H) 2404 0,16% 1200 12 MHz 0 -26 (E6H) 1202 0,16% 19200 11,059 MHz 1 -3 (FDH) 19200 0 9600 11,059 MHz 0 -3 (FDH) 9600 0 2400 11,059 MHz 0 -12 (F4H) 2400 0 1200 11,059 MHz 0 -24 (E8H) 1200 0 2.2.3 Ngắt của 8051 (interrupt). Giới thiệu. Một ngắt là sự xảy ra một điều kiện - một sự kiện - làm tạm thời ngưng chương trình hiện hành, để điều kiện đó được phục vụ bằng một chương trình khác. Các ngắt đóng một vai trò quan trọng trong thiết kế các ứng dụng vi điều khiển. Chúng cho phép hệ thống đáp ứng bất đồng bộ với một sự kiện và giải quyết sự kiện đó trong khi một chương trình khác đang thực thi. Một hệ thống được điều khiển bằng ngắt làm người sử dụng cảm giác như hệ thống thực hiện nhiều công việc một cách đồng thời. Dĩ nhiên CPU mỗi lần không thể thực thi nhiều hơn một lệnh. Nhưng nó có thể tạm ngưng việc thực hiện một chương trình này, để thực hiện chương trình khác, rồi quay về chương trình thứ nhất. Việc phục vụ ngắt giống như việc gọi một chương trình con, CPU chuyển qua thực hiện chương trình con, sau đó quay trở lại chương trình chính. Khác biệt là trong hệ thống điều khiển bằng ngắt, thì sự ngắt quãng không xảy ra như kết quả của một lệnh (lệnh CALL subroutine), mà là đáp ứng với một “sự kiện” xảy ra bất đồng bộ với chương trình chính. Hệ thống sẽ không xác định chương trình chính sẽ bị ngắt quãng tại đâu. 1
- Chương trình giải quyết ngắt được gọi là chương trình phục vụ ngắt (ISR: Interrupt Service Routine) hoặc chương trình xử lý ngắt. ISR thực thi khi đáp ứng một ngắt, và thông thường là để thực hiện tác vụ xuất nhập dữ liệu với một thiết bị. Khi ngắt xảy ra, chương trình chính tạm thời dừng hoạt động và rẽ nhánh đến ISR: ISR thực thi và kết thúc bằng lệnh trở về từ ngắt, lúc này chương trình chính tiếp tục thực hiện ở chỗ mà nó tạm dừng. Thường người ta xem chương trình chính như thực thi ở mức cơ sở (base - level), và các ISR thực thi ở mức ngắt (interrupt - level). Người ta cũng dùng các thuật ngữ foreground chỉ mức cơ sở và background chỉ mức ngắt. Hình ảnh khái quát của các ngắt được mô tả trong hình 8.17: Đáp ứng ngắt ISR ISR ISR Quay về Main Main Main Main Hình 8.17: Việc thực hiện chương trình với đáp ứng ngắt. Tổ chức ngắt của 8051. Có 5 nguồn yêu cầu ngắt trong hệ thống 8051: 2 ngắt ngoài, 2 ngắt từ timer và 1 ngắt cổng nối tiếp. Tất cả các ngắt đều được mặc định bị cấm sau khi reset hệ thống, và được cho phép từng nguồn riêng biệt bằng phần mềm. Khi có hai hoặc nhiều yêu cầu ngắt đồng thời, hoặc một ngắt xảy ra trong khi một ngắt khác đang được phục vụ, hệ thống sẽ đáp ứng bằng cách xét theo vòng tuần tự và theo mức ưu tiên để định trình cho việc thực hiện các ngắt. Vòng tuần tự thì cố định, nhưng ưu tiên ngắt thì có thể lập trình được. Cho phép và cấm các ngắt: Mỗi nguồn ngắt được cho phép hoặc cấm một cách riêng biệt qua thanh ghi cho phép ngắt (IE - Interrupt Enable) có định địa chỉ theo bit ở địa chỉ A8H. Mỗi nguồn ngắt sẽ có 1 bit trong thanh ghi IE để có thể lập trình cho phép riêng biệt, ngoài ra còn có một bit cho phép/cấm toàn bộ các ngắt (khi được xóa sẽ cấm tất cả các ngắt), như trình bày trong bảng sau: Bit Ký hiệu Địa chỉ Chức năng (1: cho phép; 0: cấm) IE7 EA AFH Cho phép/cấm toàn bộ các ngắt. IE6 - AEH Không định nghĩa. IE5 - ADH Dự phòng cho thế hệ kế tiếp. IE4 ES ACH Cho phép ngắt cổng nối tiếp. IE3 ET1 ABH Cho phép ngắt timer 1. IE2 EX1 AAH Cho phép ngắt ngoài cấp từ INT1. IE1 ET0 A9H Cho phép ngắt timer 0 IE0 EX0 A8H Cho phép ngắt ngoài INT0 1
- Như vậy khi muốn cho phép bất kỳ ngắt nào cần phải lập hai bit: bit cho phép riêng và bit cho phép toàn bộ. Ví dụ, các ngắt từ Timer 1 được cho phép như sau: SETB ET1 ; Cho phép ngắt từ Timer 1 SETB EA ; Đặt bit cho phép toàn bộ. Cũng có thể sử dụng lệnh sau: MOV IE, # 10001000B Mặc dù hai cách này có cùng kết quả sau khi reset hệ thống, nhưng chúng sẽ có kết quả sẽ khác nếu IE được ghi ở giữa chương trình. Cách thứ nhất không ảnh hưởng đến 5 bit khác trong thanh ghi IE, trái lại cách thứ hai sẽ xóa các bit khác. Nên khởi trị IE theo cách thứ hai thường sử dụng ở đầu chương trình (nghĩa là sau khi mở máy hoặc reset hệ thống), còn khi muốn cho phép và cấm các ngắt ngay trong chương trình thì nên dùng cách thứ nhất, để tránh ảnh hưởng đến các bit khác trong thanh ghi IE. Ưu tiên ngắt: Mỗi nguồn ngắt được lập trình riêng vào một trong hai mức ưu tiên qua thanh ghi ưu tiên ngắt IP (Interrupt Priority) được địa chỉ theo bit ở địa chỉ B8H. Chức năng các bit của IP được mô tả trong bảng sau: Bit Ký hiệu Địa chỉ Chức năng (1: mức ưu tiên cao; 0: mức ưu tiên thấp) IP7 - - Không định nghĩa. IP6 - - Không định nghĩa. IP5 - BDH Dự phòng. IP4 PS BCH Ưu tiên cho ngắt cổng nối tiếp. IP3 PT1 BBH Ưu tiên cho ngắt timer 1. IP2 PX1 BAH Ưu tiên cho ngắt ngoài INT1. IP1 PT0 B9H Ưu tiên cho ngắt timer 0. IP0 PX0 B8H Ưu tiên cho ngắt ngoài INT0. IP mặc định bị xóa sau khi reset hệ thống để đặt tất cả các ngắt ở mức ưu tiên thấp. Việc “ưu tiên” cho phép một ISR sẽ bị ngắt bởi một ngắt khác, nếu ngắt này có độ ưu tiên cao hơn ngắt đang phục vụ. Điều này thực hiện dễ dàng trên 8051, vì chỉ có hai mức ưu tiên. Nếu một ISR có ưu tiên thấp đang thực thi, khi một ngắt có ưu tiên cao xảy ra thì ISR hiện hành sẽ bị ngắt. ISR có ưu tiên cao không thể bị ngắt. Chương trình chính thực hiện ở mức cơ sở và không liên hệ với bất cứ ngắt nào, nó có thể luôn bị ngắt, bất chấp ưu tiên của ngắt. Nếu hai ngắt có độ ưu tiên khác nhau xảy ra đồng thời, thì ngắt có độ ưu tiên cao hơn sẽ được phục vụ trước. Hỏi vòng tuần tự: Nếu hai ngắt cùng độ ưu tiên xảy ra đồng thời, vòng tuần tự sẽ xác định ngắt nào được phục vụ trước. Vòng tuần tự được qui định là: INT 0, Timer 0, INT 1, Timer 1, cổng nối tiếp. Hình 8.18 minh họa các cơ chế phục vụ của 5 nguồn ngắt,. Trạng thái của tất cả các nguồn ngắt khả dụng qua các bit cờ tương ứng trong các SFR. Dĩ nhiên, nếu có bất kỳ ngắt nào bị cấm, ngắt không xảy ra, nhưng phần mềm vẫn có thể kiểm tra cờ ngắt. IE IP High Priority Low Priority INT0 1 IT0 IE0 Interrupt polling sequence TF0 INT1 IT1 IE1 TF1 RI TI Interrupt Enable Global Enable Hình 8.18: Cơ chế ngắt của 8051.
- Các ví dụ timer và cổng nối tiếp trong các mục trước đã sử dụng các cờ ngắt, mà không gây ra ngắt thật sự. Ngắt cổng nối tiếp có từ logic OR của ngắt thu (RI) và ngắt phát (TI). Các bit cờ tạo các ngắt được tóm tắt ở bảng sau: Ngắt Cờ SFR và vị trí bit INT0 IE0 TCON.1 INT1 IE1 TCON.3 Timer 1 TF1 TCON.7 Timer 0 TF0 TCON.5 Serial port TI SCON.1 Serial port RI SCON.0 Các vector xử lý ngắt. Khi một ngắt xảy ra và được CPU chấp nhận, chương trình chính sẽ bị ngắt quãng và những hoạt động sau xảy ra: - Hoàn tất việc thực thi lệnh hiện hành. - Cất PC vào ngăn xếp. - Trạng thái ngắt hiện hành được cất bên trong. 1
- - Các ngắt bị chặn ở mức ngắt. - Nạp vào PC địa chỉ vector của ISR. - ISR thực thi. ISR thực thi và đáp ứng các yêu cầu của ngắt. ISR hoàn tất bằng lệnh RETI (quay về từ ngắt). Điều này làm lấy lại giá trị cũ của PC từ đỉnh ngăn. Việc thực hiện chương trình chính tiếp tục ở chỗ mà nó đã bị dừng. Các vector ngắt. Khi chấp nhận ngắt, giá trị được nạp vào PC được gọi là vector ngắt. Nó là địa chỉ bắt đầu của ISR cho nguồn tạo ngắt. Các vector ngắt được cho ở bảng sau: Ngắt Cờ Địa chỉ vector ngắt Reset RST 0000H INT0 IE0 0003H Timer 0 TF0 000BH INT1 IE1 0013H Timer 1 TF1 001BH Serial port RI hoặc TI 0023H Vector reset hệ thống (RST ở địa chỉ 0000H) có trong bảng, vì nó giống ngắt: nó ngắt chương trình chính và nạp giá trị mới cho PC. Khi “chỉ đến một ngắt”, cờ gây ngắt tự động được xóa bởi phần cứng. Ngoại lệ chỉ có RI và TI của các ngắt cổng nối tiếp cần được xoá bằng phần mềm. Vì có tới hai nguồn có thể xảy ra cho ngắt cổng nối tiếp, nên CPU không xóa cờ ngắt này. Các bit phải được kiểm tra trong ISR để xác định nguồn ngắt và cờ tạo ngắt sẽ được xóa bằng phần mềm. Thông thường sẽ có một lệnh rẽ nhánh thích hợp tuỳ theo nguồn ngắt. Vì các vector ngắt ở phần đầu của bộ nhớ chương trình, nên lệnh đầu tiên của chương trình chính thường là lệnh nhảy qua vùng nhớ này, ví dụ như LJMP 0030H. Thiết kế chương trình dùng các ngắt. Các ví dụ về timer và cổng nối tiếp trong các phần trước không sử dụng các ngắt, mà sử dụng các “vòng lặp đợi” để kiểm tra các cờ báo tràn (TF0 hoặc TF1), hoặc các cờ thu và phát cổng nối tiếp (TI hoặc RI). Với phương pháp này thời gian hoạt động có giá trị của CPU bị tiêu tốn trong các vòng lặp đợi các cờ tác động. Điều này hoàn toàn không thích hợp với các ứng dụng điều khiển, trong đó bộ vi điều khiển phải tương tác với nhiều thiết bị nhập và xuất đồng thời. Phần này sẽ khảo sát cách phát triển chương trình dùng ngắt để điều khiển. Mỗi chương trình bắt đầu tại địa chỉ 0000H, với giả thiết rằng nó sẽ bắt đầu thực hiện sau khi reset hệ thống. Khung một chương trình độc lập dùng ngắt có thể thực hiện như sau: ORG 0000H ; Điểm vào reset LJMP MAIN ; Các điểm vào ISR ORG 0030H ; Điểm vào chương trình chính 1
- MAIN: ; Bắt đầu chương trình chính. Lệnh đầu tiên nhảy đến địa chỉ 0030H, vừa qua các vị trí vector bắt đầu của các ISR. Như trình bày trên hình 8.19, chương trình chính bắt đầu ở địa chỉ 0030H. Bộ nhớ chương trình bên ngoài. FFFF Chương trình chính 0030 002F Điểm bắt đầu sau khi reset và khi xảy ra LJMP main các ngắt Hình 8.19: Tổ chức bộ nhớ chương trình khi sử dụng các ngắt. Các chương trình phục vụ ngắt có kích thước nhỏ: Các chương trình phục vụ ngắt phải bắt đầu ở gần phần đầu của bộ nhớ chương trình, dưới các địa chỉ trong bảng Các vector ngắt. Mặc dù chỉ có 8 byte ở giữa các điểm vào ngắt, có thể đủ để thực hiện hoạt động phục vụ ngắt mong muốn và quay về chương trình chính. Nếu chỉ có một nguồn ngắt được sử dụng, ví dụ Timer 0, thì có thể sử dụng một khung chương trình như sau: ORG 0000H ; Reset LJMP MAIN ORG 000BH ; Điểm vào Timer 0 T0ISR: ; Bắt đầu ISR cho Timer 0 RETI ; Quay về chương trình chính MAIN: ; Chương trình chính Nếu sử dụng nhiều ngắt, cần phải bảo đảm mỗi chương trình phục vụ ngắt bắt đầu ở đúng địa chỉ đã qui định cho nó, và không chạy quá sang ISR kế. Trong ví dụ trên, vì chỉ có một ngắt được sử dụng, chương trình chính có thể bắt đầu ngay sau lệnh RETI. Các chương trình phục vụ ngắt có kích thước lớn: Nếu ISR dài hơn 8 byte, cần có lệnh nhảy để chuyển nó tới nơi khác trong bộ nhớ chương trình, nếu không nó sẽ đi lố qua điểm vào của ngắt kế. Với lệnh nhảy đến vùng nhớ khác, có thể mở rộng chiều dài ISR. Ví dụ chỉ xét Timer 0, có thể sử dụng khung chương trình sau: ORG 0000H ; Điểm bắt đầu sau khi reset LJMP MAIN ORG 000BH ; Điểm bắt đầu của ngắt Timer 0 1
- LJMP T0ISR ORG 0030H ; Dưới các vector ngắt tiếp theo MAIN: T0ISR: ; ISR cho Timer 0 RETI ; Quay về chương trình chính. Xét một chương trình đơn giản nhất không thực hiện gì cả, chương trình chính chỉ khởi động các timer, cổng nối tiếp và các thanh ghi ngắt sau đó không làm gì nữa. Công việc hoàn toàn được thực hiện trong các ISR. Sau các lệnh khởi động, chương trình chính chứa lệnh: HERE: SJMP HERE Hay dạng viết gọn như sau: SJMP $ Khi ngắt xảy ra, chương trình chính bị ngắt quãng tạm thời, trong khi ISR thực hiện. Lệnh RETI ở cuối ISR trả điều khiển về chương trình chính và nó tiếp tục không làm gì cả. Trong nhiều ứng dụng điều khiển, nhiều công việc thật ra được thực hiện hoàn toàn trong các ISR. Khi cần các công việc thực hiện ngoài ngắt, lệnh SJMP $ (HERE: SJMP HERE) có thể được thay thế bằng các lệnh cần thực hiện trong ứng dụng. Các ngắt của 8051. Các ngắt timer: Các ngắt timer có địa chỉ vector ngắt là 000BH (Timer 0) và 001BH (Timer 1). Ngắt timer xảy ra khi các thanh ghi timer (TLx/THx) tràn và set cờ báo tràn (TFx) lên 1. Chú ý rằng các cờ timer (TFx) không cần phải xóa bằng phần mềm. Khi cho phép các ngắt, TFx tự động bị xóa bằng phần cứng khi CPU chuyển đến ISR. Các ngắt cổng nối tiếp: Ngắt cổng nối tiếp xảy ra khi hoặc cờ ngắt phát (TI) hoặc cờ ngắt thu (RI) được đặt lên 1. Ngắt phát xảy ra khi truyền xong một ký tự vừa được ghi vào SBUF. Ngắt thu xảy ra khi một ký tự đã được nhận xong và đang đợi trong SBUF để được đọc. Ngắt cổng nối tiếp khác với ngắt timer là cờ gây ra ngắt không bị xóa bằng phần cứng khi CPU chuyển tới ISR. Nguyên nhân là do có hai nguồn ngắt cổng nối tiếp: TI và RI. Nguồn ngắt phải được xác định trong ISR và cờ tạo ngắt cần được xóa bằng phần mềm. Các ngắt ngoài: Các ngắt ngoài xảy ra khi có một mức thấp hoặc cạnh xuống trên chân INT0 hoặc INT1 của 8051. Các cờ tạo các ngắt này là các bit IE0 và IE1 trong TCON. Khi quyền điều khiển đã chuyển đến ISR, cờ tạo ra ngắt chỉ được xóa nếu ngắt được tích cực bằng cạnh xuống. Nếu ngắt được tích cực theo mức, thì mức cao của nguồn yêu cầu ngắt bên xoá cờ thay cho phần cứng. Việc chọn ngắt tích cực mức thấp hay tích cực cạnh xuống được lập trình qua các bit IT0 và IT1 trong TCON. Ví dụ, nếu IT1 = 0, ngắt ngoài 1 được kích khởi bằng mức thấp ở chân INT1. Nếu IT1 = 1, ngắt ngoài 1 sẽ được kích khởi bằng cạnh xuống. Trong chế độ này, nếu các mẫu liên tiếp trên chân INT1 chỉ mức cao trong một chu kỳ và thấp trong chu kỳ kế, cờ yêu cầu ngắt IE1 trong TCON được đặt lên 1. Rồi bit cờ IE1 yêu cầu ngắt. Vì các chân ngắt ngoài được lấy mẫu một lần ở mỗi chu kỳ máy, ngõ vào cần được giữ trong tối thiểu 12 chu kỳ dao động để bảo đảm lấy mẫu đúng. Nếu ngắt ngoài được tác 1
- động theo cạnh xuống, nguồn bên ngoài phải giữ chân yêu cầu cao tối thiểu 1 chu kỳ và giữ nó ở mức thấp thêm một chu kỳ nữa để bảo đảm phát hiện được cạnh xuống. IE0 và IE1 tự động được xóa khi CPU chuyển tới ngắt. Nếu ngắt ngoài được tác động theo mức, nguồn bên ngoài phải giữ yêu cầu tác động cho đến khi ngắt được yêu cầu thật sự được tạo ra. Rồi nó phải không tác động yêu cầu trước khi ISR được hoàn tất, nếu không một ngắt khác sẽ được lặp lại. Thông thường khi vào ISR người ta làm nguồn yêu cầu đưa tín hiệu tạo ngắt về trạng thái không tác động. 2.3 TẬP LỆNH VÀ HƯỚNG DẪN LẬP TRÌNH TRÊN 8051. Các chương trình được cấu tạo từ nhiều lệnh nối tiếp nhau, một chương trình thường cần được xây dựng một cách logic nhất, để có thể thực hiện một cách nhanh chóng hiệu quả nhất. Cũng như các bộ vi xử lý thông thường, mỗi họ vi điều khiển có một tập lệnh riêng của nó. Tập lệnh của 8051 được xây dựng tối ưu cho các ứng dụng điều khiển 8 bit, nó có các chế độ định vị địa chỉ cho phép việc truy cập RAM nội một cách nhanh chóng, thích hợp với các ứng dụng có cấu trúc dữ liệu nhỏ. Tập lệnh của nó cũng được mở rộng để xử lý các biến theo bit, cho phép việc truy cập trực tiếp các bit tiện lợi cho các hệ thống điều khiển yêu cầu quá trình xử lý logic. Cũng như các bộ vi xử lý 8 bit điển hình, tập lệnh của 8051 có các opcode 8 bit. Điều này cho phép thực hiện 2 8=256 lệnh khác nhau, trong đó 255 lệnh được thi hành và 1 lệnh không được định nghĩa. Phần toán hạng trong lệnh cũng bao gồm1 hoặc 2 byte chỉ thị dữ liệu, hoặc địa chỉ của dữ liệu cần xử lý trong lệnh. Toàn bộ tập lệnh có 139 lệnh 1 byte, 92 lệnh 2 byte và 24 lệnh 3 byte. 2.3.1 Các chế độ định vị địa chỉ (addressing mode). Trong các lệnh xử lý dữ liệu (tính toán, sao chép ) cần phải chỉ thị nơi chứa dữ liệu đó (trong thanh ghi, trong RAM nội, trong bộ nhớ ngoài ). Việc chỉ thị vị trí của dữ liệu trong lệnh được thực hiện bằng các cách định vị địa chỉ. Các chế độ định vị địa chỉ thường gắn liền với tập lệnh của mỗi họ vi xử lý. Chúng cho phép định rõ nguồn hoặc đích chứa dữ liệu theo các cách khác nhau tùy thuộc vào trạng thái của sự lập trình. 8051 có 8 chế độ định vị địa chỉ: - Thanh ghi. - Trực tiếp. - Gián tiếp. - Tức thời. - Tương đối. - Tuyệt đối. - Dài. - Chỉ số. Định vị địa chỉ thanh ghi (register addressing): 8051 có bốn tập gồm 32 thanh ghi 8 bit nằm ở 32 byte đầu tiên của RAM nội từ địa chỉ 00H đến 1FH. Nhưng tại 1 thời điểm chỉ có tập hoạt động, chúng được ký hiệu từ R0 tới 1
- R7. Các tập thanh ghi được chọn bằng các bit PSW4, PSW3 của từ trạng thái chương trình (PSW). Trong cấu trúc các lệnh sử dụng định vị thanh ghi, các thanh ghi được mã hoá bằng 3 bit trọng số thấp của mã lệnh. Như vậy, mã chức năng và toán hạng của lệnh được kết hợp trong một byte 1 byte như hình 8.20. Trong lệnh gợi nhớ, định vị địa chỉ thanh ghi được chỉ thị bằng ký hiệu Rn (với n từ 0 tới 7).Ví dụ lệnh cộng giá trị trong thanh ghi R7 với thanh chứa được viết: ADD A,R7 Lệnh có opcode là 00101111B: 5bit cao 00101 chỉ thị lệnh ADD và 3 bit thấp 111 chỉ thị thanh ghi R7. Một số lệnh ngầm định cho 1 thanh ghi nào đó, vì thế mã opcode không cần các bit mã hoá cho các thanh ghi này. Các thanh ghi thường được ngầm định trong tập lệnh của 8051 như: thanh ghi chứa A, thanh ghi con trỏ dữ liệu DPTR, thanh ghi bộ đếm chương trình PC, cờ C và cặp thanh ghi AB. Định vị địa chỉ trực tiếp (direct addressing): Định vị địa chỉ trực tiếp cho phép truy xuất bất kỳ địa chỉ hoặc thanh ghi phần cứng nào trong chip. Trong kiểu định vị này, một byte địa chỉ trực tiếp thêm vào sau opcode của chỉ thị hợp dịch vị trí của dữ liệu như hình 8.20b. Opcode n n n a) Định vị địa chỉ thanh ghi, ví dụ ADD A,R5 Opcode Direct address b) Định vị địa chỉ trực tiếp, ví dụ ADD A,direct Opcode i c) Định vị địa chỉ gián tiếp, ví dụ ADD A,@R0 Opcode Direct address d) Định vị địa chỉ tức thời, ví dụ ADD A,#55H Opcode Relative offset e) Định vị địa chỉ tương đối, ví dụ ADD A,#55H A10 – A8 Opcode A7 – A0 f) Định vị địa chỉ tuyệt đối, ví dụ AJMP dest Opcode A15 – A8 A7 – A0 g) Định vị địa chỉ dài, ví dụ AJMP dest Opcode + Acc = Effective Address h) Định vị địa chỉ dài, ví dụ AJMP dest 1 Hình 8.20: Các chế độ định vị địa chỉ của 8051.
- Tất cả các cổng I/O và các thanh ghi chức năng đặc biệt, thanh ghi điều khiển và thanh ghi trạng thái, đều nằm trong vùng địa chỉ từ 128 đến 255 (80H đến FFH) của RAM nội. Khi giá trị byte địa chỉ trực tiếp nằm trong khoảng này (ứng với bit 7 =1), thì các thanh ghi chức năng đặc biệt được truy xuất. Ví dụ cổng 0 và cổng 1 được quy định địa chỉ trực tiếp là 80H và 90H, trong mã gợi nhớ chúng được ký hiệu là P0 và P1. Ví dụ lệnh: MOV P1,A Khi hợp dịch sẽ đổi địa chỉ trực tiếp của cổng 1 (P1) thành 90H, và đặt vào byte thứ 2 của lệnh (byte thứ nhất là Opcode của lệnh). Định vị địa chỉ gián tiếp (indirect addressing): Trong định vị gián tiếp, người ta sử dụng thanh ghi để giữ địa chỉ của một ô nhớ nội chứa dữ liệu cần xử lý trong lệnh. Cách định vị này đặc biệt tiện lợi khi truy cập một chuỗi dữ liệu trong RAM nội, khi đó chỉ cần tăng hoặc giảm giá trị thanh ghi để trỏ tới dữ liệu kế của chuỗi. 8051 chỉ sử dụng các thanh ghi R0 và R1 cho định vị địa chỉ gián tiếp. Bit có trọng số thấp nhất trong opcode của mã lệnh, được sử dụng để mã hoá hai thanh ghi này như trên hình 8.20c. Trong mã gợi nhớ, định vị gián tiếp được ký hiệu bằng dấu ‘@’ được đặt trước R0 hoặc R1. Ví dụ nếu R1 chứa giá trị 40H, và nội dung ô nhớ 40H là 55H, thì lệnh: MOV A,@R1 sẽ chuyển giá trị 55H vào thanh ghi A. Các lệnh sử dụng định vị địa chỉ gián tiếp, sẽ giúp giảm ngắn các đoạn chương trình xử lý các chuỗi dữ liệu trong bộ nhớ. Ví dụ đoạn chương trình sau sẽ xoá các ô nhớ từ địa chỉ 60H tới địa chỉ 7FH: MOV R0,#60H LOOP: MOV @R0,#0 INC R0 CJNE R0,#80H,LOOP Lệnh đầu tiên nạp địa chỉ đầu tiên của khối dữ liệu trong bộ nhớ. Lệnh thứ 2 sử dụng định vị gián tiếp để ghi giá trị 0 vào ô nhớ có địa chỉ chứa trong R0. Lệnh thứ 3 tăng R0 lên 1 để trỏ tới ô nhớ kế tiếp. Và lệnh cuối cùng kiểm tra xem R0 đã chứa địa chỉ của cuối khối dữ liệu chưa, nếu chưa thì lặp lại các bước trên, lệnh sử dụng giá trị so sánh là 80H để đảm bảo ô nhớ 7FH được xoá trước khi vòng lặp kết thúc. Định vị địa chỉ tức thời (immediate addressing): Khi toán hạng của lệnh là một hằng số, mà không phải là một biến, thì hằng số này có thể chỉ thị ngay trong mã lệnh như một byte dữ liệu tức thời. Byte dữ liệu tức thời này sẽ nằm ngay sau byte opcode của lệnh như trên hình 8.20d. Trong lệnh gợi nhớ, định vị địa chỉ trực tiếp được ký hiệu bằng dấu ‘#’ nằm trước số, 1 tên được định nghĩa trước hoặc 1 biểu thức số học biểu diễn bằng số, các tên, các hoạt động. Trình hợp dịch tính toán giá trị và thay thế dữ liệu trực tiếp vào trong lệnh. Hằng số sẽ được trình hợp dịch thay thế bằng giá trị cụ thể nằm trong byte thứ 2 của mã. Ví dụ lệnh : MOV A,#12 sẽ nạp giá trị 12 (0CH) vào thanh chứa. 1
- Hầu hết các lệnh định vị địa chỉ tức thời, đều có dữ liệu tức thời 8 bit, trừ một ngoại lệ lệnh nạp giá trị 16 bit vào thanh ghi DPTR. Ví dụ lệnh: MOV DPTR,#8000H sẽ bao gồm 3 byte, nó nạp giá trị 16 bit (8000H) vào thanh ghi con trỏ dữ liệu. Định địa chỉ tương đối (relative addressing): Định vị địa chỉ tương đối chỉ sử dụng với những lệnh nhảy. Một địa chỉ tương đối (hoặc độ dời - offset) là 1 số 8 bit có dấu, nó sẽ được cộng vào bộ đếm chương trình PC để chuyển điều khiển chương trình tới vị trí mới trong bộ nhớ. Phạm vi chuyển điều khiển nằm trong khoảng -128 đến 127. Độ dời tương đối là 1 byte nằm sau opcode của lệnh như biểu diễn trên hình 8.20e. Trước khi được cộng thêm, bộ đếm chương trình sẽ được tăng tới địa chỉ của lệnh nằm kế lệnh nhảy, và địa chỉ mới sẽ được tính tương đối so với địa chỉ này. Trong lệnh chỉ có số độ dời để cộng thêm vào PC, mà không có một giá trị địa chỉ tuyệt đối của nơi cần chuyển tới. Trong lệnh gợi nhớ, thông thường không chỉ thị giá trị của số độ dời. Đích chuyển tới sẽ được chỉ thị bằng một nhãn, chương trình hợp dịch sẽ chuyển đổi nhãn thành số độ dời. Ví dụ nhãn THERE đại diện cho lệnh nằm ở ô nhớ 1040H và lệnh: SJMP THERE ở trong bộ nhớ tại các ô nhớ 1000H và 1001H, thì trình hợp dịch gán số độ dời tương đối là 3EH vào byte thứ 2 của mã lệnh (1002H + 3EH = 1040H). Định vị địa chỉ tương đối có thuận lợi là mã lệnh không phụ thuộc vào vị trí lệnh nhảy trong bộ nhớ, nhưng nó cũng có bất lợi là chỉ chuyển điều khiển được trong một phạm vi ngắn từ -128 đến 127 byte. Định vị địa chỉ tuyệt đối (Absolute Addressing): Định vị địa chỉ tuyệt đối chỉ được dùng với các lệnh ACALL và AJMP. Các lệnh 2 byte này cho phép rẽ nhánh chương trình trong các trang nhớ 2K của bộ nhớ chương trình, nó chiếm 11 bit thấp của địa chỉ đích chuyển tới (A0-A10) được cung cấp trong lệnh như trên hình 8.20f. 5 bit cao của địa chỉ đích là 5 bit cao hiện có trong bộ đếm chương trình. Vì thế lệnh chỉ cho phép rẽ nhánh trong vùng nhớ 2KB (vì A11 – A15 không thay đổi). Ví dụ nhãn THERE biểu diễn cho một lệnh tại địa chỉ 0F46H, và lệnh: AJMP THERE nằm tại địa chỉ 0900H và 0901H, thì trình hợp dịch sẽ mã hoá lệnh thành: 11100001 trong byte thứ nhất (bao gồm A10 – A8 và opcode của lệnh). Và 01000110 trong byte thứ 2 (bao gồm các bit A7 – A0). 5 bit cao của bộ đếm chương trình không bị thay đổi khi thực hiện lệnh này. Chú ý rằng địa chỉ đích nằm trong vùng 2K từ 0800H tới 0FFFH. Định vị địa chỉ tuyệt đối có lợi điểm là ngắn (2 byte), nhưng bất lợi vì chỉ rẽ nhánh được trong một vùng giới hạn và mã lệnh phụ thuộc vào vị trí của nó trong bộ nhớ. Định vị địa chỉ dài (Long Addressing): Định vị địa chỉ dài chỉ được dùng với lệnh LCALL và LJMP. Chúng là các lệnh 3 byte bao gồm: 1 địa chỉ nơi chuyển tới 16 bit đầy đủ nằm trong byte 2 và byte 3 của mã lệnh (hình 8.20g). lợi điểm của lệnh là có thể chuyển điều khiển tới bất kỳ vị trí nào trong vùng nhớ mã lệnh 64K, nhưng có bất lợi là lệnh dài (3 byte) và mã lệnh tuỳ thuộc vào vị trí của 1
- nó trong bộ nhớ. Việc phụ thuộc của mã lệnh vào vị trí, sẽ làm chương trình hoạt động sai nếu được nạp vào một vùng nhớ khác. Ví dụ một chương trình bắt đầu tại địa chỉ 2000H, và nếu có lệnh LJMP 2040H, thì chương trình sẽ không được ghi vào vị trí khác. Ví dụ nếu ghi chương trình trên bắt đầu tại ô nhớ 4000H, thì lệnh LJMP 2040H vẫn chuyển điều khiển về địa chỉ 2040H, đây là vị trí không đúng vì chương trình đã chuyển tới vị trí mới. Định vị địa chỉ chỉ số (Indexed Addressing): Định vị địa chỉ chỉ số dùng 1 thanh ghi cơ bản (bộ đếm chương trình con trỏ dữ liệu), và một số độ dời (trong thanh ghi A) để tạo thành địa chỉ tác động (effective address), sử dụng cho lệnh JMP hoặc MOVC. Các bảng nhảy hoặc các bảng tra có thể thực hiện một cách dễ dàng bằng cách dùng định vị địa chỉ chỉ số. Ví dụ: DPTR đang trỏ đến địa chỉ 1000H của EPROM ngoài, và thanh ghi A chứa nội dung là 09H thì lệnh: MOVC A,@A+DPTR sẽ nạp nội dung của ô nhớ 1000H+09H=1009H. 2.3.2 Tập lệnh của 8051. Tập lệnh của 8051 chia ra 5 nhóm lệnh chính bao gồm: Các lệnh số học, các lệnh logic, các dịch chuyển dữ liệu, các lệnh xử lý bit, các lệnh rẽ nhánh chương trình. Bảng tham khảo nhanh của các lệnh như sau: Cách viết mã gợi nhớ Mô tả hoạt động Các lệnh số học. A = A +source ADD A,source ADD A,#data ADDC A,#source Cộng có nhớ ADDC A,#data SUBB A,source A = A – source – CF SUBB A,data INC A Tăng A INC source DEC A Giảm A DEC source INC DPTR Tăng DPTR MUL AB Nhân A với B DIV AB Chia A cho B DA A Chỉnh thập phân giá trị trong A Các lệnh logic ANL A,source Logic AND ANL A,#data ANL direct,A ANL direct,#data ORL A,source Logic OR ORL A,#data ORL direct,A ORL direct,#data 1
- XRL A,source Logic XOR XRL A,#data XRL direct,A XRL direct,#data CLR A Xoá A CPL A Bù 1 của A RL A Quay trái A RLC A Quay trái A qua cờ nhớ RR A Quay phải A RRC A Quay phải A qua cờ nhớ SWAP A Chuyển đổi 2 nibble của A Các lệnh truyền dữ liệu MOV A,source A = source MOV A,#data MOV dest, A MOV dest,source MOV dest,#data MOV DPTR,#data16 MOVC A,@A+DPTR Chuyển dữ liệu từ bộ nhớ ngoài vào A MOVC A,@A+PC MOVX A,@Ri Chuyển dữ liệu từ bộ nhớ RAM nội vào A MOVX A,@DPTR PUSH direct Cất vào ngăn xếp POP direct Lấy ra khỏi ngăn xếp XCH A,source Chuyển đổi vị trí hai dữ liệu XCHD A@Ri Các lệnh xử lý bit CLR C Xoá bit CLR bit SETB C Lập bit SETB bit CPL C Bù 1 bit CPL bit ANL C,bit And bit với cờ C ANL C,/bit And bit đảo với cờ C ORL C,bit Or bit với cờ C ORL C,/bit Or bit đảo với cờ C MOV C,bit Chuyển bit vào cờ C MOV C,/bit JC rel Nhảy nếu cờ C = 1 JNC rel Nhảy nếu cờ C = 0 JB bit,rel Nhảy nếu bit = 1 JNB bit,rel Nhảy nếu bit = 0 1
- JBC bit,rel Nhảy nếu bit lập sau đó xoá Các lệnh rẽ nhánh ACALL addr11 Gọi chương trình con LCALL addr16 RET Quay về từ chương trình con RETI Quay về từ chương trình phục vụ ngắt AJMP addr11 Nhảy tuyệt đối LJMP addr16 Nhảy dài SJMP rel Nhảy ngắn JMP @A+DPTR Nhảy chỉ số JZ rel Nhảy nếu A = 0 JNZ rel Nhảy nếu A = 1 CJNE A,direct,rel So sánh và nhảy nếu không bằng CJNE A,#data,rel CJNE Rn,#data,rel CJNE @Ri,#data,rel DJNZ Rn,rel Giảm và nhảy nếu chưa bằng 0 DJNZ direct,rel NOP Không hoạt động. Với: - Rn: các thanh ghi R0 – R7. - Direct: 8 bit địa chỉ RAM nội (00 – FFH). - @Ri: định vị địa chỉ gián tiếp sử dụng R1 và R2 - source, dest: hoặc Rn hoặc direct hoặc @Ri - #data: hằng số 8 bit. - #data16: hằng số 16 bit. - Bit: địa chỉ trực tiếp theo bit (0 – 7) - Rel: số độ dời có dấu 8 bit. - Addr11: 11 bit địa chỉ trong trang nhớ 2K hiện hành. - Addr16: 16 bit địa chỉ. 2.3.3 Chương trình hợp ngữ của 8051. Giới thiệu. Theo phân cấp ngôn ngữ lập trình, hợp ngữ nằm giữa ngôn ngữ máy và ngôn ngữ cấp cao. Các ngôn ngữ cấp cao điển hình như ngôn ngữ Pascal, c, sử dụng các từ hoặc các khai báo dễ hiểu với người sử dụng, mặc dù nó vẫn còn khoảng cách rất xa so với ngôn ngữ tự nhiên. Còn ngôn ngữ máy là ngôn ngữ nhị phân của máy tính. Một chương trình ngôn ngữ máy là một chuỗi các byte nhị phân biểu diễn cho các lệnh mà máy tính có thể thực hiện được. Hợp ngữ thay thế các mã nhị phân của ngôn ngữ máy, thành các mã gợi nhớ để thuận lợi hơn khi lập trình. Ví dụ lệnh cộng trong ngôn ngữ máy được biểu diễn bằng mã nhị phân ‘’10110011’’, còn trong hợp ngữ là ‘’ADD’’. Việc lập trình được thực hiện bằng hợp ngữ thay vì bằng ngôn ngữ máy. 1
- Các toán hạng của lệnh được biểu diễn bằng các cách định vị địa chỉ khác nhau, trong mã nhị phân của các lệnh ngôn ngữ máy, cũng được thay thế bằng các ký hiệu trong lệnh hợp ngữ. Một chương trình hợp ngữ (assembly) không thể thực hiện được trên máy tính, mà nó phải được dịch sang mã nhị phân ngôn ngữ máy. Tuỳ thuộc vào mức độ phức tạp của mỗi chương trình, mà quá trình dịch sang chương trình ngôn ngữ máy có thể bao gồm một hoặc nhiều bước. Chương trình dịch tối thiểu được gọi là chương trình hợp dịch, nó dịch các lệnh gợi nhớ thành các lệnh mã máy. Bước đòi hỏi tiếp theo thường là liên kết (linker). Một chương liên kết thực hiện việc kết hợp các phần khác nhau của chương trình trên các tập tin khác nhau, và thiết lập địa chỉ trong bộ nhớ nơi chương trình sẽ thực hiện. Hoạt động của trình hợp dịch (assembler operation). Có nhiều trình hợp dịch và các chương trình hỗ trợ khác hiện có để phát triển các ứng dụng vi điều khiển. ASM51 hợp dịch chuẩn nhất so với các chương trình khác. Trong phần này sẽ giới thiệu về cấu trúc lập trình với ASM51. Mặc dù đã được tiêu chuẩn hoá, nhưng một số khai báo trong phần này cũng có thể không sử dụng được với các trình hợp dịch khác. ASM51 là trình hợp dịch mạnh, nó sử dụng cho việc phát triển hệ thống vi điều khiển trên các hệ thống Intel và các máy tính họ IBM PC. Vì các máy tính sử dụng để chạy phần mềm này có CPU khác 8051, nên ASM51 được gọi là trình hợp dịch chéo (cross assembler). Chương trình nguồn 8051 có thể viết trên máy tính, bằng các trình soạn thảo văn bản, sau đó có thể hợp dịch thành file đối tượng (object) và file liệt kê (listing) bằng ASM51. Chú ý rằng, máy tính với một CPU khác nên nó sẽ không hiểu được các lệnh nhị phân của file đối tượng. Vì thế cần một chương trình có khả năng nạp chương trình đối tượng vào hệ thống 8051 để thực hiện. Để thực hiện việc hợp dịch bằng ASM51, có thể đánh lệnh sau từ dấu nhắc hệ thống: ASM51 source file {assembly controls} Source file là tên của file nguồn cần hợp dịch, còn assembler controls là các khoá điều khiển tạo ra các tác động khác nhau khi hợp dịch. ASM51 sẽ nhận một file nguồn làm ngõ vào (ví dụ PROGRAM.SCR) và tạo ra 1 file đối tượng (PROGRAM.OBJ) và file listing (PROGRAM.LST) Vì hầu hết các trình hợp dịch xem xét chương trình nguồn 2 lần trong lúc dịch nó sang ngôn ngữ máy, nên chúng được mô tả qua giai đoạn hợp dịch (two - pass assembler) là: Giai đoạn 1 (pass1): file nguồn được xem xét từng đường và bảng ký hiệu được xây dựng. Vị trí bộ đếm chương trình được mặc định là 0, hoặc được thiết lập bằng chỉ thị ORG (origin). Khi file được xem xét, bộ đếm được tăng lên tuỳ theo độ dài của mỗi lệnh. Các chỉ thị định nghĩa dữ liệu (DB hoặc DW) tăng bộ đếm bằng với số byte được định nghĩa. Các chỉ thị nhớ lưu trữ (DS) tăng bộ đếm bằng số byte được dự trữ. Khi tìm thấy 1 nhãn (bắt đầu một hướng rẽ nhánh), thì nó sẽ được đặt trong bảng ký hiệu theo giá trị hiện hành của bộ đếm. Các ký hiệu được định nghĩa bằng chỉ thị EQU (equal) được đặt trong bảng ký hiệu. Bảng ký hiệu được cất giữ và sau đó dùng trong giai đoạn hợp dịch thứ 2. Giai đoạn 2 (pass2): tạo ra các file đối tượng và liệt kê. Các lệnh gợi nhớ được dịch thành các opcode và đặt trong file ra. Các toán hạng được định giá trị và đặt phía sau 1
- opcode. Khi các toán hạng là các ký hiệu, giá trị của chúng sẽ được lấy lại từ bảng ký hiệu (được tạo ra trong giai đoạn 1), và dùng để tạo thành dữ liệu hoặc địa chỉ đúng cho các lệnh. Với 2 giai đoạn được thực hiện như trên, nên chương trình nguồn có thể sử dụng các ký hiệu trước khi nó được định nghĩa, ví dụ như các lệnh rẽ nhánh ở đầu chương trình mà các nhãn chuyển tới chưa được định nghĩa. File đối tượng khi hợp dịch thành công sẽ chỉ chứa các byte nhị phân (00H đến FFH) của chương trình ngôn ngữ máy. File đối tương định vị (object relocatable) sẽ chứa một bảng ký hiệu và thông tin khác cần thiết cho sự liên kết và định vị chương trình. File liệt kê là một file văn bản bao gồm cả các lệnh gợi nhớ và mã máy tương ứng của nó. Khi có lệnh lỗi, file liệt kê cũng chứa cả các thông báo lỗi. Khuôn dạng một chương trình hợp ngữ 8051. Các lệnh trong chương trình hợp ngữ bao gồm: các lệnh máy, chỉ thị hợp dịch của trình hợp dịch, lệnh điều khiển trình hợp dịch và các chú thích. Các lệnh máy tương đương với các lệnh gợi nhớ, chúng được đổi thành các lệnh mã máy khi hợp dịch (ví dụ như ANL). Các chỉ thị hợp dịch của trình hợp dịch, được sử dụng để trình hợp dịch định nghĩa cấu trúc chương trình, các ký hiệu, các dữ liệu, các hằng (ví dụ ORG). Các lệnh điều khiển sẽ thiết lập các chế độ hợp dịch, và chỉ thị hướng thực hiện của trình hợp ngữ (ví dụ $TITLE). Các chú thích sử dụng giải thích về hoạt động và mục đích của các chuỗi lệnh, giúp người đọc dễ hiểu hơn. Các dòng lệnh phải được viết theo một nguyên tắc nhất định được qui định bởi trình hợp dịch. Khuôn dạng mỗi hàng lệnh như sau: (label:) mnemonic [ operand ] [ ; operand ] [ ] [ ; comment ] Chỉ có phần mã gợi nhớ (mnemonic) là bắt buộc phải có trong hàng lệnh trong tất cả các trình hợp dịch. Một số trình biên dịch yêu cầu phải có nhãn ở cột thứ nhất trong tất cả các dòng lệnh, và các phần sau nó phải được ngăn cách với nhau bằng khoảng trắng (space) hoặc khoảng cách quãng (tab). Với ASM51 nhãn không nhất thiết phải có trên mỗi hàng lệnh, và nhãn cũng không cần phải nằm cùng hàng với lệnh gợi nhớ. Nhãn (label field): Một nhãn tượng trưng cho địa chỉ của lệnh (hoặc dữ liệu) nằm sau nó. Khi rẽ nhánh đến lệnh này, nhãn này được dùng trong toán hạng của lệnh rẽ nhánh hoặc lệnh nhảy (ví dụ SJMP SKIP). Khác với “nhãn” luôn chỉ thị một địa chỉ, ký hiệu (symbol) có ứng dụng tổng quát hơn. Nhãn chỉ là một trong các loại của ký hiệu và nó được phân biệt bằng dấu hai chấm (:) phía sau. Ký hiệu để gán các giá trị hoặc thuộc tính sử dụng trong các chỉ thị hợp dịch của hợp ngữ như: EQU, SEGMENT, bit, DATA Các ký hiệu có thể là địa chỉ, hằng số, tên các đoạn (segment), hoặc các cấu trúc khác được hiểu bởi người lập trình. Sau đây là 1 ví dụ để phân biệt nhãn và ký hiệu: PAR EQU 500 ; PAR là ký hiệu biểu diễn thay cho giá trị 500. START: MOV A,#0FFH; start là nhãn tượng trưng địa chỉ lệnh MOV. Một ký hiệu hoặc nhãn phải bắt đầu bằng một chữ cái, dấu ’?’ hoặc dấu ‘_’, và có thể chứa tới 31 ký tự. Các ký hiệu có thể là chữ hoa hoặc chữ thường đều được hiểu giống nhau, nhưng chúng không được trùng với các lệnh gợi nhớ, các ký hiệu đã được định nghĩa trước và các chỉ thị hợp dịch. 1
- Lệnh gợi nhớ (mnemonic): Các lệnh gợi nhớ hoặc các chỉ thị hợp dịch được viết tại phần mnemonic của dòng lệnh sau nhãn hoặc ký hiệu. Ví dụ các lệnh gợi nhớ như: ADD, MOV, DIV, INC ; Ví dụ các chỉ thị hợp dịch như: ORG, EQU hoặc DB. Toán hạng (operand): Phần toán hạng được viết sau phần mã gợi nhớ trong hàng lệnh. Vùng này chứa địa chỉ hoặc dữ liệu sử dụng trong lệnh. Một nhãn có thể được dùng để biểu diễn cho địa chỉ của dữ liệu, hoặc một ký hiệu có thể được dùng để biểu diễn cho hằng dữ liệu. Có nhiều cách biểu diễn các toán hạng tuỳ thuộc vào các lệnh cụ thể. Một số lệnh không có toán hạng (như RET, NOP), còn một số lệnh lại có nhiều toán hạng được phân ra bằng các dấu phẩy. Chú thích (comment): Các chú thích làm dễ hiểu chương trình, chúng đặt ở cuối mỗi dòng lệnh, và trước nó phải có dấu chấm phẩy (;). Cũng có thể thực hiện cả một dòng chú thích bằng cách bắt đầu bằng dấu ‘;’. Một chương trình con hoặc một đoạn lệnh dài có thể bắt đầu bằng một khối chú thích (gồm nhiều dòng liên tiếp) để giải thích tính chất chung của phần chương trình bên dưới. Các ký hiệu hợp dịch đặc biệt (special assembler symbol): Các ký hiệu hợp dịch đặc biệt được dùng trong các chế độ định vị thanh ghi cụ thể. Chúng bao gồm thanh ghi A, R0 – R7, DPTR, PC, C, và AB. Cũng như ký hiệu $ được dùng để biểu diễn giá trị hiện hành của bộ đếm chương trình. Ví dụ lệnh JNB TI,$ tương đương với dòng lệnh sau: HERE : JNB TI,HERE Địa chỉ gián tiếp (indirect address): một số lệnh có toán hạng là một thanh ghi chứa địa chỉ của dữ liệu. Ký hiệu @ cho biết địa chỉ gián tiếp và chỉ có thể dùng với R0, R1, DPTR. Ví dụ lệnh MOV A,@R0 nạp dữ liệu từ RAM nội tại địa chỉ trong R0 vào thanh chứa A. Lệnh MOVC A,@A+PC nạp dữ liệu từ bộ nhớ mã ngoài tại địa chỉ là tổng nội dung thanh ghi A với bộ đếm chương trình vào thanh chứa A. Dữ liệu tức thời (Immediate data): Các lệnh sử dụng định vị tức thời, cung cấp dữ liệu toán hạng trong một phần của lệnh. Các dữ liệu tức thời phải bắt đầu bằng dấu ‘#’. Ví dụ CONSTANT EQU 100 MOV A,#0FFH ORL 40H,#CONSTANT Tất cả các toán hạng tức thời (trừ trong lệnh MOV DPTR,#DATA) đều là 8 bit. Nếu dữ liệu được viết thành 16 bit thì byte thấp sẽ được sử dụng. Tất cả các bit trong byte cao phải giống nhau (00H hoặc FFH). Nếu không sẽ có thông báo lỗi ‘value not fit in a byte’ (giá trị không nằm trong một byte). Ví dụ các lệnh sau đúng cú pháp: MOV A,#0FF00H MOV A,#00FFH Hai lệnh sau đây sinh ra thông báo lỗi: MOV A,#0FE00H MOV A,#01FFH Các hằng số thập phân từ -256 đến +256 cũng có thể sử dụng được cho toán hạng tức thời. Ví dụ 2 lệnh sau đúng cú pháp và tương đương với nhau: MOV A,# -256 1
- MOV A,#0FF01H Địa chỉ trực tiếp (DATA address): Nhiều lệnh truy xuất các vùng nhớ sử dụng định vị trực tiếp và cần 1 toán hạng địa chỉ RAM nội (00H đến FFH). Các ký hiệu đã được định nghĩa có thể được dùng cho các địa chỉ SFR. Ví dụ: MOV A,45H hay MOV A,SBUF tương đương với lệnh MOV A,99H. Địa chỉ bit (bit address): Một trong các điểm mạnh của các bộ vi điều khiển là khả năng truy xuất các bit riêng lẻ. Các lệnh truy xuất các bit phải cung cấp 1 địa chỉ bit trong RAM nội (vùng 00H đến 7FH), hoặc địa chỉ bit trong các SFR (vùng 80H đến FFH). Có 3 cách để chỉ thị địa chỉ bit trong một lệnh: dùng địa chỉ bit trực tiếp, dùng chỉ số chỉ thị vị trí của bit trong một byte dữ liệu, dùng ký hiệu hợp dịch đã được định nghĩa trước. Ví dụ: SETB 0E7H ; Dùng địa chỉ bit trực tiếp SETB ACC.7; Dùng chỉ số chỉ thị vị trí bit. JNB TI, $ ; Dùng ký hiệu được định nghĩa ‘’TI’’. Địa chỉ mã (code address): Địa chỉ mã được dùng cho toán hạng của các lệnh nhảy bao gồm: nhảy tương đối (như SJMP và nhảy có điều kiện), nhảy và gọi tuyệt đối (ACALL, AJMP), nhảy và gọi dài (LJMP, LCAL). Địa chỉ mã thường được cho ở dạng nhãn. Ví dụ: HERE: _ _ _ SJMP HERE ASM51 sẽ xác định mã địa chỉ đúng để đưa vào lệnh: hoặc là địa chỉ độ dời 8 bit có dấu, hoặc địa chỉ trang 11 bit hoặc địa chỉ dài 16 bit tuỳ theo từng lệnh. Các lệnh nhảy và gọi sử dụng chung (generic jumps and calls): ASM51 cho phép người lập trình dùng các lệnh gợi nhớ sử dụng chung JMP hoặc CALL. Lệnh ‘’JMP’’ có thể được dùng để thay cho SJMP, AJMP hoặc LJMP, và ‘’CALL’’ có thể được dùng để thay cho ACALL hoặc LCALL. Trình hợp dịch biến đổi lệnh gợi nhớ chung thành một lệnh “thực tế” sau vài quy luật đơn giản. Lệnh gợi nhớ chung được biến đổi thành dạng ngắn (chỉ sử dụng cho JMP) nếu nơi nhảy đến không theo hướng tới và trong vùng -128, hoặc thành dạng tuyệt đối nếu đích chuyển đến không theo hướng tới vượt quá giới hạn ngắn, nhưng nằm trong vùng 2K. Nếu các dạng ngắn và tuyệt đối không sử dụng được thì lệnh chung sẽ được chuyển thành dạng dài. Ví dụ : ORG 1234H Start: INC A JMP Start ;Hợp dịch như lệnh SJMP ORG Start + 200 JMP Start ; Hợp dịch như lệnh AJMP JMP Finish ; Hợp dịch như lệnh LJMP Finish:INC A END Sự hợp dịch này không thực hiện việc lựa chọn tốt nhất cho chương trình. Ví dụ nếu nhảy theo hướng tới (JMP Finish) chỉ cách khoảng vài byte nhưng lệnh chung JMP vẫn được 1