Full Version : Universal Serial PC Interface (ASM)
avr >>COMMUNICATIONS & WEB PROJECTS >>Universal Serial PC Interface (ASM)


Admin5- 04-20-2006
A universal serial PC interface

What is it good for?

Well, I guess every hobbyist some when comes up with ideas of controlling or measuring something with a PC. Of course the idea is tempting, there are so many easy-to-learn program languages available for PCs today that almost everyone can write the software to switch on the light when he is on vacation, to control these cute little toy robots or to measure the amount of rain over the day. So if you are a somewhat advanced hobbyist, the application is only limited by your fantasy (i.e. the sky is the limit).

But: How can we close the gap between a few lines of software code and a real electrical signal outside of the computer? Of course there are many solutions to this problem, many of them require serious "hacking" to access one of the i/o ports of a computer. (Especially Windows NT4 required very advanced programming skills if you wanted to use i/o ports for non-standard applications). One port that is easy to access from a software point of view is the serial RS232 port (COM1, COM2, etc.). All modern software development tools support the RS232 port, so its usually no problem at all to send or receive data via this port.

What makes the RS232 very unattractive for hobbyists is the fact the data bits are in a serial time synchronous format with critical timing and a relatively complex start/stop-bit overhead. To make it even worse the bit levels are -12V for high and +12V for a low bit, so connecting RS232 signals to a circuit that uses 5V logical levels is not trivial either. Simply forget about connecting the RS232 directly to a relay driver stage or things like that.
And that is where this circuit comes in. It converts a RS232 bit stream into standard digital signal inputs and outputs. It even provides you with a couple of 10bit ADCs so you can read analog voltage levels into your PC with a resolution of 1024 different levels.

How does it work?

First of all the RS232 levels are converted to normal logical levels by a MAX3232. This is a standard IC that includes voltages converters which are able to produce 2xVcc and -2xVcc. Even if you use only 3.2V as Vcc, it will give you somewhat over plus and minus 6 volts, that is more than sufficient for a reliable operation of the RS232 port. I have used Vcc=3.2 Volts but I assume for most of you it is more convenient to use Vcc=5V since that will give you standard TTL level signals at the in/out ports. Since the ADC has a resolution of 10bits, the max. value it can deliver is 3FF hex. That value always corresponds to a input level that is equal to Vcc. Feel free to choose any Vcc voltage between 3Volts and 5.5Volts, both ICs will work fine in that range according to their specification.

The second step is the conversion from parallel digitial data bit into the RS232 serial bit stream and vice versa. For that we use a AT90LS4433 8bit microprocessor. It has a hardware-implemented RS232 port, a number of general purpose digital i/o-ports and internal 10bit ADCs. All it takes to make the whole thing flying is a software for the micro that reads commands from the RS232 port and reads/sends bits and/or reads analog voltage levels.

Here is the assembler code that can be assembled in ATMELs AVR-Studio.

inoutbox.asm (Assembler source code for those who are interessted.)
If you don't care about the source code and just want to make it work you can use this files.
inoutbox.hex (Hex-File which can be loaded into the CPU directly.)
inoutbox.eep (EEPROM-File which can be loaded into the CPU directly.)
Both, the .hex and the .eep files must be loaded into the micro, otherwise it won't work! For software download I recommend to use one of the many SPI in-circuit programmers. The "Atmel-standard" in-circuit programming connector can be seen in the schematic (marked SPI connector).
How can I communicate with the interface?

Set your RS232 (COM1, COM2, whatever you use) to 9k6, 8, N, 1 (Baud rate 9600 b/s, 8 data bits, no parity bit, 1 stop bit). The interface accepts the following commands via the RS232 port:


Command Meaning What is it good for?
sb <bit> set bit sets one of the digital outputs of the interface to high
cb <bit> clear bit sets one of the digital outputs of the interface to low
rb <bit> read bit reads one of the digital inputs and sends the result back to the PC
ra <bit> read ADC reads one of the ADC inputs and sends the result back to the PC
ei <string> echo input echos the string that was received by the micro (for debugging)

If you use a terminal program to communicate with the interface you can use the BACKSPACE key to correct your input.

Here are a few examples to illustrate what you strings you have to send to the interface to perform certain actions.

sb 3
cb 0
ra 2
ei This is a test...

Link: http://www.dl5neg.de/in_out_box/in_out_box.html

CODE

