Thaimicrotron.com : Home
 

การใช้งานพอร์ตอนุกรมเพื่อตรวจสอบการทำงานของโปรแกรม
และการปฏิบัติตามคำสั่ง

 
     
  วัตถุประสงค์  
 
  • เพื่อเป็นการศึกษา การปฏิบัติตามคำสั่งแบบสตริง (เป็นค่ำสั่งหลายตัวอักษร)
  • แนวทางการออกแบบ การตรวจสอบการทำงานของโปรแกรมผ่านพอร์ตอนุกรม (Debugger)
  • การควบคุมเอาต์พุตผ่านพอร์ตอนุกรม
 
     
  วงจรและการเตรียมอุปกรณ์เหมือนกับ EXAM8  
     
  วิธีการทดลอง  
 
  1. เมื่อ download ตัวอย่างข้างล่างแล้วคอมไพล์ เป็น HEX ไฟล์แล้ว ให้โปรแกรม ลงชิพไมโครคอนโทรลเลอร์ ด้วยเครื่องโปรแกรม JDT-2008
  2. ตรวจสอบว่ามี IC เบอร์ ICL232 หรือ MAX232 เสียบอยู่บน socket บนบอร์ดทดลองแล้วหรือยัง ถ้ายังให้ติดต่อขอจากอาจารย์ผู้ควบคุม LAB
  3. ตรวจสอบว่าได้ถอด IC เบอร์ 75176 ออกแล้วหรือยัง เพราะไม่สามารถใช้งานร่วมกับ IC เบอร์นี้ได้ เมื่อใช้งาน พอร์ตอนุกรมแบบ RS232
  4. เมื่อโปรแกรมไมโครชิพเสร็จแล้วให้ถอดสายสัญญาณที่ต่อระหว่าง PC กับ เครื่องโปรแกรมออก เพราะต้องใช้ พอร์ตอนุกรมนี้ ในการทดลอง โดยต่อสายสัญญาณ ที่ให้มา ด้าน DB9 เข้ากับ COM1 ของ PC แทนสายสัญญาณ ของเครื่องโปรแกรม แล้วต่อ Connector 3 Pin เข้ากับบอร์ดทดลองดังรูป
 
 
  5. ให้ดับเบิ้ลคลิกที่ไอคอน
เพื่อเรียกให้โปรแกรม Hyper Terminal ทำงาน (หากยังไม่ได้ติดตั้งโปรแกรม Hyper Terminal ให้ทำการติดตั้งก่อน)
       
  6. จ่ายไฟให้บอร์ดทดลอง แล้วดูผลที่ปรากฏบนหน้าจอโปรแกรม Hyper Terminal
         
 
     
  ตัวอย่างโปรแกรมการปฏิบัติตามคำสั่งแบบสตริง ,การตรวจสอบ การทำงานของโปรแกรม ผ่านพอร์ตอนุกรม และการควบคุม เอาต์พุต ผ่านพอร์ตอนุกรม  
     
  EXAM9  
 
;EXAM9.ASM
;String Command
;
MAXBUFFER       EQU    8

;User internal ram area
	ORG     30H

buffer: 	DS      MAXBUFFER
StrBuff:        DS	1		;Restore char form RS232


	ORG	0000H


;*** Power up delay ***
;Wait for other Device
RES:	MOV	R2,#40H
RES1:	MOV	R3,#0
RES2:	DJNZ	R3,RES2
	DJNZ	R2,RES1

	MOV	P1,#0FFH	;OFF All P1 bit

MAIN:	LCALL	InitUART	;Initial UART 9600,n,8,1 no parity

	MOV	DPTR,#Hello
	LCALL	SendSROM
	MOV	DPTR,#Ready0	;Show Prompt
	LCALL	SendSROM

;get
ScanStr:
	MOV	R0,#buffer	;point to buffer
	LCALL	GetStr

	MOV	R0,#buffer	;load buffer Ptr
	LCALL	GetCmd		;found = 1...n
	JZ	ScanEx		; 0 = isn't Command

	MOV	StrBuff,A	;store result in StrBuff

