Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

How to convert several variables into an array of bytes?

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR
View previous topic :: View next topic  
Author Message
hzz

Bascom Member



Joined: 20 Feb 2007
Posts: 311

spain.gif
PostPosted: Mon Jan 25, 2021 9:05 pm    Post subject: How to convert several variables into an array of bytes? Reply with quote

Code:
Dim Btemp as Byte : Btemp=33
Dim Wtemp as Word : Wtemp=222
Dim Ltemp as Long : Ltemp = 111
Dim Data_str as string * 200
Dim Data_arr(201) As Byte At Data_str Overlay
 

I would like to "store" the variables into the string "Data_str" or into the array "Data_ar" so that it will contain the following bytes:

Byte1 = 033 = Btemp
Byte2 = 000 = Wtemp MSB
Byte3 = 222 = Wtemp LSB
Byte4 = 000 = Ltemp MSB MSB
Byte5 = 000 = Ltemp MSB
Byte6 = 000 = Ltemp LSB
Byte7 = 111 = Ltemp LSB LSB

Is there a BASCOM function that can help to do it?

The purpose is to be able to calculate the CRC of these data and send it via serial port with a binary protocol.
Regards!

(BASCOM-AVR version : 2.0.8.3 )
Back to top
View user's profile
Evert :-)

Bascom Expert



Joined: 18 Feb 2005
Posts: 2133

netherlands.gif
PostPosted: Mon Jan 25, 2021 10:02 pm    Post subject: Reply with quote

You can OVERLAY the bytes (or other types) over the array

Code:
Dim MyAr(100) As Byte
Dim Mybyte1 As byte At MyAr() + &H01 Overlay
Dim Mybyte2 As byte At MyAr() + &H02 Overlay
Dim Mybyte2 As byte At MyAr() + &H03 Overlay
Dim MyWord1 As Word At MyAr() + &H04 Overlay '<- Note Word takes 2 bytes
Dim Mybyte3 As byte At MyAr() + &H06 Overlay  
 


Now you can easy change the values of the variable Mybyte1 etc...
Calculating crc can be done over the array MyAr

_________________
www.evertdekker.com Bascom code vault
Back to top
View user's profile Visit poster's website
hzz

Bascom Member



Joined: 20 Feb 2007
Posts: 311

spain.gif
PostPosted: Mon Jan 25, 2021 10:51 pm    Post subject: Reply with quote

Thanks Evert!
What you propose will solve my example but I cannot use a fixed array as the variables are not always the same. The problem is the following:

Given any sequence of variables of type Byte, Word, DWord and Long I need a function that returns a string whose bytes are the bytes of the variables one after the other.
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 1939

blank.gif
PostPosted: Tue Jan 26, 2021 1:38 am    Post subject: Reply with quote

hzz wrote:
I need a function that returns a string whose bytes are the bytes of the variables one after the other.

Did you consider, that a zero is a normal value for a normal variable, but for a string it's the string terminator?
Any string function will terminate as it meets a zero.
A byte array as overlay does not show this problem.
Back to top
View user's profile
i.dobson

Bascom Expert



Joined: 05 Jan 2006
Posts: 1546
Location: Basel, Switzerland

switzerland.gif
PostPosted: Tue Jan 26, 2021 8:47 am    Post subject: Reply with quote

Hello,

As MWS said 0 is used as a end of string flag. If you can use an array of bytes as your "return value" then overlay will work. I actually use overlays quite alot:-

Code:

'--The following parameters are written to the eeprom--------------------------
Dim Zeropoint(2) As Word                                                        'Raw zero            4bytes
Dim Scale_factor(2) As Single                                                   '1pascal=RAW units   8bytes
Dim Min_pressure_seal As Integer                                                'Min seal pressure allowed 2bytes
Dim Seal_inflate_timeout As Word                                                'Timeout to reach it 2bytes
Dim Alarm_pressure_seal As Integer                                              'Alarm limit for seal 2bytes
Dim Eeprom_checksum As Byte                                                     'EEPROM CHECKSUM      1bytes
'--END OF EEPROM LIST-------------------------------------------------------
Dim Eeprom_parameters(20) As Byte At Zeropoint(1) Overlay                       'OVERLAY for EEPROM
 