;********************************************************************
;
; Program: inoutbox.asm
;
; Author:  Herbert Dingfelder, DL5NEG
;
; Function:  serves as a universal serial interface-box
;   between a PC and the outside world
;   reads simple control commands from the serial
;   port of the PC and sets/reads the pin on the
;   in-out-box accordingly
;   during active communcation a LED is switched on
;
; Hardware: AT90LS4433 Atmel 8Bit AVR Microprocessor
;   crystal frequency is 3.6864 MHz
;
; History: 15.02.2001 Start of development
;     RS232 communication works
;     Online editing with terminal works
;     Switch-on Message works
;   16.02.2001 Implementation of Commands started
;   26.02.2001 UART synchonsisation debugged
;   27.02.2001 ADconversion routine works
;   09.03.2001 Set Bit Routine included
;   12.03.2001 Clear Bit Routine included
;   13.03.2001 Read Bit Routine included
;     bin2bit introduced for cleaner code
;   -> Version 1.0 released
;   12.06.2001 bugfix: C5 for LED was not set as output
;   -> Version 1.01 released
;   03.11.2001 Code cleanup for internet publishing
;   -> Version 1.1  released
;   15.08.2002 bugfix: two ",0" as termination were
;     missing in the string definitions at
;     the end of the code
;     (no effect on 4433 but problem if code
;     is ported for 8535)
;   -> Version 1.2 released
;
;********************************************************************


;*** includes ***

.include "4433def.inc"


;*** definitions, equations, constants ***

.def char     = r0
.def ad_high     = r1
.def ad_low     = r2
.def rb_value     = r3
.def power        = r4
.def bbres        = r5
.def temp     = r16
.def wait     = r17
.def wait1     = r18
.def wait2     = r19
.def data     = r20
.def data_received = r21
.def str_len     = r22
.def command     = r23
.def sendbyte     = r24
.def hex_ascii     = r25
.def temp_sub      = r26

.def str_ptr_l     = r30
.def str_ptr_h     = r31

.equ val_bit7 = 128
.equ string = $0060; string start in memory
 ; (SRAM starts at $0060, not at $0000 !!!)

.equ stringmaxlen = 40 ; max. number of char in the input string


;*** interrupt table ***
.CSEG
.ORG 0x00
rjmp reset ;jump to reset handler
reti  ;irq0 handler
reti  ;irq1 handler
reti  ;timer1 capture handler
reti  ;timer1 compare handler
reti  ;timer1 overflow handler
reti  ;timer0 overflow handler
reti  ;spi transfer complete handler
rjmp uart_rx ;uart rx complete handler
reti  ;udr empty handler
reti  ;uart tx complete handler
reti  ;adc conversion complete interrupt handler
reti  ;eeprom ready handler
reti  ;analog comparator handler



;++++++++++++++++++++++++++ main +++++++++++++++++++++++++++++++++



main:

ldi str_ptr_l, string; load the string pointer with the string
clr str_ptr_h ; start address

clr str_len ; reset the number of char in the string

rcall sendstartmsg; send the startup-message via the UART

 
loop:
sbi PORTC, 5 ; switch of the LED (active low)

sbrs data_received,0; skip the jump if bit0 is set
  ; i.e. if a databyte was received from UART

rjmp loop ; wait for a received databyte in this loop


;a data byte was received from UART, lets handle it:

clr data_received; reset my own received flag

cbi PORTC, 5 ; switch on the LED (active low)
   
cpi data, 13 ; was the databyte a CR (ASCII 13) ?
brne not_cr
rcall cr_received
rjmp loop
not_cr:

cpi data, 8 ; was the databyte a Backspace (ASCII 8) ?
brne not_bs
rcall backspace
rjmp loop
not_bs:

cpi data, 10 ; was the databyte a LF (ASCII 10) ?
breq loop ; if yes -> do nothing and ignore it
 
cpi str_len, stringmaxlen; ignore input if max. number of char in the
breq loop ; input string is already reached


; the databyte is a normal character, add it to the input string

inc str_len ; increments the number of char. in the string

st z+, data ; stores the databyte in the string and inc.
  ; the pointer to the next addr.

mov sendbyte, data; echo the received character
rcall send_ser
 
rjmp loop



;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++






;---------------------- subroutine reset -------------------------
reset:

init_stack:
ldi temp, low(RAMEND); init stack pointer to last byte of ram
out SPL, temp

init_portd:  ; configure Port D as input
clr temp ;(Bit 2-7 will be used as general input)
out DDRD, temp ;(see init_uart for bits 0 and 1)
ldi temp, 0b11111100;switch on the internal pull-up resistors
out PORTD, temp ;  to prevent floating of the inputs