;Check Command No.
;Check Command 1
	XRL	A,#01		;?Compare A=1
	JZ	Cmd1		;switch to x

;Check Command 2
	MOV	A,StrBuff	;Restore
	XRL	A,#02		;?Compare A=2
	JZ	Cmd2
	
	JMP	ScanStr

;Treat Command
Cmd1:	MOV	R0,#buffer+3
	LCALL	LineFeed
	LCALL	SendSRAM	;Show agument
	LCALL	LineFeed

	MOV	dptr,#Ready0	;Show Prompt
	LCALL	SendSROM
	SJMP	ScanStr

Cmd2:	MOV	DPTR,#DoCmd2
	LCALL	SendSROM

	MOV	dptr,#Ready0	;Show Prompt
	LCALL	SendSROM

	JMP	ScanStr


ScanEx:	MOV	DPTR,#ErrMsg1
	LCALL	SendSROM
	LCALL	LineFeed


	JMP	ScanStr


;END MAIN

;*** Get Command ***
;R0    point to Str buffer
;DPTR  point to command
;R2    save
;R7    result
;return command in	A
;	found		1...n
;	not found	0
;
;REG change = R0,R2,R7
;
GetCmd:	MOV	R7,#01		;count
	MOV	A,R0		;save R0->R2
	MOV	R2,A		;Restore Ptr

	MOV	DPTR,#Command1
	LCALL	StrCmp
	JZ	CmdEQU		;A=0 Equ

;If not Equ next Cmp

	INC	R7		;inc result
	MOV	A,R2		;get ptr
	MOV	R0,A		;Reload	Ptr

	MOV	DPTR,#Command2

	LCALL	StrCmp
	JZ	CmdEQU

;not found
	MOV	R7,#0		;result	is NULL

CmdEQU:	MOV	A,R7		;result	in R7
	RET


;StrCmp(@R0,DPTR);
;R0    point to Str buffer
;DPTR  point to command
;reg change  = R0,DPTR
;result in A  0   = Equ
;             FFh = nEqu
StrCmp:	CLR	A
	MOVC	A,@A+dptr
	JZ	StrEq		;end of	str
	XRL	A,@R0		;Compare A=@R0 ?
	JNZ	StrNEq
	       
	INC	R0		;next char in buffer
	INC	dptr		;next command
	JMP	StrCmp
	       
StrNEq:	MOV	A,#0FFh		;not equal
	RET    
StrEq:	CLR	A		;equal ret 0
	RET    

;*** Get String ***
;IN R0 pointer to String Buffer
;R3 count n of Str
;
GetStr:	MOV	R3,#0
GetSnx:	CLR	A
	LCALL	RBYTE		;READ -> A
	LCALL	SBYTE		;A    -> Send ECho
	MOV	StrBuff,A	;Restore char in StrBuff

;check end of str
	XRL	A,#0Dh		;Carriage Return 
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#0Ah		;line feed  LF
	JZ	ChkStr

	MOV	A,StrBuff	;Restore char in StrBuff
	XRL	A,#20h		;Space Bar
	JZ	Din



	MOV	@R0,StrBuff	;store in buffer
	INC	R0		;next point
	INC	R3		;count str

;Test buffer full
	MOV	A,R3
	XRL	A,#MAXBUFFER	;Compare with MAXBUFFER
	JZ	Sendfull	;>= MAXBUFFER

	SJMP	GetSnx

ChkStr:	MOV	A,R3
	JZ	SendOK
	MOV	@R0,#0		;end of String
	RET

Din:	MOV	R0,#buffer
	LCALL	DumpI
	
	MOV	dptr,#Ready0	;Show Prompt
	LCALL	SendSROM

	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr


SendOK:	MOV	DPTR,#Ready0	;Show Prompt
	LCALL	SendSROM
	SJMP	GetSnx

Sendfull:
	MOV	DPTR,#ErrMsg2
	LCALL	SendSROM
	MOV	R0,#buffer	;Point to buffer
	SJMP	GetStr

