View previous topic :: View next topic |
Author |
Message |
hzz
Joined: 20 Feb 2007 Posts: 314
|
Posted: Mon Jan 25, 2021 9:05 pm Post subject: How to convert several variables into an array of bytes? |
|
|
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 |
|
|
Evert :-)
Joined: 18 Feb 2005 Posts: 2156
|
Posted: Mon Jan 25, 2021 10:02 pm Post subject: |
|
|
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 |
|
|
hzz
Joined: 20 Feb 2007 Posts: 314
|
Posted: Mon Jan 25, 2021 10:51 pm Post subject: |
|
|
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 |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jan 26, 2021 1:38 am Post subject: |
|
|
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 |
|
|
i.dobson
Joined: 05 Jan 2006 Posts: 1570 Location: Basel, Switzerland
|
Posted: Tue Jan 26, 2021 8:47 am Post subject: |
|
|
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 _________________ Walking on water and writing software to specification is easy if they're frozen. |
|
Back to top |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jan 26, 2021 11:25 am Post subject: |
|
|
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:
instead of
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 |
|
|
i.dobson
Joined: 05 Jan 2006 Posts: 1570 Location: Basel, Switzerland
|
Posted: Tue Jan 26, 2021 11:34 am Post subject: |
|
|
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 _________________ Walking on water and writing software to specification is easy if they're frozen. |
|
Back to top |
|
|
hzz
Joined: 20 Feb 2007 Posts: 314
|
Posted: Tue Jan 26, 2021 12:31 pm Post subject: |
|
|
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 |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jan 26, 2021 1:07 pm Post subject: |
|
|
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 |
|
|
MWS
Joined: 22 Aug 2009 Posts: 2262
|
Posted: Tue Jan 26, 2021 1:38 pm Post subject: |
|
|
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 |
|
|
hzz
Joined: 20 Feb 2007 Posts: 314
|
Posted: Tue Jan 26, 2021 2:14 pm Post subject: |
|
|
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 |
|
|
hzz
Joined: 20 Feb 2007 Posts: 314
|
|
Back to top |
|
|
|