init_uart:
sbi DDRD,1 ; UART TX-pin (PortD, Bit1) as output
cbi DDRD,0 ; UART RX-pin (PortD, Bit0) as input

ldi temp, 0b10011000; enable TX, enable RX, enable RX-interrupt
out UCSRB,temp

ldi temp,23 ; 9600 Baud with fq=3.6864 MHz
out UBRR,temp
clr temp
out UBRRH,temp
 
init_portc:
ldi temp, 0b00100000; configure Port C as input
out DDRC, temp ;   except C5 =output for LED

init_portb:
ser temp ; configure Port B as output
out DDRB, temp

enable_irq:
ldi temp, val_bit7; set bit 7 in Statusregister to
out SREG, temp ; enable the interupts

rcall pause ; for phasing in the UART:
ldi temp, 32 ; pause - send one character - pause
out UDR, temp
rcall pause
 
rjmp main ; everything initialized, now lets go...


;----------------- interrupt routine uart_rx ---------------------

uart_rx:

in data, UDR ; read received data from UART

inc data_received; increment number of received datas

reti  ; end of interrupt routine


;--------------------- subroutine pause --------------------------
;(pause for about 10ms)
pause:
ldi wait,35

wl:
ser wait1
wl1: dec wait1
brne wl1

dec wait
brne wl

ret

;----------------- subroutine send_ser----------------
; sends one byte via UART and waits long enough for the
; byte to be send
send_ser:

out UDR, sendbyte; send the character via UART

serl:
sbis UCSRA, UDRE; wait till TX is ready
rjmp serl

ret

;------------------------subroutine rec_cmd -----------------------
; This subroutine tries to recognize the command in the inputstring
; Returns the number of the command (0 if no command could be recog.)
rec_cmd:


;*** check if at least 2 char are in the string, otherwise old
;characters may be recognized as commands ********

clr command ; preset reg command with 0 (no command rec.)

cpi str_len, 2 ; check if input is at least 2 char. long
brlo nocommand ; if no -> go to end of routine (returns 0)
 

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+
cpi temp, 's'
brne noset

ld temp, z+
cpi temp, 'b'
brne noset

ldi command, 1 ; the command was recognized as SB set bit
noset:

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+
cpi temp, 'c'
brne noclr

ld temp, z+
cpi temp, 'b'
brne noclr

ldi command, 2 ; the command was recognized as CB clear bit
noclr:

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string
ld temp, z+
cpi temp, 'r'
brne norb

ld temp, z+
cpi temp, 'b'
brne norb

ldi command, 4 ; the command was recognized as RB read bit
norb:

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string
ld temp, z+
cpi temp, 'r'
brne nora

ld temp, z+
cpi temp, 'a'
brne nora

ldi command, 3 ; the command was recognized as RA read ADC
nora:

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string
ld temp, z+
cpi temp, 'e'
brne noei

ld temp, z+
cpi temp, 'i'
brne noei

ldi command, 5 ; the command was recognized as ei echo input
noei:


nocommand:

ret


;-------------------------output string----------------------------
; reads characters from the flash meomory and puts them out via the
; the uart, stops when a '\0' is read from the memory. Starts to read
; at the location Z points to
outputstring:

lpm   ;read one byte from flash (acc. to Z-pointer)

tst char ;check if the char is zero (marks end of string)
breq endos ;if end-of-string -> jump to end of routine

mov sendbyte,char;transver the character to sendbyte
rcall send_ser ;call send_ser to transmit the char. via UART

adiw ZL,1 ;increment Z for next char. (add 1 to 16bit reg.)

rjmp outputstring;jump up for next character

endos:
ret


;---------------------------setbit---------------------------------
; sets a bit on Output Port B according to inputstring
setbit:
ldi str_ptr_l, low(2*sb_ok)
ldi str_ptr_h, high(2*sb_ok)
rcall outputstring


ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+ ; overread the first 2 characters (sb...)
ld temp, z+

ld temp, z+ ; read the 3rd char.

cpi temp, ' ' ; if the 3rd char is no space -> error
brne sbparametererr

cpi str_len, 4 ; is the input exactly 4 character long?
brne sbparametererr; if not -> error

ld temp, z+ ; read the 4th char. (number of ADC)

subi temp, 48 ; sub 48 to convert ASCII -> BIN

cpi temp, 6 ; check if Bit-Nr. is >= 6
brsh sbparametererr; only 1-4 allowed, if >=6 -> error


; all errors excluded, lets go on with bit setting