In this example the main code can access the variables (for example Zeropoint(1)) as a word and the routines that read/write the EEPROM use the byte array (Eeprom_parameters(1 to 20). I've been using the routine for almost 9 years in a product that we've sold amost 2000 times and have never had problem with it.

Regards
Ian Dobson

_________________
Home of AVRTimer, the Bascom timer value calculator.
http://www.planet-ian.com

Walking on water and writing software to specification is easy if they're frozen.
Back to top
View user's profile Visit poster's website
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 1939

blank.gif
PostPosted: Tue Jan 26, 2021 11:25 am    Post subject: Reply with quote

i.dobson wrote:
I've been using the routine for almost 9 years

Three hints:

1) It's possible to let Bascom do the range calculation:
Code:
'--The following parameters are written to the eeprom--------------------------
Dim Zeropoint(2) As Word                                                        'Raw zero            4bytes
Dim Scale_factor(2) As Single                                                   '1pascal=RAW units   8bytes
Dim Min_pressure_seal As Integer                                                'Min seal pressure allowed 2bytes
Dim Seal_inflate_timeout As Word                                                'Timeout to reach it 2bytes
Dim Alarm_pressure_seal As Integer                                              'Alarm limit for seal 2bytes
Dim Eeprom_checksum As Byte                                                     'EEPROM CHECKSUM      1bytes
Dim Endpoint As Byte At Eeprom_checksum  Overlay
'--END OF EEPROM LIST-------------------------------------------------------
Const numEEParam = varptr("Endpoint") - varptr("Zeropoint") + 2
Dim Eeprom_parameters(numEEParam) As Byte At Zeropoint Overlay

The '+ 2' reflects to the fact you save one byte more, than your variables represent.
If the exact range is required, then it is '+ 1'
In case you restore also 20 bytes from EEProm, and it looks like you do:
Quote:
use the byte array (Eeprom_parameters(1 to 20)

you restore erroneously also the next following real (non-overlay) variable in your code.

Rule: Varptr("var") returns always the variable's start address at compile time.
Var must be enclosed by double quotes, a given index has NO effect, i.e. varptr("Zeropoint") returns the same address as varptr("Zeropoint(2)")

As calculation is done by assuming the last variable is a byte, it must be taken care whether the range-end address is anything other than byte.
If the last variable is a word, then it's again one byte more, DWord three bytes more, a.s.o.
This can be avoided by wasting one SRam byte for 'Endpoint' by NOT declaring it as Overlay, but instead put it as last byte of the range to save.

2) This:
Code:
'--The following parameters are written to the eeprom--------------------------
'--END OF EEPROM LIST-------------------------------------------------------

is as said not exactly correct, you save one byte more, as you have a range of 19 bytes, while you save 20.
Especially if you have more variables, or a bigger range, my hint avoids errors and spares tedious counting work.

3) If you leave out the index:
Code:
At Zeropoint

instead of
Code:
At Zeropoint(1)

then it's easier to change the index start with Config Base = 0.
Rule: Pointing to an array without index always points to the first byte.
Back to top
View user's profile
i.dobson

Bascom Expert



Joined: 05 Jan 2006
Posts: 1546
Location: Basel, Switzerland

switzerland.gif
PostPosted: Tue Jan 26, 2021 11:34 am    Post subject: Reply with quote

Hi MWS

