Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] AT89C5131 - serial port (SBUF) does not receive value

Status
Not open for further replies.

Irolan

Newbie level 5
Joined
Jan 16, 2013
Messages
10
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,382
Hi everyone,

first of all, I'm sorry if this was already answered somewhere, I searched but couldn't find anything like this.
I have the following problem.
I'm using a 8051 derivate, the Atmel AT89C5131 controller and write my programs in Keil µVision 4. Recently, I tried to work with the serial interface, but found that it doesn't seem to work.
So, what I'm trying to do is this: I have have two identical controllers, connected via serial interface (serial to serial, NOT usb) the first one sends signals to the second one, which is then supposed to process them and show them on a display. The first controller works fine and it also sends stuff, I checked that using an oscylloscope.

Here's the parts of the code relevant for the serial interface:

Code:
;-------------------------------------------------------------------------------------------------------------------------------------------------------
;HEAD

...
     org	0023h			;vector address for serial interrupt
     ljmp	serial_int
...

;-------------------------------------------------------------------------------------------------------------------------------------------------------
;MAIN PROGRAM

...
     clr	SM0				
     setb	SM1			;UART mode 1 (8-bit variable)
     clr	SM2			;no multi processor mode
     setb	REN			;enable serial reception

     ;set baud rate to 4800
     mov	BRL,#178
     mov	BDRCON,#00000110b	;set RBCK (internal bdr-generator for reception), fast generator (SPD)
     orl	PCON,#1000000b		;set SMOD1 without touching the rest of the bits
     setb	ES			;enable serial interrupt
     orl	BDRCON,#00010000b	;set BRR to start generator without touching the rest of the bits
...

;-------------------------------------------------------------------------------------------------------------------------------------------------------
;SERIAL INTERRUPT

serial_int:
     jnb	RI,ri_not_set		;jump if RI flag is not set, otherwise...
     clr	RI 			;...since we are here, the last interrupt was a reception, RI is now set – thus clear RI
     mov	A,SBUF			;...store received signal in accu
     movc	A,@A+dptr		;...indirect indexed addressing of table, store in accu
     mov	P0,A			;...send content of accu to port 0 (in this case, there's a 7-segment-display I'm trying to gate)
     sjmp	end_serial		;...jump to return

ri_not_set:
     clr	TI			;since we are here, the last interrupt was a transmission, TI is set – thus clear TI

end_serial:
     reti				;we're done here, return to main program


Now, here's the problem. Whatever I do, the serial buffer register SBUF contains no value. So, A+dptr always equals 0+dptr, meaning whatever the interface receives, the data pointer always points at the first address of the table, thus always returning the starting value.
I tried moving the clr RI command, since I thought maybe that clears the SBUF too, no change.
I tried giving the Accu a fix value, that works. So it's obviously the SBUF not receiving a value.
Also, although I'm sending signals to the serial interface, the serial interrupt is never triggered.

The problem seems to be in my code, not in the connection. While debugging, I changed the value of SBUF and forced an interrupt, still "mov A,SBUF" does not do anything.

Does anyone know what's going on?
 
Last edited:

The movc A,@A+dptr after mov A,SBUF is puzzling to me.
From Keil: The MOVC instruction moves a byte from the code or program memory to the accumulator.
A = (A + DPTR).
This will overwrite SBUF transfer into A.
 

The movc A,@A+dptr after mov A,SBUF is puzzling to me.
From Keil: The MOVC instruction moves a byte from the code or program memory to the accumulator.
A = (A + DPTR).
This will overwrite SBUF transfer into A.

Well, that's the way I learnt it, and so far, it worked. When using an indirectly indexed addressing, I need to use movc instead of mov (why ever that may be, it's the only time I've ever seen it).
The rest is from right to left, as usual. So I take the data pointer and add it to the current value of A, which is the offset in this case. If A is, say, 5, then it means take the element of the table that comes 5 addresses after the starting address. Then write the value in this address into A again. It's like you'd write
int i = 0;
i = i + 5;
in a high programming language. It's the only way it works, I can't use another register anywhere in this construction.
 

The 8051 has mov A,direct and mov A,#immed. SBUF can be simply read by mov A,SBUF(direct addressing)
because the SBUF is in the 128 byte direct addressing area .