ldi sendbyte, ' '; output space
rcall send_ser

mov sendbyte, temp; output bit number
subi sendbyte, -48; (convert to ASCII before output)
rcall send_ser

ldi str_ptr_l, low(2*sb_hs)  ; output "has been set"
ldi str_ptr_h, high(2*sb_hs)
rcall outputstring

mov power, temp ; convert the bitnumber to a set bit
rcall bin2bit ; (calculates bbres=2^power)

in temp, PORTB ; read current value of PORTB
or temp, bbres ; set the chosen bit
out PORTB, temp ; write the value back to PORTB

rjmp sbend ; all done, go to end of subroutine

sbparametererr:
ldi str_ptr_l, low(2*parerr) ;write to terminal:
ldi str_ptr_h, high(2*parerr);Parameter error
rcall outputstring

sbend:
ret

;---------------------------clearbit---------------------------------
; clears a bit on Output Port B according to input
clearbit:
ldi str_ptr_l, low(2*cb_ok)
ldi str_ptr_h, high(2*cb_ok)
rcall outputstring


ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+ ; overread the first 2 characters (sb...)
ld temp, z+

ld temp, z+ ; read the 3rd char.

cpi temp, ' ' ; if the 3rd char is no space -> error
brne cbparametererr

cpi str_len, 4 ; is the input exactly 4 character long?
brne cbparametererr; if not -> error

ld temp, z+ ; read the 4th char. (number of ADC)

subi temp, 48 ; sub 48 to convert ASCII -> BIN

cpi temp, 6 ; check if Bit-Nr. is >= 6
brsh cbparametererr; only 1-4 allowed, if >=6 -> error


; all errors excluded, lets go on with bit clearing

ldi sendbyte, ' '; output space
rcall send_ser

mov sendbyte, temp; output bit number
subi sendbyte, -48; (convert to ASCII before output)
rcall send_ser

ldi str_ptr_l, low(2*cb_hc)  ; output "has been cleared"
ldi str_ptr_h, high(2*cb_hc)
rcall outputstring


mov power, temp ; convert the bitnumber to a set bit
rcall bin2bit ; (calculates bbres=2^power)

in temp, PORTB ; read current value of PORTB
com bbres ; invert all bits in bbres
and temp, bbres ; clear the chosen bit
out PORTB, temp ; write the value back to PORTB


rjmp cbend ; all done, go to end of subroutine

cbparametererr:
ldi str_ptr_l, low(2*parerr) ;write to terminal:
ldi str_ptr_h, high(2*parerr);Parameter error
rcall outputstring

cbend:
ret


;---------------------------read adc-------------------------------
readadc:
ldi str_ptr_l, low(2*ra_ok) ;write to terminal: READ ADC -
ldi str_ptr_h, high(2*ra_ok)
rcall outputstring


ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+ ; overread the first 2 characters (ra...)
ld temp, z+

ld temp, z+ ; read the 3rd char.

cpi temp, ' ' ; if the 3rd char is no space -> error
brne parametererr

cpi str_len, 4 ; is the input exactly 4 character long?
brne parametererr; if not -> error

ld temp, z+ ; read the 4th char. (number of ADC)

cpi temp, '0' ; ADC 0 is not allowed
breq parametererr; if 0 -> error

subi temp, 48 ; sub 48 to convert ASCII -> BIN

cpi temp, 5 ; check if ADC-Nr. is >= 5
brsh parametererr; only 1-4 allowed, if >=5 -> error


; all errors excluded, lets go on with the AD conversion

out ADMUX, temp ; switch the MUX to the selected ADC


subi temp, -48 ; output the ADC number to the terminal
mov sendbyte, temp
rcall send_ser

ldi sendbyte, '='; output =
rcall send_ser

ldi sendbyte, '$'; output $ to make clear the output is hex
rcall send_ser

 
ldi temp, 0b11100110; status for ADC: enable adc, start
out ADCSR, temp ; 1st conversion, free run,
  ; clock prescaled with factor 64
  ; ->57kHz clock with fq=3.686MHz

rcall pause ; wait for ADconversion to be performed

in ad_low, ADCL ; read adc-value (low byte must be
in ad_high, ADCH; read first!!!)


mov temp, ad_high; get the high-byte of the ADC value,
cbr temp, $F0 ; mask out higher nibble (lower remains)

mov hex_ascii, temp; convert the hex-number into ASCII
rcall hex2ascii
mov sendbyte, hex_ascii; send the ASCII character to the terminal
rcall send_ser

