Thiết kế và xây dựng mạch đo nhiệt độ đơn giản

LỜI NÓI ĐẦU Ngày này, việc ứng dụng máy tính vào các kỹ thuật đo lường và điều khiển không còn mới vì khi các thiết bị, hệ thống đo lường và điều khiển được ghép nối với máy tính sẽ có thời gian thu thập và xử lý dữ liệu ngắn trong khi mức độ chính xác vẫn được đảm bảo, nhưng điều đáng quan tâm hơn cả là khả năng tự động hoá trong việc thu thập và xử lý dữ liệu. Chính vì điều này làm cho máy tính được ứng dụng trong hầu hết vào các lĩnh vực trong cuộc sống hàng ngày đặc biệt là trong lĩnh vực c

doc247 trang | Chia sẻ: huyen82 | Lượt xem: 1399 | Lượt tải: 2download
Tóm tắt tài liệu Thiết kế và xây dựng mạch đo nhiệt độ đơn giản, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ông nghiệp. Một bước tiến quan trọng trong kỹ thuật vi xử lý là sự ra đời của các bộ vi xử lý kỹ thuật số. Đây là một vi mạch điện tử có mật độ tích hợp cao bao gồm rất nhiều các mạch số có khả năng nhận, xử lý và xuất dữ liệu. Đặc biệt là quá trình xử lý dữ liệu được thực hiện theo một chương trình là một tập hợp các lệnh từ bên ngoài mà người sử dụng có thể thay đổi dễ dàng tùy thuộc vào từng ứng dụng. Do đó một bộ vi xử lý có thể thực hiện được rất nhiều các yêu cầu điều khiển khác nhau tuỳ thuộc vào nhu cầu sử dụng. Sự ra đời của kỹ thuật vi xử lý là sự kết hợp giữa kỹ thuật phần cứng và phần mềm đã làm cho hoạt động của các mạch điện tử trở nên mềm dẻo hơn với những phần mềm rất linh hoạt mà người sử dụng có thể sửa chữa, thay đổi hoặc bổ sung làm cho ứng dụng ngày càng trở nên hoàn thiện mà không cần phải thiết kế lại toàn bộ ứng dụng. Trong đồ án này, em sử dụng vi mạch điều khiển AT90S8535 của hãng Atmel để thiết kế một mạch đo nhiệt độ đơn giản. Đây là một bộ vi xử lý 8 bit năng lượng thấp (theo kiểu chíp CMOS) trên cơ sở cấu trúc RICS của hãng Atmel, tốc độ xử lý dữ liệu của IC AT90S8535 rất cao (xấp xỉ 8 MISP tại tần số 8MHz) cho phép hệ thống có thể được thiết kế tối ưu làm tăng tốc độ xử lý. Do đó, nó cung cấp khả năng linh hoạt rất cao trong các ứng dụng nhúng. Vì vậy, việc tìm hiểu cấu trúc và đặc tính của vi mạch điều khiển AT90S8535 có thể giúp chúng ta sử dụng vi mạch điều khiển này cho các ứng dụng cần thiết. Em xin chân thành cảm ơn thầy cô đã tận tình hướng dẫn để em hoàn thành đồ án này. Em cũng xin chân thành cảm ơn các anh ở trung tâm NET.JSC đã giúp đỡ em trong suốt thời gian thực hiện đồ án. Tuy nhiên, do trình độ còn nhiều hạn chế nên đồ án không thể tránh khỏi những thiếu sót, vì vậy em rất mong được sự chỉ bảo của các thầy cô cũng như của những người đi trước trong lĩnh vực này để đồ án của em hoàn thiện hơn qua đó em có thể xây dựng được những ứng dụng trong thực tế. CHƯƠNG I NHIỆM VỤ VÀ PHƯƠNG HƯỚNG THỰC HIỆN 1.1. Nhiệm vụ của đồ án. Từ mục đích tổng quát của đề tài là thiết kế và xây dựng một hệ thống đo nhiệt độ đơn giản, có thể phân tách ra thành các nhiệm vụ chính cần thực hiện như sau: Thiết kế và xây dựng hệ thống ghép nối vi điều khiển (mC) AT90S8535 với module LCD (4x20 character), keypad (16 keys), cảm biến nhiệt LM335. Ngoài ra hệ thống còn phải có khả năng giao tiếp với máy tính (PC) qua cổng RS 232. Hình 1.1 : Sơ đồ tổng thể của hệ thống cần thiết kế PC mC + I/O port LCD display KeyPad 16 RS 232 L335 Thiết kế và xây dựng phần mềm điều khiển mC để thu thập dữ liệu từ cảm biến nhiệt nhiệt LM335, từ keypad hoặc từ PC. Xử lý dữ liệu nhận được để hiển thị trên LCD hoặc truyền sang PC. Xây dựng phần mềm trên PC để có thể giao tiếp được với mC qua cổng RS 232 1.2. Phân tích nhiệm vụ. Để có thể thiết kế và xây dựng được hệ thống như trên cần phải thực hiện các bước sau : Nghiên cứu và tìm hiểu bộ vi xử lý AT90S8535. Tìm hiểu sự hoạt động của module LCD và cảm biến nhiệt LM 335. Tìm hiểu sự hoạt động và phương pháp mã hoá keypad để có thể ghép nối với mC. Tìm hiểu phương pháp truyền thông sử dụng chuẩn RS 232. Thiết kế sơ đồ mạch nối ghép giữa mC với LCD, keypad, IC LM335 và giữa mC với máy tính thông qua cổng RS 232. Lập trình phần mềm nạp cho mC để thực hiện các kết nối trên. Viết phần mềm trên PC để giao tiếp với mC qua cổng RS 232. Lắp giáp mạch đã thiết kế, chạy kiểm thử và đánh giá kết quả. Viết báo cáo tốt nghiệp. 1.3. Phương hướng thực hiện. 1.3.1. Lựa chọn thiết bị. Lựa chọn vi điều khiển : Trong thực tế có rất nhiều các họ vi xử lý khác nhau có thể sử dụng được trong ứng dụng này như họ vi điều khiển 8051 của Intel, 68hC11 của Motorola hay họ vi điều khiển 8515 của ATMEL... Tuy nhiên, trong đồ án sử dụng bộ vi xử lý AT90S8535 của ATMEL, do đây là một sản phẩm mới của hãng ATMEL nên việc tìm hiểu nó sẽ đem lại rất nhiều lợi ích trong việc thiết kế các ứng dụng đo lường và điều khiển. Về mặt cấu tạo nó cũng tương tự như bộ vi xử lý AT90S8515 đã có từ khá lâu với 4 cổng I/O lập trình được. Nhưng về mặt công dụng thì bộ vi xử lý AT90S8535 được tích hợp nhiều chức năng hơn so với bộ vi xử lý AT90S8515, đặc biệt trên mC AT90S8535 được tích hợp một bộ ADC cho phép mỗi chân của port A được sử dụng là đầu vào cho bộ ADC, làm cho việc sử dụng mC AT90S8535 trong các ứng dụng linh hoạt hơn rất nhiều so với mC AT90S8515 đang được sử dụng rộng rãi tại Việt Nam. Thiết bị hiển thị dữ liệu : Đối với các loại dữ liệu được hiển thị dưới dạng số thì giải pháp tối ưu là sử dụng các LED 7 thanh do loại thiết bị hiển thị này có giá thành tương đối rẻ. Tuy nhiên, do ứng dụng không chỉ hiển thị chữ số (giá trị nhiệt độ) mà còn phải hiển thị cả các ký tự trong bảng chữ cái, do đó lựa chọn thiết bị hiển thị LCD vì loại thiết bị hiển thị này có khả năng hiển thị cả chữ cái và chữ số một cách rõ nét. Mặc dù so với các loại đèn LED thì LCD có giá thành cao hơn, nhưng bù lại thiết bị hiển thị LCD có nhiều đặc tính ưu việt hơn hẳn so với các loại đèn LED. Đặc biệt, thiết bị LCD cung cấp khả năng hiển thị dữ liệu vô cùng linh hoạt do ta có thể điều khiển xuất dữ liệu một cách trực tiếp thông qua tập lệnh điều khiển của vi mạch điều khiển và bộ mã ký tự sẵn có trong CGRAM của LCD. Một điều cần quan tâm khác là thiết bị LCD tiêu tốn rất ít năng lượng. Trên thị trường hiện nay có khá nhiều module LCD của các hãng khác nhau như Samsung, Hitachi, Motorola... với nhiều loại kích thước. Trong đồ án sử dụng module LCD có kích thước 4x20 characters với 16 chân ghép nối. Không nhất thiết phải chọn hãng cung cấp vì các module LCD đều được xây dựng theo cùng một tiêu chuẩn, do đó cách thức điều khiển và ghép nối các module LCD thông dụng hiện nay cũng tương tự nhau. Thiết bị vào dữ liệu và điều khiển (Keypad) : Để người sử dụng có thể giao tiếp được với hệ thống, cần phải ghép nối mC với một module keypad. Do ứng dụng có thể làm việc với cả chữ cái và chữ số nên ta sử dụng keypad loại 16 keys, trong đó mỗi một phím được thiết kế như một công tắc để có thể nhập được dữ liệu có dạng như sau : 10 chữ số trong hệ thập phân từ 0..9. 26 chữ cái la tinh từ A..Z. Các phím điều khiển bao gồm : Send, Bspace, •, –, —/˜, Clear. Do số ký tự có thể được sử dụng cùng với các phím chức năng lớn hơn rất nhiều so với tổng số phím sẵn có trên module keypad. Vì vậy, bắt buộc phải sử dụng phương pháp Multikey, tức là sử dụng phần mềm để mỗi một phím trên module keypad có thể mã hoá được không ít hơn hai ký tự khác nhau. Bằng cách này, với keypad có 16 phím ta có thể mã hoá được toàn bộ bảng chữ cái và chữ số đồng thời vẫn có thể thực hiện được các chức năng điều khiển như trình bầy ở trên. Giao tiếp giữa mC và PC : Mặc dù hệ thống được thiết kế dựa trên mC AT90S8535 đã có thể làm việc độc lập trong qua trình thu thập, xử lý và hiển thị dữ liệu tới người sử dụng mà không cần có sự trợ giúp của PC. Tuy nhiên, trong hầu hết các ứng dụng đều cần phải lưu trữ lại dữ liệu mà nếu thực hiện việc này dựa trên mC AT90S8535 đòi hỏi rất nhiều kỹ thuật và chi phí. Trong khi đó, thao tác lưu trữ dữ liệu trên PC lại rất đơn giản, vì vậy giải pháp tối ưu nhất là sử dụng PC để làm nhiệm vụ phức tạp này. Vấn đề còn lại chỉ là thao tác truyền dữ liệu cần lưu trữ từ mC sang PC, việc này được thực hiện khá đơn giản vì bản thân mC AT90S8535 đã được tích hợp một bộ UART để sử dụng trong hoạt động truyền tin với các thiết bị ở xa. Như vậy, dựa vào mạch UART của mC ta có thể thực hiện truyền nhận dữ liệu với PC theo chuẩn RS 232. Một vấn đề cần quan tâm khi ghép nối mC với PC theo chuẩn RS 232 là sự tương quan về mặt điện áp tín hiệu dạng TTL của mC và điện áp tín hiệu dạng RS 232 của PC. Để thực hiện việc chuyển đổi tín hiệu dạng TTL sang dạng tín hiệu RS 232 ta sử dụng IC Max232, IC này có nhiệm vụ tạo ra tín hiệu ±10V từ mức điện áp TTL để tạo sự tương thích về mức điện áp với chuẩn RS 232. 1.3.2. Phương hướng thiết kế. Từ sơ đồ tổng thể của hệ thống như trên hình 1.1 và từ việc lựa chọn thiết bị như trình bầy ở trên, hệ thống cần thiết kế có thể được thể hiện như trong sơ đồ hình 1.2, trong đó : Khối LCD display : Sử dụng module LCD sẵn có trên thị trường được ghép nối với mC để hiển thị các thông tin cần thiết cho người sử dụng. Khối Keypad : Được nối ghép với mC để người sử dụng có thể nhập dữ liệu hoặc điều khiển sự hoạt động của hệ thống. Module này được thiết kế dưới dạng các công tắc và sử dụng trực tiếp các đặc tính của các cổng I/O lập trình được của mC để thực hiện mà không cần nguồn hỗ trợ bên ngoài. Khối LM 335 : Là một IC cảm biến nhiệt làm nhiệm vụ biến đổi nhiệt độ môi trường sang dạng điện áp để làm đầu vào cho bộ ADC của mC làm việc. Khối Max 232 : Sử dụng IC Max 232 ghép nối trược tiếp với mC làm nhiệm vụ trao đổi thông tin giữa mC và PC theo chuẩn RS 232. Khối nguồn : Làm nhiệm vụ biến nguồn xoay chiều 220V sang nguồn một chiều ±5V ổn định để cấp nguồn cho các khối khác hoạt động. Hình 1.2 : Sơ đồ khối thiết kế phần cứng Max 232 Nguồn mC + I/O port LM335 Keypad LCD display CHƯƠNG 2 LỰA CHỌN LINH KIỆN THIẾT KẾ VÀ MỘT SỐ LÝ THUYẾT VỀ CHUYỂN ĐỔI A/D 2.1. Lựa chọn linh kiện thiết kế. 2.1.1. Giới thiệu vi mạch điều khiển AT90S8535. AT90S8535 là một vi mạch điều khiển năng lượng thấp 8 bit (công nghệ chíp CMOS) trên cơ sở cấu trúc RICS của hãng ATMEL, nó thuộc họ vi điều khiển AT90S/LS8535. Bằng cách thực hiện mỗi lệnh trong một đơn chu kỳ, AT90S8535 có thể đạt tới 1 MIPS cho mỗi MHz cho phép hệ thống có thể được thiết kế một cách tối ưu nhất sự tiêu thụ năng lượng làm tăng tốc độ xử lý. Về mặt cấu tạo mC này cũng tương tự như mC AT90S8515 với 4 cổng I/O lập trình được, tuy nhiên về mặt chức năng thì mC AT90S8535 được tích hợp thêm nhiều tính năng mới mà mC AT90S8515 không có. Các đặc trưng chính của mC AT90S8535 được trình bầy dưới đây : 8KB bộ nhớ chương trình 512 byte EEPROM 512 byte SRAM 32 line (4 cổng) I/O lập trình được 32 thanh ghi đa năng 8 bit 8 kênh đầu vào ADC riêng biệt với 10 bit kết quả 2 bộ Timer/Counter 8 bit với bộ đếm độc lập và chế độ so sánh 1 bộ Timer/Counter 16 bit với bộ đếm độc lập và các chế độ PWM 1 bộ UART lập trình trao đổi thông tin nối tiếp 1 bộ Watchdog Time lập trình được với bộ tạo giao động trong 1 bộ so sánh analog 1 cổng phối ghép nối tiếp thiết bị ngoại vi SPI 3 chế độ làm việc là : Idle, Power-Save và Power-down Nguồn cung cấp từ 4.0 - 6.0V, tần số làm việc 0 - 8MHz. Vi mạch điều khiển AT90S8535 được chế tạo theo công nghệ chíp nhớ cố định với mật độ cao. Bộ nhớ Flash ISP trên chíp cho phép bộ nhớ chương trình có thể được lập trình lại thông qua một cổng SPI phối ghép nối tiếp với thiết bị ngoại vi. Ngoài ra, mC AT90SS8535 còn hỗ trợ cho việc lập trình thông qua các công cụ pháp triển hệ thống như C, assemblers... Vi điều khiển AT90S8535 có 4 cấu hình chân khác nhau là : PDIP (Có 40 chân), PLCC, TQFP, MLF (Có 44 chân). Sơ đồ chân của mỗi loại như sau. Hình 2.1 : Cấu hình chân của mC AT90S8535 PDIP PLCC TQFP MLF Chức năng các chân của mC AT90S8535 như sau : VCC : Chân cấp nguồn 5V GND : Chân nối đất RESET : Là đầu vào reset. Tín hiệu reset ở bên ngoài sẽ tạo ra bởi mức thấp của trở kháng trên chân Reset. Xung reset dài quá 50ns sẽ tạo ra tín hiệu reset. Xung ngắn hơn sẽ không đảm bảo phát sinh tín hiệu reset. XTAL1 : Là một đầu vào có tác dụng đảo chiều bộ khuếch đại tạo dao động và là đầu vào của mạch điều khiển đồng hồ bên trong. XTAL2 : Là đầu ra của tín hiệu đảo từ bộ khuếch đại tạo dao động AVCC : Là chân cung cấp điện áp cho cổng A và bộ chuyển đổi ADC, nếu ADC không được sử dụng thì chân này phải được nối với nguồn 5V (chân VCC), nếu ADC được sử dụng thì chân này phải được nối tới nguồn 5V qua bộ lọc thông thấp. AREF : Là đầu vào chuẩn của tín hiệu tương tự cho bộ chuyển đổi ADC. Để cho ADC hoạt động được, nguồn sử dụng cho chân này phải có phạm vị từ 2V đến AVCC. AGND : Chân nối đất của tín hiệu analog, nếu bo mạch có một mức nối đất riêng của tín hiệu analog, thì chân này phải được nối tới mức nối đất này. Nếu không có, chân này được nối tới chân GND. Port A (PA7..PA0) : Là một cổng vào ra hai chiều 8 bit. Các chân của cổng có thể cung cấp các trở kháng trong cho phép chọn từng bit. Đệm ra của cổng A có khả năng kéo dòng lên tới 20mA và có thể điều khiển trực tiếp sự hiển thị LED. Khi các chân PA0 đến PA7 được sử dụng như các cổng vào và ở mức thấp, chúng sẽ là đầu vào hiện thời nếu các điện trở trong được kích hoạt. Cổng A cũng có thể được sử dụng như những đầu vào analog để đưa tín hiệu tới bộ bộ chuyển đổi ADC. Các chân của cổng A ở trạng thái không xác định khi reset, ngay cả khi đồng hồ không hoạt động. Port B (PB7..BP0) : Là một cổng vào ra hai chiều 8 bit với các trở kháng trong. Đệm ra của cổng B có khả năng kéo dòng lên tới 20mA. Khi là đầu vào, các chân của cổng B trong trạng thái trở kháng thấp sẽ là đầu vào hiện thời nếu các điện trở trong được kích hoạt. Cổng B là cổng cung cấp các chức năng khác nhau với những đặc tính đặc biệt của mC AT90S8535. Các chân của cổng B ở trạng thái không xác định khi reset, ngay cả khi đồng không hoạt động. Port C (PC0..PC7) : Là một cổng vào ra hai chiều 8 bit với các trở kháng trong. Đệm ra của cổng C có khả năng kéo dòng lên tới 20mA. Khi là đầu vào, các chân của cổng C trong trạng thái trở kháng thấp sẽ là đầu vào hiện thời nếu các điện trở được kích hoạt. Hai chân của cổng C có thể được lựa chọn để sử dụng giống như bộ tạo dao động cho bộ Timer/Counter2. Các chân của cổng C ở trạng thái không xác định khi reset, ngay cả khi đồng không hoạt động. Port D (PD0..PD7) : Là một cổng vào ra hai chiều 8 bit với các trở kháng trong. Đệm ra của cổng C có khả năng kéo dòng lên tới 20mA. Khi là đầu vào, các chân của cổng D trong trạng thái trở kháng thấp sẽ là đầu vào hiện thời nếu các điện trở được kích hoạt. Cổng D cũng cung cấp những chức năng có đặc tính đặc biệt của mC AT90S8535. Các chân của cổng D ở trạng thái không xác định khi reset, ngay cả khi đồng không hoạt động. Hình 2.2 : Sơ đồ khối vi mạch điều khiển AT90S8535 2.1.1.1. Cấu trúc của vi mạch AT90S8535. Vi mạch điều khiển AT90S8535 có những phương thức truy cập nhanh tới tâp thanh ghi đa năng bao gồm 32 thanh ghi 8 bit với thời gian truy cập trong một đơn chu kỳ đồng hồ. Điều này có nghĩa trong một đơn chu kỳ, một thao tác của bộ ALU được thực hiện sẽ lấy hai toán hạng từ hai thanh ghi trong tập thanh ghi, sau khi thao tác được thực hiện và kết qua trả sẽ được lưu trở lại tập thanh ghi trong một chu kỳ đồng hồ. Sáu trong số 32 thanh ghi đa năng này có thể được sử dụng như 3 thanh ghi địa chỉ gián tiếp 16 bit trỏ đến không gian địa chỉ dữ liệu, làm cho phép tính địa chỉ đạt được hiệu quả cao. Một trong 3 con trỏ địa chỉ này cũng được sử dụng giống như con trỏ địa chỉ tới vùng nhớ dữ liệu cố định. Các thanh ghi địa chỉ này là các thanh ghi 16 bit X, Y, Z. Hình 2.3 : Sơ đồ khối kiến trúc của mC AT90S8535 Bộ ALU cung cấp các chức năng tính toán số học và logic giữa các thanh ghi hoặc giữa một hằng số và một thanh ghi. Những thao tác của một thanh ghi đơn cũng được thực hiện trong bộ ALU. Sự hoạt động của ALU được phân chia làm 3 loại chính là số học, logic và các chức năng bit. Ngoài các chức năng của thanh ghi, các chế độ đánh địa chỉ bộ nhớ thông thường cũng có thể được sử dụng trên các tập các thanh ghi. Điều này được thực hiện qua việc tập thanh ghi được gán 32 địa chỉ thấp nhất của không gian địa chỉ dữ liệu ($00..$1F), Cho phép chúng có thể được truy nhập như là là các địa chỉ nhớ bình thường. Không gian vùng nhớ I/O bao gồm 64 địa chỉ ($20..$5F) dành cho các chức năng điều khiển thiết bị ngoại vi của mC như : Các thanh ghi điều khiển, bộ Timer/Couter, bộ chuyển đổi ADC và các chức năng I/O khác. Vùng nhớ I/O có thể được truy nhập trực tiếp hoặc gián tiếp thông qua tập các thanh ghi. mC AT90S8535 sử dụng kiến trúc Harvard - với bộ nhớ và bus độc lập cho chương trình và dữ liệu. Bộ nhớ chương trình được thực hiện với một “pipeline” hai trạng thái. Trong khi một lệnh đang được thực hiện, lệnh tiếp theo được nạp trước từ bộ nhớ chương trình. Cách thức này cho phép các lệnh liên tiếp được thực hiện trong từng đơn chu kỳ đồng hồ. Bộ nhớ chương trình là bộ nhớ Flash cho phép nạp dữ liệu trong hệ thống. Với những lệnh nhẩy và lệnh gọi, toàn bộ không gian địa chỉ 4K được truy nhập trực tiếp. Hầu hết các lệnh của AVR đều có độ dài 16 bit. Mỗi địa chỉ bộ nhớ chương trình bao gồm một lệnh 16 bit hoặc 32 bit. Mỗi một module ngắt có những thanh ghi điều khiển trong không gian I/O với một bit cho phép ngắt chung được đặt trong thanh ghi trạng thái. Mỗi ngắt khác nhau có một vector ngắt độc lập trong bảng vector ngắt ở tại vị trí bắt đầu của bộ nhớ chương trình. Mỗi ngắt khác nhau đều có mức độ ưu tiên tuân theo vị trí vector ngắt của chúng. Địa chỉ của vector ngắt càng thấp, mức độ ưu tiên càng cao. Khi xẩy ra ngắt, một chương trình con phụ vụ ngắt được gọi, địa chỉ trở về PC được đẩy vào ngăn xếp. Vùng nhớ ngăn xếp được cấp phát trong vùng nhớ dữ liệu của SRAM và do đó, dung lượng của ngăn xếp bị giới hạn bởi tổng dung lượng của SRAM và cách sử dụng thông thường của SRAM. Tất cả các chương trình của người sử dụng phải được khởi đầu bằng con trỏ ngăn xếp (SP) trong thủ tục reset (trước khi các chương trình con hoặc các ngắt được thực thi). Con trỏ stack sử dụng 10 bit để truy nhập ghi/đọc trong không gian I/O. 512 byte dữ liệu SRAM có thể được truy cập dễ dàng bởi 5 chế độ địa chỉ khác nhau được cung cấp bởi mC AT90S8535. Hình 2.4 : Bản đồ bộ nhớ của mC AT90S8535 2.1.1.2. Tập thanh ghi đa năng của mC AT90S8535. Tất cả các thanh ghi trong tập thanh ghi của mC AT90S8535 khi thực một hiện lệnh trong tập lệnh đều có thể được truy cập trực tiếp trong một đơn chu kỳ đồng hồ. Ngoại trừ 5 lệnh trực tiếp SBCI, SUBI, CPI, ANDI, ORI giữa một hằng số và một thanh ghi và lệnh LDI sử dụng để nạp tức thì hằng dữ liệu, những lệnh này phải sử dụng các thanh ghi của nửa thứ hai trong tập thanh ghi (từ R16..R31). Các lệnh còn lại đều có thể sử dụng bất kỳ thanh ghi nào trong tập thanh ghi. Hình 2.5 : Địa chỉ 32 thanh ghi đa năng của mC Qua hình 2.5 có thể thấy, mỗi thanh ghi đều được gán một địa chỉ trong không gian địa chỉ dữ liệu, chúng được đặt trong 32 vị trí đầu tiên của không gian dữ liệu sử dụng. Mặc dù không được thực hiện một cách vật lý như trong SRAM, việc tổ chức bộ nhớ này cung cấp sự linh hoạt lớn trong việc truy nhập tới các thanh ghi, như các thanh ghi X, Y, Z có thể được thiết lập để trỏ tới bất kỳ thanh ghi nào trong tập thanh ghi. Các thanh ghi từ R26..R31 được thêm vào một số chức năng nhằm mở rộng khả năng sử dụng của tập thanh ghi. Những thanh ghi này là những con trỏ địa chỉ được sử dụng trong chế độ địa chỉ gián tiếp của không gian dữ liệu. Ba thanh ghi địa chỉ gián tiếp là X, Y, Z được mô tả như trong hình 2.6 : Hình 2.6 : Mô tả các thanh ghi địa chỉ gián tiếp X, Y, Z Trong các chế độ địa chỉ khác nhau, các thanh ghi này có chức năng điều chỉnh linh hoạt đối với từng trường hợp, tự động tăng, giảm hoặc không đổi. 2.1.1.3. Bộ số học và Logic - ALU. Bộ ALU của mC AT90S8535 được nối trực tiếp với 32 thanh ghi đa năng. Trong một đơn chu kỳ đồng hồ, các thao tác của ALU giữa các thanh ghi trong tập thanh ghi được thực hiện và giữa một thanh ghi với một hằng số hoặc trên một đơn thanh ghi. Các hoạt động của ALU được chia làm 3 loại chính là : số học, logic và các phép toán trên bit. 2.1.1.4. Đặc điểm các bộ nhớ trong của mC AT90S8535. Bộ nhớ chương trình (Flash program memory) : Trong mC AT90S8535 chứa đựng 8KB bộ nhớ Flash lập trình được dùng để lưu trữ chương trình. Nó được tổ chức như một bộ nhớ 4Kx16 bit để phù hợp với sự làm việc của các lệnh có độ dài 16 hoặc 32 bit. Bộ nhớ Flash này có thể chịu được ít nhất 1000 chu kỳ ghi/xoá. Vì bộ đếm chương trình (PC) của mC AT90S8535 có độ dài 12 bit, do đó nó có thể mã hoá 4096 địa chỉ trong bộ nhớ chương trình. Bộ nhớ SRAM : 608 vị trí địa chỉ thấp nhất trong vùng nhớ dữ liệu được dùng để địa chỉ hoá cho tập thanh ghi, bộ nhớ I/O và SRAM. 96 vị trí địa chỉ đầu tiên là của tập thanh ghi và bộ nhớ I/O, 512 vị trí địa chỉ tiếp theo là của bộ nhớ SRAM. Một địa chỉ bất kỳ trong trong không gian địa chỉ dữ liệu SRAM đều có thể được xác định thông qua 5 chế độ địa chỉ khác nhau là : trực tiếp, tương đối, gián tiếp, gián tiếp với sự giảm trước và gián tiếp với sự tăng sau. Trong tập thanh ghi, các thanh ghi từ R26 tới R31 được sử dụng như các thanh ghi con trỏ địa chỉ gián tiếp. Ở chế độ địa chỉ trực tiếp có cho phép truy cập tới toàn bộ không gian dữ liệu. Chế độ địa chỉ tương đối cho phép xác định 63 vị trí địa chỉ từ địa chỉ cơ sở cho bởi các thanh ghi Y hoặc Z. Khi sử dụng các chế độ thanh ghi gián tiếp với sự tự động giảm trước hoặc tăng sau, nội dung của các thanh ghi địa chỉ X, Y và Z đều tự động tăng hoặc giảm sau khi thực hiện. 32 thanh ghi đa năng, 64 thanh ghi I/O và 512 byte của bộ nhớ trong SRAM trong AT90S8535, tất cả đều có thể được truy nhập thông qua các chế độ địa chỉ này. Hình 2.7 : Tổ chức bộ nhớ SRAM của mC Bộ nhớ EEPROM : mC AT90S8535 có 512 byte bộ nhớ EEPROM, được tổ chức như một không gian dữ liệu riêng biệt cho phép mỗi byte có thể được ghi/đọc. Bộ nhớ EEPROM có thể thực hiện ít nhất 100.000 chu kỳ ghi/xoá. Sự truy nhập giữa EEPROM và mC được thực hiện thông qua các thanh ghi địa chỉ, thanh ghi dữ liệu và thanh ghi điều khiển của EEPROM, các thanh ghi này có thể được truy cập trong không gian I/O. Thời gian truy cập ghi EEPROM trong phạm vi từ 2.5 đến 4 ms, tuỳ thuộc vào điện áp trên chân VCC. EEPROM có một chức năng tự động tính thời gian cho phép phần mềm của người sử dụng kiểm tra khi byte tiếp theo có thể được ghi/đọc. Một ngắt đặc biệt kiểm tra sự sẵn sàng của EEPROM có thể được thiết lập để kích hoạt khi EEPROM sẵn sàng tiếp nhận dữ liệu mới. Để ngăn cản việc ghi EEPROM ngoài ý muốn, một quy trình ghi cụ thể phải được tuân theo. Khi đọc EEPROM, mC bị tạm dừng trong 4 chu kỳ đồng hồ trước khi lệnh tiếp theo được thực hiện. Khi ghi EEPROM, mC tạm dừng trong 2 chu kỳ đồng hồ trước khi thực hiện lệnh tiếp theo. Thanh ghi địa chỉ EEPROM : EEARH và EEARL Các thanh ghi địa chỉ của EEPROM (EEARH và EEARL) chỉ định địa chỉ của một byte trong không gian 512 byte EEPROM. Các byte dữ liệu của EEPROM được địa chỉ hóa từ 0 đến 511. Thanh ghi dữ liệu EEPROM : EEDR Trong thao tác ghi của EEPROM, thanh ghi EEDR chứa dữ liệu được ghi tới EEPROM theo địa chỉ được xác định bởi thanh ghi EEAR. Trong thao tác đọc EEPROM, thanh ghi EEDR chứa dữ liệu đọc ra từ EEPROM tại địa chỉ cho trong thanh ghi EEAR. Thanh ghi điều khiển EEPROM : EECR Bit 3 - EERIE : Bit cho phép sẵn sàng ngắt của EEPROM Khi bit I trong thanh ghi SREG và bit EERIE được thiết lập, ngắt trạng thái sẵn sàng của EPROM được cho phép. Khi bị xoá ngắt bị vô hiệu hoá. Ngắt trạng thái sẵn sàng EEPROM tạo ra một ngắt cứng khi bit EEWE bị xoá. Bit 2 - EEMWE : Bit cho phép thao tác ghi EEPROM Bit EEMWE xác định có hay không sự thiết lập bit EEWE để gây ra thao tác ghi EEPROM. Khi bit EEMWE được thiết lập, thì sự thiết lập của bit EEWE sẽ ghi dữ liệu vào EEPROM tại địa chỉ đã lựa chọn. Nếu bit EEMWE là 0, thì sự thiết lập của bit EEWE sẽ không có kết quả. Khi bit EEMWE đã được thiết lập bởi phần mềm, phần cứng xoá bit này về 0 sau 4 chu kỳ đồng hồ. Bit 1 - EEWE : Bit cho phép ghi EEPROM Tín hiệu cho phép ghi EEPROM (EEWE) là một xung chọn ghi tới EEPROM. Khi địa chỉ và dữ liệu đã được thiết lập phù hợp, bit EEWE phải được thiết lập để ghi giá trị vào trong EEPROM. Bit EEEMWE phải được thiết lập khi giá trị logic 1 được ghi vào bit EEWE, nếu không thì không xẩy ra thao tác ghi EEPROM. Quy trình dưới đây phải được tuân theo khi ghi EEPROM (thứ tự của bước 2 và 3 không cần quan tâm). 1. Đợi cho đến khi bit EEWE trở về 0 2. Ghi địa chỉ mới của EEPROM tới thanh ghi địa chỉ EEPROM (tuỳ chọn) 3. Ghi dữ liệu mới vào thanh ghi EEDR (tuỳ chọn) 4. Ghi giá trị logic 1 vào bit EEMWE trong thanh ghi EECR (Để có thể ghi giá trị logic 1 vào bit EEMWE, thì bit EEWE phải được ghi là 0 trong cùng một chu kỳ đồng hồ) 5. Trong vòng 4 chu kỳ đồng hồ sau khi thiết lập bit EEMWE, ghi giá trị logic 1 tới bit EEWE. Chú ý : Một ngắt giữa bước 4 và 5 sẽ làm lỗi chu kỳ ghi, vì bit EEMWE sẽ hết thời gian. Nếu một thủ tục ngắt truy xuất tới EEPROM trong khi một ngắt khác cũng đang truy xuất EEPROM, thì nội dung của các thanh ghi EEAR và EEDR sẽ bị thay đổi, gây lỗi ngắt truy xuất EEPROM. Để tránh những vấn đề này cần xoá các cờ ngắt chung trong thời gian thực hiện 4 bước cuối cùng. Khi thời gian truy cập ghi kết thúc (2.5ms và VCC = 5V hoặc 4ms và VCC = 2.7V), bit EEWE được xoá bởi phần cứng, Sử dụng phần mềm có thể thăm dò bít này và đợi nó trở về không trước khi thực hiện ghi byte tiếp theo. Khi bit EEWE đã được thiết lập, mC tạm dừng trong 2 chu kỳ đồng hồ trước khi lệnh tiếp theo được thực hiện. Bit 0 - EERE : Bit cho phép đọc EEPROM Tín hiệu cho phép đọc EEPROM là xung chọn đọc đến EEPROM. Khi địa chỉ phù hợp được thiết lập trong thanh ghi EEAR, bit EERE phải được thiết lập. Khi bit EERE bị xoá bởi phần cứng, dữ liệu yêu cầu được tìm thấy trong thanh ghi EEDR. Sự truy xuất đọc EEPROM cần một lệnh và không cần thăm dò bit EERE. Khi bit EERE đã được thiết lập, mC tạm dừng trong 4 chu kỳ đồng hồ trước khi lệnh tiếp theo được thực hiện. Người sử dụng cần phải thăm dò bit EEWE trước khi bắt đầu thao tác đọc. Nếu dữ liệu hoặc địa chỉ mới được ghi vào các thanh ghi vào/ra của EEPROM khi một thao tác ghi đang diễn ra, thì thao tác ghi sẽ bị ngắt và kết quả không được xác định. 2.1.1.5. Các chế độ địa chỉ của mC AT90S8535. Vi mạch điều khiển AT90S8535 hỗ trợ các chế độ địa chỉ rất mạnh và hiệu quả cao cho việc truy nhập tới bộ nhớ chương trình (bộ nhớ Flash) và bộ nhớ dữ liệu (SRAM, tập thanh ghi và bộ nhớ I/O). Dưới đây là các chế độ địa chỉ của mC AT90S8535 : Địa chỉ trực tiếp một thanh ghi Toán hạng được chứa trong thanh ghi d (Rd) Địa chỉ trực tiếp hai thanh ghi Các toán hạng được chứa trong thanh ghi r (Rr) và d (Rd). Kết quả được lưu trong thanh ghi d (Rd) Địa chỉ I/O trực tiếp Toán hạng địa chỉ chứa trong 6 bit LSB của từ lệnh, n là địa chỉ của thanh ghi nguồn hoặc đích Địa chỉ dữ liệu trực tiếp 16 bit địa chỉ dữ liệu được chứa trong 16 bit LSB của hai từ lệnh. Rd/Rr chỉ rõ thanh ghi nguồn hoặc thanh ghi đích. Địa chỉ dữ liệu tương đối Toán hạng địa chỉ là kết quả của nội dung thanh ghi Y hoặc Z được cộng với địa chỉ chứa trong 6 bit LSB của từ lệnh (a) Địa chỉ dữ liệu gián tiếp Toán hạng địa chỉ là nội dung của thanh ghi X, Y hoặc Z Địa chỉ dữ liệu gián tiếp giảm trước Nội dung các thanh ghi X, Y, Z giảm 1 trước khi thực hiện Toán hạng địa chỉ là nội dung đã giảm của thanh ghi X, Y, Z Địa chỉ dữ liệu gián tiếp tăng sau Thanh ghi X, Y hoặc Z được cộng 1 sau khi thực hiện. Địa chỉ toán hạng là nội dung của thanh ghi X, Y hoặc Z trước khi cộng Địa chỉ cố định khi thực hiện lệnh LPM Địa chỉ byte cố định được xác định bởi nội dung của thanh ghi Z. 15 bit MSB lựa chọn địa chỉ từ (0 – 4K), bit LSB cho phép chọn byte thấp nếu LSB = 0 hoặc byte cao nếu đặt LSB = 1. Địa chỉ gián tiếp trong bộ nhớ chương trình với lệnh IJMP và ICALL Chương trình được tiếp tục thực hiện tại địa chỉ được chứa bởi thanh ghi Z (Bộ đếm chương trình (PC) được nạp với nội dung của thanh ghi Z) Địa chỉ tương đối của bộ nhớ chương trình với lệnh RJMP và RCALL Chương trình được tiếp tục thực hiện tại địa chỉ PC + k + 1 Địa chỉ tương đối k bắt đầu từ - 2048 tới 2047 2.1.1.6. Thời gian truy cập bộ nhớ và thời gian thực hiện lệnh. mC AT90S8535 được điều khiển bởi đồng hồ hệ thống 0, được tạo trực tiếp từ đồng hồ bên ngoài của chip và không sử dụng bộ chia thời gian trong. Hình 2.8 mô tả quá trình tìm và thực hiện lệnh song song theo cấu trúc Harvard và khái niệm tập thanh ghi truy nhập nhanh. Hình 2.8: Quá trình tìm và thực hiện lênh song song Hình 2.9 mô tả khái niệm thời gian thao tác trong của tập thanh ghi. Trong một đơn chu kỳ đồng hồ, một thao tác sử dụng hai toán hạng trong hai thanh ghi của ALU được thực hiện và kết quả được lưu trở lại thanh ghi đích. Hình 2.9: Hoạt động của ALU trong đơn chu kỳ đồng hồ Sự truy nhập vào bộ nhớ SRAM được thực hiện trong hai chu kỳ đồng hồ và được mô tả như hình dưới. Hình 2.10 : Các chu kỳ truy cập bộ nhớ SRAM 2.1.1.7. Không gian bộ nhớ I/O. Bảng 2.1 : Không gian I/O của mC AT90S8535 Địa chỉ I/O (Địa chỉ SRAM) Tên thanh ghi/cổng Chức năng $3F ($5F) SREG Thanh ghi trạng thái $3E ($5E) SPH địa chỉ byte cao của con trỏ Stack $3D ($5D) SPL Địa chỉ byte thấp của con trỏ Stack $3B ($5B) GIMSK Thanh ghi mặt nạ ngắt chung $3A ($5A) GIFR Thanh ghi cờ ngắt chung $39 ($59) TIMSK Thanh ghi mặt nạ ngắt của bộ Timer/Counter $38 ($58) TIFR Thanh ghi cờ ngắt của bộ Timer/Counter $35 ($55) MCUCR Thanh ghi điều khiển chung của MCU $34 ($45) MCUSR Thanh ghi trạng thái chung của MCU $33 ($53) TCCR0 Thanh ghi điều khiển bộ Timer/Counter 0 $32 ($52) TCNT0 8 bit dữ liệu của bộ Timer/Counter 0 $2F ($4F) TCCR1A Thanh ghi điều khiển A của bộ Timer/Counter 1 $2E ($4E) TCCR1B Thanh ghi điều khiển B của bộ Timer/Counter 1 $2D ($4D) TCNT1H Byte cao của bộ Timer/Counter 1 $2C ($4C) TCNT1L Byte thấp của bộ Timer/Counter 1 $2B ($4B) OCR1AH Byte cao của thanh ghi A so với đầu ra của Timer/Counter1 $2A ($4A) OCR1AL Byte thấp của thanh ghi A so với đầu ra của Timer/Counter1 $29 ($49) OCR1BH Byte cao của thanh ghi B so với đầu ra của Timer/Counter1 $28 ($48) OCR1BL Byte thấp của thanh ghi B so với đầu ra của Timer/Counter1 $27 ($47) ICR1H Thanh ghi lưu trữ Byte cao của đầu vào Timer/Counter1 $26 ($46) ICR1L Thanh ghi lưu trữ Byte cao đầu vào của Timer/Counter1 $25 ($45) TCCR2 Thanh ghi điều khiển bộ Timer/Counter 2 $24 ($44) TCNT2 8 bit dữ liệu của bộ Timer/Counter 2 $23 ($43) OCR2 Thanh ghi so với đầu ra của bộ Timer/Counter 2 $22 ($42) ASSR Thanh ghi trạng thái chế độ không đồng bộ $21 ($41) WDTCR Thanh ghi điều khiển mạch kiểm tra tuần tự bộ định thời gian $1F ._.($3E) EEARH Thanh ghi địa chỉ Byte cao của EEPROM $1E ($3E) EEARL Thanh ghi địa chỉ Byte thấp của EEPROM $1D ($3D) EEDR Thanh ghi dữ liệu EEPROM $1C ($3C) EECR Thanh ghi điều khiển EEPROM $1B ($3B) PORTA Thanh ghi dữ liệu, cổng A $1A ($3A) DDRA Thanh ghi điều hướng dữ liệu, cổng A $19 ($39) PINA Các chân vào của cổng A $18 ($38) PORTB Thanh ghi dữ liệu cổng B $17 ($37) DDRB Thanh ghi điều hướng dữ liệu, cổng B $16 ($36) PINB Các chân vào của cổng B $15 ($35) PORTC Thanh ghi dữ liệu cổng C $14 ($34) DDRC Thanh ghi điều hướng dữ liệu, cổng C $13 ($33) PINC Các chân vào của cổng C $12 ($32) PORTD Thanh ghi dữ liệu của cổng D $11 ($31) DDRD Thanh ghi điều hưởng dữ liệu, cổng D $10 ($30) PIND Các chân vào của cổng D $0F ($2F) SPDR Thanh ghi dữ liệu cổng vào/ra của thiết bị ngoại vi $0E ($2E) SPSR Thanh ghi trạng thái của SPI $0D ($2D) SPCR Thanh ghi điều khiển SPI $0C ($2C) UDR Thanh ghi dữ liệu vào/ra của bộ UART $0B ($2B) USR Thanh ghi trạng thái UART $0A ($2A) UCR Thanh ghi điều khiển UART $09 ($29) UBRR Thanh ghi tốc độ baud của UART $08 ($28) ACSR Thanh ghi điều khiển và trạng thái của mạch so sánh Analog $07 ($27) ADMUX Thanh ghi lựa chọn của bộ dồn kênh ADC $06 ($26) ADCSR Thanh ghi điều khiển và trạng thái của bộ ADC $05 ($25) ADCH Thanh ghi dữ liệu byte cao của bộ ADC $04 ($24) ADCL Thanh ghi dữ liệu byte thấp của bộ ADC Tất cả các cổng I/O của mC AT90S8535 và các thiết bị ngoại vi đều được đặt trong gian cổng I/O. Các vị trí cổng I/O được truy nhập bởi lệnh IN và OUT truyền dữ liệu giữa 32 thanh ghi đa năng và không gian I/O. Các thanh ghi I/O có địa chỉ trong phạm vi từ $00 đến $1F có thể được truy nhập trực tiếp tới các bit bằng cách sử dụng các lệnh SBI và CBI. Trong các thanh ghi này, giá trị các bit đơn có thể được kiểm tra bằng cách sử dụng các lệnh SBIS và SBIC. Khi sử dụng các lệnh I/O cụ thể IN và OUT, các địa chỉ I/O từ $00 đến $3F phải được sử dụng. Khi xác định địa chỉ các thanh ghi I/O như địa chỉ của SRAM, phải thêm $20 vào các địa chỉ này. Bảng 2.2 : Vị trí các bit trong các thanh ghi I/O Address Name Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 $3F ($5F) SREG I T H S V N Z C $3E ($5E) SPH - - - - - - SP9 SP8 $3D ($5D) SPL SP7 SP6 SP5 SP4 SP3 SP2 SP1 SP0 $3C ($5C) Res $3B ($5B) GIMSK INT1 INT0 - - - - - - $3A ($5A) GIFR INTF1 INTF0 $39 ($59) TIMSK OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 - TOIE0 $38 ($58) TIFR OCF2 TOV2 ICF1 OCF1A OCF1B TOV1 - TOV0 $37 ($57) Res $36 ($56) Res $35 ($55) MCUCR - SE SM1 SM0 ISC11 ISC10 ISC01 ISC00 $34 ($54) MCUSR - - - - - - EXTRF PORF $33 ($53) TCCR0 - - - - - CS02 CS01 CS00 $32 ($52) TCNT0 Timer/Counter0 (8 Bits) $31 ($51) Res $30 ($50) Res $2F ($4F) TCCR1A COM1A1 COM1A0 COM1B1 COM1B0 - - PWM11 PWM10 $2E ($4E) TCCR1B ICNC1 ICES1 - - CTC1 CS12 CS11 CS10 $2D ($4D) TCNT1H Timer/Counter1 – Counter Register High Byte $2C ($4C) TCNT1L Timer/Counter1 – Counter Register Low Byte $2B ($4B) OCR1AH Timer/Counter1 – Output Compare Register A High Byte $2A ($4A) OCR1AL Timer/Counter1 – Output Compare Register A Low Byte $29 ($49) OCR1BH Timer/Counter1 – Output Compare Register B High Byte $28 ($48) OCR1BL Timer/Counter1 – Output Compare Register B Low Byte $27 ($47) ICR1H Timer/Counter1 – Input Capture Register High Byte $26 ($46) ICR1L Timer/Counter1 – Input Capture Register Low Byte $25 ($45) TCCR2 - PWM2 COM21 COM20 CTC2 CS22 CS21 CS20 $24 ($44) TCNT2 Timer/Counter2 (8 Bits) $23 ($43) OCR2 Timer/Counter2 Output Compare Register $22 ($42) ASSR - - - - AS2 TCN2UB OCR2UB TCR2UB $21 ($41) WDTCR - - - WDTOE WDE WDP2 WDP1 WDP0 $20 ($40) Res $1F ($3F) EEARH EEAR8 $1E ($3E) EEARL EEAR7 EEAR6 EEAR5 EEAR4 EEAR3 EEAR2 EEAR1 EEAR0 $1D ($3D) EEDR EEPROM Data Register $1C ($3C) EECR - - - - EERIE EEMWE EEWE EERE $1B ($3B) PORTA PORTA7 PORTA6 PORTA5 PORTA4 PORTA3 PORTA2 PORTA1 PORTA0 $1A ($3A) DDRA DDA7 DDA6 DDA5 DDA4 DDA3 DDA2 DDA1 DDA0 $19 ($39) PINA PINA7 PINA6 PINA5 PINA4 PINA3 PINA2 PINA1 PINA0 $18 ($38) PORTB PORTB7 PORTB6 PORTB5 PORTB4 PORTB3 PORTB2 PORTB1 PORTB0 $17 ($37) DDRB DDB7 DDB6 DDB5 DDB4 DDB3 DDB2 DDB1 DDB0 $16 ($36) PINB PINB7 PINB6 PINB5 PINB4 PINB3 PINB2 PINB1 PINB0 $15 ($35) PORTC PORTC7 PORTC6 PORTC5 PORTC4 PORTC3 PORTC2 PORTC1 PORTC0 $14 ($34) DDRC DDC7 DDC6 DDC5 DDC4 DDC3 DDC2 DDC1 DDC0 $13 ($33) PINC PINC7 PINC6 PINC5 PINC4 PINC3 PINC2 PINC1 PINC0 $12 ($32) PORTD PORTD7 PORTD6 PORTD5 PORTD4 PORTD3 PORTD2 PORTD1 PORTD0 $11 ($31) DDRD DDD7 DDD6 DDD5 DDD4 DDD3 DDD2 DDD1 DDD0 $10 ($30) PIND PIND7 PIND6 PIND5 PIND4 PIND3 PIND2 PIND1 PIND0 $0F ($2F) SPDR SPI Data Register $0E ($2E) SPSR SPIF WCOL - - - - - - $0D ($2D) SPCR SPIE SPE DORD MSTR CPOL CPHA SPR1 SPR0 $0C ($2C) UDR UART I/O Data Register $0B ($2B) USR RXC TXC UDRE FE OR - - - $0A ($2A) UCR RXCIE TXCIE UDRIE RXEN TXEN CHR9 RXB8 TXB8 $09 ($29) UBRR UART Baud Rate Register $08 ($28) ACSR ACD - ACO ACI ACIE ACIC ACIS1 ACIS0 $07 ($27) ADMUX - - - - - MUX2 MUX1 MUX0 $06 ($26) ADCSR ADEN ADSC ADFR ADIF ADIE ADPS2 ADPS1 ADPS0 $05 ($25) ADCH - - - - - - ADC9 ADC8 $04 ($24) ADCL ADC7 ADC6 ADC5 ADC4 ADC3 ADC2 ADC1 ADC0 $03 ($20) Res $02 ($22) Res $01 ($21) Res $00 ($20) Res Res : Reserved Một vài bit cờ trạng thái có thể được xoá bằng cách ghi trị 1 vào vị trí của nó. Chú ý đối với các lệnh CBI và SBI sẽ có tác dụng trên tất cả các bit trong thanh ghi I/O và thao tác ghi lại 1 vào bất kỳ cờ nào đã được thiết lập đồng nghĩa với việc xoá cờ đó. Tuy nhiên, các lệnh CBI và SBI chỉ làm việc với các thanh ghi có địa chỉ từ $00 đến $1F. Chức năng của mỗi bit trong các thanh ghi sẽ được giới thiệu trong từng phần có liên quan, dưới đây là hai thanh ghi chính của vi mạch điều khiển AT90S8535. Thanh ghi trạng thái mC : SREG Thanh ghi trạng thái (Status register) của mC AT90S8535 có địa chỉ tại vị trí $3F ($5F) trong không gian I/O được định nghĩa như sau : Bit 7 - I : Bit cho phép ngắt chung (Global Interrupt Enable) Bit cho phép ngắt chung phải được thiết lập để cho phép các ngắt. Sau đó, mỗi sự điều khiển ngắt cho phép riêng được thực hiện trong các thanh ghi điều khiển độc lập. Nếu bit cho phép ngắt chung bị xoá, thì không có ngắt nào được cho phép. Bit I được xoá bởi phần cứng sau khi một ngắt xảy ra và được thiết đặt bởi lệnh RETI để cho phép các ngắt tiếp theo. Bit 6 - T : Bit lưu trữ sao chép (Bit Copy Storage) Các lệnh sao chép bit BLD (BitLoaD) và BST (BitSTore) sử dụng bit T như là nguồn hoặc đích cho thao tác bit. Một bit của một thanh ghi trong tập thanh ghi có thể sao chép vào trong bit T bằng lệnh BST và một bit trong T có thể được sao chép vào một bit trong thanh ghi của tập thanh ghi bởi lệnh BLD. Bit 5 - H : Bit cờ nhớ phụ (Half-carry Flag) Cờ nhớ phụ H xác định số nhớ trong một số thao tác số học. Bit 4 - S : Bit dấu (Sign Bit, S = N Å V) Bit dấu S luôn là một phép logic NAND giữa cờ phủ định N và cờ tràn số bù hai V. Bit 3 - V : Bit cờ tràn bù hai (Two’s Complement Oveflow Flag) Cờ tràn số bù hai V hỗ trợ cho phép tính số bù hai. Bit 2 - N : Bit cờ phủ định (Negative Flag) Cờ phủ định N cho biết một kết quả âm từ một phép tính số học hoặc logic. Bit 1 - Z : Bit cờ Zero (Zero Flag) Cờ Zero Z cho biết một kết quả bằng không từ một phép tính số hoặc logic. Bit 0 - C : Bit cờ nhớ (Carry Flag) Cờ carry C xác định số nhớ trong một phép tính số hoặc logic. Chú ý : Thanh ghi trạng thái không tự động được lưu và khôi phục khi tham gia vào một thủ tục ngắt hoặc khi trở về từ một thủ tục ngắt. Do đó, nó phải được thực hiện bởi phần mềm. Thanh ghi con trỏ ngăn xếp : SP Con trỏ ngăn xếp của mC AT90S8535 được thực hiện như hai thanh ghi 8 bit ở địa chỉ $3E($5E) và $3D($5D) trong không gian I/O. Do bộ nhớ SRAM của AT90S8535 có $25F địa chỉ, do đó con trỏ SP cần sử dụng 10 bit để xác định các vị trí địa chỉ cần thiết. Con trỏ ngăn xếp SP trỏ tới vùng dữ liệu ngăn xếp trong SRAM nơi mà một chương trình con phuc vụ ngắt và ngắt được định vị. Không gian ngăn xếp trong vùng dữ liệu SRAM phải được khai báo trong chương trình trước bất kỳ lời gọi chương trình con nào được thực hiện hoặc bất kỳ ngắt nào được cho phép. Con trỏ ngăn xếp phải được thiết đặt ở những địa chỉ lớn hơn $60. SP giảm đi 1 byte khi dữ liệu được đẩy vào Stack bởi lệnh PUSH và nó giảm đi 2 byte khi một địa chỉ được đẩy vào Stack trong lời gọi chương trình con hoặc ngắt. SP được tăng lên 1 byte khi dữ liệu được lấy ra khỏi Stack với lệnh POP và nó được tăng 2 byte khi một địa chỉ được lấy ra từ Stack với lệnh trở về từ chương trình con RET hoặc lệnh trở về từ một ngắt RETI. 2.1.1.8. Ngắt và xử lý ngắt trong mC AT90S8535. mC AT90S8535 cung cấp 16 nguồn gây ngắt khác nhau và một ngắt Reset. Các ngắt này và ngắt Reset có một vector chương trình độc lập trong không gian bộ nhớ chương trình. Tất cả các ngắt được gán với các bit cho phép ngắt riêng và phải được thiết lập cùng với bit I trong thanh ghi SREG để cho phép ngắt xảy ra. Vị trí địa chỉ thấp nhất trong không gian bộ nhớ chương trình được tự động định nghĩa là địa chỉ của vector Reset, tiếp theo đó là địa chỉ của các vector ngắt khác. Danh sách đầy đủ của các vector ngắt được thể hiện trong bảng 2.3, bảng này cũng cho biết các cấp độ ưu tiên của các ngắt tuỳ theo vị trí địa chỉ của vector ngắt của nó theo nguyên tắc, địa chỉ càng thấp thì mức độ ưu tiên càng cao. RESET có mức ưu tiên cao nhất, tiếp theo là INT0 v.v... Bảng 2.3 : Địa chỉ của các vector ngắt trong mC AT90S8535 TT Địa chỉ vector ngắt Nguồn gây ngắt Định nghĩa ngắt 1 $000 RESET Reset và khởi động lại mạch Watchdog 2 $001 INT0 Yêu cầu ngắt từ bên ngoài cấp 0 3 $002 INT1 Yêu cầu ngắt từ bên ngoài cấp 1 4 $003 TIMER2 COMP Ngắt thích ứng so sánh của T/C 2 5 $004 TIMER2 OVF Ngắt tràn của T/C 2 6 $005 TIMER1 CAPT Ngắt lưu giữ sự kiện của T/C 1 7 $006 TIMER1 COMPA Ngắt thích ứng so sánh A của T/C 1 8 $007 TIMER1 COMPB Ngắt thích ứng so sánh B của T/C 1 9 $008 TIMER1 OVF Ngắt tràn của T/C 1 10 $009 TIMER0 OVF Ngắt tràn của T/C 0 11 $00A SPI, STC Ngắt kết thúc truyền nối tiếp qua SPI 12 $00B UART, RX Ngắt kết thúc nhận dữ liệu của UART 13 $00C UART, UDRE Ngắt báo thanh ghi dữ liệu của UART rỗng 14 $00D UART, TX Ngắt hoàn thành truyền dữ liệu qua UART 15 $00E ADC Ngắt hoàn thành chuyển đổi ADC 16 $00F EE_RDY Ngắt báo EEPROM đã sẵn sàng R/W 17 $010 ANA_COMP Ngắt so sánh độ dài tín hiệu Analog Một chương trình bình thường có thể thiết lập cho các địa chỉ của vector Reset và các vector ngắt khác như sau : Địa chỉ Lệnh Nhãn/toán hạng Giải thích $000 rjmp RESET ;Điều khiển Reset $001 rjmp EXT_INT0 ;Điều khiển IRQ0 $002 rjmp EXT_INT1 ;Điều khiển IRQ1 $003 rjmp TIM2_COMP ;Điều khiển so sánh Timer2 $004 rjmp TIM2_OVF ;Điều khiển tràn Timer2 $005 rjmp TIM1_CAPT ;Điều khiển bắt sự kiện Timer1 $006 rjmp TIM1_COMPA ;Điều khiển so sánh A của Timer1 $007 rjmp TIM1_COMPB ;Điều khiển so sánh B của Timer1 $008 rjmp TIM1_OVF ;Điều khiển tràn Timer1 $009 rjmp TIM0_OVF ;Điều khiển tràn Timer0 $00a rjmp SPI_STC ;Điều khiển kết thúc truyền dữ liệu qua SPI $00b rjmp UART_RXC ;Điều khiển kết thúc UART RX $00c rjmp UART_DRE ;Điều khiển thông báo hết dữ liệu trong UDR $00d rjmp UART_TXC ;Điều khiển kết thúc UART TX $00e rjmp ADC ;Ngắt thông báo kết thúc chuyển đổi ADC $00f rjmp EE_RDY ;EEPROM sẵn sàng $010 rjmp ANA_COMP ;Điều khiển bộ so sánh tín hiệu tương tự $011 MAIN: ldi r16, high(RAMEND) ;Bắt đầu chương trình chính $012 out SPH,r16 $013 ldi r16, low(RAMEND) $014 out SPL,r16 $015 xxx ... .... .... Các nguồn Reset của mC AT90S8535. mC AT90S8535 có 3 nguồn Reset khác nhau là : Power-on Reset (Reset khi nguồn bật), Reset ngoài và Watchdog Reset. Power-on Reset : MCU được thiết lập lại khi điện áp cung cấp thấp hơn ngưỡng điện áp Power-on Reset (VPOT). Reset ngoài : MCU được thiết lập lại khi một mức điện áp thấp xuất hiện trên chân RESET trong khoảng thời gian lớn hơn 50ns. Watchdog Reset : MCU được thiết lập lại khi chu kỳ của mạch Wachdog timer kết thúc và mạch Wachdog được cho phép. Trong thời gian Reset, tất cả các thanh ghi I/O được thiết lập lại với giá trị khởi tạo và sự thực hiện chương trình được bắt đầu từ địa chỉ $000. Lệnh đặt trong địa chỉ $000 phải là lệnh RJMP (lệnh nhảy quan hệ) để thi hành thủ tục Reset. Nếu một chương trình không cho phép bất một ngắt nào, thì các vector ngắt sẽ không được sử dụng và đoạn mã của chương trình có thể được đặt tại các vị trí này. Thông tin về bất cứ nguồn Reset nào gây ra sự thiết lập lại MCU được thể hiện đầy đủ trong các bit của thanh ghi trạng thái MCU - MCUSR. Thanh ghi trạng thái MCU : MCUSR Bit 7... 2 : Ressered bits Bit 1 - EXTRF : Bit cờ Reset từ bên ngoài (EXTernal Reset Flag) Sau một tín hiệu Reset Power-on, bit này không được xác định (X). Nó chỉ có thể được thiết lập bởi một tín hiệu reset từ bên ngoài. Một tín hiệu Reset Watchdog sẽ không thay đổi giá trị của bit này. Bit này được xoá bằng cách ghi giá trị logic 0 vào bit. Bit 0 - PORF : Bit cờ Reset Power-on (Power-On Reset Flag) Bit này chỉ được thiết lập bởi một tín hiệu Reset Power-on. Một tín hiệu Reset Watchdog hoặc tín hiệu Reset từ bên ngoài sẽ không làm thay đổi giá trị của bit này. Bit được xoá bằng cách ghi giá trị 0 vào bit. Bảng 2. 4 : Giá trị của các bit EXTRF và PORF sau Reset Nguồn Reset EXTRF PORF Power-on Reset Không thay đổi 1 External Reset 1 Không thay đổi Watchdog Reset Không thay đổi Không thay đổi Có thể sử dụng các giá trị của các bít này để xác định một điều kiện gây ra Reset. Đối với phần mềm cần phải xoá cả hai bit PORF và EXTRF càng sớm càng tốt trong chương trình. Kiểm tra giá trị của các bit PORF và EXTR trước khi các bit được xoá. Nếu bit được xoá trước khi xuất hiện một tín hiệu Reset từ bên ngoài hoặc của Watchdog, thì nguồn gốc của ngắt có thể được tìm thấy bằng cách sử dụng bảng 2.5. Bảng 2.5 : Xác định nguồn Reset EXTRF PORF Nguồn Reset 0 0 Watchdog Reset 0 1 Power-on Reset 1 0 External Reset 1 1 Power-on Reset Xử lý ngắt của mC AT90S8535 Vi mạch điều khiển AT90S8535 có hai thanh ghi điều khiển mặt nạ ngắt 8 bit là : Thanh ghi mặt nạ ngắt chung - GIMSK (General Interrupt Mask register) và thanh ghi mặt nạ ngắt của các mạch Timer/Counter – TISMK (Timer/Counter Interrupt Mask register). Khi xẩy ra một ngắt, bit cho phép ngắt chung I bị xoá và tất cả các ngắt bị cấm. Sử dụng phần mềm có thể thiết lập cho bit I để cho phép các ngắt đang bị che. Bit I được lập sau khi thực hiện lệnh trở về từ ngắt - RETI. Khi bộ đếm chương trình PC trỏ tới một vector ngắt hiện tại để thực hiện chương trình con phục vu ngắt, phần cứng sẽ xoá cờ ngắt tương ứng với ngắt pháp sinh. Một vài cờ ngắt cũng có thể được xoá bằng cách ghi giá trị logic 1 vào vị trí bit cờ đó. Nếu một điều khiện ngắt xẩy ra khi bit cho phép ngắt tương ứng bị xoá, thì cờ ngắt sẽ được thiết lập và được nhớ cho đến khi ngắt đó được cho phép hoặc cờ được xoá bởi phần mềm. Nếu một hoặc nhiều điều kiện ngắt xẩy ra khi bit cho phép ngắt chung bị xoá, các cờ ngắt tương ứng sẽ được thiết lập và được nhớ cho đến khi bit cho phép ngắt chung được thiết lập và các ngắt sẽ được thực hiện tuỳ theo cấp ưu tiên của mỗi ngắt. Chú ý : Mức ngắt ngoài không có cờ và sẽ chỉ được nhớ lâu bằng điều kiện ngắt tích cực. Ngoài ra, thanh ghi trạng thái SREG sẽ không tự động lưu lại khi tham gia một ngắt và khôi phụ lại khi trở về từ chương trình con phục vụ ngắt, do đó nó phải được điều khiển bằng phần mềm. Các thanh ghi điều khiển ngắt của mC AT90S8535 Thanh ghi mặt nạ ngắt chung : GIMSK (General Interrupt Mask) Bit 7 - INT1 : Bit cho phép ngắt ngoài mức 1 (External Interrupt Request 1 Enable) Khi bit INT1 được thiết lập và bit I trong thanh ghi trạng thái SREG được thiết lập, thì chân yêu cầu ngắt mức 1 từ bên ngoài được cho phép. Các bit ISC11 và ISC10 trong thanh ghi điều khiển chung MCUCR sẽ xác định ngắt từ bên ngoài được kích hoạt theo sườn lên hay sườn xuống hoặc theo mức nhận biết của tín hiệu trên chân INT1. Sự kích hoạt trên chân này sẽ gây ra một yêu cầu ngắt cho dù chân INT1 được cấu hình như một đầu ra. Ngắt tương ứng của một yêu cầu ngắt ngoài mức 1 được thực hiện từ địa chỉ $002 trong bộ nhớ chương trình. Bit 6 - INT0 : Bit cho phép ngắt ngoài mức 0 (External Interrupt Request 0 Enable) Khi bit INT0 và bit I trong thanh ghi trạng thái SREG được thiết lập, thì chân yêu cầu ngắt mức 0 từ bên ngoài được cho phép. Các bit ISC01 và ISC00 trong thanh ghi điều khiển chung MCUCR sẽ xác định ngắt từ bên ngoài được kích hoạt theo sườn lên hay sườn xuống hoặc theo mức nhận biết của tín hiệu trên chân INT0. Sự kích hoạt trên chân này sẽ gây ra một yêu cầu ngắt cho dù chân INT0 được cấu hình như một đầu ra. Ngắt tương ứng của một yêu cầu ngắt ngoài mức 0 được thực hiện từ địa chỉ $001 trong bộ nhớ chương trình. Bit 5 .. 0 : Reserved bits. Thanh ghi cờ ngắt chung : GIFR (General Interrupt Flag Register) Bit 7- INTF1 : Bit cờ ngắt ngoài mức 1 (External Interrupt Flag 1) Khi một tín hiệu theo sườn hoặc một sự thay đổi mức logic trên chân INT1 sẽ gây ra một yêu cầu ngắt, bit INTF1 được thiếp lập. Cờ này luôn được xoá khi chân này được thiết lập cho các ngắt có mức yêu tiên thấp, do đó trạng thái của một ngắt có mức ưu tiên thấp có thể được xác định bằng cách đọc bit này. Nếu bit I trong thanh ghi trạng thái SREG và bit INT1 trong thanh ghi mặt nạ ngắt chung GIMSK được thiết lập, MCU sẽ nhẩy tới địa chỉ ngắt $002. Do ngắt được tác động bởi tín hiệu sườn và sự thay đổi mức logic, cờ này được xoá khi thủ tục ngắt được thực hiện, nó cũng có thể được xoá bởi việc ghi giá trị logic 1 vào vị trí của cờ. Bit 6 - INTF0 : Bit cờ ngắt ngoài mức 0 (External Interrupt Flag 0) Khi một tín hiệu sườn hoặc một sự thay đổi logic trên chân INT0 gây ra một yêu cầu ngắt, bit INTF0 được thiếp lập. Cờ này luôn được xoá (0) khi chân này được đặt cấu hình cho các ngắt có mức ưu tiên thấp, như vậy trạng thái của một ngắt có mức ưu tiên thấp có thể được xác định bằng cách đọc bit này. Nếu bit I trong thanh ghi trạng thái SREG và bit INT1 trong thanh ghi mặt nạ ngắt chung GIMSK được thiết lập, MCU sẽ nhẩy tới địa chỉ ngắt $001. Do ngắt được tác động bởi tín hiệu sườn và sự thay đổi mức logic, cờ này được xoá khi thủ tục ngắt được thực hiện, nó cũng có thể được xoá bởi việc ghi giá trị logic 1 vào vị trí của cờ. Thanh ghi mặt nạ ngắt của các bộ Timer/Counter : TIMSK Bit 7 - OCIE2 : Bit cho phép ngắt so sánh bằng T/C2 (Timer/Counter2 Output Compare Match Interrupt Enable) Khi bit OCIE2 được thiết lập và bit I trong thanh ghi trạng thái (SREG) được thiết lập, ngắt so sánh bằng T/C2 được cho phép. Ngắt tương ứng tại địa chỉ $003 được thực hiện nếu xuất hiện một tín hiệu so sánh bằng trong T/C2 (tức là, khi bit OFC2 được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 6 - TOIE2 : Bit cho phép ngắt tràn T/C2 (Timer/Counter2 Overflow Interrupt Enable) Khi bit TOIE2 được thiết lập và bit I trong thanh ghi trạng thái (SREG) được thiết lập, ngắt tràn T/C2 được cho phép. Ngắt tương ứng tại địa chỉ $004 được thực hiện nếu xuất hiện một tín hiệu tràn trong T/C2 (tức là, khi bit TOV2 được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 5 - TICIE1 : Bit cho phép ngắt bắt sự kiện vào của T/C1 (Timer/Counter1 Input Capture Interrup Enable) Khi bit TICIE1 được thiết lập và bit I trong thanh ghi trạng thái (SREG) được thiết lập, ngắt bắt sự kiện vào của T/C1 được cho phép. Ngắt tương ứng tại đại chỉ $005 được thực hiện nếu xuất hiện một sự kiện gây ra sự bắt tín hiệu trên chân 20, PD6 (ICP) (tức là, khi bit ICF1 được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 4 - OCIE1A : Bit cho phép ngắt so sánh bằng A của T/C1 (Timer/Counter1 Output CompareA Match Interrupt Enable) Khi bit OCIE1A được thiết lập và bit I trong thanh ghi trạng thái được thiết lập, ngắt so sánh bằng A của T/C1 được cho phép. Ngắt tương ứng tại đại chỉ $006 được thực hiện nếu xuất hiện một tín hiệu so sánh bằng A trong T/C1. (tức là, khi bit OCF1A được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 3 - OCIE1A : Bit cho phép ngắt so sánh bằng B của T/C1 (Timer/Counter1 Output CompareB Match Interrupt Enable) Khi bit OCIE1B được thiết lập và bit I trong thanh ghi trạng thái được thiết lập, ngắt so sánh bằng B của T/C1 được cho phép. Ngắt tương ứng tại địa chỉ $007 được thực hiện nếu xuất hiện một tín hiệu so sánh bằnh B trong T/C1. (tức là, khi bit OCF1B được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 2 - TOIE1 : Bit cho phép ngắt tràn của T/C1 (Timer/Counter1 Overflow Interrupt Enable) Khi bit TOIE1 được thiết lập và bit I trong thanh ghi trạng thái (SREG) được thiết lập, ngắt tràn T/C1 được cho phép. Ngắt tương ứng tại đại chỉ $008 được thực hiện nếu xuất hiện một tín hiệu tràn trong T/C1 (tức là, khi bit TOV1 được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Bit 1: Không sử dụng Bit 0 - TOIE0 : Bit cho phép ngắt tràn của T/C0 (Timer/Counter0 Overflow Interrupt Enable) Khi bit TOIE0 được thiết lập và bit I trong thanh ghi trạng thái (SREG) được thiết lập, ngắt tràn T/C0 được cho phép. Ngắt tương ứng tại đại chỉ $009 được thực hiện nếu xuất hiện một tín hiệu tràn trong T/C0 (tức là, khi bit TOV0 được thiết lập trong thanh ghi cờ ngắt T/C [TIFR]). Thanh ghi cờ ngắt của các bộ Timer/Counter : TIFR (Timer/Counter Interrupt Flag) Bit 7 - OFC2 : Bit cờ so sánh đầu ra của T/C2 (Output compare Flag2) Bit OCF2 được thiết lập khi xuất hiện tín hiệu so sánh bằng giữa bộ T/C2 và dữ liệu trong OCR2 (Thanh ghi so sánh đầu ra của T/C 2). OCF2 được xoá bằng phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Bit OCF2 có thể được xoá bằng cách ghi giá trị logic 1 vào cờ này. Khi bit I trong thanh ghi trạng thái SREG và bit OCIE (T/C2 compare Match Interupt Enable) và bit OCF2 được thiết lập, ngắt thích ứng so sánh của T/C2 được thực hiện. Bit 6 - TOV2 : Bit cờ tràn của T/C2 (Timer/Counter2 Overflow Flag) Bit TOV2 được thiết lập khi xuất hiện một tín hiệu tràn trong T/C2. Bit TOV2 được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Một cách khác, bit TOV2 có thể được xoá bằng cách ghi giá trị 1 vào bit cờ này. Khi bit I trong thanh ghi trạng thái SREG và bit TOIE2 (T/C2 Overflow Interupt Enable) và bit TOV2 được thiết lập, ngắt tràn của T/C2 được thực hiện. Trong chế độ PWM, bit này được thiết lập khi bộ T/C1 bắt đầu đếm từ giá trị $0000 Bit 5 - ICF1 : Cờ bắt tín hiệu vào T/C1 (Input Capture Flag1) Bit ICF1 được thiết lập để dựng cờ cho phép lưu giữ một sự kiện đầu vào, và cho biết giá trị của T/C1 đã được chuyển đến thanh ghi bắt tín hiệu vào (ICR1). Bit ICF1 được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Một cách khác, bit ICF1 có thể được xoá bằng cách ghi giá trị 1 vào bit cờ này. Khi bit I trong thanh ghi trạng thái SREG, bit TICIE1 (Timer/Counter1 Input Capture Interrupt Enable) và bit ICF1 được thiết lập, ngắt bắt lưu giữ đầu vào T/C1 được thực hiện. Bit 4 - OCF1A : Bit cờ so sánh A đầu ra của T/C1 (Output Compare Flag 1A) Bit OCF1A được thiết lập khi xuất hiện tín hiệu so sánh bằng giữa T/C1 và dữ liệu trong OCR1A (Output Compare Register 1A). Bit OCF1A được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Cũng có thể xoá bit OCF1A bằng cách ghi giá trị 1 vào vị trí cờ này. Khi bit I trong thanh ghi trạng thái SREG, bit OCIE1A (Timer/Counter1 Compare Match InterruptA Enable) và bit OCF1A được thiết lập, ngắt so sánh bằng A của T/C1 được thực hiện. Bit 3 - OCF1B : Bit cờ so sánh B đầu ra của T/C1 (Output Compare Flag 1B) Bit OCF1B được thiết lập khi xuất hiện tín hiệu so sánh bằng giữa T/C1 và dữ liệu trong OCR1B (Output Compare Register 1B). Bit OCF1B được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Cũng có thể xoá bit OCF1B bằng cách ghi giá trị 1 vào vị trí cờ này. Khi bit I trong thanh ghi trạng thái SREG, bit OCIE1B (Timer/Counter1 Compare Match InterruptB Enable) và bit OCF1B được thiết lập, ngắt thích ứng so sánh B của T/C1 được thực hiện. Bit 2 - TOV1 : Bit cờ tràn của T/C1 (Timer/Counter1 Overflow Flag) Bit TOV1 được thiết lập khi xuất hiện một tín hiệu tràn trong T/C1. Bit TOV1 được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Một cách khác, bit TOV1 có thể được xoá bằng cách ghi giá trị 1 vào bit cờ này. Khi bit I trong thanh ghi trạng thái SREG, bit TOIE1 (Timer/Counter1 Overflow Interrupt Enable) và bit TOV1 được thiết lập, ngắt tràn của T/C1 được thực hiện. Trong chế độ PWM, bit này được thiết lập khi bộ T/C1 bắt đầu đếm từ giá trị $0000. Bit 1 : Không sử dụng Bit 0 - TOV0 : Bit cờ tràn T/C0 (Timer/Counter0 Overflow Flag) Bit TOV0 được thiết lập khi xuất hiện một tín hiệu tràn trong T/C0. Bit TOV0 được xoá bởi phần cứng khi thực hiện chương trình điều khiển vector ngắt tương ứng. Một cách khác, bit TOV0 có thể được xoá bằng cách ghi giá trị 1 vào bit cờ này. Khi bit I trong thanh ghi trạng thái SREG, bit TOIE0 (Timer/Counter0 Overflow Interrupt Enable) và bit TOV0 được thiết lập, ngắt tràn của T/C0 được thực hiện. Trong chế độ PWM, bit này được thiết lập khi bộ T/C1 bắt đầu đếm từ giá trị $0000. Các ngắt ngoài của mC AT90S8535 Các ngắt ngoài của mC AT90S8535 được gây ra bởi sự thay đổi tín hiệu trên các chân INT1 và INT0. Có thể thấy rằng, nếu được cho phép các ngắt ngoài sẽ xảy ra cho dù các chân INT1/INT0 được thiết lập như là các đầu ra. Đặc điểm này cung cấp một cách tạo ra ngắt bằng phần mền. Các ngắt ngoài có thể được tạo ra khi xuất hiện sườn xuống hoặc sườn lên hay mức thấp của tín hiệu. Khi ngắt ngoài được cho phép và được thiết lập điều kiện kích hoạt theo mức, ngắt sẽ xảy ra trong khoảng thời gian chân được giữ ở mức thấp. Các ngắt ngoài được thiết lập như mô tả trong thanh ghi điều khiển MCU (MCUCR). Thanh ghi điều khiển MCU : MCUCR (MCU Control Register) Thanh ghi MCUCR chứa các bit điều khiển dành cho các chức năng chung của MCU. Bit 7 : Không sử dụng. Bit 6 - SE : Bit cho phép nghỉ (Sleep Enable) Bit SE phải được thiết lập để đưa MCU vào chế độ nghỉ khi lệnh SLEEP được thực hiện. Để tránh đưa MCU vào chế độ nghỉ ngoài ý muốn, chỉ nên thiết lập bit SE trước khi thực hiện lệnh SLEEP. Bit 4,5 - SM1/SM0 : Các bit chọn chế độ nghỉ (Sleep Mode Select Bits 0 and 1) Các bit này cho phép chọn người lập trình chọn một trong 3 chế độ nghỉ có sẵn của mC AT90S8535 như trong bảng 2.6. Bảng 2.6 : Lựa chọn các chế độ nghỉ của mCAT90S8535 SM1 SM0 Sleep Mode 0 0 Idle 0 1 Không sử dụng 1 0 Power - down 1 1 Power - Save Bit 3,2 - ISC11,ISC10 : Các bit điều khiển nhận biết ngắt mức 1 (Interrupt Sense Control 1 Bits 1 and 0) Ngắt ngoài mức 1 được kích hoạt bởi chân yêu cầu ngắt ngoài INT1 nếu bit I trong thanh ghi trạng thái SREG và mặt nạ ngắt tương ứng trong thanh ghi mặt nạ ngắt GIMSK được thiết lập. Các sườn và mức kích hoạt ngắt trên chân yêu cầu ngắt ngoài INT1 được định nghĩa trong bảng 2.7. Bảng 2.7 : Điều khiển nhận biết ngắt ngoài mức 1 ISC11 ISC10 Mô tả 0 0 Mức thấp trên chân INT1 phát sinh một yêu cầu ngắt 0 1 Dự trữ (Reserved) 1 0 Yêu cầu phát sinh ngắt trên chân INT1 theo sườn xuống 1 1 Yêu cầu ngắt phát sinh trên chân INT1 theo sườn lên Giá trị trên chân INT được lấy mẫu trước khi kiểm tra các sườn. Nếu yêu cầu ngắt tác động theo sườn được lựa chọn, thì những xung cuối cùng kéo dài hơn một chu kỳ đồng hồ CPU sẽ phát sinh một ngắt. Xung ngắn sẽ không đảm bảo phát sinh ngắt. Nếu yêu cầu ngắt tác dộng theo mức thấp được lựa chọn, thì mức thấp phải được giữ cho đến khi hoàn thành lệnh đang thực hiện mới gây ra yêu cầu ngắt. Nếu được cho phép, một ngắt tác động theo mức sẽ phát sinh một yêu cầu ngắt trong khoảng thời gian chân INT1 được giữ ở mức thấp. Bit 1,0 - ISCO1,ISCO0 : Các bit điều khiển nhận biết ngắt mức 0 (Interrupt Sense Control 1 Bits 1 and 0) Ngắt ngoài mức 0 được kích hoạt bởi chân yêu cầu ngắt ngoài INT0 nếu bit I trong thanh ghi trạng thái SREG và mặt nạ ngắt tương ứng trong thanh ghi mặt nạ ngắt GIMSK được thiết lập. Các sườn và mức kích hoạt ngắt trên chân yêu cầu ngắt ngoài INT0 được định nghĩa trong bảng 2.8. Bảng 2.8 : Điều khiển nhận biết ngắt ngoài mức 0 ISC01 ISC00 Mô tả 0 0 Mức thấp của chân INT0 phát sinh một yêu cầu ngắt 0 1 Dự trữ (Reserved) 1 0 Yêu cầu phát sinh ngắt của chân INT0 theo sườn xuống 1 1 Yêu cầu ngắt của chân INT0 phát sinh ngắt theo sườn lên Giá trị trên chân INT được lấy mẫu trước khi kiểm tra các sườn. Nếu yêu cầu ngắt tác động theo sườn được lựa chọn, thì những xung cuối cùng kéo dài hơn một chu kỳ đồng hồ CPU sẽ phát sinh một ngắt. Xung ngắn sẽ không đảm bảo phát sinh ngắt. Nếu yêu cầu ngắt tác động theo mức thấp được lựa chọn, thì mức thấp phải được giữ cho đến khi hoàn thành lệnh đang thực hiện mới gây ra yêu cầu ngắt. Nếu được cho phép, một ngắt tác động theo mức sẽ phát sinh một yêu cầu ngắt trong khoảng thời gian chân INT0 được giữ ở mức thấp. Thời gian hồi đáp ngắt (Interrup response time) Thời gian hồi đáp thực hiện ngắt của tất cả các ngắt được cho phép của mC AT90S8535 tối thiểu là 4 chu kỳ đồng hồ. Bốn chu kỳ đồng hồ sau khi cờ ngắt được thiết lập, chương trình con xử lý ngắt hiện thời mới được thực hiện, trong khoảng thời gian 4 chu kỳ đồng hồ này, bộ đếm chương trình PC (2 bytes) được đẩy vào đỉnh ngăn xếp và con trỏ stack SP giảm 2. Một lệnh nhảy quan hệ nhảy tới chương trình con phục vụ ngắt và lệnh nhảy này mất hai chu._.lưu trữ 5.3. Nhận xét và đánh giá. Nhìn chung, phần mềm trên máy tính và chương trình điều khiển mC chạy thử nghiệp cho kết quả tốt. Hai chương trình này hoạt động một cách đồng bộ trong việc truyền nhận dữ liệu, do đó kết nối thành một hệ thống hoàn chỉnh. Phần mềm trên PC không chỉ biểu diễn được các giá trị nhiệt độ dạng đồ thị theo thời gian mà còn có thể lưu trữ các thông tin cần thiết trong quá trình thu thập dữ liệu và các thông tin lưu trữ này có thể được xem lại khi cần thiết. Kết quả ADC được truyền sang máy tính để máy tính thực hiện các thao tác phức tạp như dựng đồ thị và lưu trữ, điều này giúp cho công việc lập trình trở nên đơn giản và đỡ tốn thời gian cũng như chi phí so với việc thực hiện công việc này trên mC. Về cơ bản mạch phần cứng đã được lắp rắp hoàn chỉnh và chạy thử cho kết quả tốt đáp ứng được yêu cầu đề ra của đồ án. Song do điều kiện về thời gian nên không kịp thiết kế mạch in theo kỹ thuật có nên cũng phần nào ảnh hưởng đến chất lượng kỹ thuật cũng như chất lượng về mặt cảm quan của sản phẩm. Ngoài ra, do kinh nghiệm trong việc thiết kế phần cứng còn nhiều hạn chế nên việc ghép nối giữa mC với các modul khác qua các cổng I/O của mC AT90S8535 chưa thực sự tối ưu. Hoạt động trao đổi dữ liệu dữ máy tính và RTU được thực hiện dựa trên phương pháp truyền thông nối tiếp theo chuẩn RS232, do đó tốc độ truyền dữ liệu bị hạn chế. Mặt khác, do dữ liệu được truyền trực tiếp từ mC tới máy tính mà không qua Modem nên khoảng cách giữa máy tính vào RTU cũng bị giới hạn. Mặc dù hệ thống cần thiết kế đã hoàn thành, tuy nhiên có thể thấy nó có một số hạn chế trong đó hạn chế lớn nhất là khả ứng dụng trong thực tế của sản phẩm không cao. Nên mặc dù việc thay đổi đại lượng biến đổi ở đầu vào của bộ chuyển đổi A/D trong hệ thống để phù hợp với các ứng dụng thực tế không đòi hỏi nhiều chi phí và thời gian thiết kế lại mạch, nhưng chương trình điều khiển mC và chương trình trên PC cần có những thay đổi thích hợp. KẾT LUẬN Trong bản báo có đồ án tốt nghiệp này, em đã nêu ra một số lý thuyết sử dụng để thiết kế và quy trình công việc phải thực hiện trong thực tế. Nói chung công việc đã hoàn thành theo đúng tiến độ đề ra, tuy nhiên do năng lực cũng như kinh nghiệm về lĩnh vực công nghệ phần cứng còn nhiều yếu kém nên đồ án không thể tránh được những thiếu sót. Tuy nhiên, trong thời gian thực hiện đồ án, em cũng đã rút ra được một số kinh nghiệm quý báu, điều này rất cần thiết cho em khi ra làm việc thực tế. Nói chung, hệ thống cần thiết kế đã hoàn thành và chạy thử nghiệp cho kết quả tốt. Do mục đích của đồ án là tìm hiểu nguyên lý hoạt động và thực hiện điều khiển một bộ vi xử lý AT90S8535, đây là một mC còn rất mới của hãng ATMEL nên sản phẩm được thiết kế hầu như không được ứng dụng trong thực tế mà chỉ mang tính thử nghiệm. Tuy nhiên, thông qua quá trình tìm hiệu và sử mC AT90S8535 để thiết kế, có thể giúp em hiểu phần nào về công nghệ phần cứng ứng dụng trong các lĩnh vực khác nhau trong cuộc sống. Sau khi hoàn thành đồ án, em sẽ tìm hiểu thêm các kiến thức về kỹ thuật phối ghép để có thể thực hiện thiết kế những mạch điện tử có khả năng ứng dụng cao trong thực tế. Một lần nữa em xin chân thành cảm ơn thầy giáo hướng dẫn Bùi Quốc Anh đã tận tình hướng dẫn và giúp đỡ em rất nhiều trong suốt thời gian thực hiện đồ án này. Em cũng xin chân thành sự giúp đỡ của các anh làm việc ở trung tâm NET.JSC đã giúp đỡ em hoàn thành bản đồ án này. PHỤ LỤC CHƯƠNG TRÌNH ĐIỀU KHIỂN mC AT90S8535 .nolist .include "\AVR\AvrAssembler\Appnotes\8535def.inc" .list ;Defined register .def Save = r1 .def HPtrTx = r2 .def LPtrTx = r3 .def HPtrRxL = r4 .def HPtrRxH = r5 .def ShowRxL = r6 .def ShowRxH = r7 .def ResultADCL = r8 .def ResultADCH = r9 .def Implement = r10 .def StatementReg = r13 .def TimeOut = r16 .def Temp = r17 .def Instr = r18 .def Data = r19 .def AddrShow = r20 .def KeyPress = r21 .def CtrlReg = r22 .def OldKey = r23 .def Position = r24 .def PositionH = r25 ;Defined control constant .equ RS = 6 ;RS signal .equ RW = 5 ;RW signal .equ E = 4 ;Enable signal ;Control KeyPad .equ Row1 = 7 .equ Row2 = 6 .equ Row3 = 5 .equ Row4 = 4 .equ Col1 = 0 .equ Col2 = 1 .equ Col3 = 2 .equ Col4 = 3 .equ INTRATE = 4 ;INT rate keypress .equ EnImpKey = 1 .equ ImpKey = 0 .equ EnSelectTxRx = 4 .equ SelectTxRx = 2 .equ EnShowRxBuff = 8 .equ ShowRxBuff = 3 .equ EnInstroduc = 2 .equ Instroduc = 1 .equ EnOnKeyPress = $80 .equ OnKeyPress = 7 .equ PressOne = 0 .equ PressTwo = $10 .equ PressThree = $20 .equ PressFour = $30 .equ CR = $0D .equ Statement = $23 ;Ascii '#' .equ EnShow_CK = $01 ;Show cencius .equ Show_CK = 0 .equ EnShowSymbolTempr = $02 ;Show symbol Tempr .equ ShowSymbolTempr = 1 .equ EnCencius = $01 ;Display temprature for cencius ;Macro get address of last char in string .macro Get_Addr_Char ldi Position,@0 ;Last position show @0 ldi Instr,@1 ;Display on line @1 ldi Temp,@2 ;Total char of string @2 ldi ZL,LOW(@3<<1) ;Name of string @3 ldi ZH,HIGH(@3<<1) adiw ZL,@2-1 ;Get address of last char in string .endmacro ;Macro get address of string .macro Get_Addr_String ldi Instr,@0 ;Position show @0 ldi @1,LOW(@3<<1) ;Low pointer @1, name's string @3 ldi @2,HIGH(@3<<1) ;High pointer @2 ldi Temp,@4 ;Total char @4 .endmacro ;Macro set first ascii code for keypress .macro Set_First_Ascii ldi Data,@0 ;Ascii of number @0 ldi Position,@1 ;Ascii of prechar @1 .endmacro ;Macro get position to display for char .macro Get_Position cpi @0,@1 ;Position to show @0, breq GetPos ;Position last @1 inc @0 GetPos: mov Instr,@0 .endmacro ;Create buffer for RxD and TxD .dseg .org $0060 TxBuff : .byte 128 ;Buffer send RxBuff : .byte 128 ;Buffer receive ;Defined constant of buffer .equ EndTxBuff = LOW(TxBuff)+127 .equ StartTxBuff = LOW(TxBuff)-1 .equ EndRxBuffL = $62 .equ EndRxBuffH = $01 .equ StartRxBuff = LOW(RxBuff) .cseg .org $000 rjmp RESET rjmp SCAN_CODE .org $006 rjmp ENABLE_ADC ;Enable ADC .org $008 rjmp KEY_RATE ;INT KEYRATE .org $00B rjmp Rx_COMPELET .org $00E rjmp END_CONVERT ;End convert ADC .org $011 PrefA1 : .db "TRUONG DHBK HA NOI" PrefA2 : .db "KHOA CNTT" PrefA3 : .db "DO AN TOT NGHIEP" PrefA4 : .db "NG.CUU IC AT90S8535" PrefB1 : .db "SINH VIEN THUC HIEN" PrefB2 : .db "VU TAN MANH" PrefB3 : .db "GIAO VIEN HUONG DAN" PrefB4 : .db "BUI QUOC ANH" Tile : .db " MEASURE TEMPERATURE" Info : .db "CURRTEMP =" Symbol : .db "Tx:" ADCon : .db "Waiting" OverTx : .db "OverB! you send?" SendTo : .db "Sending... " RESET: ldi Temp,LOW(RAMEND) ;Init Stack out SPL,Temp ldi Temp,HIGH(RAMEND) out SPH,Temp cli ;Init register Control clr CtrlReg clr StatementReg clr Implement ;Init port I/O of LCD ldi Temp,$0F ;Data lines out DDRC,Temp ldi Temp,$70 ;Control Lines (bits 4,5,6) out DDRD,Temp ;Init INT0 and LCD busy ldi Temp,$02 out PORTD,Temp ;set pullup on pin 2 rcall LCD_INIT rcall SHOW_PREFACEA rcall SHOW_PREFACEB rcall DISPLAY_INTERFACE Get_Addr_String $8B,ZL,ZH,ADCon,7 rcall SHOW_STRING ;Show string wait rcall SHOW_SELECT_TxRx ;Create port for KeyPad and int register ldi Temp,$F0 ;lower nibble input out DDRB,Temp ldi Temp,$0F ;Set pullup on lower nibble out PORTB,Temp ldi OldKey,-1 ldi AddrShow,$97 ;Preaddress to show clr KeyPress ;Init address pointer to buffer Tx clr XH ldi Temp,StartTxBuff mov LPtrTx,Temp ldi Temp,LOW(TxBuff) mov HPtrTx,Temp ;Init pointer to buffer Rx clr YH ldi YL,StartRxBuff mov HPtrRxH,YH mov HPtrRxL,YL ;Init INT of KeyPad ldi Temp,$40 out GIMSK,Temp ldi Temp,$00 ;Soure trigger INT0 at lower out MCUCR,Temp ;Init UART ldi Temp,$98 ;Enable INT Rx compelet out UCR,Temp ;8 bit data 1 stop, 1 start ldi Temp,$33 ;baud = 9600bps out UBRR,Temp clr Implement ;Init register statement ;Init Interrup comperaA match of TC1 ldi Temp,$10 out TIMSK,Temp ldi Temp,$0C ;Set value $0000 to counter out TCCR1B,Temp ;CK/256 = 31.250Hz ldi Temp,$01 ;Value for comperaA match 312 out OCR1AH,Temp ;312*(256*0,125)us = 10ms ldi Temp,$38 out OCR1AL,Temp ;Init ADC ldi Temp,$00 ;Input ADC is PA0 out ADMUX,Temp ldi Temp,$8F ;Enable single mode out ADCSR,Temp ldi Temp,-1 mov ResultADCH,Temp ;Condition show symbol Tempr clr ResultADCL sei MAIN: sbrs KeyPress,OnKeyPress ;Have a key press rjmp NoKeyPress cbr KeyPress,EnOnKeyPress ;Get real KeyPress sbrs CtrlReg,ImpKey rjmp NormalKey rcall CONTROL_KEY rjmp EndKeyPress NormalKey:rcall DISPLAY_KEY in Temp,TIFR ;Clear flag TC1 andi Temp,INTRATE out TIFR,Temp in Temp,TIMSK ;Enabl Int KeyRate sbr Temp,TOIE1 out TIMSK,Temp ldi Temp,$E7 ;Init counter for int overflow TC1 out TCNT1H,Temp ;65.536 - 6.250 = $E796 ldi Temp,$96 ;6.250*(256*0.125) = 200mS out TCNT1L,Temp EndKeyPress:in Temp,GIFR ;Clear flag INT SCAN_CODE out GIFR,Temp ldi Temp,$40 ;Enable INT SCAN_CODE out GIMSK,Temp NoKeyPress:ldi Temp,-1 cp ResultADCH,Temp brne SetShowSymbol mov Temp,StatementReg sbr Temp,EnShowSymbolTempr mov StatementReg,Temp SetShowSymbol:sbrc StatementReg,ShowSymbolTempr rcall SHOW_SYMBOL_CK tst Implement brmi SkipToBack rcall EXCUTER_FROM_PC SkipToBack:rjmp MAIN ;Program control LCD ;(RS = 0,RW = 1) LCD_BUSY: sbi PORTD,RW ;Select DR Busy: sbi PORTD,E ;Read 4 MSBs bit nop cbi PORTD,E sbis PIND,7 ;LCD Busy rjmp NoBusy sbi PORTD,E ;Ignore 4 LSBs bit nop cbi PORTD,E rjmp Busy NoBusy: sbi PORTD,E cbi PORTD,RW cbi PORTD,E ret ;Instroduction in register Intr ;(RS = 0, RW = 0) LCD_INSTR: swap Instr ;Send 4 MSB bits out PORTC,Instr nop sbi PORTD,E nop cbi PORTD,E swap Instr ;Send 4 LSB bits out PORTC,Instr nop sbi PORTD,E nop cbi PORTD,E ret ;Data in register Data ;(RS = 1, RW = 0) LCD_DATA: sbi PORTD,RS swap Data ;Send 4 MSB bits out PORTC,Data nop sbi PORTD,E nop cbi PORTD,E swap Data ;Send 4 LSB bits out PORTC,Data nop sbi PORTD,E nop cbi PORTD,E cbi PORTD,RS ret ;Init LCD LCD_INIT: ldi TimeOut,$96 ;Wait 15ms after LCD on rcall DELAY ldi Instr,$3F ;Function set rcall LCD_INSTR ldi TimeOut,$29 ;Wait 4.1ms rcall DELAY rcall LCD_INSTR ldi TimeOut,$01 ;Wait 100us rcall DELAY rcall LCD_INSTR ldi Instr,$28 ;Set 4 bits interface rcall LCD_BUSY ;on 2 line, font 5x7 dots rcall LCD_INSTR ldi Instr,$08 ;LCD off rcall LCD_BUSY rcall LCD_INSTR ldi Instr,$01 ;Reset DDRAM rcall LCD_BUSY rcall LCD_INSTR ldi Instr,$0C ;LCD on rcall LCD_BUSY rcall LCD_INSTR ldi Instr,$06 ;Set address of rcall LCD_BUSY ;DDRAM increment rcall LCD_INSTR ret ;Run char to fixed Position, char in Data ;first address in Instr RUN_TO_POS: cpi Data,$20 breq NoRun push Temp push Instr RunChar: rcall LCD_BUSY rcall LCD_INSTR rcall LCD_BUSY rcall LCD_DATA ;Show char cp Instr,Position ;Right position show breq HaltRun ldi Temp,$0A ;Wait 250ms rcall TIMEWAIT push Data ;Clear char ldi Data,$20 rcall LCD_INSTR ;Get position to clear rcall LCD_BUSY rcall LCD_DATA pop Data inc Instr ;Next position show rjmp RunChar HaltRun: pop Instr pop Temp NoRun: ret ;Run char of string, Z pointer to last char of string ;coordine in Position, line address in Instr, total char in Temp RUN_STRING: lpm ;Load char to Data mov Data,r0 rcall RUN_TO_POS sbiw ZL,1 ;Next char in string dec Position ;Next position show dec Temp ;Remain char count brne RUN_STRING ret ;Clear char of display string to end of line, char in Data ;end of line in Position, address of char to clear in Instr CLEAR_TO_POS: cpi Data,$20 breq NoClear push Instr push Temp CLRChar: push Data ;Clear char ldi Data,$20 rcall LCD_INSTR rcall LCD_BUSY rcall LCD_DATA pop Data cp Instr,Position ;End of line? breq HaltCLR inc Instr ;Next position show rcall LCD_BUSY rcall LCD_INSTR rcall LCD_BUSY rcall LCD_DATA ;Reshow char at new position ldi TimeOut,10 ;Wait 250ms rcall TIMEWAIT rjmp CLRChar HaltCLR: pop Temp pop Instr NoClear: ret ;Clear display string, Z pointer to last char of string, End of line ;in Position, address of char to clear in Instr, Totla char in Temp CLEAR_STRING: lpm ;Load char to Data mov Data,r0 rcall CLEAR_TO_POS sbiw ZL,1 ;Next char to clear dec Instr ;Next address of char to clear dec Temp ;Remain char count brne CLEAR_STRING ret ;Display notify PrefaceA SHOW_PREFACEA: Get_Addr_Char $92,$80,18,PrefA1 rcall RUN_STRING ;Display on line 1 Get_Addr_Char $CD,$C0,9,PrefA2 rcall RUN_STRING ;Display on line 2 Get_Addr_Char $A5,$94,16,PrefA3 rcall RUN_STRING ;Display on line 3 Get_Addr_Char $E7,$D4,19,PrefA4 rcall RUN_STRING ;Display on line 4 ret ;Display notify PrefaceB SHOW_PREFACEB: Get_Addr_Char $93,$92,18,PrefA1 rcall CLEAR_STRING ;Clear string on line 1 Get_Addr_Char $93,$80,19,PrefB1 rcall RUN_STRING ;Display new string on line 1 Get_Addr_Char $D3,$CD,9,PrefA2 rcall CLEAR_STRING Get_Addr_Char $CE,$C0,11,PrefB2 rcall RUN_STRING Get_Addr_Char $A7,$A5,16,PrefA3 rcall CLEAR_STRING Get_Addr_Char $A7,$94,19,PrefB3 rcall RUN_STRING Get_Addr_Char $E7,$E7,19,PrefA4 rcall CLEAR_STRING Get_Addr_Char $E3,$D4,12,PrefB4 rcall RUN_STRING ret ;Display string, position in Instr, Z pointer ;to first char of string, total char in Temp SHOW_STRING: rcall LCD_INSTR ShowNext: lpm mov Data,r0 rcall LCD_BUSY rcall LCD_DATA adiw ZL,1 dec Temp brne ShowNext ret ;Show symbol RxTx SHOW_RxTx: cpi Position,9 breq TwoChar cpi Position,10 breq ThrChar ldi Temp,1 rjmp ShowSym TwoChar: ldi Temp,2 rjmp ShowSym ThrChar: ldi Temp,3 ShowSym: ldi Instr,$94 push Temp rcall SHOW_STRING pop Temp ldi Instr,$D4 mov ZL,XL mov ZH,XH push Temp rcall LCD_BUSY rcall SHOW_STRING pop Temp cpi Temp,3 brlo EndRxTx ldi Data,$52 ;ASCII code of R rcall LCD_BUSY rcall LCD_INSTR rcall LCD_BUSY rcall LCD_DATA EndRxTx: ret ;Show interface to LCD, total char in Temp DISPLAY_INTERFACE: ldi Instr,$01 ;Clear screen rcall LCD_INSTR ldi TimeOut,49 ;Wait 4.1ms rcall DELAY ldi ZL,LOW(Tile<<1) ;String on line 1 ldi ZH,HIGH(Tile<<1) adiw ZL,19 ldi YL,LOW(Info<<1) ;String on line 2 ldi YH,HIGH(Info<<1) adiw YL,9 ldi XL,LOW(Symbol<<1) ;String on line 3,4 ldi XH,HIGH(Symbol<<1) adiw XL,2 ldi Instr,$80 ldi Temp,1 ;Total char show on line 1 ldi Position,1 ;Total char show on line 2 ReShow: push Instr push ZL push ZH push Temp rcall SHOW_STRING ;Show line 1 pop Temp cpi Temp,11 ;Show line 2 brlo ShowOne ldi Instr,$C0 push Temp mov Temp,Position mov ZL,YL mov ZH,YH rcall SHOW_STRING ;Show line 2 sbiw YL,1 ;Part of string shown on line 2 cpi Position,8 brlo ShowTwo mov ZL,XL mov ZH,XH rcall SHOW_RxTx ;Show all screen sbiw XL,1 ShowTwo: pop Temp inc Position ShowOne: pop ZH pop ZL pop Instr sbiw ZL,1 ;Part of string will show ldi TimeOut,4 ;Wait 100ms rcall TIMEWAIT inc Temp cpi Temp,21 brlo ReShow ret ;Get ascii code of keypress GET_ASCII_CODE: cpi Temp,0 breq EndGetAscii add Position,Temp mov Data,Position EndGetAscii:ret ;Find ascii code of keypress, ;ascii code contain Data FIND_ASCII_CODE: cp KeyPress,OldKey ;First time key press brne FirstPress subi CtrlReg,-$10 ;increment total time keypress cbr CtrlReg,$40 ;Get real time keypress dec AddrShow ;reshow new char dec LPtrTx ;restore new char rjmp GetTimeKey FirstPress: mov OldKey,KeyPress cbr CtrlReg,$F0 ;Reset time keypress GetTimeKey:mov Temp,CtrlReg ;Get time keypress swap Temp andi Temp,$0F cpi KeyPress,5 ;Scan code < 5 brge Key5To9 cpi KeyPress,3 brge Key3Or4 cpi KeyPress,1 brne Key0Or2 Set_First_Ascii $31,$43 ;Ascii of 1 and D rcall GET_ASCII_CODE rjmp EndFindAscii Key0Or2: cpi KeyPress,2 breq Key2 Set_First_Ascii $30,$40 rcall GET_ASCII_CODE rjmp EndFindAscii Key2: Set_First_Ascii $32,$46 rcall GET_ASCII_CODE rjmp EndFindAscii Key3Or4: cpi KeyPress,3 breq Key3 Set_First_Ascii $34,$4C rcall GET_ASCII_CODE rjmp EndFindAscii Key3: Set_First_Ascii $33,$49 rcall GET_ASCII_CODE rjmp EndFindAscii Key5To9: cpi KeyPress,7 brge Key7To9 cpi KeyPress,6 brne Key5 Set_First_Ascii $36,$52 rcall GET_ASCII_CODE rjmp EndFindAscii Key5: Set_First_Ascii $35,$4F rcall GET_ASCII_CODE rjmp EndFindAscii Key7To9: cpi KeyPress,8 brne Key7Or9 Set_First_Ascii $38,$58 cpi Temp,3 brne SkipFour cbr CtrlReg,$F0 ;Loopback times keypress ldi Temp,0 ;to skip keypress four SkipFour: rcall GET_ASCII_CODE rjmp EndFindAscii Key7Or9: cpi KeyPress,9 brne Key7 Set_First_Ascii $39,$19 cpi Temp,2 brne SkipThree cbr CtrlReg,$F0 ldi Temp,0 SkipThree: rcall GET_ASCII_CODE rjmp EndFindAscii Key7: Set_First_Ascii $37,$55 rcall GET_ASCII_CODE EndFindAscii:ret ;Display char in Tx buffer, use pointer Z ;total char to show in Temp, position show in Instr DISPLAY_CHAR_IN_TxBUFF: rcall LCD_INSTR NextShow: ld Data,Z+ rcall LCD_BUSY rcall LCD_DATA dec Temp brne NextShow ret ;Get pointer to first char show in Tx buff on LCD GET_POINTER: push Temp mov Temp,AddrShow subi Temp,$97 ;Total current char display mov Position,LPtrTx sub Position,HPtrTx cp Position,Temp breq NoGetPoint mov Position,LPtrTx sub Position,Temp mov HPtrTx,Position ;Set pointer pop Temp NoGetPoint:ret ;Display char in TxBuff to LCD ;Total char to show in Temp SHOW_CHAR_IN_TxBuff: rcall GET_POINTER cpi AddrShow,$A7 brne NoReShow cpi Temp,15 ;Number char Need to show? brne Show16Char inc HPtrTx ;Show 15 last char Show16Char:ldi Instr,$98 ;Show 16 last char clr ZL mov ZL,HPtrTx ;Get pointer to char push Data rcall DISPLAY_CHAR_IN_TxBUFF pop Data NoReShow:ret ;Show char corresponding keypress, and store char ;into TxBuff to send to PC DISPLAY_KEY: rcall FIND_ASCII_CODE inc LPtrTx ;Increment pointer buffer ldi Temp,EndTxBuff+1 cp LPtrTx,Temp ;Over TxBuff breq OverBuff ldi Temp,15 rcall SHOW_CHAR_IN_TxBuff ;Reshow 15 lastchar in buff Get_Position AddrShow,$A7 rcall LCD_INSTR ;Show char to LCD rcall LCD_BUSY rcall LCD_DATA mov XL,LPtrTx st X,Data ;Store char rjmp EndDisplay OverBuff: Get_Addr_String $98,ZL,ZH,OverTx,16 rcall SHOW_STRING dec LPtrTx ;Get back LPtrTx EndDisplay:ret ;Show symbol select on Tx or Rx SHOW_SELECT_TxRx: ldi Temp,1 sbrs CtrlReg,SelectTxRx rjmp SelectTx ldi Instr,$97 rcall CLEAR_LINE ldi Instr,$D7 rjmp ShowSymbol SelectTx: ldi Instr,$D7 rcall CLEAR_LINE ldi Instr,$97 ShowSymbol:rcall LCD_BUSY rcall LCD_INSTR ldi Data,$7E ;Symbol select rcall LCD_BUSY rcall LCD_DATA ret ;Perform function select display on Tx or Rx SELECT_TxRx: sbrs CtrlReg,SelectTxRx rjmp EnableRx cbr CtrlReg,EnSelectTxRx ;Select Tx rjmp ShowSelect EnableRx: sbr CtrlReg,EnSelectTxRx ;Select Rx ShowSelect:rcall SHOW_SELECT_TxRx ret ;Clear char at Addrshow CLEAR_CHAR_IN_LCD: ldi Temp,16 rcall SHOW_CHAR_IN_TxBuff mov Instr,AddrShow rcall LCD_INSTR ldi Data,$20 rcall LCD_BUSY rcall LCD_DATA dec AddrShow cpi AddrShow,$97 brne EndClear ldi Temp,LOW(TxBuff) cp HPtrTx,Temp breq EndClear inc AddrShow ;Yet char mov Instr,AddrShow rcall LCD_BUSY rcall LCD_INSTR dec HPtrTx mov XL,HPtrTx ld Data,X ;Get next char to show rcall LCD_BUSY rcall LCD_DATA EndClear:ret ;Perform function backspace BACK_SPACE: sbrc CtrlReg,SelectTxRx ;Selecting Rx rjmp NoPerform cpi AddrShow,$97 breq NoPerform ;No char dec LPtrTx rcall CLEAR_CHAR_IN_LCD NoPerform:ret ;Clear char in line, address start in Instr ;Total char to clear in Temp CLEAR_LINE: rcall LCD_INSTR ldi Data,$20 NextClear: rcall LCD_BUSY rcall LCD_DATA dec Temp brne NextClear ret ;Perform function clear TxRx CLEAR_Tx_OR_Rx: sbrc CtrlReg,SelectTxRx rjmp SelectRx ldi Instr,$98 ldi Temp,16 ;Total char to clear rcall CLEAR_LINE ldi Temp,LOW(TxBuff) mov HPtrTx,Temp ldi Temp,StartTxBuff mov LPtrTx,Temp ldi AddrShow,$97 rjmp HalfClear SelectRx: ldi Instr,$D8 ;Clear display line ldi Temp,16 rcall CLEAR_LINE clr YH ;Reset pointer to RxBuff ldi YL,StartRxBuff mov HPtrRxH,YH mov HPtrRxL,YL HalfClear: ret ;Display char in Rx buffer, use pointer Z ;total char to show in Temp, position show in Instr DISPLAY_CHAR_IN_RxBUFF: rcall LCD_INSTR NextDisplay:ld Data,Z+ rcall LCD_BUSY rcall LCD_DATA cpi ZL,EndRxBuffL+1 brne NoResetPoint clr ZH ldi ZL,StartRxBuff NoResetPoint:dec Temp brne NextDisplay ret ;Perform function shift right SHIFT_RIGHT: sbrc CtrlReg,SelectTxRx rjmp ShiftR_Rx cpi AddrShow,$97 breq NoShiftR ;No char mov Position,AddrShow subi Position,$98 ;Number of current char mov Temp,LPtrTx sub Temp,HPtrTx cp Temp,Position breq NoShiftR inc HPtrTx clr ZH mov ZL,HPtrTx mov Temp,LPtrTx sub Temp,HPtrTx inc Temp cpi Temp,16 ;Number char to show brge ShowAllChar push Temp ldi Temp,$A7 ;Clear part last in LCD sub Temp,AddrShow mov Instr,AddrShow inc Instr rcall CLEAR_LINE pop Temp rjmp SetAddr ShowAllChar:ldi Temp,16 SetAddr: ldi Instr,$98 rcall DISPLAY_CHAR_IN_TxBUFF rjmp NoShiftR ShiftR_Rx: cp HPtrRxL,YL breq NoShiftR ;No char in RxBuff mov Position,ShowRxL mov PositionH,ShowRxH adiw Position,15 cpi Position,EndRxBuffL+1 brlo CheckLastPoint clr PositionH subi Position,$62 ldi Temp,StartRxBuff-1 add Position,Temp CheckLastPoint:cp Position,YL breq NoShiftR mov Position,ShowRxL mov PositionH,ShowRxH adiw Position,1 cpi Position,EndRxBuffL+1 brne GetNewPoint ;Reset pointer clr PositionH ldi Position,StartRxBuff GetNewPoint:mov ShowRxL,Position ;Get new pointor mov ShowRxH,PositionH mov ZL,ShowRxL mov ZH,ShowRxH ldi Instr,$D8 ldi Temp,16 rcall DISPLAY_CHAR_IN_RxBUFF NoShiftR: ret ;Perform function shift left SHIFT_LEFT: sbrc CtrlReg,SelectTxRx rjmp ShiftL_Rx ldi Temp,LOW(TxBuff) cp HPtrTx,Temp breq NoShiftL ;No shift dec HPtrTx mov Temp,LPtrTx sub Temp,HPtrTx inc Temp ;Total char to show cpi Temp,17 brlo ShiftTxL ldi Temp,16 ShiftTxL: ldi Instr,$98 ;Position to show clr ZH mov ZL,HPtrTx rcall DISPLAY_CHAR_IN_TxBUFF rjmp NoShiftL ShiftL_Rx: cp ShowRxL,HPtrRxL breq NoShiftL mov Position,ShowRxL mov PositionH,ShowRxH sbiw Position,1 cpi Position,StartRxBuff-1 brne NoGetNewPoint ldi Position,EndRxBuffL ldi PositionH,EndRxBuffH NoGetNewPoint:mov ShowRxL,Position ;Get new pointor mov ShowRxH,PositionH ldi Temp,16 ldi Instr,$D8 mov ZL,ShowRxL mov ZH,ShowRxH rcall DISPLAY_CHAR_IN_RxBUFF NoShiftL: ret ;Perform function Send SEND_TxBUFF_TO_PC: sbrc CtrlReg,SelectTxRx ;Selecting Rx rjmp NoSend cpi AddrShow,$97 ;No char in buff breq NoSend Get_Addr_String $98,ZL,ZH,SendTo,16 rcall SHOW_STRING ldi XL,LOW(TxBuff) SendChar: ld Data,X WaitReady:sbis USR,UDRE rjmp WaitReady out UDR,Data cp XL,LPtrTx breq ClearToSend inc XL rjmp SendChar ClearToSend:rcall CLEAR_Tx_OR_Rx NoSend: ret ;Perform control key CONTROL_KEY: cbr CtrlReg,EnImpKey ;Clear confirm controlkey cpi KeyPress,13 brge Key13To15 cpi KeyPress,11 brne Key10Or12 rcall BACK_SPACE rjmp EndControlKey Key10Or12:cpi KeyPress,10 breq Key10 rcall SHIFT_LEFT rjmp EndControlKey Key10: rcall SEND_TxBUFF_TO_PC rjmp EndControlKey Key13To15:cpi KeyPress,14 breq Key14 cpi KeyPress,15 breq Key15 rcall SHIFT_RIGHT rjmp EndControlKey Key15: rcall CLEAR_Tx_OR_Rx rjmp EndControlKey Key14: rcall SELECT_TxRx EndControlKey:ldi OldKey,-1 ;Reset OldKey ret ;Service INT0 SCAN_CODE: in Save,SREG ldi KeyPress,$00 out GIMSK,KeyPress ldi TimeOut,2 ;Wait 0.2ms for settle rcall DELAY ;Find col sbis PINB,Col1 ldi KeyPress,0 sbis PINB,Col2 ldi KeyPress,4 sbis PINB,Col3 ldi KeyPress,8 sbis PINB,Col4 ldi KeyPress,12 ;invert port to find col push Temp ldi Temp,$F0 ;Lower ninble is output out DDRB,Temp ldi Temp,$0F ;Set pullup on upper out PORTB,Temp ldi TimeOut,2 ;Wait 0.2ms for settle rcall DELAY ;Find Row sbis PINB,Row1 subi KeyPress,0 sbis PINB,Row2 subi KeyPress,-1 sbis PINB,Row3 subi KeyPress,-2 sbis PINB,Row4 subi KeyPress,-3 ;Get sort KeyPress cpi KeyPress,10 brlo Normal sbr CtrlReg,EnImpKey ;Confirm Control key Normal: sbr KeyPress,EnOnKeyPress ;Confirm a key press in Temp,TIMSK ;Disable int KEY_RATE overflow sbrs Temp,TOIE1 ;Enable? rjmp HalfScanCode cbr Temp,INTRATE out TIMSK,Temp HalfScanCode:pop Temp out SREG,Save reti ;Service INT delay for reloop of keypress KEY_RATE: in Save,SREG ldi OldKey,-1 ;Reset register for compera push Temp in Temp,TIMSK cbr Temp,INTRATE out TIMSK,Temp ;Disable INT KEY_RATE pop Temp out SREG,Save reti ;Service INT Receive compelet Rx_COMPELET: in Save,SREG push Data in Data,UDR ;Get data sbrs CtrlReg,Instroduc rjmp Get_Code ;Get symbol of Statement mov Implement,Data cbr CtrlReg,EnInstroduc rjmp HalfRx Get_Code: cpi Data,Statement ;Receive symbol Statement brne RxData sbr CtrlReg,EnInstroduc rjmp HalfRx RxData: cpi Data,CR ;End of receive brne SetStore sbr CtrlReg,EnShowRxBuff ;Reques show data in Rx buff ldi Data,$7C ;Symbol "|" end of char SetStore: cpi YL,EndRxBuffL+1 brne StoreRx clr YH ;Back to head RxBuff ldi YL,StartRxBuff inc HPtrRxL ;Increment head pointer StoreRx: st Y+,Data ;Store data to RxBuff push Temp ldi Temp,StartRxBuff cp HPtrRxL,Temp breq HalfRx cpi YL,EndRxBuffL+1 brne GetHPtrRx clr HPtrRxH ;Reset pointer head RxBuff mov HPtrRxL,Temp rjmp ResetHPtrRx GetHPtrRx: mov HPtrRxL,YL ;Get pointer head RxBuff mov HPtrRxH,YH ResetHPtrRx:pop Temp HalfRx: pop Data out SREG,Save reti ;Service INT enable adc ENABLE_ADC: in Save,SREG sbi ADCSR,ADSC ;Enable convert out SREG,Save reti ;Mull result convert with content Data to divide ;Mulled in Data MULL_RESULT_CONVER: clc clr r11 mov r12,ResultADCL Mull_Data: dec Data breq HalfMull add ResultADCL,r12 adc ResultADCH,r11 rjmp Mull_Data HalfMull: ret ;Divide result convert to get temperature ;result in ResultADCH, remainde in ResultADCL ;Divider in Data DIVIDE_TO_GET_TEMPR: clr r11 sub r12,r12 LoopDivide:cp ResultADCH,r11 brne Divide cp ResultADCL,Data brlo EndDivide Divide: sub ResultADCL,Data sbc ResultADCH,r11 clc inc r12 rjmp LoopDivide EndDivide: mov ResultADCH,r12 ret ;Service INT end convert adc ;Result in ResultADCH, remainde in ResultADCL END_CONVERT: in Save,SREG in ResultADCL,ADCL in ResultADCH,ADCH lsr ResultADCH ;Get 8 bit result ror ResultADCL lsr ResultADCH ror ResultADCL push Data ldi Data,Statement SendConfirm:sbis USR,UDRE rjmp SendConfirm out UDR,Data ldi Data,$64 ;Mull result with 100 rcall MULL_RESULT_CONVER ldi Data,$FF ;Divide with 255 to get tempr rcall DIVIDE_TO_GET_TEMPR SendResult: sbis USR,UDRE rjmp SendResult out UDR,ResultADCH ;Get result push ResultADCH clr ResultADCH ;Clear upper byte ldi Data,$0A rcall MULL_RESULT_CONVER ldi Data,$FF rcall DIVIDE_TO_GET_TEMPR ldi Data,$80 cp ResultADCL,Data brlo Get_Remainder inc ResultADCH Get_Remainder:mov ResultADCL,ResultADCH pop ResultADCH SendRemainde:sbis USR,UDRE rjmp SendRemainde out UDR,ResultADCL ;Get remainder ;thay bng dung co bao rcall DISPLAY_TEMPR_TO_LCD pop Data out SREG,Save reti ;Show temperature to LCD DISPLAY_TEMPR_TO_LCD: push Instr ldi Instr,$CB rcall LCD_INSTR push ResultADCL mov ResultADCL,ResultADCH clr ResultADCH sbrs StatementReg,Show_CK rjmp ShowTemprC clr Instr ldi Data,$C8 ;Get Kelvin add ResultADCL,Data adc ResultADCH,Instr ldi Data,$49 add ResultADCL,Data adc ResultADCH,Instr ShowTemprC:ldi Data,$64 rcall DIVIDE_TO_GET_TEMPR ;Get number hundres ldi Data,0 cp ResultADCH,Data breq No100 mov Data,ResultADCH subi Data,-$30 rjmp Show100 No100: ldi Data,$20 Show100: rcall LCD_BUSY rcall LCD_DATA ldi Data,$0A clr ResultADCH rcall DIVIDE_TO_GET_TEMPR ldi Data,0 cp ResultADCH,Data breq No10 mov Data,ResultADCH rjmp Show10 No10: ldi Data,$30 Show10: rcall LCD_BUSY rcall LCD_DATA mov Data,ResultADCL subi Data,-$30 rcall LCD_BUSY rcall LCD_DATA ldi Data,$2E rcall LCD_BUSY rcall LCD_DATA pop ResultADCL mov Data,ResultADCL subi Data,-$30 rcall LCD_BUSY rcall LCD_DATA pop Instr ret ;Show symbol temperature SHOW_SYMBOL_CK: mov Temp,StatementReg cbr Temp,EnShowSymbolTempr mov StatementReg,Temp ldi Instr,$D0 rcall LCD_INSTR ldi Data,$DF rcall LCD_BUSY rcall LCD_DATA sbrs StatementReg,Show_CK rjmp ShowSymbolC ldi Data,$4B ;Ascii of K rjmp DisplaySymbol ShowSymbolC: ldi Data,$43 ;Ascii of C DisplaySymbol: rcall LCD_BUSY rcall LCD_DATA ret ;Excuter statement from PC EXCUTER_FROM_PC: ldi Temp,EnCencius cp Implement,Temp brne EnKenvin mov Temp,StatementReg cbr Temp,EnShow_CK rjmp Excuted EnKenvin: mov Temp,StatementReg sbr Temp,EnShow_CK Excuted: sbr Temp,EnShowSymbolTempr mov StatementReg,Temp ldi Temp,-1 mov Implement,Temp ret ;Program time out delay ;TimeOut delay = (0.1*TimeOut)ms DELAY: push Data push Temp Reloop: ldi Data,$03 Back: ldi Temp,$56 Loop: dec Temp brne Loop dec Data brne Back dec TimeOut brne ReLoop pop Temp pop Data ret ;TimeWait = (25*Temp)ms TIMEWAIT: ldi TimeOut,$FA rcall DELAY dec Temp brne TIMEWAIT ret MỤC LỤC ._.

Các file đính kèm theo tài liệu này:

  • docDA2052.doc
Tài liệu liên quan