in contrast to MOV A,#SBUF(immed), then using a second indirect memory access which would be needed for direct memory over address 128.
Then it is puzzling to index into code memory with movc.
MOVC is accessing code memory space and not SFR or direct ram.

I think removing:
movc A,@A+dptr

then you will have:
A<=SBUF ; direct SFR read from SBUF
P0<=A ;direct SFR write to P0
therefore
P0 <= SBUF
:D
 

No, you don't understand. I MUST use movc A,@A+dptr as I'm addressing a table. That's specified in the exercise I'm doing. There is

Code:
     mov     dptr,#Table
and somewhere below that
Table:
     db     0x82, 0x6B, 0x98 0x28, 0xE1, 0x24, 0x84, 0x6A
     db     0x80, 0x20, 0x00, ...

somewhere in the code. The only way to access the table IS via the movc-thing.
If you look at my code from the initial post, you will see that I in fact did a direct mov A,SBUF. THAT is the part that does not work. The movc-part works fine, however, there is no value coming from SBUF.
Basically, it's like this. The dptr is set to the starting address of the table, meaning it points at 0x82. Normally, I would do an "inc dptr" after "mov P0,A". That's what's happening in the first controller (sender).
Now, in this case, I want to use the value received by controller 2 (receiver) to set the offset added to dptr. Simply put, if SBUF receives a 2, this 2 is to be written into A. "@A+dptr" will then contain the starting address of Table with an offset of 2, meaning it now points at 0x98. The 0x98 are then written into A, which is then sent to P0.

Thing is, when SBUF sends or receives something, the serial interrupt is triggered. The serial interface of the second controller is set to receive only. However, even if signals reach the interface, the interrupt is not triggered. When I force a value into SBUF via debugging and force-trigger the interrupt, the value is not written into A (or any other register).

About these random hex numbers in the table, they're the gate signals for the 7-segment-display. 0x82 displays a 0, 0x6B displays a 1 and so on. 0x00 is actually unnecessary, it's a marker used for further stuff.
SBUF will only receive actual numbers, tho (0, 1, 2, ...) to be used as offset.
 
Last edited:

OK..
Is master interrupt enabled and TXD/RXD cross connected?
XD
 

OK..
Is master interrupt enabled and TXD/RXD cross connected?
XD

With master interrupt, I assume you mean "setb EA" (enable all interrupts), yes, that is set.
Unless I didn't do anything wrong with the cable, it's connected properly. However, if that was the problem, it would work when debugging. As µVision allows me to manually write values into registers and force-trigger interrupts.
 

Can you post your full code and circuit? Which pins are the RX and TX? If the post which has Rx and Tx is P3 then clear P3 in the initialization. In C it is P3 = 0x00;
You clear P3 in assembly. Are the baudrates of the 2 mcu's same?
 

Can you post your full code and circuit? Which pins are the RX and TX? If the post which has Rx and Tx is P3 then clear P3 in the initialization. In C it is P3 = 0x00;
You clear P3 in assembly. Are the baudrates of the 2 mcu's same?

I'm afraid I can't give you the circuit. The course is about micro controller programming, not electronics, so it was drawn on the board where to connect which cable. Besides, I mentioned before, if it was the connection, then it would work just fine when debugging.
The code for the second controller (receiver) is below. Tell me if you want to see the code for the first controller (sender) as well. It works fine tho, and according to what I saw on the oscylloscope, it also sends the proper signals (one could tell the different numbers by the high/low states visible on the screen).

Code:
$NOMOD51						;deactivate pre-defined 8051 registers
$include (reg_C5131.inc)				;include this file instead

code_s		segment code
			cseg at	0000h			;address of first command
			ljmp	begin			;large jump in 64k address space

			org	000bh			;vector address Timer 0
			ljmp	timer0_int

			org	0023h			;vector address serial interrupt
			ljmp	serial_int

			org	0100h			;start address program
			rseg	code_s			;code segment, variable position

;-------------------- Initialisierung ----------------------------------------