mov temp, ad_low; get the low-byte of the ADC value,
cbr temp, $0F ; mask out lower nibble (higher remains)
swap temp ; swap nibbles to shift the higher nibble down

mov hex_ascii, temp; convert the hex number into ASCII
rcall hex2ascii
mov sendbyte, hex_ascii; send the ASCII character to the terminal
rcall send_ser

mov temp, ad_low; get the low-byte of the ADC value,
cbr temp, $F0 ; mask out higher nibble (lower remains)

mov hex_ascii, temp; convert the hex-number into ASCII
rcall hex2ascii
mov sendbyte, hex_ascii; send the ASCII character to the terminal
rcall send_ser

ldi sendbyte, 32; send one space to the terminal
rcall send_ser
 
rjmp endadc

parametererr:

ldi str_ptr_l, low(2*parerr) ;write to terminal:
ldi str_ptr_h, high(2*parerr);Parameter error
rcall outputstring

endadc:
ret


;-------------------------hex2ascii------------------------------
;converts a byte with value 0-15 to a ascii-code in hex notation
;parameter: hex_ascii (contains the hex value before this routine
;is called and contains the ascii value afterwards)
hex2ascii:

subi hex_ascii, -48; add 48 for bin->ascii conversion
  ; (there is no addi!-> sub -48)

cpi hex_ascii, 58; 10 is 58 after the add above
brlo h2a_end ; if<58 ok, if not make 10->A, etc.

subi hex_ascii, -7; if 10-15 -> add 6 (58->65=A etc.)

h2a_end:
ret


;--------------------------read bit------------------------------
readbit:
ldi str_ptr_l, low(2*rb_ok)
ldi str_ptr_h, high(2*rb_ok)
rcall outputstring

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

ld temp, z+ ; overread the first 2 characters (ra...)
ld temp, z+

ld temp, z+ ; read the 3rd char.

cpi temp, ' ' ; if the 3rd char is no space -> error
brne rbparametererr

cpi str_len, 4 ; is the input exactly 4 character long?
brne rbparametererr; if not -> error

ld temp, z+ ; read the 4th char. (number of ADC)

subi temp, 48 ; sub 48 to convert ASCII -> BIN

cpi temp, 8 ; check if Bit-Nr. is >= 8
brsh rbparametererr; only 2-7 allowed, if >=8 -> error

cpi temp, 2 ; check if Bit-Nr. is < 2
brlo rbparametererr; only 2-7 allowed, if <2 -> error


; all errors excluded, lets go on with the bit reading

mov power, temp ; convert the bitnumber to a set bit
rcall bin2bit ; (calculates bbres=2^power)

in rb_value, PIND; read the physical status of the PortD pins
and rb_value, bbres; mask out the chosen bit
; now r_value is zero when the bit was cleared or
; r_value is not equal to zero when the bit was set

; now we can go ahead with the output to the terminal
subi temp, -48 ; output the bit number to the terminal
mov sendbyte, temp
rcall send_ser

ldi sendbyte, '='; output =
rcall send_ser
 
tst rb_value ; test if r_value is zero or not
breq bitzero ; if zero go to bitzero

ldi sendbyte, '1'; output char. '1' to the terminal
rcall send_ser
rjmp endrb ; all done, got to end of subr.

bitzero:
ldi sendbyte, '0'; output char. '0' to the terminal
rcall send_ser
rjmp endrb ; all done, got to end of subr.

rbparametererr:

ldi str_ptr_l, low(2*parerr) ;write to terminal:
ldi str_ptr_h, high(2*parerr);Parameter error
rcall outputstring

endrb:
ret


;---------------------------bin2bit--------------------------------
; converts a number (0-7) into a set bit in a byte
; e.g. the bit number 3 into 00001000, i.e. mathemtically
; it simply calulates n to the power of 2
; parameter is reg. exp, result is stored in bbres
bin2bit:

ldi temp_sub, 0b00000001; preset bbres with 1
mov bbres, temp_sub

bbloop:
tst power ; test if power is already zero
breq bbdone ; if yes go to end of subroutine

lsl bbres ; logic shift left (bbres=2*bbres)

dec power ; decrement power

rjmp bbloop ; go up for next round

bbdone:
ret

;--------------------------echo input------------------------------
echoinput:
ldi str_ptr_l, low(2*ei_ok)
ldi str_ptr_h, high(2*ei_ok)
rcall outputstring

ldi str_ptr_l, string; set the string pointer to the first char
clr str_ptr_h ; in the string

