Các mạch số trong và ngoài C AT90S8535 có thể tạo ra EMI làm ảnh hưởng đến sự chính xác của việc lấy mẫu tính hiệu tương tự. Nếu độ chính xác của sự chuyển đổi bị lỗi thì có thể giảm nhiễu bằng việc áp dụng các kỹ thuật sau:
1. Phần tương tự của C AT90S8535 và tất cả các thành phần tương tự trong ứng dụng nên có một chân nối đất tương tự riêng trên PCB. Chân nối đất này được nối tới chân nối đất số qua một điểm đơn trên PCB.
2. Giữ cho đường đi của tín hiệu tương tự càng ngắn càng tốt. Đảm bảo các đường đi của tín hiệu tương tự hướng tới chân nối đất tránh sự chuyển đổi sang các đường số tốc độ cao.
3. Chân AVCC trên C AT90S8535 nên được nối tới chân VCC qua một mạch LC như trong hình 2.30.
4. Sử dụng chức năng khử nhiễu của ADC để giảm nhiễu sinh ra từ MCU.
5. Nếu một số chân cổng A được sử dụng như các đầu ra số thì các chân này không được chọn khi một quá trình chuyển đổi đang diễn ra.
140 trang |
Chia sẻ: oanh_nt | Lượt xem: 1595 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Thiết kế hệ thống phần mềm cho c at90s8535, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
diện LCD), (dịch chuyển chuỗi được lựa chọn trên giao diện LCD sang trái một ký tự), (dịch chuyển chuỗi được lựa chọn trên giao diện LCD sang phải một ký tự), / (lựa chọn chuỗi hiển thị trong TxBuff hay RxBuff), Clear (xoá chuỗi được lựa chọn trên giao diện LCD và bộ đệm tương ứng).
Nếu là phím thường, ngắt xác định thời gian lặp phím KEY_RATE bị cấm để chương trình điều kiển có thể xác định đúng số lần phím được ấn lại (do mỗi phím được mã hoá nhiều hơn 2 ký tự). Các thao tác tiếp theo được thực hiện bởi chương trình con DISPLAY_KEY, được goi từ chương trình điều khiển.
Ngắt cho phép chuyển đổi A/D : Do mục đích sử dụng trong đồ án, nên chu kỳ chuyển đổi của bộ ADC trong mC cần một thời gian lâu hơn rất nhiều so với thời gian chuyển đổi thực tế mà bộ ADC có thể đạt được. Để có thể kéo dài chu kỳ chuyển đổi của bộ ADC, ngắt so sánh bằng của bộ Timer/Counter1 được sử dụng. Ngắt này được gọi với chu kỳ 10ms và chức năng của nó là cho phép bộ ADC lấy mẫu thực hiện chuyển đổi A/D.
Ngắt xác định thời gian lặp phím : Do mỗi một phím thường trên bàn phím được mã hoá nhiều hơn 2 ký tự. Vì vậy, cần phải xác định ký tự nào thực sự được lựa chọn trong số các ký tự mã hoá bởi phím được ấn. Để làm được điều này, ngắt tràn của bộ Timer/Counter1 được sử dụng với chu kỳ 200ms. Khi một phím thường được ấn, ngắt này được reset và nếu trước khi cờ ngắt này được dựng mà phím được ấn lại thì ký tự tiếp theo được phím mã hoá sẽ được lựa trọn.
Ngắt nhận dữ liệu : Khi mC AT90S8535 nhận được một byte dữ liệu từ PC, ngắt kết thúc nhận dữ liệu của bộ UART được gọi. Ngắt này có nhiệm vụ kiểm tra dữ liệu nhậ được là mã lệnh hay là ký tự hiển thị.
Nếu là mã lệnh, cờ báo nhận lệnh từ PC được dựng và mã lệnh được lưu lại trong thanh ghi Implement. Sau đó lệnh tương ứng sẽ được thực hiện từ chương trình điều khiển thông qua lời gọi đến chương trình con EXCUTER_FROM_PC.
Nếu nhận ký tự hiển thị, ký tự này sẽ được lưu vào bộ đêm RxBuff cho đến khi nhận được mã phím Enter cờ báo cần hiển thị chuỗi ký tự nhận được sẽ được dựng và dữ liệu sẽ được hiển thị trên giao diện LCD.
Ngắt kết thúc chuyển đổi A/D : Ngắt này được gọi sau khi một thao tác chuyển đổi A/D hoàn thành. Ngắt này có nhiệm vụ chuyển kết quả chuyển đổi từ số hệ 2 sang số hệ 10, kết quả này sẽ được gửi sang PC đồng thời dựng cờ báo có kết quả chuyển đổi A/D. Thao tác tiếp theo được thực hiện trong chương trình con DISPLAY_TEMPR_TO_LCD được gọi từ chương trình điều khiển khi cờ trên được nhận ra.
Ngoài các ngắt kể trên, chương trình còn có một số chương trình con có các chức năng khác nhau trợ giúp cho chương trình điều khiển hoạt động, bao gồm :
Các chương trình con điều khiển LCD controller : LCD_BUSY (kiểm tra LCD controller đang thực hiện thao tác trong?), LCD_INSTR (ghi lệnh tới LCD controller) và LCD _DATA (ghi dữ liệu tới LCD controller).
Các chương trình con tính toán và hiển thị kết quả thu được từ ADC : MULL_RESULT_CONVER, DIVIDE_TO_GET_TEMPR (thực hiện nhân chia 16 bit để thu được kết quả ADC ở số hệ 10), DISPLAY_TEMPR_TO_LCD (hiển thị kết quả của ADC ra giao diện LCD dưới dạng 0C hay 0K tuỳ thuộc vào điều kiện được xác định trong chương trình).
Các chương trình điều khiển của các phím chức năng : SHIFT_LEFT, SHIFT_RIGHT, SEND_TxBUFF_TO_PC, CLEAR_Tx_OR_Rx, BACK_SPACE, SELECT_TxRx.
Các chương trình điều khiển đối với phím thường : GET_ASCII_CODE (xác định mã ASCII của phím được ấn), FIND_ASCII_CODE (tìm mã ASCII tươngứng với số lần ấn của phím), DISPLAY_KEY (hiển thị phím được ấn và lưu vào bộ đếm TxBuff để chuyền sang PC).
Các chương trình điều khiển hiển thị dữ liệu ra giao diện LCD : SHOW_PREFACEA, SHOW_PREFACEB (hiển thị lời giới thiệu), DISPLAY_INTERFACE (hiển thị giao diện làm việc của LCD), SHOW_STRING (hiển thị một chuỗi ký tự ra giao diện LCD) vv...
4.2. Lưu đồ thuật toán của các chức năng chính.
4.2.1. Chức năng giao tiếp với LCD controller.
Để mC có thể giao tiếp được với LCD controller, ta cần thực hiện khởi tạo LCD controller ngay sau khi nguồn được bật. Do mục đích của đồ án, ta sử dụng cơ chế khởi tạo LCD controller ở chế độ giao tiếp 4 bit bus. 3 chương trình con được sử dụng để giao tiếp với LCD controller là LCD_BUSY, LCD_INSTR và LCD_DATA. Lệnh được đặt trong thanh ghi Instr và dữ liệu trong thanh ghi Data.
Hình 4.3 : Lưu đồ chương trình kiểm tra LCD busy
Bắt đầu
Cho phép đọc thanh ghi lệnh của LCD controller (RS = 0, RW = 1)
Đọc 4 bit MSB
của thanh ghi lệnh
Đọc 4 bit LSB
của thanh ghi lệnh
Kết thúc
BF = 1?
N
Y
Hình 4.4 : Lưu đồ chương trình ghi lệnh và
dữ liệu tới LCD controller
Bắt đầu
Cho phép ghi thanh ghi lệnh của LCD controller (RS = 0, RW = 0)
Ghi 4 bit MSB của mã
lệnh tới thanh ghi lệnh
Kết thúc
Lấy 4 bit thấp
của mã lệnh
Ghi 4 bit LSB của mã
lệnh tới thanh ghi lệnh
Bắt đầu
Cho phép ghi thanh ghi dữ liệu của LCD controller (RS = 1, RW = 0)
Ghi 4 bit MSB của byte
dữ liệu tới thanh dữ liệu
Kết thúc
Lấy 4 bit thấp
của byte dữ liệu
Ghi 4 bit LSB của byte
dữ liệu tới thanh dữ liệu
4.2.2. Chức năng điều khiển và hiển thị kết quả ADC.
Khi bộ ADC thực hiện xong một chu kỳ chuyển đổi, kết quả chuyển đổi sẽ được lưu vào thanh ghi ADCL và ADCH, tiếp sau đó cờ ngắt kết thúc chuyển đổi A/D được dựng và chương trình con phục vụ ngắt tương ứng là END_CONVERT được gọi.
Hình 4.6 : Lưu đồ chương trình con phục vụ ngắt END_CONVERT
Bắt đầu
Lưu lại trạng thái MCU
Lấy kết quả chuyển đổi A/D
Lưu lại các thanh ghi cần sử dụng
Gửi ký hiệu truyền dữ
liệu ( # ) sang PC
Lấy phần nguyên của kết quả ADC đặt vào ResultADCH
Thực hiện chương trình MULL_RESULT_CONVER với số nhân = 100
Thực hiện chuơng trinh DIVIDE_TO_GET_TEMPR với số chia = 255
Gửi phần nguyên của
kết quả ADC sang PC
Lấy phần thập phân của kết quả ADC đặt vào ResultADCL
Thực hiện chương trình MULL_RESULT_CONVER với số nhân = 10
Thực hiện chuơng trinh DIVIDE_TO_GET_TEMPR với số chia = 255
Gửi phần thập phân
của kết quả ADC sang PC
Dựng cờ báo cần hiển thị
kết quả ADC ra giao diện LCD
Lấy lại giá trị các thanh ghi sử dụng
Lấy lại trạng thái MCU
Kết thúc
Trong ngắt END_CONVERT có sử dụng hai module MULL_RESULT_CONVER và DIVIDE_TO_GET_TEMPR được sử dụng để chuyển kết quả ADC sang số thập phân. Trước khi thực hiện các module này cần phải xác định số nhân hoặc số chia trong thanh ghi Data. Chương trình MULL_RESULT_CONVER sẽ thực hiện nhân nội dung hai thanh ghi ResultADCL và Data, kết quả đặt trong thanh ghi ResultADCH và ResultADCL. Chương trình DIVIDE_TO_GET_TEMPR thực hiện chia kết quả từ chương trình MULL_RESULT_CONVER cho nội dung thanh ghi Data, phần nguyên của kết quả đặt trong thanh ghi ResultADCH, phần dư của kết quả đặt trong thanh ghi ResultADCL.
Hình 4.7 : Lưu đồ chương trình MULL_RESULT_CONVER
Bắt đầu
Xoá cờ carry ( C = 0 )
Khởi tạo các thanh ghi tạm
R11 = 0, R12 = ResultADCL
Giảm số nhân đi một
Data Data - 1
Kết thúc
Data = 0?
Y
N
ResultADCL ResultADCL + R12
ResultADCH ResultADCH + R11 + C
Hình 4.8 : Lưu đồ chương trình DIVIDE_TO_GET_TEMPR
Bắt đầu
Xoá cờ carry ( C = 0 )
Khởi tạo các thanh ghi tạm R11 0, R12 0
ResultADCL ResultADCL - Data
ResultADCH ResultADCH - R11 - C
C 0
R12 R12+1
Kết thúc
N
Lấy phần nguyên của kết quả
ResultADCH R12
ResultADCL < Data?
N
ResultADCH = 0?
Y
Y
Ngoài hai module trên, để hiển thị kết quả chuyển đổi A/D tới giao diện LCD, cần sử dụng chương trình con DISPLAY_TEMPR_TO_LCD chương trình này được gọi từ chương trình điều khiển khi cờ báo có kết quả ADC cần được hiển thị. Dữ liệu đầu vào của chương trình này là nội dung hai thanh ghi chứa kết quả A/D dưới dạng số hệ 10 sau khi thực hiện ngắt END_CONVERT, trong đó phần nguyên chứa trong thanh ghi ResultADCH và phần thập chứa trong thanh ghi ResultADCL.
Hình 4.9 : Lưu đồ chương trình con DISPLAY_TEMPR_TO_LCD
Kết thúc
Bắt đầu
Lấy toạ độ đầu Instr $CB
Lưu nội dung ResultADCL
ResultADCL ResultADCH
ResultADCL 0
N
Show_CK = 1?
Y
Đổi giá trị nhiệt độ sang 0K
ResultADCH:ResultADCL ResultADCH:ResultADCL + 273
Lấy số hàng trăm để hiển thị
Gọi chương trình DIVIDE_TO_GET_TEMPR với Data = $64
Y
ResultADCH = 0?
N
Lấy mã ASCII của số cần hiển thị
Data ResultADCH
Data Data + 30
Không hiển thị số hàng trăm
Data $20
Hiện dữ liệu
Lấy số hàng chục để hiển thị
ResultADCH 0
Gọi chương trình DIVIDE_TO_GET_TEMPR với Data = $0A
Y
ResultADCH = 0?
N
Lấy mã ASCII của số cần hiển thị
Data ResultADCH
Data Data + $30
Hiện 0 ở hàng chục
Data $30
Hiện dữ liệu
Hiện số hàng đơn vị
Data ResultADCL
Data Data + $30
Hiện dữ liệu
Hiện dấu chấm thập phân
Data $2E
Hiện dữ liệu
Hiện số thập phân
Lấy lại nội dung ResultADCL
Data ResultADCL
Data Data + $30
Hiện dữ liệu
4.2.3. Chức năng giao tiếp với KeyPad.
Chức năng giao tiếp với bàn phím được bắt đầu bằng việc giải mã ma trận bàn phím để xác định phím nào trên bàn phím được ấn. Để mC nhận biết có phím ấn, một yêu ngắt ngoài được xác định bằng mức thấp trên chân INT0 (PD2) được phát sinh và ngắt bàn phím SCAN_CODE được thực hiện. Trước khi bắt thực hiện chương trình con phục vụ ngắt, cần đặt 0 trên các hàng và đặt 1 trên các cột.
Hình 4.10 : Lưu đồ ngắt SCAN_CODE giải mã ma trận bàn phím
Bắt đầu
Lưu lại trạng thái MCU
Keypress 0
Câm ngắt bàn phím
Đợi 0.2ms cho
cổng ổn định
Col1 = 0?
Y
N
Col2 = 0?
Y
N
Col3 = 0?
Y
N
Col4 = 0?
Y
N
KeyPress 0
KeyPress 4
KeyPress 8
KeyPress 12
Đảo 4 bit của cổng B
Đưa 0 ra các cột vào đưa 1 ra các hàng
Đợi 0.2ms cho các cột ổn định
Row1 = 0?
Y
N
KeyPress KeyPress + 0
Row2 = 0?
Y
N
KeyPress KeyPress + 1
Row3 = 0?
Y
N
KeyPress KeyPress + 3
A
B
Kết thúc
Row4 = 0?
Y
N
KeyPress KeyPress + 4
A
B
KeyPress<10?
N
Y
Dựng cờ báo phím điều khiển
Dựng cờ báo có phím ấn
Cấn ngắt KEY_RATE
Lấy lại trạng thái MCU
Do mỗi một phím thường trên bàn phím được mã hoá nhiều hơn một ký tự, vì vậy để xác định được chính xác ký tự nào được mã hoá của phím bị ấn được lựa chọn một thanh ghi OldKey được sử dụng. Nội dung của thanh ghi này chứa giá trị của phím được ấn và được dùng để so sánh với giá trị của phím được ấn trong thanh ghi KeyPress ở lần tiếp theo. Nếu hai thanh ghi này có giá trị bằng nhau thì tổng số lần ấn phím tăng lên 1 và ký tự tiếp theo được mã hoá bởi phím sẽ được chọn, ngược lại phím được coi là ấn lần đầu tiên. Nội dung thanh ghi OldKey sẽ được ghi nhớ trong một khoảng thời gian 200ms, nếu sau khoảng thời gian này mà phím không được ấn lại nội dung thanh ghi OldKey được xác lập lại trang thái không phím nào được ấn (OldKey = -1). Việc này được thực hiện bởi chương trình phục vụ ngắt KEY_RATE của ngắt tràn TC1.
Hình 4.11 : Lưu đồ ngắt KEY_RATE
Kết thúc
Lưu trạng thái MCU
Cấn ngắt KEY_RATE
Lấy lại trạng thái MCU
Bắt đầu
OldKey -1
Tuỳ thuộc vào phím được ấn là phím điều khiển hay phím thường mà chương trình điều khiển sẽ thực hiện một trong hai chương trình con DISPLAY_KEY ứng với một phím thường và CONTROL_KEY ứng với một phím điều khiển.
Hình 4.12 : Lưu đồ chương trình DISPLAY_KEY
Kết thúc
Gọi chương trình FIND_ASCII_CODE
Hiện thông báo
tràn bộ đệm TxBuff
Bắt đầu
LPtrTx = EndTxBuf+1?
Y
N
Tăng con trỏ cuối bộ đệm TxBuff
LPtrTx LPtrTx + 1
Hiện 15 ký tự cuối trong bộ đệm
Gọi chương trình SHOW_CHAR_IN_TxBuff
Xác định vị trí hiển thị tiếp theo
Hiện ký tự tương ứng phím ấn
Lưu ký tự vào bộ đệm TxBuff
XL LPTrTx, X Data
Giảm con trỏ cuối bộ đệm TxBuff
LPtrTx LPtrTx - 1
Chương trình con FIND_ASCII_CODE có chức năng tìm mã ascii tương ứng với ký tự được lựa chọn và lưu kết quả vào thanh ghi Data với số lần phím được ấn lưu trong 4 bit cao của thanh ghi điều khiển CtrlReg.
Hình 4.13 : Lưu đồ chương trình FIND_ASCII_CODE
Bắt đầu
Tăng tổng số lần ấn phím
Xác định vị trí hiển thị và con trỏ LPtrTx
KeyPress = OldKey?
N
Y
A
OldKey KeyPress
Tổng số lần ấn phím = 0
Số lần ấn phím = 4 ?
N
Y
B
Data $38
Position $58
Data $37
Position $55
Temp 0
CtrlReg CtrlReg$0F
Data $39
Position $19
A
B
Tổng số lần ấn phím = 0
CtrlReg CtrlReg$0F
Lấy tổng số lần ấn phím
Temp CtrlReg
swap Temp
Temp Temp$0F
Keypress<5?
N
C
Y
Keypress<3?
N
Y
Keypress= 1?
Y
N
Data $31
Position $43
Keypress= 2?
Y
Data $32
Position $46
N
Data $30
Position $40
Keypress=4?
N
Y
Data $33
Position $49
Data $34
Position $4C
Lấy mã ASCII của ký tự tương ứng
chương trình GET_ASCII_CODE
Kết thúc
C
Keypress<7?
Y
N
Keypress= 6?
N
Y
Data $35
Position $4F
Data $36
Position $52
Keypress= 8?
Y
N
Temp= 3?
N
Y
Temp 0
CtrlReg CtrlReg$0F
Keypress= 9?
Y
N
Temp= 2?
N
Y
Tổng số lần ấn phím = 0
CtrlReg CtrlReg$0F
Chương trình con GET_ASCII_CODE có chức năng lấy mã ascii và lưu vào trong thanh ghi Data. Đầu vào của chương trình là thanh ghi Data chứa mã ascii của chữ số và thanh ghi Position chứa mã ascii của ký tự đứng ngay trước ký tự đầu tiên được mã hoá bởi phím. Ví dụ, phím số 1 mã hoá các ký tự 1, D,E và F, khi đó nếu phím số 1 được ấn thì Data chứa giá trị $30 (mã ascii của số 1) còn Position chứa giá trị $43 (mã ascii của ký tự đứng trước chữ D). Tổng số lần ấn phím được đặt trong thanh ghi Temp.
Hình 4.14 : Lưu đồ chương trình GET_ASCII_CODE
Bắt đầu
Position Position + Temp
Data Postion
Temp = 0?
Y
N
Kết thúc
Trước khi hiển thị ký tự của phím được ấn ra màn hình LCD, chương trình DISPLAY_KEY, gọi chương trình con SHOW_CHAR_IN_TxBuff để hiện thị lại 15 ký tự cuối cùng được lưu trong bộ đệm TxBuff, nếu tổng số ký tự đang có trong bộ đệm TxBuff lớn hơn 15 ký tự.
Ngoài chương trình DISPLAY_KEY được thực hiện khi một phím thường được ấn. Một chương trình khác là chương CONTROL_KEY sẽ được chương trình điều khiển thực hiện mỗi khi một phím chức năng được ấn. Trên bàn phím có tất cả 6 phím chức năng như trình bầy ở các phần trước. Tuỳ thuộc vào việc giải mã bàn phím các chương trình con tương ứng với phím chức năng bị ấn sẽ được thực hiện.
Hình 4.15 : Lưu đồ chương trình CONTROL_KEY
Kết thúc
Bắt đầu
Gọi chương trình BACK_SPACE
KeyPress <13?
N
Y
Xoá cờ báo phím điều khiển
Y
N
Gọi chương trình SHIFT_LEFT
N
Y
Gọi chương trình SEND_TxBUFF_TO_PC
KeyPress =11?
KeyPress =10?
Gọi chương trình SELECT_TxRx
Y
N
Gọi chương trình SHIFT_RIGHT
N
Y
Gọi chương trình CLEAR_Tx_OR_Rx
KeyPress =14?
KeyPress =15?
4.2.4. Chức năng truyền nhận dữ liệu nối tiếp với PC.
Khi PC thực hiện truyền dữ liệu cho mC, thì mỗi khi mC hoàn thành việc nhận một byte dữ liệu từ cổng nối tiếp, cờ ngắt kết thúc nhận của bộ UART trên mC AT90S8535 được dựng. Chương trình con phục vụ ngắt tương ứng là Rx_COMPELET được thực hiện. Chương trình này có nhiệm vụ phân biệt dạng dữ liệu nhận được từ PC là mã lệnh hay chuỗi ký tự hiển thị để báo cho chương trình điều khiển thực hiện những tác vụ tương ứng.
Hình 4.16 : Lưu đồ ngắt Rx_COMPELET
Bắt đầu
Lưu lại trạng thái MCU
Lưu thanh ghi cần sử dụng
Kết thúc
Đọc dữ liệu nhận được
Data URD
Mã lệnh?
Y
N
Ký tự #?
Y
N
CR?
Y
N
Xác định địa chỉ cần lưu
ký tự vừa nhận trong RxBuff
Ghi ký tự vừa nhận
vào bộ đệm RxBuff
Xác định con trỏ hiển thị của chuỗi ký tự
Lấy lại giá trị các thanh ghi
Lấy lại trạng thái MCU
Lấy mã lệnh
Implement Data
Xoá cờ báo
nhận mã lệnh
Dựng cờ báo
nhận mã lệnh
Dựng cờ báo cần hiển thị dữ liệu nhận được
Khi mC nhận được một lệnh từ PC gửi tới, thanh ghi chứa mã lệnh Implement sẽ chứa giá trị mã hoá của lệnh. Khi mC nhận được một lệnh từ CPU, chương trình con EXCUTER_FROM_PC sẽ được gọi để thực hiện lệnh. Trong đồ án này, chương trình trên PC chỉ có thể truyền hai lệnh đơn giản cho mC thực hiện là hiển thị giá trị nhiệt độ theo 0C hay 0K.
Hình 4.17 : Lưu đồ chương trình con EXCUTER_FROM_PC
Bắt đầu
Xác lập lại nội dung thanh ghi mã lệnh
Implement -1
Hiển thị 0C?
Y
N
Kết thúc
Xoá cờ cho phép
hiển thị theo độ K
Dựng cờ cho phép hiển ký hiệu dạng nhiệt độ hiển thị
Dựng cờ cho phép
hiển thị theo độ K
Không chỉ có khả năng nhận dữ liệu từ PC, mà mC AT90S8535 cũng có thể gửi một chuỗi dữ liệu trong bộ đệm TxBuff sang PC tại bất kỳ thời điểm nào mỗi khi phím Send trên bàn phím được ấn.
Hình 4.18 : Lưu đồ chương trình SEND_TxBUFF_TO_PC
Bắt đầu
SelectRx?
Y
N
Kết thúc
TxBuff = 0?
Y
N
Hiện thông báo truyền dữ liệu
Lấy địa chỉ đầu của bộ đệm
XL LOW(TxBuff)
Truyền dữ liệu sang PC
Chương 5
Thiết kế hệ thống phần mềm trên PC
5.1. Mục đích của phần mềm trên PC.
Để hệ thống có thể giao tiếp được với máy tính, ta cần phải thiết kế một phần mềm trên máy tính để nó có thể giao tiếp được với mC. Điều này có nghĩa là ta phải thiết lập một hệ thống trao đổi dữ liệu giữ máy tính và mC, nhằm mục đích tạo ra một sự kết hợp giữa máy tính và mC để tạo nên một hệ thống hoàn chỉnh cho dù chúng ở cách xa nhau. Mặt khác, so với mC thì PC có nhiều khả năng xử lý dữ liệu với độ phức tạp cao, điều này làm cho hệ thống hoạt động một cách thực sự có hiệu quả.
Toàn bộ chương trình phần mềm viết cho PC được thực hiện trên ngôn ngữ Visual C++ 6.0. Phương pháp trao đổi dữ liệu giữa PC và mC được thực hiện theo phương pháp truyền nối tiếp theo chuẩn RS232 như đã trình bầy ở các chương trước. Sơ đồ tổng thể của chương trình viết trên PC như trên hình 5.1.
Hình 5.1 : Sơ đồ khối chương trình viết trên PC
Chương trình
Truyền thông tin sang mC qua cổng RS232
Nhận dữ liệu từ giao
diện nối tiếp RS232
Xử lý dữ liệu
nhận được
Hiện thông tin nhận được từ mC
Hiện dữ liệu
nhận được từ mC
Lưu trữ dữ
liệu nhận được
Sau khi chương trình được khởi động, nó sẽ do tìm port nối tiếp và thiết lập kết nối với mC. Nếu kết nối không được thực hiện, thì thao tác truyền nhận dữ liệu giữa PC và mC sẽ không được thực hiện. Trong trường hợp này, chương trình chỉ thực hiện các thao tác với các thông tin đã được lưu lại trên PC. Khi kết nối thành công chương trình sẽ liên tục nhận dữ liệu được gửi từ mC, khi đó chương trình sẽ thực hiện các xử lý tiếp theo tuỳ thuộc loại dữ liệu nhận được là thông tin hay giá trị nhiệt độ.
Trong trường hợp chương trình không tự động thực hiện được kết nối, người sử dụng có thể tự thực hiện kết nối khi cần thiết bằng cách gọi chương trình thực hiện kết nối mới thông qua chức năng Configure\Set port to connect của Menu chính trong chương trình.
Hình 5.2 : Giao diện thiếp lập kết nối với mC
5.2. Một số chức năng chính của chương trình
Sau khi kết nối được thực hiện, kết quả chuyển đổi A/D của mC sẽ được gửi liên tục sang PC. Khi nhận được dữ liệu, chương trình sẽ thực hiện phân tích dữ liệu nhận được. Nếu nhận được ký tự "#" thì hai byte dữ liệu tiếp theo sẽ được nhận dưới dạng giá trị của kết quả chuyển đổi A/D. Chương trình sẽ thực hiện hiển thị giá trị nhiệt độ vừa nhận được lên đồ thị nhiệt độ tức thời. Trong khoảng thời gian 1 phút, giá trị nhiệt độ trung bình sẽ được lưu lại cơ sở dữ liệu để có thể xử lý lại đồng thời giá trị này cũng được hiển thị trên đồ thị nhiệt độ trung bình.
Hình 5.3 : Giao diện nhận và hiển thị kết quả ADC
Bất kỳ byte dữ liệu nào nhận được mà trước đó chương trình không nhận được ký tự "#" đều được coi là ký tự hiển thị và sẽ được hiển thị trên cửa sổ truyền nhận thông tin giữa PC và mC. Đồng thời chương trình cũng có thể gửi một chuỗi thông tin sang mC để hiển thị trên giao diện LCD. Thao tác này có thể được thực hiện đồng thời với thao tác truyền dữ liệu của mC do vi mạch UART của mC hoạt động ở chế độ chuyền song công. Chương trình cũng có thể gửi lệnh để mC thực hiện thông qua việc lựa chọn thang nhiệt độ hiển thị là 0C hay 0K trong hộp thoại điều khiển và truyền nhận thông tin của chương trình.
Hình 5.4 : Giao diện truyền nhận thông tin
Ngoài các chức năng trên chương trình cũng cho phép xem lại dữ liệu được thu thập từ trước thông qua chức năng File\View data from list của Menu chương trình. Chức năng này không chỉ cho phép xem lại dữ liệu mà nó có thể dựng lại đồ thị diễn biến của nhiệt độ được lưu trong cơ sở dữ liệu theo thời gian giá trị nhiệt độ được cập nhật.
Hình 5.5 : Giao diện xem lại dữ liệu được 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
Các file đính kèm theo tài liệu này:
- DAN021.doc