playing with strings

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am just playing around with assembly trying to get familier with strings. I am trying to determine the length of the string, here is kinda how I started, but I need some help as to it doesnt work :(

mytext: .db "This is text>",0x00

then I figured I need to copy into ram ?

ldi ZL, low(mytext)
ldi ZH, high(mytext)

the call my count function
.def temp =r18

countstr:
ldi r18,0x00
cpi z,temp ; compare against 0
brne addcount
rjmp total

addcount:
inc count; increment count for number of charectors
inc Z; need to increment the z register ??
rjmp countstr

total:
havent done anything here , just a loop, until I figure out what I want to do with the count, display on PORTB leds ?

So, I dont know if I am on the right track or not ? Can someone help me out ? Just want to calculate the length of the string, I am a c person, and trying to learn assembyl, so thanks for any help !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Starting from the beginning:

> ldi ZL, low(mytext)
> ldi ZH, high(mytext)

Looks good.

> countstr:
> ldi r18,0x00
> cpi z,temp ; compare against 0

A few problems. First, Z holds the address of your string, not its value (in C, the LValue, not the RValue). Second, Z isn't a register, you can't compare Z to another register, you have to work with ZH or ZL. Third, "cpi" is for comparing a register to an immediate value ("cp" to compare two registers).

To get the value that Z is pointing to into a register, do a LDS or LD (for values in ram) or in this, a LPM for values in program memory. You would code it as:

ldi temp, 0
countstr:
lpm ; loads value pointed to by Z into r0
tst r0 ; null character?
breq done
inc temp ; add 1 to str length count
adiw ZH:ZL, 1 ; add 1 to Z register
rjmp countstr:

There are "tighter" ways to code this but they aren't so easy to understand.

Finally, since we are on an 8 bit cpu that uses a 16 bit address space, pointer arithmetic is a bit tricky. You can't use the same math opcodes on X, Y, and Z, you must either use auto-increment ops, or the ADIW or SBIW (add/subtract on word) ops.

Hope this helps.

admin's test signature
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

actually
> ldi ZL, low(mytext)
> ldi ZH, high(mytext)

does not look good. The X, Y, and Z registers are byte oriented, whereas the code space is word oriented. So for every word of code space you want to look at, you have two bytes.

ldi ZL, low(2*mytext)
ldi ZH, high(2*mytext)

lpm loads a value from code space to r0, that's important. Some devices (the megas???) support lpm'ing to other registers.
For adiw you only need the lower register of the pair, so

adiw ZL, 1

is correct.

Christoph

admin's test signature
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi J,

when you put a string in ROM (Flash), why don't you let the assembler calculate teh string length (it won't differ from execution to execution)?

string:   db &nbyp; low (strend - string), "this is the string"
strend:

bis die Tage...
  Mathias

admin's test signature
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi J,

(oops, typo...)

string:   db   low (strend - string), "this is the string"
strend:

bis die Tage...
Mathias

admin's test signature
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I got it working ! Here is what I have:

.def temp = r17
.def reg = r18
.def zero = r20
.def count = r19
.def curtext = r0
.equ int = 10
.equ zero = 0x00

text: .db "The count is:",0x00

rjmp init

init:
;***** Init the stack pointer *****
ldi temp,high(RAMEND)
out SPH,temp
ldi temp,low(RAMEND)
out SPL,temp
clr temp
clr reg
clr count
rjmp main

main:

ldi ZL, LOW(2*text) ;shifted becuase pgm memory is words
ldi ZH, HIGH(2*text) ;
ldi zero,0
jmp strcont

strcont:
lpm
cpse curtext,zero
rjmp inccount
rjmp total

inccount:
inc count
inc ZL
rjmp strcont

total:
rjmp total

thanks to all that help ! Now that the count is in binary, I am going to try and make it display a number on the serial port. Would this involve BCD conversion ?
If the value is 0b00001001, how do I get it to transmit a '9' to the serial port ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Its easy to convert a value from 0-9 to a string-- just add the ascii value of '0' to it. For example:

ldi r16, 5 ; value to display
addi r16, '0' ; convert it to ASCII
rcall TXMIT232 ; transmit thru serial port

Obviously if your value is 10 or more, this won't work-- you'll start getting punctuation characters or other weird things.

To do larger numbers, you must first convert it to BCD, which gives you the numeric value of each digit. Then convert each digit to ascii by the method above.

There's quite a few ways to convert to BCD, you can find sample source for it in the Academy section.

admin's test signature