nextchar:
ld temp, z+ ; load one char and inc. the point to the next one

mov sendbyte, temp; send the char out via the UART
rcall send_ser

dec str_len ; decrement the stringlenght
 
brne nextchar ; stringlength=0 reached? if not, next character

ret

;---------------------- subroutine cr_received --------------------

; whenever a CR (Return = ASCII 13) is received via the UART, this
; subroutine is called

cr_received:

ldi sendbyte,13 ; send CR, LF to start a new line
rcall send_ser
ldi sendbyte,10
rcall send_ser

rcall rec_cmd ; try to recognize the command

tst command ; if command=0 -> no command could be
brne iscommand ; recognized, send SYNTAX ERROR
ldi str_ptr_l, low(2*synerr)
ldi str_ptr_h, high(2*synerr)
rcall outputstring
iscommand:

cpi command,1 ; if command=1 -> go to setbit
brne cr_nosetbit
rcall setbit
cr_nosetbit:

cpi command,2 ; if command=2 -> go to clearbit
brne cr_noclearbit
rcall clearbit
cr_noclearbit:

cpi command,3 ; if command=3 -> go to read adc
brne cr_noreadadc
rcall readadc
cr_noreadadc:

cpi command,4 ; if command=4 -> go to read bit
brne cr_noreadbit
rcall readbit
cr_noreadbit:

cpi command,5 ; if command=5 -> echo input
brne cr_noechoinput
rcall echoinput
cr_noechoinput:


clr str_len ; empty the inputstring and
ldi str_ptr_l, string; reset the
clr str_ptr_h ; stringpointer for the next string

ldi sendbyte,13 ; send CR, LF to start a new line
rcall send_ser
ldi sendbyte,10
rcall send_ser

ldi sendbyte,13 ; send CR, LF to start a new line
rcall send_ser
ldi sendbyte,10
rcall send_ser


ret


;----------------------- sendstartmsg -----------------------------
sendstartmsg:

.eseg
on_msg:
.db 13,10,13,10
.db "Universial serial PC interface, Herbert Dingfelder DL5NEG",13,10
.db "For users guide check out www.t-online.de/home/dl5neg",13,10
.db "For futher questions send a mail to dl5neg",13,10
.db "Firmware Version 1.1, built 03.11.2001",13,10,13,10,0
.cseg

ldi temp,low(on_msg) ;load the EEPROM pointer with the address where
out EEAR,temp ;the message (see above) is stored

EERead:
sbic EECR,EEWE;if EEWE not clear
rjmp EERead ;wait more


sbi EECR,EERE;set EEPROM Read strobe
  ;This instruction takes 4 clock cycles since
  ;it halts the CPU for two clock cycles
in temp,EEDR;get data

tst temp ;end of message is marked by an zerobyte
breq ssm_end ;check if 0, if yes jump to end of routine

mov sendbyte, temp;transver the character to register sendbyte
rcall send_ser ;call send_ser to transmit the char. via UART

in temp, EEAR ;increment EEAR (pointer to current address
inc temp ;in the EEPROM) for next character
out EEAR, temp

rjmp EERead ;jump up for next character

ssm_end:
ret


;---------------------- subroutine backspace ----------------------------

; whenever a Backspace (Return = ASCII 8) is received via the UART, this
; subroutine is called

backspace:

tst str_len ; is the stringlength=0 ? If yes ignore Backspace
breq end_bs

ld temp, -z ; set stringpointer one character left
  ; (temp is not needed, the command is only used
  ; to decrement Z)

dec str_len ; decrease the number of char in the string

ldi sendbyte, 8 ; send Backspace, Space, Backspace because
rcall send_ser ; the BS alone only moves the cursor one step
  ; left but does not delete the char from the
ldi sendbyte, 32; screen
rcall send_ser
 
ldi sendbyte, 8  
rcall send_ser  
 
end_bs:
ret  ; return from subroutine


;*************** output messages *****************************************

synerr: .db "SYNTAX ERROR - available commands: sb, cb, rb, ra, ei",0
sb_ok:  .db "SET BIT - Bit",0
sb_hs:  .db " has been set",0
cb_ok:  .db "CLEAR BIT - Bit",0
cb_hc:  .db " has been cleared",0
rb_ok:  .db "READ BIT - Bit ",0
ra_ok:  .db "READ ADC - ADC",0
ei_ok:  .db "ECHO INPUT - ",0
ok_out: .db "OK",0
parerr: .db " parameter not allowed or parameter syntax incorrect!",0





Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.