Turn a WORD variable into separate BYTE variables

mortifyu

New Member
Hello Guru’s,

First and foremost I genuinely hope all are safe and well and are coping with the current global corona virus pandemic. PLEASE! Look after yourselves and each other during this critical time.

Now that I have that out of the way...

Guy/Gals, I want to display a 10bit WORD variable as individual BYTE variables.

Such as:

W0=1016

to become:

B2=1
B3=0
B4=1
B5=6

to be able to:

sertxd(“Number= “,#B2,#B3,#B4,#B5)

The reason I want to do this is because I am working with a 2004A 20X4 LCD with I2C interface from banggood.

After scouring through the forum notes on info regarding use of these displays with PICAXE, I just still don’t quite get it no matter how many times I read other forum posts.

I do now however have some of Hippy’s sample code from previous forum threads working fine. The only problem is the code offered only sends single BYTES one at a time and I would like to display a 4 digit WORD value derived from READADC10.

Further to this, it’d be nice if I could write text on one line to be sent.


I think this will be a pretty simple thing to do, but lately my brain is melting with so many I am currently working on.



Kind regards,
Mort.
 

AllyCat

Senior Member
Hi,

You can also "Do It Yourself" and maybe even save a few program bytes compared with BINTOASCII. ;)

The first digit is W0 divided by 1000
The second digit is the remainder when W0 is divided by 1000, then divided by 100
The third digit is the remainder when W0 is divided by 100, then divided by 10
The final digit is the remainder when W0 is divided by 10.
Code:
W0 = 1016
B2 = W0 / 1000
B3 = W0 // 1000 / 100
B4 = W0 // 100 / 10
B5 = W0 // 10
SERTXD(#B2,#B3,#B4,#B5)
That also allows you to "re-use" the individual bytes of W0 within the SERTXD (i.e. B1 and B0, with care !) which BINTOASCII won't allow you to do. ;)

Cheers, Alan.
 

hippy

Technical Support
Staff member
sertxd(“Number= “,#B2,#B3,#B4,#B5)
If that's what you actually want to do then you can do it by SERTXD(#w0) and selecting the number of leading zeroes you need. One way ...
Code:
Select Case w0
  Case < 10   : SerTxd( "000" , #w0 )
  Case < 100  : SerTxd( "00"  , #w0 )
  Case < 1000 : SerTxd( "0"   , #w0 )
  Else        : SerTxd(         #w0 )
End Select
There are many variations on that, such as checking for >= 1000 first, moving the SERTXD(#w0) part out to after the END-SELECT, even going for fall-through -
Code:
If w0 < 10   Then : SerTxd( "0" ) : End If
If w0 < 100  Then : SerTxd( "0" ) : End If
If w0 < 1000 Then : SerTxd( "0" ) : End If
SerTxd( #w0 )
I have no idea which is smallest code or fastest execution.
 

mortifyu

New Member
Thank you!

The BINTOASCII command did the trick. However, Alan's example did not display on the LCD correctly, but I don't understand why. I can certainly see how it works and do understand it and it does work correctly with PE6 simulator.

The LCD displayed filled squares (such as the bottom right corner character in the attached map) and did not at all change by varying the W value.

LCD Character Map.gif


Regards,
Mort.
 

hippy

Technical Support
Staff member
The reason I want to do this is because I am working with a 2004A 20X4 LCD with I2C interface from banggood.
It would be worth posting your code, definitely a link to the datasheet of the LCD you are using, and a circuit diagram or details of how things are connected wouldn't go amiss.

The blocks on the LCD you describe would generally indicate the display has powered on but not been initialised. There could be a number of reasons for that.
 

inglewoodpete

Senior Member
The blocks on the LCD you describe would generally indicate the display has powered on but not been initialised. There could be a number of reasons for that.
Those blocks suggest that mortifyu can't write anything to the LCD, let alone word variables. First things first: can you write text to the LCD?
 

mortifyu

New Member
Sorry, I did not clarify that the blocks are displayed instead of numbers, not the entire display. See attached images.
As an end result I want to display 0-330 ohms in 0.1 ohm steps, but I don't see that I can achieve that being limited to only 10bit ADC (1024steps).
ie. 330ohms / 1024 = 0.32
Further to the circuit will be a 4022 octal counter being pulsed by the 08M2 switching in eight different resistors to the RIN terminal so as to display the different values of each simultaneously on the LCD. (Any suggestions on this part of the project would also be welcomed.)

LINK to where I purchased the LCD:

DATASHEET
Unfortunately I can't seem to find any in depth datasheet on the LCD, but I have acquired qc2004a.pdf

CIRCUIT DIAGRAM
Multi-Line Resistance Measurement Circuit.pdf
This is only a small portion of the overall circuit but does denote the necessary circuit in which I require PROGRAMMING assistance.

2x Images showing GOOD and BAD Display result.

LCD Display OK.jpg LCD Display Error.jpg

CURRENT PROGRAM CODE
Code:
'This Sample code originally provided by Hippy
'Modified by MortifyU to suit QC2004A
'This program used to measure and display UNKNOWN RESISTANCES 0-330ohms.
'08M2 PICAXE

Symbol bitRS = bit8
Symbol bitWR = bit9
Symbol bitE  = bit10
Symbol bitD4 = bit12
Symbol bitD5 = bit13
Symbol bitD6 = bit14
Symbol bitD7 = bit15
Symbol bitBL = bit11

Initialisation:

  HI2cSetup I2CMASTER, $4E, I2CFAST, I2CBYTE

  b0 = $33 : Gosub SendB0AsInitByte
  b0 = $33 : Gosub SendB0AsInitByte
  b0 = $32 : Gosub SendB0AsInitByte
  b0 = $28 : Gosub SendB0AsCommandByte
  b0 = $0C : Gosub SendB0AsCommandByte
  b0 = $06 : Gosub SendB0AsCommandByte
  b0 = $01 : Gosub SendB0AsCommandByte

  Pause 2



MainProgram:

  b0 = $80 : Gosub SendB0AsCommandByte    'Start at Line 1, Pos 1
 
  for b11 = 0 to 19                'The text 'TESTING OUTPUT LINES' = 20 characters incl. spaces
    lookup b11,("TESTING OUTPUT LINES"),b0
    Gosub SendB0AsDataByte
  next b11

  b0 = $C4 : Gosub SendB0AsCommandByte    'Start at Line 2, Pos 5
 
  for b11 = 0 to 11                'The text '--- Ohms ---' = 12 characters incl. spaces
    lookup b11,("--- Ohms ---"),b0
    Gosub SendB0AsDataByte
  next b11


DO

readadc10 c.4, w2

b0 = $94 : Gosub SendB0AsCommandByte
b0 = "1" : Gosub SendB0AsDataByte
b0 = ":" : Gosub SendB0AsDataByte

'***************************************************************************************************************
'Equivalent to bintoascii command suggested by Alleycat (Alan) produces ALL segments of each character to be on.
'b6 = w2 / 1000
'b7 = w2 // 1000 / 100
'b8 = w2 // 100 / 10
'b9 = w2 // 10
'***************************************************************************************************************
bintoascii w2,b6,b7,b8,b9,b10


b0=b8 : Gosub SendB0AsDataByte
b0=b9 : Gosub SendB0AsDataByte
b0=b10 : Gosub SendB0AsDataByte

LOOP


SendB0AsInitByte:

  Pause 15
  bitBL = 1
  bitWR = 0         ; Keep WR signal low

SendB0AsCommandByte:

  bitRS = 0         ; Send byte as a command

SendB0AsDataByte:

  bitD4 = bit4      ; Send msb first
  bitD5 = bit5
  bitD6 = bit6
  bitD7 = bit7

  bitE  = 1
  b2    = b1        ; b2 holds msb with E set
  bitE  = 0         ; b1 holds msb with E clear

  HI2cOut b1, ( b2, b1 )

  bitD4 = bit0      ; Send lsb second
  bitD5 = bit1
  bitD6 = bit2
  bitD7 = bit3

  bitE  = 1
  b2    = b1        ; b2 holds lsb with E set
  bitE  = 0         ; b1 holds lsb with E clear

  HI2cOut b1, ( b2, b1 )

  bitRS = 1         ; Send data byte next time
 
  Return


Thanks in advance Guru's.


Regards,
Mort.
 

Attachments

Last edited:

hippy

Technical Support
Staff member
Sorry, I did not clarify that the blocks are displayed instead of numbers, not the entire display. See attached images.
Thanks for the clarifications. So it looks like it's just an issue in getting the characters out.

I can't see anything immediately wrong with what you have. Your earlier '1' and ':' moves those to b0 and sends them and they come out okay, so not sure why doing the same with your BINTOASCII results afterwards doesn't. Very weird.

2x Images showing GOOD and BAD Display result
Might hep if you could explain how you are getting good and bad results, in what circumstances is it good or bad ?

Added : You could try changing I2CFAST to I2CSLOW to see if that improves things.
 
Last edited:

hippy

Technical Support
Staff member
As an end result I want to display 0-330 ohms in 0.1 ohm steps, but I don't see that I can achieve that being limited to only 10bit ADC (1024steps).
The easiest way I can imagine being able to do that is to charge up a capacitor and see how long it takes to charge, and from that calculate what the resistance must be.

Or having to use some sort of comparison where you control something with 12-bit or greater accuracy and see what that has to be to get a match of some kind. Not sure what off-hand.
 

mortifyu

New Member
The BINTOASCII command works fine, hence 1: 103

However Alleycat's suggestion only displayed 1: ▒ ▒ ▒

For the higher resolution (0.1ohms) I think I may have to find a dedicated 12bit ADC chip with RS232 return or something along those lines.

I was kinda hoping you smart blokes might have suggested some tricky way for me to gain higher resolution with 08M2. It was just a dream :unsure::)

Change from I2CFAST to I2CSLOW makes no difference.
 

Aries

New Member
The BINTOASCII command works fine, hence 1: 103

However Alleycat's suggestion only displayed 1: ▒ ▒ ▒
The clue is in the name - BINTOASCII produces ASCII (character) codes in the output.
Alleycat's version produces NUMBERS. To get what you want, use:
Code:
'Equivalent to bintoascii command suggested by Alleycat (Alan) produces ALL segments of each character to be on.
'b6 = w2 / 1000 + "0"
'b7 = w2 // 1000 / 100 + "0"
'b8 = w2 // 100 / 10 + "0"
'b9 = w2 // 10 + "0"
 

mortifyu

New Member
The clue is in the name - BINTOASCII produces ASCII (character) codes in the output.
Well this sounds logical, but... If this was the problem, then one would expect a change in what is displayed when the ADC10 WORD value is varied, but it doesn’t. With Alleycat’s CODE, what is displayed never changes with an ADC value varied anywhere between 0-1024.
 

AllyCat

Senior Member
Hi,
Code:
SERTXD(#B2,#B3,#B4,#B5)
Without the # symbols, the program sends values from 0 - 9, which are the (ASCII) "User Defined" characters. If these have not been set up, then the program will just display "undefined" pixel patterns (which in practice may all be the same), regardless of the values sent.

Cheers, Alan.
 

mortifyu

New Member
Hi,

Without the # symbols, the program sends values from 0 - 9, which are the (ASCII) "User Defined" characters. If these have not been set up, then the program will just display "undefined" pixel patterns (which in practice may all be the same), regardless of the values sent.

Cheers, Alan.

Ah o.k., thanks for the clarification there. So... As much as BINTOASCII has solved my dilemma, just for educational purpose, is there a way to use your suggested calculations and then implement the result so as to be able to effectively say: b0=#b8 : Gosub SendB0AsDataByte... ?


Regards,
Mort.
 

hippy

Technical Support
Staff member
Well this sounds logical, but... If this was the problem, then one would expect a change in what is displayed when the ADC10 WORD value is varied, but it doesn’t. With Alleycat’s CODE, what is displayed never changes with an ADC value varied anywhere between 0-1024.
It sounds like you have multiple issues; that there's something we haven't spotted which causes the '103' result. Two immediate possibilities are not reading the pot input but something else, or converting the wrong word variable to give the digits you are then displaying.

is there a way to use your suggested calculations and then implement the result so as to be able to effectively say: b0=#b8 : Gosub SendB0AsDataByte... ?
In my current I2C reference code I have a "SendB0AsDigit" routine ...
Code:
SendB0AsDigit:
  b0 = b0 // 10 + "0"
  Goto SendB0AsDataByte
That means, BINTOASCII or the below -
Code:
b0 = w2 / 10000 // 10 + "0" : Gosub SendB0AsDataByte
b0 = w2 / 1000  // 10 + "0" : Gosub SendB0AsDataByte
b0 = w2 / 100   // 10 + "0" : Gosub SendB0AsDataByte
b0 = w2 / 10    // 10 + "0" : Gosub SendB0AsDataByte
b0 = w2         // 10 + "0" : Gosub SendB0AsDataByte
Can be replaced with the shorter -
Code:
b0 = w2 / 10000 : Gosub SendB0AsDigit
b0 = w2 / 1000  : Gosub SendB0AsDigit
b0 = w2 / 100   : Gosub SendB0AsDigit
b0 = w2 / 10    : Gosub SendB0AsDigit
b0 = w2         : Gosub SendB0AsDigit
If you had multiple numbers to display it would make sense to add a 'SendW2AsNumber" routine or similar and put the above in that.
 

mortifyu

New Member
On the same lines as I wrote before, use something like:
Code:
b0 = b8 + "0"
gosub etc
BINGO! Yes, this worked and displayed the result correctly. Thanks mate ;)

Code:
readadc10 c.4, w2

b0 = $94 : Gosub SendB0AsCommandByte
b0 = "1" : Gosub SendB0AsDataByte
b0 = ":" : Gosub SendB0AsDataByte

'b6 = w2 / 1000             'Thousands omitted because I only want to display HUNDREDS,TENS,UNITS
b7 = w2 // 1000 / 100
b8 = w2 // 100 / 10
b9 = w2 // 10


b0=b7 + "0" : Gosub SendB0AsDataByte     ' +"0" <<< As suggested by Aries & Hippy
b0=b8 + "0" : Gosub SendB0AsDataByte
b0=b9 + "0" : Gosub SendB0AsDataByte

'b0=b8 : Gosub SendB0AsDataByte
'b0=b9 : Gosub SendB0AsDataByte
'b0=b10 : Gosub SendB0AsDataByte

LOOP

Thank you EVERYBODY ;)


Now... best way to go about displaying one decimal place? Instead of displaying 1: 103, I'd like to for example display 1: 103.3




Regards,
Mort.
 
Last edited:

mortifyu

New Member
It sounds like you have multiple issues; that there's something we haven't spotted which causes the '103' result....

No no, 103 is correct. For how I purposely had the ADC resistor divider set, it was technically displaying 0103 except I omitted displaying the first 0.
 

hippy

Technical Support
Staff member
No no, 103 is correct.
Your "If this was the problem, then one would expect a change in what is displayed when the ADC10 WORD value is varied, but it doesn’t" suggested the value being seen wasn't changing, which I took to be the "103" your previous image had shown.

Let's forget AllyCat's code; we have identified why that did not work immediately for you and the resolution for that. Let's just deal with what does work.

best way to go about displaying one decimal place? Instead of displaying 1: 103, I'd like to for example display 1: 103.3
You would need to have a four digit number stored in w2, for example 1033 for the above.

This will display the 1234 in w2 as 123.4 -
Code:
w2 = 1234
b0 = w2 / 1000 : Gosub SendB0AsDigit
b0 = w2 / 100  : Gosub SendB0AsDigit
b0 = w2 / 10   : Gosub SendB0AsDigit
b0 = "."       : Gosub SendB0AsDataByte
b0 = w2        : Gosub SendB0AsDigit
Code:
SendB0AsDigit:
  b0 = b0 // 10 + "0"
  Goto SendB0AsDataByte
 
Top