Hướng dẫn làm Lab 1: Cấu trúc chương trình đề xuất cho các bài thí nghiệm | Đại học Bách Khoa, Đại học Đà Nẵng

Hưỡng dẫn làm Lab 1: Cấu trúc chương trình đề xuất cho các bài thí nghiệm | Đại học Bách Khoa, Đại học Đà Nẵng giúp sinh viên tham khảo, ôn luyện và phục vụ nhu cầu học tập của mình cụ thể là có định hướng, ôn tập, nắm vững kiến thức môn học và làm bài tốt trong những bài kiểm tra, bài tiểu luận, bài tập kết thúc học phần, từ đó học tập tốt và có kết quả cao cũng như có thể vận dụng tốt những kiến thức mình đã học

Hướng dẫn TN VXL
Cấu trúc chương trình đề xuất cho các bài thí nghiệm.
Phần này đưa ra đề xuất cấu trúc chương trình cho TN VXL, từ đó đưa ra gợi ý về việc sắp xếp
code sao cho hợp lý để thực hiện bài TN. Khi code một yêu cầu nào đó, tốt nhất là phân tích và
sắp xếp chương trình gọn gàn, hợp lý, bài 1 còn dễ qua mấy bài sau thì @@.
.ORG 0
RJMP MAIN
//Khai báo các vector ngắt.
/* Từ 0x00 đến 0x3C là nơi khai báo các vector ngắt, không nến viết code trong
vùng này, vì vậy chương trình chính nến bắt đầ4u từ 0x40*/
.ORG 0X40
MAIN:
/*Trong MAIN khai báo những gì chỉ; chạy 1 lầ4n, ví dụ:
Cầu hình PORT INPUT, OUTPUT
Khơ;i động LCD 16x2, Khơ;i tạo hiế;n thị LCD
...*/
LOOP:
/*Chương trình trong vòng lập chạy liến tục, ví dụ kiế;m tra nút nhần, quét led ma
trận, quét led 7 đoạn, đọc giá trị ADC liến tục rô4i hiế;n thị lến LCD...*/
/*...*/
JMP LOOP
//--------------------------------------------------------
//Các Chương trình con
//--------------------------------------------------------
CTRINH_CON_1:
//Nội dung Chương trình con thứ 1
RET
//--------------------------------------------------------
CTRINH_CON_2:
//Nội dung Chương trình con thứ 2
RET
//--------------------------------------------------------
//Các chương trình xư; lý ngắt
//--------------------------------------------------------
TIMER1_ISR:
//Nội dung đoạn chương trình xư; lý ngắt TIMER1
RETI
Ví dụ LAB1_1 Bài 1.
Trước khi làm bài này, SV cần hiểu được thiết kế trong board TN. Dưới đây là thiết kế khối DIP
SWITCH. DIP SWITCH là linh kiện có mã số U21 trong hình, (các bạn đã gặp nó trong TN KTS), và
được kết nối với hàng header 8x2 J41, thiết kế này giúp linh động trong việc kết nối với VXL, có
thể kết nối cả 8 DIP SW vào PORT A, B, C hoặc D tùy ý.
Giả sử DIP SW kết nối với PORT A thì DIP SW ở trạng thái OFF thì PORT A có giá trị là gì?
Giá trị High-Z (thả nổi). Vì DIP SW off, mạch hở.
Vì vậy PORT A phải khai báo thêm điện trở kéo lên, nếu vậy thì lúc này port A mức 1.
Tương tự khối BAR LED, tín hiệu điều khiển từ vxl mức 1 => đèn sáng.
Tóm lại: DIP SW OFF => PORT A mức 1 => Đèn phải tắt (theo đề) => Tức tín hiệu điều khiển đèn
mức 0, nó bị ngược lại so với tín hiệu đọc được.
Vì vậy tín hiệu đk đèn port b= tín hiệu đọc được từ port A XOR 0xFF. (Để đảo bit lại)
Chương trình đề xuất:
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/*PORT A kết nôi vào DIP SWITCH => PORT A cầ4n pha;i là input, input thì pha;i khai
báo thếm điện trơ; kéo lến. Không khai báo kéo lến sẽ bị nhiế[u, lúc TN thư; bo; khai
báo điện trơ; kéo lến rô4i đưa tay lại gầ4n dầy port sẽ biết.
PORT B kết nôi với LED đế; hiế;n thị => PORT B là output, sau khi khai báo B là
output thì cầ4n đặt giá trị ban đầ4u cho đèn là sáng hay tắt.
...*/
R16,0x00 LDI
OUT DDRA,R16
R16,0XFF LDI
OUT PORTA,R16
R16,0XFF LDI
OUT DDRB,R16
LDI R16,0X00
OUT PORTB,R16
LOOP:
/* SWITCH OFF -> đèn tắt, chương trình cầ4n làm là:
Đọc giá trị từ Port A
Lầy bù giá trị đã đọc
Xuầt giá trị đã bù ra PORT B
*/
IN R19,PINA
LDI R17,0XFF
EOR R19,R17
OUT PORTB,R19
JMP LOOP
LAB1_1 Bài 2.
Gợi ý, mầy dầu ... là phầ4n code các bạn tự bô; xung vô, bài này có thế; bị tràn sô
khi hiế;n thị, kệ đi hiế;n thị 8 bit cuôi là đc rô4i.
/* Kết nôi dầy
DIP SW -> PORT A
BARLED -> PORT B
*/
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/* Khai báo */
//PORT A input, PULL-up.
LDI R16,0x00
OUT DDRA,R16
LDI R16,0XFF
OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4u bằng 0.
R16,0XFF LDI
OUT DDRB,R16
LDI R16,0X00
OUT PORTB,R16
LOOP:
/* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19
IN R19, PINA
LDI R17, 0XFF
EOR R19, R17
// Cộng thếm 5, xem lại các lệnh ADC, ADD, ADIW.
ADIW R19, 5
// Xuầt giá trị ra PORT B
OUT PORTB, R19
JMP LOOP
LAB1_1 Bài 3
Gợi ý, mầy dầu ... là phầ4n code các bạn tự bô; xung vô. Đế4 ví dụ bị nhầ4m nhé, đúng
là 0011_1111. Kết qua; tôi đa là 15*15 = 225 => 8 bit cuôi cu;a kết qua; là được.
/* Kết nôi dầy
DIP SW -> PORT A
BARLED -> PORT B
*/
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/* Khai báo */
//PORT A input, PULL-up.
LDI R16,0x00
OUT DDRA,R16
LDI R16,0XFF
OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4u bằng 0.
LDI R16,0XFF
OUT DDRB,R16
LDI R16,0X00
OUT PORTB,R16
LOOP:
/* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19
IN R19, PINA
LDI R17, 0XFF
EOR R19, R17
// Tách 4 bit cao trong R19 lưu vào R20, 4 bit thầp đế; trong R19
//VD: R20 = 0000 0011 và R19 = 00001111
MOV R20, R19
SWAP R20
ANDI R20, 0X0F
ANDI R19, 0X0F
// Thực hiện phép nhần ko dầu bằng hàm MUL, kết qua; phép nhần là mầy bit, lưu
trong đầu, cái nào trong? (tự xem lại)
MUL R19, R20
// Xuầt giá trị 8 bit thầp ra PORT B
OUT PORTB, R0
JMP LOOP
LAB1_1 Bài 4
Gợi ý, mầy dầu ... là phầ4n code các bạn tự bô; xung vô. Sô có dầ4u bù 2 nhé các
bạn.
/* Kết nôi dầy
DIP SW -> PORT A
BARLED -> PORT B
*/
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/* Khai báo */
//PORT A input, PULL-up.
LDI R16,0x00
OUT DDRA,R16
LDI R16,0XFF
OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4u bằng 0.
LDI R16,0XFF
OUT DDRB,R16
LDI R16,0X00
OUT PORTB,R16
LOOP:
/* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19
IN R19, PINA
LDI R17, 0XFF
EOR R19, R17
// Tách 4 bit cao trong R19 lưu vào R20, 4 bit thầp đế; trong R19
// VD: R20 = 0000 0011 và R19 = 00001111
MOV R20, R19
SWAP R20
ANDI R20, 0X0F
ANDI R19, 0X0F
// Kiế;m tra bit 3 trong R20 và R19 có là bit 1 (sô ầm không), nếu là sô ầm, chèn
1111 vào 4 bit trọng sô cao.
// VD: R20 = 0000 0011 và R19 = 1111 1111
LDI R22, 0X02
LDI R21, 0X08
AND R21, R19
SBRC R21, 3 // kt bit dầu nếu ầm thì cộng thếm 1111
ADIW R19, 0XF0
SBRS R21, 3 // kt bit dầu nếu dương thì trừ thanh ghi R22 đi 1
DEC R22
LDI R21, 0X08
AND R21, R20
SBRC R21, 3
ADIW R20, 0XF0
SBRS R21, 3
DEC R22
// Thực hiện phép nhần bằng lệnh MUL, MULS, MULSU.
SBRC R22, 1 // R22 = 2 => 2 sô có dầu
MULS R19, R20
SBRC R22, 0 // R22 = 1 => 1 sô có dầu 1 sô không dầu
MULSU R19, R20
DEC R22
BRCC SKIP
MUL R19 R20
// Xuầt giá trị 8 bit thầp ra PORT B
SKIP:
OUT PORTB, R0
JMP LOOP
LAB1_1 Bài 5
Gợi ý, mầy dầu ... là phầ4n code các bạn tự bô; xung vô. Bài này mục đích là làm
việc trến từng bit trong port. SW trong board thí nghiệm 1 chần xuông đầt rô4i,
chần điế4u khiế;n nôi VXL, vậy nhần nút sẽ là mức 0, không nhần sẽ là mức 1 (pha;i
khai báo input pull-up). Lúc làm TN coi chừng nhầ4m với bàn phím ma trận 4x4 nhé.
/* Kết nôi dầy
DIP SW0 -> PA0
LED đơn -> PA1
*/
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/* Khai báo */
//PA0 input, PULL-up.
CBI DDRA, 0
SBI PORTA, 0
//PA1 OUTPUT, gán giá trị ban đầ4u bằng 0.
SBI DDRA, 1
CBI PORTA, 1
LOOP:
/* Vòng lập liến tục */
// Tự làm nha, nhớ chú thích đầ4y đu;.
IN R19, PORTA
SBRC R19, 0
ANDI R19, 0X00 // PA0 = 1 => ko nhần => AND thanh ghi với 0 đế; PA1 = 0
SBRS R19, 0
ORI R19, 0x02 // PA0 = 0 => nhần => OR thanh ghi với 2 đế; PA1 = 1
JMP LOOP
LAB1_2 Bài 1
Bài này sinh viên đổi đoạn code đã cho thành dạng theo cấu trúc đã trình bày ở trên, đổi đi, xài
cho quen sau này học mấy bài sau đỡ viết lộn.
/* Kết nôi dầy
TEST STATION -> PA0
*/
.ORG 0
RJMP MAIN
//--------------------------------------------------------
.ORG 0X40
MAIN:
/* Khai báo */
//PA0 OUTPUT
SBI DDRA, 0
LOOP:
/* Vòng lập liến tục */
SBI PORTA, PINA0
CBI PORTA, PINA0
rjmp loop
LAB1_2 Bài 2
Bài này đụng đến chương trình con rồi. Khi viết chương trình con, tốt nhất là viết chú thích cho
chương trình con đó, để sau này có gì dùng lại, đặc biệt là khi đi thi TN. Trong báo cáo phải viết
chú thích chương trình con.
Ví dụ: Đề bài yêu cầu viết chương trình con CONG5 có nhiệm vụ cộng 3 số 8 bit lưu trong R19,
R20, R21, kết quả trả về R23:R22.
Gợi ý viết chú thích:
//--------------------------------------------------------
//CONG5
//--------------------------------------------------------
/*
INPUT: R19, R20, R21
OUTPUT: R22, R23
Description: R23:R22 = R19 + R20 + R21
*/
CONG5:
//Đoạn chương trình thực hiện yếu cầ4u.
RET
.ORG 0
RJMP MAIN
.ORG 0X40
MAIN:
//Khai báo PA0 OUTPUT, gán giá trị ban đầ4u bằng 1
LDI R16, 0XFF
OUT DDRA, R16
OUT PORTA, R16
LOOP:
//Đa;o bit PA0
IN R19, PORTA
COM R19
//Gọi lại chương trình con Delay1s
RCALL Delay1s
JMP LOOP
//--------------------------------------------------------
//Các Chương trình con
//--------------------------------------------------------
/* Delay1ms
INPUT: None
OUTPUT: None
Description: Delay bằng vòng lập 1ms, với thạch anh 8MHz, hệ sô chia 8.
*/
Delay1ms:
LDI R20, 250
LP: NOP
DEC R20
BRNE LP
RET
//--------------------------------------------------------
Delay10ms:
LDI R20, 10
LP10:
RCALL Delay1ms
DEC R20
BRNE LP10
RET
//--------------------------------------------------------
Delay100ms:
LDI R20, 100
LP100:
RCALL Delay1ms
DEC R20
BRNE LP100
RET
//--------------------------------------------------------
Delay1s:
LDI R21, 10
LDI R20, 100
LP1000: RCALL Delay1ms
DEC R20
BRNE LP1000
DEC R21
BRNE LP1000
RET
LAB1_2 Bài 3
Thanh ghi dịch sử dụng là 74HC595.
Các chân quan trọng cần nhớ
Tên STT Loại Mô tả
/CLR 10 Input Chân clear dữ liệu trong 595, tích cực thấp (0 là
clear), nếu lập trình có yêu cầu dùng chân này thì
kết nối với VXL rồi set chân này lên 1, nếu muốn
clear thì cho xuống 0. Nếu không muốn lập trình
chân này thì cắm thẳng lên 5V.
SRCLK 11 Input Clock thanh ghi dịch, lấy cạnh lên (rising edge).
Các bạn hình dung trong con IC 595 có 1 thanh
ghi 8 bit, mỗi khi có cạnh lên, dữ liệu hiện tại có
trên chân SDI sẽ được dịch vào thanh ghi này.
VD: Sau khi clear 595, giả sử chân SDI luôn bằng
1, mỗi khi có clock trên chân SRCLK này, dữ liệu
trong thanh ghi sẽ thay đổi như sau:
0000 0000
1000 0000
1100 0000…
RCLK 12 Input Đây là Clock chốt, lấy cạnh lên.
Mỗi khi có cạnh lên, dữ liệu hiện tại chứa trong
thanh ghi 8 bit trong con 595 sẽ được đưa ra ngõ
ra ở các chân QA đến QH tương ứng.
SDI 14 Input Serial Data Input muốn đưa vào.
QA->QH Output Các bit out.
Để tạo hiệu ứng theo yêu cầu bài TN3, ta viết thứ tự thực hiện như sau:
Đảm bảo các chân SRCLK và RCLK = 0 ban đầu
SDI = 1 (đèn sáng)
SRCLK = 1 ; tạo xung cạnh lên đưa SDI =1 vào 595
SRCLK = 0
RCLK = 1 ; tạo xung chốt đưa dữ liệu ra QA đến QH
RCLK = 0
Delay 500 ms
Lập lại đoạn code trên 8 lần.
SDI = 0 (đèn tắt)
SRCLK = 1 ; tạo xung cạnh lên đưa SDI =0 vào 595
SRCLK = 0
RCLK = 1 ; tạo xung chốt đưa dữ liệu ra QA đến QH
RCLK = 0
Delay 500 ms
Lập lại đoạn code trên 8 lần.
Mở rộng để tham khảo cho các bài về sau. Giả sử có 8 bit được chứa trong R17= A7A6A5A4
A3A2A1A0, cần đặt 8 bit này ra con 595 thì ta làm thế nào. (MSB đi đầu)
Đảm bảo các chân SRCLK và RCLK = 0 ban đầu
Đặt chân SDI = A7
SRCLK = 1 ; tạo xung cạnh lên đưa A7 vào 595
SRCLK = 0
Đặt chân SDI = A6
SRCLK = 1 ; tạo xung cạnh lên đưa A6 vào 595
SRCLK = 0
Đặt chân SDI = A0
SRCLK = 1 ; tạo xung cạnh lên đưa A0 vào 595
SRCLK = 0
RCLK = 1 ; tạo xung cạnh lên đưa dữ liệu ra QA đến QH.
RCLK = 0
Trên đây là các bước cơ bản để hiểu thôi, còn các bạn viết phải dùng vòng lập để thực hiện việc
này. Tham khảo đoạn code dưới đây, sửa từ ví dụ 10.26 trong giáo trình. Trong ví dụ 10.26, 2
chân clock SRCLK và RCLK nối với nhau, code dưới đây có sửa lại 1 tí.
//Khúc này gán các chần port, pin bằng từ khóa, vì phầ4n cứng thay đô;i linh động
được nến định danh như vậy dế[ sư;a đô;i. Ví dụ nay kết nôi port A, hôm sau phầ4n
cứng lại kết nôi port B thì chỉ; cầ4n đô;i trong định danh, nhanh gọn không thiếu
xót.
.EQU shiftPORT=PORTA
.EQU ShiftDDR=DDRA
.EQU ShiftSDI=0 ;SDI => PA0
.EQU ShiftCLK=1 ;SRCLK => PA1
.EQU ShiftLATCH=2 ;RCLK => PA2
.ORG 0
RJMP MAIN
.ORG 0X40
MAIN:
//Khai báo PA0, PA1, PA2 là output, giá trị khơ;i tạo là 0. Nến viết bằng từ khóa
định danh phía trến luôn nhé.
...
LOOP:
JMP LOOP
//--------------------------------------------------------
//Các Chương trình con
//--------------------------------------------------------
/* SHO_8
INPUT: R20
OUTPUT: QA đến QH trến IC595
Description:
*/
SHO_8:
LDI R20,9
SH_LOOP:
ROL R17
BRCC BIT_0
SBI shiftPORT,shiftSDI
RJMP NEXT
BIT_0:
CBI shiftPORT,shiftSDI
NEXT:
SBI shiftPORT,shiftCLK
CBI shiftPORT,shiftCLK
DEC R20
BRNE SH_LOOP
SBI shiftPORT,shiftLATCH
CBI shiftPORT,shiftLATCH
RET
LAB1_3 Bài 1
Lý thuyết về LCD
Module LCD được sử dụng nhiều trong các ứng dụng nhúng hiện nay, chúng dùng để hiển thị
thông tin một cách linh hoạt và tiết kiệm năng lượng. Có nhiều loại module LCD, trong đó thông
dụng nhất là loại LCD 16x2 là loại hiển thị 2 hàng mỗi hàng 16tự. Mỗi tự được hiển thị
bởi một ma trận điểm ảnh có kích thước 5x8 điểm hoặc 5x11 điểm ảnh, tùy chế độ mà người lập
trình thiết lập.
Phần lớn các module LCD sử dụng giao tiếp 16 chân trong đó có:
8 đường dữ liệu
3 đường điều khiển
3 đường cấp nguồn cho module
2 đường cấp nguồn cho LED nền trên LCD
Châ
n
Tên Mô tả chức năng
1 V
SS
GND.
2 V
DD
+5 Volt.
3 V
EE
Tương phản (contrast): dùng để điều chỉnh độ tương phản giữ các chữ cái đèn
nền trong LCD. Chân này sđược nối vào một mạch chia áp dùng biến trở để dễ
dàng thay đổi độ tương phản khi vặn biến trở.
4 RS Chọn thanh ghi (Register Select): chọn thanh ghi trong LCD để giao tiếp.
5 R/W Đọc/ghi (Read/Write): Chọn chế độ đọc hoặc ghi vào LCD. Trong kit thí nghiệm
VXL, sinh viên chỉ thực hiện chế độ ghi vào LCD nên chân này được nối đất.
Ghi chú: đối với các tín hiệu có kí hiệu bởi dấu ‘/’ thì ta hiểu phần bên trái dấu ‘/’
tương ứng với bit 1, phần bên phải dấu ‘/’ tương ứng với bit 0.
6 E Cho phép (Enable): cho phép dữ liệu đọc/ghi trên LCD. Sau khi thiết lập các tín
hiệu cần vào LCD (từ các chân RS, R/W, dữ liệu [0-7]) thì chân này kích cạnh
xuống để thực hiện lệnh.
7 D0 Bit 0 của dữ liệu
8 D1 Bit 1 của dữ liệu
9 D2 Bit 2 của dữ liệu
10 D3 Bit 3 của dữ liệu
11 D4 Bit 4 của dữ liệu
12 D5 Bit 5 của dữ liệu
13 D6 Bit 6 của dữ liệu
14 D7 Bit 7 của dữ liệu
15 LED+ Cấp nguồn + cho đèn LED nền trên LCD
16 LED- Cấp nguồn – cho đèn LED nền trên LCD
(Phần sau đây là quan trọng phải nắm vững)
Trong LCD có chứa một CGRAM và một DDRAM:
CGRAM: Vùng RAM này khi thí nghiệm sinh viên không cần tương tác với chúng.
CGRAM có kích thước 64 Bytes chứa sẵn bảng mã hiển thị các ký tự tương ứng theo mã
ASCII. Ngoài ra nó có chứa 1 vùng trống thể tùy ý vẽ thêm các ký tự tùy chỉnh, vẽ 8
ký tự khác nhau khi dùng 5x8 điểm ảnh để thiết kế (một ký tự sử dụng 8 bytes) hoặc 4 ký
tự khác nhau khi dùng 5x11 điểm ảnh để thiết kế.
DDRAM: Vùng RAM chứa ký tự hiển thị trên màn hình LCD. Màn hình LCD 16x2 gồm
có 2 hàng, mỗi hàng gồm 16 ký tự tương ứng với địa chỉ của DDRAM được cho ở dưới.
Người lập trình muốn hiển thị ký tự gì tại vị trí nào trên màn hình LCD thì cần ghi mã số
của ký tự đó vào ô nhớ tương ứng với vị trí cần ghi trên DDRAM. Ví dụ muốn ghi ký tự
O vào ô thứ 15 của hàng đầu tiên trên LCD (Như hình 1) thì cần ghi số của ký tự O
vào ô nhớ 0EH của DDRAM. Mã số ký tự thì được tra tại hình 3 như sau. Ghi chú: bảng
mã ký tự tương ứng với mã ASCII.
Các mã lệnh để giao tiếp với LCD được liệt kê ở bảng sau, như ta thấy mã lệnh liên quan đến các
tín hiệu vào module LCD như RS, R/W, Data bit 0 đến bit 7. Muốn ghi một lệnh vào LCD cần
điều khiển các chân tín hiệu kể trên tương ứng với lệnh cần ghi sau đó kích chân cho phép
(Enable) của LCD (kích cạnh xuống).
Trong bo mạch thí nghiệm vi xử lý, phần giao tiếp LCD được thiết kế theo giao tiếp 4 bit DATA
như hình sau.
Về lập trình ta nên chia mã lệnh ghi vào LCD thành 2 loại: ghi lệnhghi tự, ứng với chân
RS = 0 và RS = 1.
- Ghi lệnh (khi RS =0): là các lệnh cấu hình LCD, thiết lập con trỏ tắt hoặc bật, nhấp nháy
con trỏ…
- Ghi ký tự (khi RS =1): là ghi/ đọc ký tự vào DDRAM để hiển thị lên LCD.
vậy ta sẽ viết 2 chương trình con nhiệm vụ ghi lệnhWRITE_COMMAND WRITE_DATA
chứa trong thanh ghi R17 ra LCD (dưới phần code gợi ý). Để sử dụng ta gán mã lệnh hoặc mã kí
tự vào R17 rồi gọi hàm này thôi, ví dụ sau.
LDI R17,$20
CALL WRITE_COMMAND
Ví dụ: Trước khi hiển thị LCD phải có một đoạn lệnh để cấu hình cho LCD như sau:
//Hàm con khơ;i tạo LCD
//Input: None
//Output: None
//Description: Khơ;i tạo LCD
INIT_LCD_4BIT:
LDI R17,$28
CALL WRITE_COMMAND
LDI R17,$01
CALL WRITE_COMMAND
LDI R17,$0C
CALL WRITE_COMMAND
LDI R17,$06
CALL WRITE_COMMAND
RET
Giờ sinh viên cần phải hiểu các mã lệnh 0x28, 0x01, 0x0C… có ý nghĩa gì.
Mã lệnh là 0x28 = 0b0010 1000 đây chính là lệnh bắt đầu với DB5 =1, khi dùng ghi lệnh thì RS
= 0, ta tra bảng, gióng xuống tìm DB5 = 1. Đây là câu lệnh Function set, với DL = 0, N =1 và F
=0. Tức là giao tiếp 4 bits, số lượng dòng hiển thị là 2 (LCD có 2 hàng trên và dưới), kích thước
ký tự là 5x8.
Ghi chú: đối với các tín hiệu có kí hiệu bởi dấu ‘/’ thì ta hiểu phần bên trái dấu ‘/’ tương ứng với
bit 1, phần bên phải dấu ‘/’ tương ứng với bit 0.
Tương tự mã lệnh 0x01=0b0000 0001 tương ứng với lệnh clear màn hình.
Tương tự với mã lệnh 0x0E = 0b0000 1110. Tức D = 1, C =1, B =0 nghĩa là: cho phép hiển
thị, cho phép bật con trỏ, không cho con trỏ nhấp nháy.
Về phần ghi ký tự cũng tương tự. Gán mã ký tự mong muốn vào R17 rồi gọi hàm . WRITE_DATA
LDI R17,$41
CALL WRITE_DATA
Ví dụ ghi ký tự V ra LCD:
LDI R17,’V’
CALL WRITE_DATA
Sau khi thực hiện lệnh ghi tự, tự sẽ được ghi vào ô DDRAM hiện hành. Nếu địa chỉ
DDRAM hiện hành thuộc khoản 0x00-0x0F hoặc 0x40H-0x4F thì trên LCD sẽ hiển thị tự
tương ứng vào ô đó, đồng thời sau đó địa chỉ DDRAM sẽ tự cộng thêm 1 và sẽ ghi ký tự ở ô tiếp
theo nếu dùng thêm lệnh ghi tự. Trường hợp ô tự hiện hành 0F (tức ô cuối cùng của
hàng 1), sau khi ghi lệnh ghi ký tự ra ô này, DDRAM sẽ được cộng lên 1 là 0x10 chứ không phải
là 0x40, nghĩa là ký tự sẽ không tự động nhảy xuống hàng dưới. Để xuống hàng hoặc ghi vào ô
ký tự cụ thể nào ta cần phải sử dụng thêm lệnh chọn địa chỉ DDRAM như sau, mã lệnh này được
tính là 0x80+địa chỉ DDRAM cần nhảy đến.
Ví dụ: muốn ghi chữ “VXL” lên LCD tại vị trí sau thì công việc cần làm là: gọi lệnh chọn địa chỉ
DDRAM tại ô 0x46, mã lệnh của lệnh này sẽ là 0x80 + 0x46 = 0xC6. Tiếp đó ghi các ký tự ‘V’,
‘X’, ‘L’.
Đoạn chương trình hiển thị chữ “VXL”, SV nên kết hợp với phương pháp tra bảng để hiển thị.
LDI R17,$C6
CALL WRITE_COMMAND
LDI R17,’V’
CALL WRITE_DATA
LDI R17,’X’
CALL WRITE_DATA
LDI R17,’L’
CALL WRITE_DATA
Code gợi ý cho bài Lab1_3 bài 1.
.EQU LCD_PORT=PORTA
.EQU LCD_DDR=DDRA
.EQU RS=0
.EQU RW=1
.EQU EN=2
.ORG 0
RJMP MAIN
.ORG 0X40
MAIN:
LDI R16,LOW(RAMEND) ;DUA DIA CHI RAMEND LEN VI TRI CAO NHAT
OUT SPL,R16
LDI R16,HIGH(RAMEND)
OUT SPH,R16
/*
Kết nôi port A vào LCD, RS=PA0, RW=PA1, EN=PA2, Data[4:7] = PA4:PA7
=> Khai báo PA012 4567 (không có PA3) là output, gán các giá trị ban đầ4u như sau:
Data = 0, RS=0, RW=1, EN=0.
*/
...
//Gọi chương trình con khơ;i tạo nguô4n (POWERUP_LCD_4BIT) cho chế độ LCD 4 bit, cụ
thế; thì xem lại giáo trình. Không gọi chương trình con này, LCD không hiế;n thị
được.
...
//Gọi chương trình con cầu hình LCD.
...
//Gọi lệnh tro; con tro; vế4 vị trí DDRAM 0x00
...
//Dưới đầy là đoạn code tra ba;ng, xuầt ký tự hàng thứ 1 ra LCD cho đến khi gặp ký
tự 0x00
LDI ZH,HIGH(LINE1<<1)
LDI ZL,LOW(LINE1<<1)
DISPLAY_LINE1:
LPM R17,Z+
CPI R17,$00
BREQ NEWLINE
CALL WRITE_DATA
RJMP DISPLAY_LINE1
NEWLINE:
//Viết lệnh xuông hàng (lệnh chọn địa chỉ; DDRAM tại 0x40)
...
//Tương tự, viết code xuầt ra hàng thứ 2
LOOP:
// Bài này vòng lập không viết gì ca;, vì mọi thứ chỉ; cầ4n chạy 1 lầ4n thôi.
RJMP LOOP
//Chương trình con
;------------------------------------------------
//POWERUP_LCD_4BIT
//Input: None
//Output: None
//Description: Hàm con power up LCD
POWERUP_LCD_4BIT:
LDI R16,250
RCALL DELAY_US
LDI R16,250
RCALL DELAY_US
LDI R17,$30
RCALL OUT_COMMAND
LDI R16,50
RCALL DELAY_US
LDI R17,$30
RCALL OUT_COMMAND
LDI R16,2
RCALL DELAY_US
LDI R17,$20
RCALL OUT_COMMAND
RET
//Hàm con khơ;i tạo LCD
//Input: None
//Output: None
//Description: Khơ;i tạo LCD
INIT_LCD_4BIT:
LDI R17,$28
CALL WRITE_COMMAND
LDI R17,$01
CALL WRITE_COMMAND
LDI R17,$0C
CALL WRITE_COMMAND
LDI R17,$06
CALL WRITE_COMMAND
RET
//Hàm con ghi lệnh ra LCD
//Input: R17
//Output: None
//Description: Ghi lệnh chứa trong R17 ra LCD.
WRITE_COMMAND:
PUSH R17
ANDI R17,$F0 ; xuat 4 bit dau ra truoc
RCALL OUT_COMMAND
POP R17
SWAP R17
ANDI R17,$F0 ; xuat 4 bit sau ra
RCALL OUT_COMMAND
RET
//Hàm con ghi ký tự ra LCD
//Input: R17
//Output: None
//Description: Ghi kí tự ra LCD theo mã ASCII, ví dụ R17=0x41 thì LCD hiế;n thị
chữ A
WRITE_DATA:
PUSH R17
ANDI R17,$F0 ; xuat 4 bit dau
RCALL OUT_DATA
POP R17
SWAP R17
ANDI R17,$F0 ; xuat 4 bit sau
RCALL OUT_DATA
RET
OUT_COMMAND:
OUT LCD_PORT,R17
CBI LCD_PORT,RS
CBI LCD_PORT,RW
SBI LCD_PORT,EN
NOP
CBI LCD_PORT,EN
LDI R16,20
CALL DELAY_US
RET
OUT_DATA:
OUT LCD_PORT,R17
SBI LCD_PORT,RS
CBI LCD_PORT,RW
SBI LCD_PORT,EN
NOP
CBI LCD_PORT,EN
LDI R16,20
CALL DELAY_US
RET
/* DELAY_US
Input: R16
Output: None
Description: DELAY R16*100 MICROSEC
*/
DELAY_US:
MOV R15,R16
LDI R16,200
L1: R14,R16MOV
L2: R14DEC
NOP
BRNE L2
DEC R15
BRNE L1
RET
LINE1: "TN VXL-AVR",.DB $00
LINE2: "10 DIEM",.DB $00
LAB1_3 Bài 2
Code gợi ý
/*
KET NOI PHAN CUNG:
PORT A: LCD
PORT B:BAR LED
PINC0: NUT NHAN
*/
.ORG 0
.EQU LCD_PORT=PORTA
.EQU LCD_DDR=DDRA
.EQU LED_PORT=PORTB
.EQU LED_DDR=DDRB
.EQU RS=0
.EQU RW=1
.EQU EN=2
RJMP MAIN
.ORG 0X40
//MAIN----------------------------------
MAIN:
LDI R16,LOW(RAMEND) ;DUA DIA CHI RAMEND LEN VI TRI CAO NHAT
OUT SPL,R16
LDI R16,HIGH(RAMEND)
OUT SPH,R16
//Khai báo PORT gắn LED là OUTPUT, gán giá trị ban đầ4u bằng 0 đế; LED tắt.
...
//Khai báo PC0 là input, có điện trơ; kéo lến
...
/*
Kết nôi port A vào LCD, RS=PA0, RW=PA1, EN=PA2, Data[4:7] = PA4:PA7
=> Khai báo PA012 4567 (không có PA3) là output, gán các giá trị ban đầ4u như sau:
Data = 0, RS=0, RW=1, EN=0.
*/
...
//Gọi chương trình con khơ;i tạo nguô4n (POWERUP_LCD_4BIT) cho chế độ LCD 4 bit, cụ
thế; thì xem lại giáo trình. Không gọi chương trình con này, LCD không hiế;n thị
được.
...
//Gọi chương trình con cầu hình LCD.
...
| 1/32

Preview text:

Hướng dẫn TN VXL
Cấu trúc chương trình đề xuất cho các bài thí nghiệm.
Phần này đưa ra đề xuất cấu trúc chương trình cho TN VXL, từ đó đưa ra gợi ý về việc sắp xếp
code sao cho hợp lý để thực hiện bài TN. Khi code một yêu cầu nào đó, tốt nhất là phân tích và
sắp xếp chương trình gọn gàn, hợp lý, bài 1 còn dễ qua mấy bài sau thì @@. .ORG 0 RJMP MAIN
//Khai báo các vector ngắ t. /* Từ 0x00 đế
n 0x3C là nơi khai báo các vector ngắ
t, không nến viết code trong
vùng này, vì vậy chương trình chính nến bắ t đầ4 u từ 0x40*/ .ORG 0X40 MAIN:
/*Trong MAIN khai báo những gì chỉ ; chạy 1 lầ4 n, ví dụ: Cầ u hình PORT INPUT, OUTPUT Khơ ;i động LCD 16x2, Khơ ;i tạo hiế; n thị LCD ...*/ LOOP:
/*Chương trình trong vòng lập chạy liến tục, ví dụ kiế; m tra nút nhầ n, quét led ma
trận, quét led 7 đoạn, đọc giá trị ADC liến tục rô4 i hiế; n thị lến LCD...*/ /*...*/ JMP LOOP
//-------------------------------------------------------- //Các Chương trình con
//-------------------------------------------------------- CTRINH_CON_1:
//Nội dung Chương trình con thứ 1 RET
//-------------------------------------------------------- CTRINH_CON_2:
//Nội dung Chương trình con thứ 2 RET
//-------------------------------------------------------- //Các chương trình xư; lý ngắ t
//-------------------------------------------------------- TIMER1_ISR:
//Nội dung đoạn chương trình xư; lý ngắ t TIMER1 RETI Ví dụ LAB1_1 Bài 1.
Trước khi làm bài này, SV cần hiểu được thiết kế trong board TN. Dưới đây là thiết kế khối DIP
SWITCH. DIP SWITCH là linh kiện có mã số U21 trong hình, (các bạn đã gặp nó trong TN KTS), và
được kết nối với hàng header 8x2 J41, thiết kế này giúp linh động trong việc kết nối với VXL, có
thể kết nối cả 8 DIP SW vào PORT A, B, C hoặc D tùy ý.
Giả sử DIP SW kết nối với PORT A thì DIP SW ở trạng thái OFF thì PORT A có giá trị là gì?
 Giá trị High-Z (thả nổi). Vì DIP SW off, mạch hở.
 Vì vậy PORT A phải khai báo thêm điện trở kéo lên, nếu vậy thì lúc này port A mức 1.
Tương tự khối BAR LED, tín hiệu điều khiển từ vxl mức 1 => đèn sáng.
Tóm lại: DIP SW OFF => PORT A mức 1 => Đèn phải tắt (theo đề) => Tức tín hiệu điều khiển đèn
mức 0, nó bị ngược lại so với tín hiệu đọc được.
Vì vậy tín hiệu đk đèn port b= tín hiệu đọc được từ port A XOR 0xFF. (Để đảo bit lại) Chương trình đề xuất: .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /*PORT A kế
t nôi vào DIP SWITCH => PORT A cầ4 n pha ;i là input, input thì pha ;i khai báo thếm điện trơ
; kéo lến. Không khai báo kéo lến sẽ bị nhiế[ u, lúc TN thư; bo; khai báo điện trơ ; kéo lến rô4 i đưa tay lại gầ4 n dầy port sẽ biế t. PORT B kế t nôi với LED đế;
hiế;n thị => PORT B là output, sau khi khai báo B là output thì cầ4 n đặt giá trị ban đầ4
u cho đèn là sáng hay tắ t. ...*/ LDI R16,0x00 OUT DDRA,R16 LDI R16,0XFF OUT PORTA,R16 LDI R16,0XFF OUT DDRB,R16 LDI R16,0X00 OUT PORTB,R16 LOOP:
/* SWITCH OFF -> đèn tắ t, chương trình cầ4 n làm là: Đọc giá trị từ Port A Lầ y bù giá trị đã đọc Xuầ
t giá trị đã bù ra PORT B */ IN R19,PINA LDI R17,0XFF EOR R19,R17 OUT PORTB,R19 JMP LOOP LAB1_1 Bài 2. Gợi ý, mầ y dầu ... là phầ4
n code các bạn tự bô; xung vô, bài này có thế; bị tràn sô khi hiế; n thị, kệ đi hiế; n thị 8 bit cuô i là đc rô4 i. /* Kế t nôi dầy DIP SW -> PORT A BARLED -> PORT B */ .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /* Khai báo */ //PORT A input, PULL-up. LDI R16,0x00 OUT DDRA,R16 LDI R16,0XFF OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4 u bằng 0. LDI R16,0XFF OUT DDRB,R16 LDI R16,0X00 OUT PORTB,R16 LOOP: /* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19 IN R19, PINA LDI R17, 0XFF EOR R19, R17
// Cộng thếm 5, xem lại các lệnh ADC, ADD, ADIW. ADIW R19, 5 // Xuầ t giá trị ra PORT B OUT PORTB, R19 JMP LOOP LAB1_1 Bài 3 Gợi ý, mầ y dầu ... là phầ4
n code các bạn tự bô; xung vô. Đế4
ví dụ bị nhầ4m nhé, đúng là 0011_1111. Kế t qua; tô
i đa là 15*15 = 225 => 8 bit cuôi cu ;a kết qua ; là được. /* Kế t nôi dầy DIP SW -> PORT A BARLED -> PORT B */ .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /* Khai báo */ //PORT A input, PULL-up. LDI R16,0x00 OUT DDRA,R16 LDI R16,0XFF OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4 u bằng 0. LDI R16,0XFF OUT DDRB,R16 LDI R16,0X00 OUT PORTB,R16 LOOP: /* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19 IN R19, PINA LDI R17, 0XFF EOR R19, R17
// Tách 4 bit cao trong R19 lưu vào R20, 4 bit thầ p đế; trong R19
//VD: R20 = 0000 0011 và R19 = 00001111 MOV R20, R19 SWAP R20 ANDI R20, 0X0F ANDI R19, 0X0F
// Thực hiện phép nhần ko dầ u bằng hàm MUL, kế t qua
; phép nhần là mầy bit, lưu
trong đầu, cái nào trong? (tự xem lại) MUL R19, R20 // Xuầ t giá trị 8 bit thầ p ra PORT B OUT PORTB, R0 JMP LOOP LAB1_1 Bài 4 Gợi ý, mầ y dầu ... là phầ4
n code các bạn tự bô; xung vô. Sô có dầ4u bù 2 nhé các bạn. /* Kế t nôi dầy DIP SW -> PORT A BARLED -> PORT B */ .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /* Khai báo */ //PORT A input, PULL-up. LDI R16,0x00 OUT DDRA,R16 LDI R16,0XFF OUT PORTA,R16
//PORT B OUTPUT, gán giá trị ban đầ4 u bằng 0. LDI R16,0XFF OUT DDRB,R16 LDI R16,0X00 OUT PORTB,R16 LOOP: /* Vòng lập liến tục */
// Đọc giá trị PORT A, lưu vào R19 IN R19, PINA LDI R17, 0XFF EOR R19, R17
// Tách 4 bit cao trong R19 lưu vào R20, 4 bit thầ p đế; trong R19
// VD: R20 = 0000 0011 và R19 = 00001111 MOV R20, R19 SWAP R20 ANDI R20, 0X0F ANDI R19, 0X0F // Kiế;
m tra bit 3 trong R20 và R19 có là bit 1 (sô
ầm không), nếu là sô ầm, chèn 1111 vào 4 bit trọng sô cao.
// VD: R20 = 0000 0011 và R19 = 1111 1111 LDI R22, 0X02 LDI R21, 0X08 AND R21, R19 SBRC R21, 3 // kt bit dầ u nế u ầm thì cộng thếm 1111 ADIW R19, 0XF0 SBRS R21, 3 // kt bit dầ u nế
u dương thì trừ thanh ghi R22 đi 1 DEC R22 LDI R21, 0X08 AND R21, R20 SBRC R21, 3 ADIW R20, 0XF0 SBRS R21, 3 DEC R22
// Thực hiện phép nhần bằng lệnh MUL, MULS, MULSU.
SBRC R22, 1 // R22 = 2 => 2 sô có dầ u MULS R19, R20
SBRC R22, 0 // R22 = 1 => 1 sô có dầ u 1 sô không dầu MULSU R19, R20 DEC R22 BRCC SKIP MUL R19 R20 // Xuầ t giá trị 8 bit thầ p ra PORT B SKIP: OUT PORTB, R0 JMP LOOP LAB1_1 Bài 5 Gợi ý, mầ y dầu ... là phầ4
n code các bạn tự bô; xung vô. Bài này mục đích là làm
việc trến từng bit trong port. SW trong board thí nghiệm 1 chần xuô ng đầt rô4i, chần điế4 u khiế; n nô
i VXL, vậy nhần nút sẽ là mức 0, không nhầ n sẽ là mức 1 (pha;i
khai báo input pull-up). Lúc làm TN coi chừng nhầ4
m với bàn phím ma trận 4x4 nhé. /* Kế t nôi dầy DIP SW0 -> PA0 LED đơn -> PA1 */ .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /* Khai báo */ //PA0 input, PULL-up. CBI DDRA, 0 SBI PORTA, 0
//PA1 OUTPUT, gán giá trị ban đầ4 u bằng 0. SBI DDRA, 1 CBI PORTA, 1 LOOP: /* Vòng lập liến tục */
// Tự làm nha, nhớ chú thích đầ4 y đu ;. IN R19, PORTA SBRC R19, 0
ANDI R19, 0X00 // PA0 = 1 => ko nhầ
n => AND thanh ghi với 0 đế; PA1 = 0 SBRS R19, 0
ORI R19, 0x02 // PA0 = 0 => nhầ
n => OR thanh ghi với 2 đế; PA1 = 1 JMP LOOP LAB1_2 Bài 1
Bài này sinh viên đổi đoạn code đã cho thành dạng theo cấu trúc đã trình bày ở trên, đổi đi, xài
cho quen sau này học mấy bài sau đỡ viết lộn. /* Kế t nôi dầy TEST STATION -> PA0 */ .ORG 0 RJMP MAIN
//-------------------------------------------------------- .ORG 0X40 MAIN: /* Khai báo */ //PA0 OUTPUT SBI DDRA, 0 LOOP: /* Vòng lập liến tục */ SBI PORTA, PINA0 CBI PORTA, PINA0 rjmp loop LAB1_2 Bài 2
Bài này đụng đến chương trình con rồi. Khi viết chương trình con, tốt nhất là viết chú thích cho
chương trình con đó, để sau này có gì dùng lại, đặc biệt là khi đi thi TN. Trong báo cáo phải viết
chú thích chương trình con.
Ví dụ: Đề bài yêu cầu viết chương trình con CONG5 có nhiệm vụ cộng 3 số 8 bit lưu trong R19,
R20, R21, kết quả trả về R23:R22. Gợi ý viết chú thích:
//-------------------------------------------------------- //CONG5
//-------------------------------------------------------- /* INPUT: R19, R20, R21 OUTPUT: R22, R23
Description: R23:R22 = R19 + R20 + R21 */ CONG5:
//Đoạn chương trình thực hiện yếu cầ4 u. RET .ORG 0 RJMP MAIN .ORG 0X40 MAIN:
//Khai báo PA0 OUTPUT, gán giá trị ban đầ4 u bằng 1 LDI R16, 0XFF OUT DDRA, R16 OUT PORTA, R16 LOOP: //Đa ;o bit PA0 IN R19, PORTA COM R19
//Gọi lại chương trình con Delay1s RCALL Delay1s JMP LOOP
//-------------------------------------------------------- //Các Chương trình con
//-------------------------------------------------------- /* Delay1ms INPUT: None OUTPUT: None
Description: Delay bằng vòng lập 1ms, với thạch anh 8MHz, hệ sô chia 8. */ Delay1ms: LDI R20, 250 LP: NOP DEC R20 BRNE LP RET
//-------------------------------------------------------- Delay10ms: LDI R20, 10 LP10: RCALL Delay1ms DEC R20 BRNE LP10 RET
//-------------------------------------------------------- Delay100ms: LDI R20, 100 LP100: RCALL Delay1ms DEC R20 BRNE LP100 RET
//-------------------------------------------------------- Delay1s: LDI R21, 10 LDI R20, 100 LP1000: RCALL Delay1ms DEC R20 BRNE LP1000 DEC R21 BRNE LP1000 RET LAB1_2 Bài 3
Thanh ghi dịch sử dụng là 74HC595.
Các chân quan trọng cần nhớ Tên STT Loại Mô tả /CLR 10 Input
Chân clear dữ liệu trong 595, tích cực thấp (0 là
clear), nếu lập trình có yêu cầu dùng chân này thì
kết nối với VXL rồi set chân này lên 1, nếu muốn
clear thì cho xuống 0. Nếu không muốn lập trình
chân này thì cắm thẳng lên 5V. SRCLK 11 Input
Clock thanh ghi dịch, lấy cạnh lên (rising edge).
Các bạn hình dung trong con IC 595 có 1 thanh
ghi 8 bit, mỗi khi có cạnh lên, dữ liệu hiện tại có
trên chân SDI sẽ được dịch vào thanh ghi này.
VD: Sau khi clear 595, giả sử chân SDI luôn bằng
1, mỗi khi có clock trên chân SRCLK này, dữ liệu
trong thanh ghi sẽ thay đổi như sau: 0000 0000 1000 0000 1100 0000… RCLK 12 Input
Đây là Clock chốt, lấy cạnh lên.
Mỗi khi có cạnh lên, dữ liệu hiện tại chứa trong
thanh ghi 8 bit trong con 595 sẽ được đưa ra ngõ
ra ở các chân QA đến QH tương ứng. SDI 14 Input
Serial Data Input muốn đưa vào. QA->QH Output Các bit out.
Để tạo hiệu ứng theo yêu cầu bài TN3, ta viết thứ tự thực hiện như sau:
Đảm bảo các chân SRCLK và RCLK = 0 ban đầu SDI = 1 (đèn sáng)
SRCLK = 1 ; tạo xung cạnh lên đưa SDI =1 vào 595 SRCLK = 0
RCLK = 1 ; tạo xung chốt đưa dữ liệu ra QA đến QH RCLK = 0 Delay 500 ms
Lập lại đoạn code trên 8 lần. SDI = 0 (đèn tắt)
SRCLK = 1 ; tạo xung cạnh lên đưa SDI =0 vào 595 SRCLK = 0
RCLK = 1 ; tạo xung chốt đưa dữ liệu ra QA đến QH RCLK = 0 Delay 500 ms
Lập lại đoạn code trên 8 lần.
Mở rộng để tham khảo cho các bài về sau. Giả sử có 8 bit được chứa trong R17= A7A6A5A4
A3A2A1A0, cần đặt 8 bit này ra con 595 thì ta làm thế nào. (MSB đi đầu)
Đảm bảo các chân SRCLK và RCLK = 0 ban đầu Đặt chân SDI = A7
SRCLK = 1 ; tạo xung cạnh lên đưa A7 vào 595 SRCLK = 0 Đặt chân SDI = A6
SRCLK = 1 ; tạo xung cạnh lên đưa A6 vào 595 SRCLK = 0 … Đặt chân SDI = A0
SRCLK = 1 ; tạo xung cạnh lên đưa A0 vào 595 SRCLK = 0
RCLK = 1 ; tạo xung cạnh lên đưa dữ liệu ra QA đến QH. RCLK = 0
Trên đây là các bước cơ bản để hiểu thôi, còn các bạn viết phải dùng vòng lập để thực hiện việc
này. Tham khảo đoạn code dưới đây, sửa từ ví dụ 10.26 trong giáo trình. Trong ví dụ 10.26, 2
chân clock SRCLK và RCLK nối với nhau, code dưới đây có sửa lại 1 tí.
//Khúc này gán các chần port, pin bằng từ khóa, vì phầ4 n cứng thay đô; i linh động
được nến định danh như vậy dế[ sư;
a đô;i. Ví dụ nay kết nô i port A, hôm sau phầ4n cứng lại kế t nôi port B thì chỉ ; cầ4n đô;
i trong định danh, nhanh gọn không thiế u xót. .EQU shiftPORT=PORTA .EQU ShiftDDR=DDRA .EQU ShiftSDI=0 ;SDI => PA0 .EQU ShiftCLK=1 ;SRCLK => PA1 .EQU ShiftLATCH=2 ;RCLK => PA2 .ORG 0 RJMP MAIN .ORG 0X40 MAIN:
//Khai báo PA0, PA1, PA2 là output, giá trị khơ ;i tạo là 0. Nến viế t bằng từ khóa
định danh phía trến luôn nhé. ... LOOP: JMP LOOP
//-------------------------------------------------------- //Các Chương trình con
//-------------------------------------------------------- /* SHO_8 INPUT: R20 OUTPUT: QA đế n QH trến IC595 Description: */ SHO_8: LDI R20,9 SH_LOOP: ROL R17 BRCC BIT_0 SBI shiftPORT,shiftSDI RJMP NEXT BIT_0: CBI shiftPORT,shiftSDI NEXT: SBI shiftPORT,shiftCLK CBI shiftPORT,shiftCLK DEC R20 BRNE SH_LOOP SBI shiftPORT,shiftLATCH CBI shiftPORT,shiftLATCH RET LAB1_3 Bài 1 Lý thuyết về LCD
Module LCD được sử dụng nhiều trong các ứng dụng nhúng hiện nay, chúng dùng để hiển thị
thông tin một cách linh hoạt và tiết kiệm năng lượng. Có nhiều loại module LCD, trong đó thông
dụng nhất là loại LCD 16x2 là loại hiển thị 2 hàng mỗi hàng 16 ký tự. Mỗi ký tự được hiển thị
bởi một ma trận điểm ảnh có kích thước 5x8 điểm hoặc 5x11 điểm ảnh, tùy chế độ mà người lập trình thiết lập.
Phần lớn các module LCD sử dụng giao tiếp 16 chân trong đó có:  8 đường dữ liệu
 3 đường điều khiển
 3 đường cấp nguồn cho module
 2 đường cấp nguồn cho LED nền trên LCD Châ Tên Mô tả chức năng n 1 VSS GND. 2 VDD +5 Volt. 3 VEE
Tương phản (contrast): dùng để điều chỉnh độ tương phản giữ các chữ cái và đèn
nền trong LCD. Chân này sẽ được nối vào một mạch chia áp dùng biến trở để dễ
dàng thay đổi độ tương phản khi vặn biến trở. 4 RS
Chọn thanh ghi (Register Select): chọn thanh ghi trong LCD để giao tiếp. 5 R/W
Đọc/ghi (Read/Write): Chọn chế độ đọc hoặc ghi vào LCD. Trong kit thí nghiệm
VXL, sinh viên chỉ thực hiện chế độ ghi vào LCD nên chân này được nối đất.
Ghi chú: đối với các tín hiệu có kí hiệu bởi dấu ‘/’ thì ta hiểu phần bên trái dấu ‘/’
tương ứng với bit 1, phần bên phải dấu ‘/’ tương ứng với bit 0. 6 E
Cho phép (Enable): cho phép dữ liệu đọc/ghi trên LCD. Sau khi thiết lập các tín
hiệu cần vào LCD (từ các chân RS, R/W, dữ liệu [0-7]) thì chân này kích cạnh
xuống để thực hiện lệnh. 7 D0 Bit 0 của dữ liệu 8 D1 Bit 1 của dữ liệu 9 D2 Bit 2 của dữ liệu 10 D3 Bit 3 của dữ liệu 11 D4 Bit 4 của dữ liệu 12 D5 Bit 5 của dữ liệu 13 D6 Bit 6 của dữ liệu 14 D7 Bit 7 của dữ liệu 15
LED+ Cấp nguồn + cho đèn LED nền trên LCD 16 LED-
Cấp nguồn – cho đèn LED nền trên LCD
(Phần sau đây là quan trọng phải nắm vững)
Trong LCD có chứa một CGRAM và một DDRAM:
 CGRAM: Vùng RAM này khi thí nghiệm sinh viên không cần tương tác với chúng.
CGRAM có kích thước 64 Bytes chứa sẵn bảng mã hiển thị các ký tự tương ứng theo mã
ASCII. Ngoài ra nó có chứa 1 vùng trống có thể tùy ý vẽ thêm các ký tự tùy chỉnh, vẽ 8
ký tự khác nhau khi dùng 5x8 điểm ảnh để thiết kế (một ký tự sử dụng 8 bytes) hoặc 4 ký
tự khác nhau khi dùng 5x11 điểm ảnh để thiết kế.
 DDRAM: Vùng RAM chứa ký tự hiển thị trên màn hình LCD. Màn hình LCD 16x2 gồm
có 2 hàng, mỗi hàng gồm 16 ký tự tương ứng với địa chỉ của DDRAM được cho ở dưới.
Người lập trình muốn hiển thị ký tự gì tại vị trí nào trên màn hình LCD thì cần ghi mã số
của ký tự đó vào ô nhớ tương ứng với vị trí cần ghi trên DDRAM. Ví dụ muốn ghi ký tự
O vào ô thứ 15 của hàng đầu tiên trên LCD (Như hình 1) thì cần ghi mã số của ký tự O
vào ô nhớ 0EH của DDRAM. Mã số ký tự thì được tra tại hình 3 như sau. Ghi chú: bảng
mã ký tự tương ứng với mã ASCII.
Các mã lệnh để giao tiếp với LCD được liệt kê ở bảng sau, như ta thấy mã lệnh liên quan đến các
tín hiệu vào module LCD như RS, R/W, Data bit 0 đến bit 7. Muốn ghi một lệnh vào LCD cần
điều khiển các chân tín hiệu kể trên tương ứng với lệnh cần ghi sau đó kích chân cho phép
(Enable) của LCD (kích cạnh xuống).
Trong bo mạch thí nghiệm vi xử lý, phần giao tiếp LCD được thiết kế theo giao tiếp 4 bit DATA như hình sau.
Về lập trình ta nên chia mã lệnh ghi vào LCD thành 2 loại: ghi lệnh và ghi ký tự, ứng với chân RS = 0 và RS = 1. -
Ghi lệnh (khi RS =0): là các lệnh cấu hình LCD, thiết lập con trỏ tắt hoặc bật, nhấp nháy con trỏ… -
Ghi ký tự (khi RS =1): là ghi/ đọc ký tự vào DDRAM để hiển thị lên LCD.
Vì vậy ta sẽ viết 2 chương trình con WRITE_COMMAND và WRITE_DATA có nhiệm vụ ghi mã lệnh
chứa trong thanh ghi R17 ra LCD (dưới phần code gợi ý). Để sử dụng ta gán mã lệnh hoặc mã kí
tự vào R17 rồi gọi hàm này thôi, ví dụ sau. LDI R17,$20 CALL WRITE_COMMAND
Ví dụ: Trước khi hiển thị LCD phải có một đoạn lệnh để cấu hình cho LCD như sau: //Hàm con khơ ;i tạo LCD //Input: None //Output: None //Description: Khơ ;i tạo LCD INIT_LCD_4BIT: LDI R17,$28 CALL WRITE_COMMAND LDI R17,$01 CALL WRITE_COMMAND LDI R17,$0C CALL WRITE_COMMAND LDI R17,$06 CALL WRITE_COMMAND RET
Giờ sinh viên cần phải hiểu các mã lệnh 0x28, 0x01, 0x0C… có ý nghĩa gì.
Mã lệnh là 0x28 = 0b0010 1000 đây chính là lệnh bắt đầu với DB5 =1, khi dùng ghi lệnh thì RS
= 0, ta tra bảng, gióng xuống tìm DB5 = 1. Đây là câu lệnh Function set, với DL = 0, N =1 và F
=0. Tức là giao tiếp 4 bits, số lượng dòng hiển thị là 2 (LCD có 2 hàng trên và dưới), kích thước ký tự là 5x8.
Ghi chú: đối với các tín hiệu có kí hiệu bởi dấu ‘/’ thì ta hiểu phần bên trái dấu ‘/’ tương ứng với
bit 1, phần bên phải dấu ‘/’ tương ứng với bit 0.
Tương tự mã lệnh 0x01=0b0000 0001 tương ứng với lệnh clear màn hình.
Tương tự với mã lệnh 0x0E = 0b0000 1110. Tức D = 1, C =1, B =0 có nghĩa là: cho phép hiển
thị, cho phép bật con trỏ, không cho con trỏ nhấp nháy.
Về phần ghi ký tự cũng tương tự. Gán mã ký tự mong muốn vào R17 rồi gọi hàm WRITE_DATA. LDI R17,$41 CALL WRITE_DATA
Ví dụ ghi ký tự V ra LCD: LDI R17,’V’ CALL WRITE_DATA
Sau khi thực hiện lệnh ghi ký tự, mã ký tự sẽ được ghi vào ô DDRAM hiện hành. Nếu địa chỉ
DDRAM hiện hành thuộc khoản 0x00-0x0F hoặc 0x40H-0x4F thì trên LCD sẽ hiển thị ký tự
tương ứng vào ô đó, đồng thời sau đó địa chỉ DDRAM sẽ tự cộng thêm 1 và sẽ ghi ký tự ở ô tiếp
theo nếu dùng thêm lệnh ghi ký tự. Trường hợp ô ký tự hiện hành là 0F (tức ô cuối cùng của
hàng 1), sau khi ghi lệnh ghi ký tự ra ô này, DDRAM sẽ được cộng lên 1 là 0x10 chứ không phải
là 0x40, nghĩa là ký tự sẽ không tự động nhảy xuống hàng dưới. Để xuống hàng hoặc ghi vào ô
ký tự cụ thể nào ta cần phải sử dụng thêm lệnh chọn địa chỉ DDRAM như sau, mã lệnh này được
tính là 0x80+địa chỉ DDRAM cần nhảy đến.
Ví dụ: muốn ghi chữ “VXL” lên LCD tại vị trí sau thì công việc cần làm là: gọi lệnh chọn địa chỉ
DDRAM tại ô 0x46, mã lệnh của lệnh này sẽ là 0x80 + 0x46 = 0xC6. Tiếp đó ghi các ký tự ‘V’, ‘X’, ‘L’.
Đoạn chương trình hiển thị chữ “VXL”, SV nên kết hợp với phương pháp tra bảng để hiển thị. LDI R17,$C6 CALL WRITE_COMMAND LDI R17,’V’ CALL WRITE_DATA LDI R17,’X’ CALL WRITE_DATA LDI R17,’L’ CALL WRITE_DATA
Code gợi ý cho bài Lab1_3 bài 1. .EQU LCD_PORT=PORTA .EQU LCD_DDR=DDRA .EQU RS=0 .EQU RW=1 .EQU EN=2 .ORG 0 RJMP MAIN .ORG 0X40
MAIN: LDI R16,LOW(RAMEND) ;DUA DIA CHI RAMEND LEN VI TRI CAO NHAT OUT SPL,R16 LDI R16,HIGH(RAMEND) OUT SPH,R16 /* Kế t nô
i port A vào LCD, RS=PA0, RW=PA1, EN=PA2, Data[4:7] = PA4:PA7
=> Khai báo PA012 4567 (không có PA3) là output, gán các giá trị ban đầ4 u như sau: Data = 0, RS=0, RW=1, EN=0. */ ...
//Gọi chương trình con khơ
;i tạo nguô4n (POWERUP_LCD_4BIT) cho chế độ LCD 4 bit, cụ thế;
thì xem lại giáo trình. Không gọi chương trình con này, LCD không hiế; n thị được. ...
//Gọi chương trình con cầ u hình LCD. ... //Gọi lệnh tro ; con tro; vế4 vị trí DDRAM 0x00 ...
//Dưới đầy là đoạn code tra ba ;ng, xuầ
t ký tự hàng thứ 1 ra LCD cho đế n khi gặp ký
tự 0x00LDI ZH,HIGH(LINE1<<1) LDI ZL,LOW(LINE1<<1) DISPLAY_LINE1: LPM R17,Z+ CPI R17,$00 BREQ NEWLINE CALL WRITE_DATA RJMP DISPLAY_LINE1 NEWLINE: //Viế
t lệnh xuông hàng (lệnh chọn địa chỉ ; DDRAM tại 0x40) ... //Tương tự, viế t code xuầ t ra hàng thứ 2 LOOP:
// Bài này vòng lập không viế t gì ca ;, vì mọi thứ chỉ ; cầ4n chạy 1 lầ4 n thôi. RJMP LOOP //Chương trình con
;------------------------------------------------ //POWERUP_LCD_4BIT //Input: None //Output: None
//Description: Hàm con power up LCD POWERUP_LCD_4BIT: LDI R16,250 RCALL DELAY_US LDI R16,250 RCALL DELAY_US LDI R17,$30 RCALL OUT_COMMAND LDI R16,50 RCALL DELAY_US LDI R17,$30 RCALL OUT_COMMAND LDI R16,2 RCALL DELAY_US LDI R17,$20 RCALL OUT_COMMAND RET //Hàm con khơ ;i tạo LCD //Input: None //Output: None //Description: Khơ ;i tạo LCD INIT_LCD_4BIT: LDI R17,$28 CALL WRITE_COMMAND LDI R17,$01 CALL WRITE_COMMAND LDI R17,$0C CALL WRITE_COMMAND LDI R17,$06 CALL WRITE_COMMAND RET //Hàm con ghi lệnh ra LCD //Input: R17 //Output: None
//Description: Ghi lệnh chứa trong R17 ra LCD. WRITE_COMMAND: PUSH R17
ANDI R17,$F0 ; xuat 4 bit dau ra truoc RCALL OUT_COMMAND POP R17 SWAP R17
ANDI R17,$F0 ; xuat 4 bit sau ra RCALL OUT_COMMAND RET //Hàm con ghi ký tự ra LCD //Input: R17 //Output: None
//Description: Ghi kí tự ra LCD theo mã ASCII, ví dụ R17=0x41 thì LCD hiế; n thị chữ A WRITE_DATA: PUSH R17 ANDI R17,$F0 ; xuat 4 bit dau RCALL OUT_DATA POP R17 SWAP R17 ANDI R17,$F0 ; xuat 4 bit sau RCALL OUT_DATA RET OUT_COMMAND: OUT LCD_PORT,R17 CBI LCD_PORT,RS CBI LCD_PORT,RW SBI LCD_PORT,EN NOP CBI LCD_PORT,EN LDI R16,20 CALL DELAY_US RET OUT_DATA: OUT LCD_PORT,R17 SBI LCD_PORT,RS CBI LCD_PORT,RW SBI LCD_PORT,EN NOP CBI LCD_PORT,EN LDI R16,20 CALL DELAY_US RET /* DELAY_US Input: R16 Output: None
Description: DELAY R16*100 MICROSEC */ DELAY_US: MOV R15,R16 LDI R16,200 L1: MOV R14,R16 L2: DEC R14 NOP BRNE L2 DEC R15 BRNE L1 RET LINE1: .DB "TN VXL-AVR",$00 LINE2: .DB "10 DIEM",$00 LAB1_3 Bài 2 Code gợi ý /* KET NOI PHAN CUNG: PORT A: LCD PORT B:BAR LED PINC0: NUT NHAN */ .ORG 0 .EQU LCD_PORT=PORTA .EQU LCD_DDR=DDRA .EQU LED_PORT=PORTB .EQU LED_DDR=DDRB .EQU RS=0 .EQU RW=1 .EQU EN=2 RJMP MAIN .ORG 0X40
//MAIN----------------------------------
MAIN: LDI R16,LOW(RAMEND) ;DUA DIA CHI RAMEND LEN VI TRI CAO NHAT OUT SPL,R16 LDI R16,HIGH(RAMEND) OUT SPH,R16 //Khai báo PORT gắ
n LED là OUTPUT, gán giá trị ban đầ4 u bằng 0 đế; LED tắ t. ...
//Khai báo PC0 là input, có điện trơ ; kéo lến ... /* Kế t nô
i port A vào LCD, RS=PA0, RW=PA1, EN=PA2, Data[4:7] = PA4:PA7
=> Khai báo PA012 4567 (không có PA3) là output, gán các giá trị ban đầ4 u như sau: Data = 0, RS=0, RW=1, EN=0. */ ...
//Gọi chương trình con khơ
;i tạo nguô4n (POWERUP_LCD_4BIT) cho chế độ LCD 4 bit, cụ thế;
thì xem lại giáo trình. Không gọi chương trình con này, LCD không hiế; n thị được. ...
//Gọi chương trình con cầ u hình LCD. ...