begin:
			mov	dptr,#Table

			; timer initialization
			mov	tmod,#1			;initialize timer
			mov	th0,#0x00
			mov	tl0,#0x00
			setb	et0			;enable timer 0 interrupt
			setb	tr0			;start timer

			; initialize and start watchdog
			mov	wdtprg,#011b		;initialize watchdog
			mov	wdtrst,#0x1e		;start watchdog
			mov	wdtrst,#0xe1

			; initialization for serial input
			clr	SM0				
			setb	SM1			;UART mode 1 (8-bit, variable)
			clr	SM2			;no multi processor mode
			setb	REN			;enable serial reception
			mov	BRL,#178		;baud rate is 4800
			mov	BDRCON,#00000110b	;set RBCK for internal baud rate generator, set SPD for fast generator
			orl	PCON,#10000000b		;set SMOD1 without touching the rest of pcon
			setb	ES			;enable serial interrupt
			orl	BDRCON,#00010000b	;start baud rate generator

			setb	EA			;enable all interrupts
																			 
;-------------------- Main program -------------------------------------------

loop1:
			orl	PCON,#00000001b	   	;set idle mode
			sjmp	loop1

;-------------------- Interrupt routines -------------------------------------

;TIMER INTERRUPT 0
timer0_int:
			clr	tr0
			mov	th0,#0x00
			mov	tl0,#0x00
			setb	tr0
			mov	WDTRST,#0x1E
			mov	WDTRST,#0xE1
			reti		

;serialER INTERRUPT
serial_int:
			jnb	RI,ri_not_set		;jump if RI flag not set, else...

			mov	A,SBUF			;...load content of serial buffer into accu
			movc	A,@A+dptr		;...read Table
			mov	P0,A			;...load content of accu into P0
			clr	RI			;...clear RI
			sjmp	end_serial		;...jump to return

ri_not_set:
			clr	TI			;clear TI flag (if RI == 0)

end_serial:
			reti


;-------------------- Display gates ------------------------------------------

Table:	db	0x82, 0x6b, 0x98, 0x28, 0xe1, 0x24, 0x84, 0x6a
	db	0x80, 0x20, 0x94, 0x00
;-----------------------------------------------------------------------------

END
 

I don't want to see your whole circuit but just the uart connections. Can you draw the circuit in proteus and post the zipped proteus file? we can simulate and debug the code.
 

I'm sorry, but I don't have the board/cable here and I don't remember which pins were which on the serial socket. The hardware's property of the school I'm attending. While I run the IDE on my laptop, I only have access to the hardware on Wednesdays, during the course. Besides, I don't have Proteus and you can't save stuff in the demo version.
Anyway, TxD and RxD are P3, however, changing P3 value doesn't do anything. And BTW, the baud rates are the same in both controllers. They're set to 4800 and, according to the debugger, run with an actual value of 4807 bd.
I did find an illustration of the pin layout of the controller in my script, maybe that helps. https://cl.ly/MEnq
The cable we used was simply two serial plugs (10 pins) connecting ground as well as TxD and RxD (crossed). The script also says that we're to use the K8 socket (whatever that means), and that on the socket, P3.0 is pin 2, P3.1 is pin 3 and ground is pin 10. Maybe that helps, I don't really know anything about that hardware stuff, sorry.
 