;*** Send String in Program Memory ***
;Input 	DPTR
SendSROM:
	CLR	A
	MOVC	A,@A+DPTR	;load char
	JZ	EndStr		;yes end
	LCALL	SBYTE		;send 1	byte
	INC	DPTR		;point to next char
	SJMP	SendSROM		;load next char

EndStr:	RET


;*** Send String in RAM ***
;Input 	R0
SendSRAM:
	MOV	A,@R0
	XRL	A,#00
	JZ	EndRStr		;yes end
	MOV	A,@R0
	LCALL	SBYTE		;send 1	byte
	INC	R0		;point to next char
	SJMP	SendSRAM	;load next char

EndRStr:
	RET


;*** Initial UART ***
InitUART:
	MOV	SCON,#01010010B	;Set SCON Serial Control Mode 1: 8-bit UART (Timer-Based). 
	MOV	TMOD,#00100000B	;Set Mode 2  8-bit Auto-Reload
	MOV	TH1,#0FDH	;Set Baud Rate 9600
	SETB	TR1		;Enable Timer 1
	RET

; ********** SBYTE SUB **********
;SEND BYTE
;IN  =	A
;REG =	NO
SBYTE:	JNB	TI,SBYTE	;Wait For Sending done
	CLR	TI
	MOV	SBUF,A
	RET

; ********** RBYTE SUB **********
;OUT =	A
;REG =	A
RBYTE:	JNB	RI,RBYTE	;Wait For Receive already
	CLR	RI
	MOV	A,SBUF
	RET

;*** Send line feed ***
LineFeed:
	MOV	A,#0Dh
	LCALL	SBYTE
feed:	MOV	A,#0Ah
	LCALL	SBYTE
	RET

;*** DUMP table	in InternalRAM	8 Byte ***
;R0 Ptr	to table in internal RAM
;
;R0,R6,R7
DumpI:	MOV	A,R0
	MOV	R7,A		;store Ptr in R7

	MOV	R6,#8
Dumpx:	MOV	A,@R0
	LCALL	SBYTEH
	INC	R0

	MOV	A,#' '		;separate with ' '
	LCALL	SBYTE

	DJNZ	R6,Dumpx

	MOV	R6,#8
Dspc:	MOV	A,#' '		;separate with ' '
	LCALL	SBYTE
	DJNZ	R6,Dspc

	MOV	A,R7		;Restore Ptr
	MOV	R0,A
	MOV	R6,#8
DASC:	MOV	A,@R0
	MOV	R7,A
	SUBB	A,#' '
	JC	Dmark
	MOV	A,R7
	LCALL	SBYTE
	JMP	Dloop

Dmark:	MOV	A,#'.'
	LCALL	SBYTE

Dloop:	INC	R0
	DJNZ	R6,DASC

	LCALL	LineFeed
	RET

; ********** SBYTEH SUB **********
; SEND 2 BYTE HEX FROM A
; IN  = A
; REG = A,R2,R3
SBYTEH:	LCALL	HTOA
	MOV	A,R2
	LCALL	SBYTE
	MOV	A,R3
	LCALL	SBYTE

	RET

; ********** HTOA SUB **********
; CONVERT HEX TO ASCII
; IN  = A
; OUT = R2,R3
; REG = A,R2,R3

HTOA:	PUSH	ACC
	SWAP	A
	LCALL	HTOAS
	MOV	R2,A
	POP	ACC
	LCALL	HTOAS
	MOV	R3,A
	RET

HTOAS:	ANL	A,#0FH
	CJNE	A,#0AH,$+3
	JNC	HTOAS1
	ORL	A,#30H
	RET
HTOAS1:	SUBB	A,#9
	ORL	A,#40H
	RET

Hello:		DB	0Dh,"*** String Command ***",0Dh,0Ah,00
ErrMsg1:	DB	0Dh,0Ah,'Invalid Command',00
ErrMsg2:	DB	0Dh,0Ah,'buffer full',0Dh,0Ah,00
Ready0:		DB	0Dh,0Ah,'MCS-51>',00

