[b][red]This message was edited by the sureshot3000 at 2002-4-11 4:51:56[/red][/b][hr]
just wondering if SOMEONE can help.i am looking for an assembler code that produces an exact 1 second time delay using an intel 8051 from the address org 8000.
also i am looking for a code using the same language and chip to control the sequence of a set of traffic lights with the following sequence

red red 4 seconds
red & amber red 2 seconds
green red 10 seconds
amber red 2 seconds
red red 4 seconds
red red & amber 2 seconds
red green 7 seconds
red amber 2 seconds

the interface between the lights and the 8051 require a logic 1 to turn the light on
thanks for any help
steve.

• First of all: I cannot test this as I don't have a 8051 assembler (or even a 8051) by me. Use this solely as a pointer in some(!) direction.

As for the first question, I'd advice you to use a timer instead... But if you want to do it the hardcoded way, you'll need to find out:
- CPU Clock Frq / Cycle Frq.
- Cycles per Instructions.

Say that the frq is 8 MHZ. Then you'd need to make a loop that waited for 8000000 cycles (minus loop setup time).

The function could look like this:
[code]
WaitSeconds: // NumSeconds in a (Note: 0 means 65536!!)
mov r2,#160 ; 12 cycles
l3: mov r1,#200 ; 12 cycles
l2: mov r0,#256 ; 12 cycles
l1: djnz r0,l1 ; 24 cycles
djnz r1,l2 ; 24 cycles
djnz r2,l3 ; 24 cycles
dec a ; 12 cycles
jnz WaitSeconds ; 24 cycles
ret
[/code]

So, the inner loop uses 24*256 = 6144 cycles
together with the next loop : (6144+12)*100 = 615600 cycles
together with the next loop : (615600+12)*13 = 8002956 cycles

So, this will wait for 8002956/8000000=1,0004 seconds, or 1 second and 40 milliseconds. It's very hard to get closer than that.

: red red 4 seconds
: red & amber red 2 seconds
: green red 10 seconds
: amber red 2 seconds
: red red 4 seconds
: red red & amber 2 seconds
: red green 7 seconds
: red amber 2 seconds

You'd be better off by explaining it like this:
[code]
Duration | Red | Amber | Green
---------+-----+-------+-------
4 | X | |
2 | X | X |
10 | | | X
2 | | X |
4 | X | |
2 | X | X |
7 | | | X
2 | | X |
[/code]

(This is my interpretation of your text)

One could make a small table that consisted of "structs":
[code]
{
BYTE Seconds;
BYTE BitCode;
};
[/code]

Where bit code is simply the byte to write to the port (or external bus). I'm simply assuming that you're writing a byte to the LED at address 0x4000, where the three LSBs are bits for Red, Amber and Green.

In ASM it would look like this:
[code]
RED_BIT .equ 1
AMBER_BIT .equ 2
GREEN_BIT .equ 4

LightTable:
.db 4,RED_BIT
.db 2,RED_BIT|AMBER_BIT
.db 10,GREEN_BIT
.db 2,AMBER_BIT
.db 4,RED_BIT
.db 2,RED_BIT|AMBER_BIT
.db 7,GREEN_BIT
.db 2,AMBER_BIT
.db 0 ; End of table...
[/code]

We could then have a routine that expects dptr to point to a valid entry in the table:

[code]
LEDOut: ; dptr pointing to valid entry (BYTE Seconds,BYTE BitCode)
clr a
movc a,@a+dptr ; Get Seconds
mov r0,a ; Store Seconds in r0
inc dptr
clr a
movc a,@a+dptr ; Get BitCode
movx @dptr,a ; Write Bit To Port
mov a,r0 ; Restore Seconds
lcall WaitSeconds
ret
[/code]

And a function calling this routine:

[code]
LEDSequence: ; Loops forever!!
mov dptr,#LightTable ; Point to start of table
loop: clr a
movc a,@a+dptr ; Get First entry
jz LEDSequence ; If 0, we've reached the end of the table, so restart...
push dptr ; Save dptr
lcall LEDOut
pop lptr ; Restore dptr
inc dptr ; Point
inc dptr ; to next address in table
sjmp loop ; Next address loop
[/code]

HTH

• Excellent reply - I have an 80C320 and could not have put it any better. But I would also agree that the built in timers are the way to go.
Regards,
Geof