Ok. The code for the receiver is above (post #9). Here is the code for the sender.
**broken link removed**
Code:
;Gating a 7 segment display via AT89C5131 contoller
;On start, display shows 0
;On pushing button R3, display will increment
;On pushing R3 while display is "9", a flashing "E" will be displayed
;Any value displayed will be sent via serial interface

$NOMOD51						;deactivate pre-defined 8051-registers
$include (reg_C5131.inc)				;include this file instead

int_z		equ	r7				;interrupt counter
errorbit	equ	0x00				;error bit, if 9 is displayed and interrupt occurs
displaybit	equ	0x01				;if error is displayed

code_s		segment code
		cseg at 0000h				;address of first command
		ljmp	begin				;large jump in 64k address area

		org	0003h				;vector address external interrupt 0
		ljmp	ex0_int

		org	000bh				;vector address timer 0
		ljmp	timer0_int

		org	0023h				;vector address serial interrupt
		ljmp	serial_int

		org		0100h			;start address of program
		rseg	code_s				;variable code segment

;-------------------- Initialization ----------------------------------------

begin:
			mov		dptr,#Zifftab

			; initialize timer
			mov	int_z,#7			;interrupt counter
			mov	tmod,#1				;timer initialization
			mov	th0,#0x00
			mov	tl0,#0x00
			setb	et0				;Timer Interrupt 0 freigeben
			setb	tr0				;Timer starten
			
			setb	ex0				;enable external interrupt 0
			setb	it0				;set external interrupt to low flank

			; initialize serial output
			clr	SM0				
			setb	SM1				;UART modus 1 (8-bit, variable)
			clr	SM2				;no multi processor mode
			mov	BRL,#178			;set baud rate to 4800
			mov	BDRCON,#00001110b		;set TBCK 1 for internal bdr generator, SPD to 1 for fast bdrg
			orl	PCON,#10000000b			;set SMOD1
			setb	ES				;enable serial interrupt
			orl	BDRCON,#00010000b		;start baud rate generator
			
			; start and initialize watchdog
			mov	wdtprg,#011b			;initialize watchdog
			mov	wdtrst,#0x1e			;start watchdog
			mov	wdtrst,#0xe1

			clr	errorbit			;clear error bit
			clr	displaybit			;clear error display bit
			
			; output 0 on P0 (this is for 7 segment display)
			clr	A
			movc	A,@A+dptr
			mov	P0,A
			inc 	dptr
			; output 0 on TxD (this is for serial transmission)
			clr	A
			movc	A,@A+dptr
			mov	SBUF,A
			inc 	dptr
			
			setb	EA				;enable all interrupts
																			 
;-------------------- Main program ------------------------------------------

loop1:
			orl	PCON,#00000001b	   		;set idle mode
			sjmp	loop1

;-------------------- Interruptroutinen --------------------------------------

;EXTERNAL INTERRUPT 0
ex0_int:	
			clr	A
			movc	A,@A+dptr			;read from zifftab
			jz	error_bit			;IF accu = 0, jump to error_bit (jz automatically compares accu)
			
			mov	P0,A				;...ELSE output value of zifftab on P0...
			inc 	dptr				;...and increment data pointer in any case...
			clr	A
			movc	A,@A+dptr			;...and read from zifftab again (now for serial output)...
			mov	SBUF,A				;...and output value on TxD...
			inc	dptr
			sjmp	end_ex0				;...jump to the end in any case

error_bit:
			setb	errorbit			;...accu was 0? THEN set error bit

end_ex0:		reti

;TIMER INTERRUPT 0
timer0_int:
			clr	tr0				;stop timer
			mov	th0,#0x00			;reload timer starting value
			mov	tl0,#0x00
			setb	tr0				;restart timer

			mov	wdtrst,#0x1e			;reset watchdog
			mov	wdtrst,#0xe1

			djnz	int_z,end_t0			;decrement int_z and IF int_z != 0, jump to end_t0...
		
			mov	int_z,#7			;...ELSE reinitialize int_z...
			jnb	errorbit,end_t0			;...and IF error bit not set (0), jump to end_t0...
			jnb	displaybit,e_notset		;...ELSE IF display bit not set (E not displayed) jump to e_notset...
e_set:
			mov	p0,#0xff			;...ELSE deactivate display bit
			clr	displaybit			;...and clear display bit (means E is not displayed)
			sjmp	end_t0				;...and jump to the end

e_notset:		mov	p0,#0x94			;...display bit is not set? Then display E...
			setb	displaybit			;...and set display bit (means E is displayed)
					
end_t0:			reti

;SERIAL INTERRUPT
serial_int:
			clr	TI
end_serial:
			reti


;-------------------- Tabellen -----------------------------------------------

Zifftab:	db	0x82, 0, 0x6b, 1, 0x98, 2, 0x28, 3 
		db	0xe1, 4, 0x24, 5, 0x84, 6, 0x6a, 7
		db	0x80, 8, 0x20, 9, 0x00
Errortab:	db	'ERROR'
;-----------------------------------------------------------------------------

END
 

If the 7 segment display shows a "9" and the button is pressed one more time, it will display an "E" for error. The timer is there to make the "E" flash.
It's also there to reinitialize the watchdog.
 

Yes, the sender works properly. It even sends the numbers out through TxD, as confirmed via oscylloscope.
 

Ok, I may have accidentally added the wrong hex file, it contains a wrong command I removed later, but I probably didn't rebuild.
Anyway, the problem is solved. Today, I had the chance to test it again using the actual controllers. It works fine, so it seems that it's actually a problem of the debugger, which doesn't relay the SBUF value. Crappy µVision.
Thank you for your efforts and sorry for the trouble, but I really didn't expect the debugger to be the problem.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top