Command1:	DB	'*wr',00
Command2:	DB	'*name',00

DoCmd2:		DB	0Dh,0Ah,'Micro#01',0Dh,0Ah,00


END
 
 
DOWNLOAD
 
     
  ผลการทดลอง  
  - เมื่อจ่ายไฟให้บอร์ดทดลอง ไมโครคอนโทรลเลอร์จะส่งข้อมูลสตริง "*** String Command ***"  
  และปรากฏ Prompt "MCS-51>" มายังที่ PC  
     
  - ป้อนคำสั่ง "*name" แล้วกด Enter ไมโครคอนโทรลเลอร์จะแสดงข้อความ"Micro#01"  
  - ป้อนคำสั่ง "*wr0" แล้วกด Enter โปรแกรมจะตรวจสอบคำสั่ง "*wr" = Write และแยก argument "0" ส่งกลับมายัง PC  
  - ป้อนคำสั่ง "*wr1" แล้วกด Enter โปรแกรมจะตรวจสอบคำสั่ง "*wr" = Write และแยก argument "1" ส่งกลับมายัง PC  
  - กด Space Bar จะเป็นการ Dump ข้อมูลใน buffer ออกมา "2A 77 72 30 00 00 00 31 *wr0...1"  
  - หากพิมพ์คำสั่งไม่ถูกต้องจะปรากฏ "Invalid Command"  
     
     
  แบบฝึกหัด  
 
จากตัวอย่าง EXAM9 ให้เขียนโปรแกรมเพื่อควบคุมเอาต์พุตโดย
เมื่อได้รับคำสั่ง "*wr1" ให้พอร์ต P1.0 ON   (LED ติด)
เมื่อได้รับคำสั่ง "*wr0" ให้พอร์ต P1.0 OFF (LED ดับ)
 
     
  note "*wr" เราเรียกว่าคำสั่ง ในที่นี้หมายถึงการเขียนข้อมูลมายังพอร์ต ส่วนข้อมูลที่ตามมาเป็น "1" หรือ "0" เรียกว่า argument จะถูกแปลความหมายว่าเป็น ON และ OFF  
 
 
  แนวทางปฏิบัติ  
  - เมื่อป้อนคำสั่งแล้วกด <ENTER> ข้อมูลที่ได้รับจากพอร์ตอนุกรมจะถูกเก็บไว้ที่ buffer และแนื่องจากคำสั่ง "*wr" มีขนาด 3 ไบท์  
  ดังนั้นตำแหน่งของ argument คือ buffer+3  
  - ดังนั้นเราต้องแก้ไขการทำงานที่ Label Cmd:1 ดังนี้  
     
 
       
;Treat Command    
Cmd1: MOV R0,#buffer+3 ;ระบุตำแหน่งของ argument
  ........   ;อ่านค่าที่ R0 ชี้มาไว้ที่ A
  ........   ;เปรียบเทียบ A กับ "1"
  ........   ;ถ้าเท่ากันให้กระโดดไปที่ PORTON
       
  ........   ;อ่านค่าที่ R0 ชี้มาไว้ที่ A
  ........   ;เปรียบเทียบ A กับ "0"
  ........   ;ถ้าเท่ากันให้กระโดดไปที่ PORTOFF
       
       
Cmd1End:      
  LCALL LineFeed  
  LCALL SendSRAM ;Show agument
  LCALL  LineFeed  
       
  MOV dptr,#Ready0 ;Show Prompt
  LCALL SendSROM  
  SJMP ScanStr  
       
PORTON: ........   ;ให้ P1.0 = Low
  SJMP Cmd1End  
       
PORTOFF: ........   ;ให้ P1.0 = Hight
  SJMP Cmd1End  
       
       
Cmd2: MOV DPTR,#DoCmd2  
       
 
     
  หมายเหตุ  
 
    ข้อความเดิม
    ส่วนที่ต้องคีย์เพิ่มขึ้นมาใหม่