Yep, I have an extra spare byte at the end of the byte array that is always 0 (I didn't include it in the code example). Thats a left over from the code development where I had a bug that trashed the byte after the end of the data structure.

I prefer to keep the element number for the byte array address (Dim Eeprom_parameters(20) As Byte At Zeropoint(1) Overlay) for me thats a lot clearer than just using the variable name.

Regards
Ian Dobson

_________________
Home of AVRTimer, the Bascom timer value calculator.
http://www.planet-ian.com

Walking on water and writing software to specification is easy if they're frozen.
Back to top
View user's profile Visit poster's website
hzz

Bascom Member



Joined: 20 Feb 2007
Posts: 311

spain.gif
PostPosted: Tue Jan 26, 2021 12:31 pm    Post subject: Reply with quote

This is the solution I have implemented (I have tested and is OK but the following is extracted from a longer code so not all variables are declared)
Code:
'     Binary Registers have the following format:
'          Type of register (1 byte)
'          Length of register (2 bytes)
'          Data (N Bytes)
'          Checksum (1 byte)

     Dim Long_variable As Long
     Dim Long0 As Byte At Long_variable Overlay
     Dim Long1 As Byte At Long_variable + 1 Overlay
     Dim Long2 As Byte At Long_variable + 2 Overlay
     Dim Long3 As Byte At Long_variable + 3 Overlay

     Dim Word_variable As Word
     Dim Word0 As Byte At Word_variable Overlay
     Dim Word1 As Byte At Word_variable + 1 Overlay

     Dim Reg_p_ar(401) As Byte
     Dim Reg_p_str As String * 400 Overlayed At Data_p_ar

     Dim K As Word

     Const Registro_mv=3

'
'________________________________________________________________________________
Mk_reg_mv:
   K = 1
'  Type of register
   Reg_p_ar(k) = Registro_mv
   K = 4                                                     'Skip bytes 2 and 3 . We will put later the length of the register

'  DATA
   Wtemp = 11                                               ' Load a Word variable for testing
      Word_variable = Wtemp
      Gosub Cargar_word

   Ltemp = 101                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 102                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 103                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

' Checksum
   Reg_chk = Checksumxor(reg_p_str)
   Reg_p_ar(k) = Reg_chk

' Length of register
   Reg_len = K
   Reg_p_ar(2) = Reg_len0
   Reg_p_ar(3) = Reg_len1

Return

'__________________________________________________________________
'__________________________________________________________________
'                              LOAD WORD
'     INPUT:
'              K= Position of first byte to be loaded into  Reg_p_ar
'              Word_variable = Variable to load
'     OUTPUT
'             Reg_p_ar  updated
'             K  updated
'__________________________________________________________________
Cargar_word:
      Reg_p_ar(k ) = Word0                                  ' LSB first
      Reg_p_ar(k + 1 ) = Word1
      K = K + 2
Return

'__________________________________________________________________
'__________________________________________________________________
'                                LOAG LONG
'     INPUT:
'              K= Position of first byte to be loaded into  Reg_p_ar
'              Word_variable = Variable to load
'     OUTPUT
'             Reg_p_ar  updated
'             K updated
'__________________________________________________________________
Cargar_long:
      Reg_p_ar(k ) = Long0                                  ' LSB first
      Reg_p_ar(k + 1) = Long1
      Reg_p_ar(k + 2) = Long2
      Reg_p_ar(k + 3) = Long3
      K = K + 4
Return
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 1939

blank.gif
PostPosted: Tue Jan 26, 2021 1:07 pm    Post subject: Reply with quote

Hi Ian,
i.dobson wrote:
I prefer to keep the element number for the byte array address (Dim Eeprom_parameters(20) As Byte At Zeropoint(1) Overlay) for me thats a lot clearer than just using the variable name.

No problem, do as you prefer, keep in mind my hint may be helpful for others.
In case range of data gets more complex, then my hint to have the compiler do the counting becomes a must, while at 19 bytes mental math will do.
Quote:
Yep, I have an extra spare byte at the end of the byte array that is always 0

It was not to see from the shown code and could have been a trap.
Back to top
View user's profile
MWS

Bascom Member



Joined: 22 Aug 2009
Posts: 1939

blank.gif
PostPosted: Tue Jan 26, 2021 1:38 pm    Post subject: Reply with quote

hzz wrote:
This is the solution I have implemented

Surly not.
Code:
     Dim Reg_p_ar(401) As Byte
     Dim Reg_p_str As String * 400 Overlayed At Data_p_ar

There is no such operator in Bascom as 'Overlayed' and also its correct usage is wrong, the compiler will spits out errors.

And beside for a hidden meaning (which I may not see, other for being able to use ChecksumXOR()), your code is utter nonsense.
Change any byte positioned into the array to zero and it fails, respectively does not what you may expect.
Back to top
View user's profile
hzz

Bascom Member



Joined: 20 Feb 2007
Posts: 311

spain.gif
PostPosted: Tue Jan 26, 2021 2:14 pm    Post subject: Reply with quote

The original code is in several files and with comments in Spanish so I edited some partes in the Forum, with mistakes as I see. The following is copied form the original working OK

I'm using it to store data formated in registers into an SDHC cards. Bedore using this, I created the record directly into the SDCH card with PUTs but the calculation of the checksum reading all bytes from the card was very inefficient. Now I do it in two steps: first i make each register with MAKE_REG and then I PUT the register in the SDHC as a string.


Code:
Variables_grabar_eventos:
 ' Cada bit de Grabar_eventos es una bandera para indicar qué eventos se han de grabar en el fichero P
Dim Grabar_eventos_p As Word
   Grabar_p_mv Alias Grabar_eventos_p.0
   Grabar_p_dt Alias Grabar_eventos_p.1
   Grabar_p_ab Alias Grabar_eventos_p.2
   Grabar_p_fb Alias Grabar_eventos_p.3
   Grabar_p_af Alias Grabar_eventos_p.4
   Grabar_p_db Alias Grabar_eventos_p.5
   Grabar_p_gb Alias Grabar_eventos_p.6
   Grabar_p_pb Alias Grabar_eventos_p.7
   Grabar_p_dm Alias Grabar_eventos_p.8

'Dim Tipo_registro_p As Byte                                 ' Utilizado en la cabecera del registro de los eventos guardados en el fichero P
Const Registro_hd = 1                                       ' Cabecera del fichero
Const Registro_dt = 2
Const Registro_mv = 3
Const Registro_fb = 4
Const Registro_af = 6

Const Registro_ab = 5
Const Registro_db = 7
Const Registro_gb = 8
Const Registro_pb = 9
Const Registro_dm = 10

'Dim Reg_type As Byte                                        ' Tipo de registro
Dim Reg_len As Word                                         ' Longitud del registro
   Dim Reg_len0 As Byte At Reg_len Overlay
   Dim Reg_len1 As Byte At Reg_len + 1 Overlay

Dim Reg_ini_pos As Long                                     'Posición del primer byte del registro (Byte TYPE)
Dim Reg_len_pos As Long                                     'Posición del campo de longitud del registro
Dim Reg_end_pos As Long                                     'Posición del último byte del registro (último byte de datos)

Dim Reg_chk As Byte                                         ' Byte de checksum

Dim Reg_p_ar(401) As Byte
Dim Reg_p_str As String * 400 At Reg_p_ar Overlay




Code:
$nocompile
'________________________________________________________________________________
'                                                   MAKE_REG

' Rutinas para construir los registros a grabar en la tarjeta SD
' Cada rutina construye un registro
' El proceso que lo requiere (en Registrar Eventos) llama a la rutina del registro que quiera construir

'Cada registro es una cadena de bytes con el siguiente formato:
'        -- Tipo de evento (1byte)
'        -- Longitud del registro (2bytes)
'           La Longitud  es el número total de bytes del registro  desde el Tipo de registro hasta el checksum ambos incluidos.
'        -- Datos  (N bytes)
'        -- Checksum (1byte)  calculado con ChecksumXOR (computed by Xor-ing all the bytes of the string) incluyendo todos
'            los bytes desde el tipo de mensaje hasta el último byte de datos ambos incluidos.



'     Dim Reg_p_ar(401) As Byte
'     Dim Reg_p_str As String * 400 Overlayed At Data_p_ar(1)

'
'________________________________________________________________________________
Mk_reg_mv:
   K = 1
'  Type of register
   Reg_p_ar(k) = Registro_mv
   K = 4

'  DATA
   Wtemp = 11                                               ' Load a Word variable for testing
      Word_variable = Wtemp
      Gosub Cargar_word

   Ltemp = 101                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 102                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 103                                              ' Load a Long variable for testing
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 104                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 105                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 106                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 107                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 108                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 109                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 110                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

   Ltemp = 111                                              ' Cargar una variable de tipo Long  para pruebas
      Long_variable = Ltemp
      Gosub Cargar_long

' Checksum
   Reg_chk = Checksumxor(reg_p_str)
   Reg_p_ar(k) = Reg_chk

' Length of register
   Reg_len = K
   Reg_p_ar(2) = Reg_len0
   Reg_p_ar(3) = Reg_len1

Return

'__________________________________________________________________
'__________________________________________________________________
'                              LOAD WORD
'     INPUT:
'              K= Position of first byte to be loaded into  Reg_p_ar
'              Word_variable = Variable to load
'     OUTPUT
'             Reg_p_ar  updated
'             K  updated
'__________________________________________________________________
Cargar_word:
      Reg_p_ar(k ) = Word0                                  ' Primero LSB
      Reg_p_ar(k + 1 ) = Word1
      K = K + 2
Return

'__________________________________________________________________
'__________________________________________________________________
'                                CARGAR LONG
'     INPUT:
'              K= Position of first byte to be loaded into  Reg_p_ar
'              Word_variable = Variable to load
'     OUTPUT
'             Reg_p_ar  updated
'             K updated
'__________________________________________________________________
Cargar_long:
      Reg_p_ar(k ) = Long0                                  ' Primero LSB
      Reg_p_ar(k + 1) = Long1
      Reg_p_ar(k + 2) = Long2
      Reg_p_ar(k + 3) = Long3
      K = K + 4
Return
Back to top
View user's profile
hzz

Bascom Member



Joined: 20 Feb 2007
Posts: 311

spain.gif
PostPosted: Wed Jan 27, 2021 7:29 pm    Post subject: Working code Reply with quote

Please see a better solution at:
https://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&p=80030#80030
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum