|
Forum Index : Microcontroller and PC projects : MMbasic RP2350 V6.01.00EXP with user-defined structures
| Author | Message | ||||
Grogster![]() Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9819 |
My guess would seem to boil down to the statement: "It's easy, once you know how." To me, structures seem like a good way to manage database-type programs, and I do use/write those kinds of programs, where data is(normally) just stored as files on the SD card, or as a whole bunch of integers and strings. Sounds like the old Windows cardfile program: (circa Windoze 3.11 and Windoze 95) TYPE CARD NAME as String PHONE as Integer ADDRESS as String EMAIL as String END TYPE ... DIM CARDFILE(500) As CARD 'Define a new "Cardfile" variable, with up to 500 "Cards" in it ...then the ONE SINGLE variable can hold ALL FOUR different data types in each element of the variable, yes? PRINT CARDFILE(15) would print the 15th card on the screen, consisting of all four variables for that "Card", yes? ...probably "No." It takes me a while to cotton onto some things! I am just using the old cardfile concept here - simple database for holding various bits of information, and each group of information is a "Card" in the cardfile. I'm using that reference, as it is familiar to me, as I used to use old cardfile a-lot back in the day! I think I understand that aspect now, I just need to re-read and understand how the IF/THEN searching thing works a bit better. Smoke makes things work. When the smoke gets out, it stops! |
||||
| toml_12953 Guru Joined: 13/02/2015 Location: United StatesPosts: 540 |
You're missing the point. Don't analyze the code. It's just to show a capability in most other languages (C, Pascal, Lua, JavaScript and Zeno to name a few) that's missing from MMBasic. |
||||
| JohnS Guru Joined: 18/11/2011 Location: United KingdomPosts: 4191 |
John The example I gave was greatly simplified to show just the essence of the problem. A better example would help. As it is, what you showed isn't the kind of thing structures are for. John You're missing the point. Don't analyze the code. It's just to show a capability in most other languages (C, Pascal, Lua, JavaScript and Zeno to name a few) that's missing from MMBasic. It's not especially useful (*) and it's not a structure. The equivalent of your example in MMBasic is just to declare two arrays. I'm sure Peter could special-case your example, which is really just type renaming not a structure, at the cost of some internal complication. (*) except in C where you can somewhat tame a horrible type involving pointers, particularly pointers to functions where the C syntax is to be kind a bit challenging - and this is another thing that MMBasic can't do (and likely shouldn't) John Edited 2025-12-30 18:09 by JohnS |
||||
| Mixtel90 Guru Joined: 05/10/2019 Location: United KingdomPosts: 8430 |
Structs looks like a lovely way to handle maps in adventure-type games. Location/room based adventures are basically databases anyway. Stan: The great thing about MMBasic is that it has incredible flexibility just in case you want to use it. I'm very unlikely to use the astronomical stuff, regular expressions, VGA222, MOD files, GPS connection, PIO programming or turtle graphics even though Peter has put in a hell of a lot of work on them. But, whether I use them or not is immaterial - they are there just in case I do need them at some unknown point in the future. They are also there should I wish to run someone else's software that does use them. :) They are there but invisible and that's not a problem at all. I can even ignore SUBs and FUNCTIONs and program using GOTO and GOSUB and the LET command if I'm feeling masochistic. :) I would suggest that if you are concerned about any slight performance hit that you don't use USB and go back to PS2 in addition to using PICO 2 (RP2350A or a board using RP2350B without PSRAM) instead of the original PICO. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10838 |
uint64_t alignment is necessary to also support the CMM2 which has 64-bit load and store instructions and 64-bit floating point. Therefore the code should always use full 64-bit alignment even though it isn't necessary for the M0+ processor in the RP2040/RP2350 |
||||
| flip Senior Member Joined: 18/07/2016 Location: AustraliaPosts: 119 |
Hi Peter, all Structs are a great inclusion - I'm having great fun with it on the new HDMIUSB from November Silicon Chip. It seems though it only works with Files opened for INPUT or OUTPUT. I can't use with a RANDOM access file, so can't seek to a position to read a specific record. Is there something I've missed? Regards Phil PS. This is options, program and the Commands entered to test 'LIST OPTIONS OPTION PICO OFF OPTION RESOLUTION 1280x720 @ 372000KHz OPTION DISPLAY 60, 160 OPTION HDMI PINS 1, 3, 5, 7 OPTION SDCARD GP29, GP30, GP31, GP32 OPTION KEYBOARD REPEAT 400,50 OPTION AUDIO I2S GP10,GP22', ON PWM CHANNEL 11 OPTION RTC AUTO ENABLE OPTION COUNT GP0,GP1,GP2,GP3 OPTION MODBUFF ENABLE 512 OPTION PLATFORM HDMIUSBI2S OPTION HEARTBEAT PIN GP25 > List Type tBox bLeft As integer bTop As Integer bWidth As Integer bHeight As Integer bFore As Integer bBack As Integer bHiFore As Integer bHiBack As Integer bHeading As String bFont As integer End Type Dim Boxes(255) As tBox Sub DrawBox(bID As Integer) Box Boxes(bID).bLeft*MM.FONTWIDTH-2,Boxes(bID).bTop*MM.FONTHEIGHT-2,Boxes(bID).bWidth*MM.FONTWIDTH+4,Boxes(bID).bHeight*MM.FONTHEIGHT+4,,1,0 Text Boxes(bID).bLeft*MM.FONTWIDTH,Boxes(bID).bTop*MM.FONTHEIGHT,Boxes(bID).bHeading Text Boxes(bID).bLeft*MM.FONTWIDTH,(Boxes(bID).bTop+1)*MM.FONTHEIGHT,"L"+Str$(Boxes(bID).bLeft)+",T"+Str$(Boxes(bID).bTop) Text Boxes(bID).bLeft*MM.FONTWIDTH,(Boxes(bID).bTop+2)*MM.FONTHEIGHT,"W"+Str$(Boxes(bID).bWidth)+",H"+Str$(Boxes(bID).bHeight) TILE Boxes(bID).bLeft,Boxes(bID).bTop,RGB(green),RGB(magenta),Boxes(bID).bWidth*MM.FONTWIDTH\8,1 TILE Boxes(bID).bLeft,Boxes(bID).bTop+1,RGB(yellow),RGB(blue),Boxes(bID).bWidth*MM.FONTWIDTH\8,Boxes(bID).bHeight-1 End Sub Sub DRBs(n%) 'Draw Random Boxes If MM.FONTHEIGHT<> MM.Info(TILE HEIGHT) Then If MM.FONTHEIGHT>7 Then TILE HEIGHT MM.FONTHEIGHT Else TILE HEIGHT 8 EndIf If n%<1 Then n%=1 If n%>255 Then n%=255 For i=0 To n% Boxes(i).bTop=Rnd*(MM.HEIGHT-5) Boxes(i).bHeight=2+Rnd*Rnd*(MM.HEIGHT-Boxes(i).bTop-4) Boxes(i).bLeft=Rnd*(MM.WIDTH-10) Boxes(i).bWidth=4+Rnd*Rnd*(MM.WIDTH-Boxes(i).bLeft-6) Boxes(i).bHeading="Box "+Str$(i) DrawBox i Next i End Sub 'File save method for Screen Definitions RUN DRBs 255 ' draw 255 random boxes B: CHDIR "Screens" Open "st.bas" for output as 1 Struct Save #1, Boxes() Close #1 ' Display method for previously SAVED screens (Boxes()) B: CHDIR "Screens" RUN ' to DIM the Boxes() array Tile height 12 timer=0:open "st.bas" for INPUT as 1:struct load #1,Boxes():for i=0 to 255:DrawBox i:next i:close 1:? timer '272.81 to restore array from B:and draw screens (Changing the last line from 'INPUT' to 'RANDOM' causes a 'nothing' array to be loaded) Edited 2025-12-30 19:05 by flip |
||||
| flip Senior Member Joined: 18/07/2016 Location: AustraliaPosts: 119 |
Actually RANDOM is OK - It looks like I forgot to do a seek first It works great for the whole array. I am still having some difficulty trying to get individual records from a complete save. The bytes are exactly correct (so I would guess no padding characters are embedded - so I expect it's raw data) Will have a bit more of a play to see if i can work out my problem! Regards Phil ps again: forgot to add the error: > B: > CHDIR "/Screens" > RUN ' to DIM the Boxes() array > Tile height 12 > timer=0:open "st.bas" for RANDOM as 1:Seek 1,1:struct load #1,Boxes(10):DrawBox 10:close 1:? timer [16] Box Boxes(bID).bLeft*MM.FONTWIDTH-2,Boxes(bID).bTop*MM.FONTHEIGHT-2,Boxes(bID).bWidth*MM.FONTWIDTH+4,Boxes(bID).bHeight*MM.FONTHEIGHT+4,,1,0 Error : Unknown structure member > Edited 2025-12-30 19:46 by flip |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10838 |
V6.01.00EXP3 PicoMiteV6.01.00EXP3.zip MMBasic_Structures_Manual.pdf Fixes bug in arrays of structures where the underlying type is not a multiple of 8 byte long Allows full line comments (REM or ') in TYPE/END TYPE blocs Fixes bugs in OPTION RESET for a couple of board types Fixes bug in RAM command usage where a reset would clear the RAM slot Adds validation to FLASH and RAM commands to stop a lockup when the LOAD subcommand was used on an empty slot Fixes incorrect naming of VGA222_640 in LIST OPTIONS Fixes incorrect naming of BLUE_H in LIST PINS Confirmed STRUCT LOAD/SAVE work with random access files Volhout, I would really appreciate it if you could give the RP2040 versions a good test with your various programs. Assuming that is all OK I will probably go straight to a release candidate for 6.02.00 with this latest version. Additional test for test scripts ' ============================================ ' TEST 75: Random access file with struct array (write and read in reverse) ' Also tests alignment of array elements where the type definition is not a ' multiple of 8 bytes ' tests comments in type definitions ' ============================================ Print "TEST 75: Random access file with struct array" ' Define a struct type with integer and string for this test Type FileRecord id As INTEGER 'comment ' another comment label As STRING length 20 rem yet another comment End Type ' Create a struct array with test data Dim fileArr75(4) As FileRecord For i% = 0 To 4 fileArr75(i%).id = (i% + 1) * 100 fileArr75(i%).label = "Record" + Str$((i% + 1) * 100) Next i% ' Write each struct element to file sequentially Open "structtest.dat" For random As #1 For i% = 0 To 4 Struct Save #1, fileArr75(i%) Next i% Close #1 ' Calculate struct size for seeking (INTEGER=8 bytes, STRING=256 bytes = 264 bytes per record) Dim structSize75% = Struct(sizeof,"FileRecord") ' Read back in reverse order using SEEK Dim readArr75(4) As FileRecord Open "structtest.dat" For Random As #1 For i% = 4 To 0 Step -1 ' Seek to byte position (1-based, so first record at position 1) Seek #1, i% * structSize75% + 1 Struct Load #1, readArr75(4 - i%) Next i% Close #1 ' Verify the data was read correctly in reverse ok% = 1 Dim expectedId%, expectedLabel$,labelNum% For i% = 0 To 4 ' readArr75(0) should have fileArr75(4) data, readArr75(1) should have fileArr75(3), etc. expectedId% = (5 - i%) * 100 expectedLabel$ = "Record" + Str$(expectedId%) If readArr75(i%).id <> expectedId% Then Print " Index"; i%; ": Expected id"; expectedId%; " got"; readArr75(i%).id ok% = 0 EndIf If readArr75(i%).label <> expectedLabel$ Then Print " Index"; i%; ": Expected label '"; expectedLabel$; "' got '"; readArr75(i%).label; "'" ok% = 0 EndIf ' Also verify using VAL() that the embedded number is correct labelNum% = Val(Mid$(readArr75(i%).label, 7)) If labelNum% <> expectedId% Then Print " Index"; i%; ": VAL extraction failed, expected"; expectedId%; " got"; labelNum% ok% = 0 EndIf Next i% If ok% Then Print " PASS: Random access file write and reverse read with strings" Else Print " FAIL: Random access file reverse read failed" EndIf ' Clean up the test file Kill "structtest.dat" Edited 2025-12-30 20:06 by matherp |
||||
| bfwolf Senior Member Joined: 03/01/2025 Location: GermanyPosts: 131 |
PicoMiteV6.01.00EXP3.zip MMBasic_Structures_Manual.pdf Fixes bug in arrays of structures where the underlying type is not a multiple of 8 byte long Allows full line comments (REM or ') in TYPE/END TYPE blocs Fixes bugs in OPTION RESET for a couple of board types Fixes bug in RAM command usage where a reset would clear the RAM slot Adds validation to FLASH and RAM commands to stop a lockup when the LOAD subcommand was used on an empty slot Fixes incorrect naming of VGA222_640 in LIST OPTIONS Fixes incorrect naming of BLUE_H in LIST PINS Confirmed STRUCT LOAD/SAVE work with random access files ... Perhaps you could add some "best practice" recommendations regarding alignment to the Struct Manual? For example, that one should avoid creating padding bytes without defined content when storing structs as "file records" in files. This can be achieved by ensuring alignment when arranging the members, or by always making string members ((n*8)-1) incremental. And if this is undesirable, one can explicitly insert "padding string members" that provide (n*8) alignment and then explicitly initialize them with 0. This prevents "random hidden members" and "nasty surprises" with the contents of the "file records". I always use this method (explicitly initialized padding members) in my C programs when structs are stored "permanently" somewhere. Of course, for structs that are "volatile" — that is, they only exist in RAM — this is completely irrelevant! --- Did you see my post: https://www.thebackshed.com/forum/ViewTopic.php?TID=18519&P=2#248815 This is about the following: I would consider renaming the function 'Struct(SIZE, array() [, dimension])' to 'Struct(BOUND, array() [, dimension])', since the function 'BOUND(array() [, dimension])' already exists for "ordinary arrays". This would simply be more consistent, and it's "awkward" to have to remember two different words for the same thing. Sure, it's "more of a cosmetic issue" — but still not unimportant when developing a programming language. And regarding my idea with 'Struct(OFFSETOF, "typeName,memberName")': If you're up for the work... Many thanks again !!! |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10838 |
Bound is tokenised so it doesn't work |
||||
| bfwolf Senior Member Joined: 03/01/2025 Location: GermanyPosts: 131 |
Bound is tokenised so it doesn't work Ah, okay, I didn't realize that conflicts could arise. So, names for which tokens for commands and functions already exist are therefore "off-limits" for "sub-function" names? How about 'SBOUND' (for Struct-Bound) or 'TBOUND' (for Type-Bound) or something that expresses it gives the "array of structs' bound") ? Just a thought... In any case, it would be nice to have a name that's "similar to BOUND". Edit: Just tried 'print bound(people(),1)' in command mode after my little test program was run before: It works !!! So it seems that the long-implemented 'BOUND()' function also works with arrays of structs! This could make Struct(SIZE typeName) obsolete !Greetings.. ![]() Edited 2025-12-30 23:13 by bfwolf |
||||
| stanleyella Guru Joined: 25/06/2022 Location: United KingdomPosts: 2715 |
first thank you to Peter for his work improving mmbasic. it's my fault if I don't understand the changes. is structured basic for large programs? I can't see the point and I think it makes code less easy to follow imho. it's said you don't have to use it but if it's a better way will all mmbasic now be structured? |
||||
| toml_12953 Guru Joined: 13/02/2015 Location: United StatesPosts: 540 |
it's my fault if I don't understand the changes. is structured basic for large programs? I can't see the point and I think it makes code less easy to follow imho. it's said you don't have to use it but if it's a better way will all mmbasic now be structured? Structures don't necessarily make a program structured (ha!) They just allow you to work with records more easily. Here's an example: Using a structure for coordinates: TYPE point x as float y as float END TYPE DIM PointArray(100) as point ' Now access the x and y components of the 5th element: PRINT PointArray(5).x PRINT PointArray(5).y Same result without structures: DIM PointArray(100,2) CONST x=1 CONST y=2 ' Now access the x and y components of the 5th element: PRINT PointArray(5,x) PRINT PointArray(5,y) Accessing different types of data isn't too hard, you just need a separate array for each datatype and keep them synchronized. Edited 2025-12-31 05:03 by toml_12953 |
||||
| stanleyella Guru Joined: 25/06/2022 Location: United KingdomPosts: 2715 |
thanks toml_12953 but I still don't get it. your code says what's the point.it don't make sense like I used mmb before Same result without structures: DIM PointArray(100,2) CONST x=1 CONST y=2 ' Now access the x and y components of the 5th element: PRINT PointArray(5,x) PRINT PointArray(5,y) |
||||
| twofingers Guru Joined: 02/06/2014 Location: GermanyPosts: 1716 |
... The point is the self-documentation of the code. Regards Michael causality ≠ correlation ≠ coincidence |
||||
| PeteCotton Guru Joined: 13/08/2020 Location: CanadaPosts: 593 |
it's said you don't have to use it but if it's a better way will all mmbasic now be structured? I think the name might be causing a bit of confusion. MMBasic is already what I understand as being "Structured Basic". That is, it doesn't need line numbers, it has WHILE, DO loops etc. and functions/subroutines. The introduction of user-defined structures isn't actually a part of "structured basic". They just happen to share the same name (from my viewpoint). There were lots of structured basics back in the day that didn't have user-defined structures. Later languages had the ability to use User-Defined Structures, or Records, or User-Defined Types (all the same thing). While I am strongly against changing MMBasic into a high language (I love using BASIC) - this is one of those circumstances where the feature is complimentary to the existing BASIC and is going to greatly simplify code and make it far more readable. I know there appears to be a bit of confusion around it currently - but I think you can see from the enthusiastic response from some of us, how massive this is going to be for us. I know we've been concentrating on arrays of structures (which is great), but they are also very useful for single elements. Say I am controlling a fuel valve with the following parameters Type FuelValve demand As FLOAT ' The % open value we are trying to set the valve to highAlarm As FLOAT ' The % opening of the valve that we should never exceed lowAlarm AS FLOAT ' The % opening of the valve that we should never drop below feedback AS FLOAT ' The % open value read back from the valve alarmIsActive AS INTEGER ' If 0 then healthy. if 1 then alarmed End Type I can define a single variable as type FuelValve Dim valve1 As FuelValve Now when I want to pass all of that data into a subroutine I just need to pass valve1, and all of the variables/values get passed. Similarly, if I want to use the the valve1.alarmIsActive integer to check if the valve has exceeded an alarm level, then I can easily set it with something like this: Function SetAlarmFlag(passedInValve AS FuelValve) As FuelValve ' First - set the return variable (SetAlarmFlag) to equal the values in the valve variable passed in Struct Copy passedInValve To SetAlarmFlag ' Now clear the .alarmIsActive flag (in case it's already set) SetAlarmFlag.alarmIsActive = 0 ' Now see if we need to set the flag IF passedInValve.demand > valve.highAlarm THEN SetAlarmFlag.alarmIsActive = 1 IF passedInValve.feedback > valve.highAlarm THEN SetAlarmFlag.alarmIsActive = 1 IF passedInValve.demand < valve.lowAlarm THEN SetAlarmFlag.alarmIsActive = 1 IF passedInValve.feedback < valve.lowAlarm THEN SetAlarmFlag.alarmIsActive = 1 End Function If you look at this function, you pass in a FuelValve variable, and it returns FuelValve variable. This can be used to easily update your FuelValve (in this case the .alarmIsActive flag is set to 1 if the demand or feedback is greater than the high alarm, or if they are less than the low alarm). In your code, you simply need to call this function, and then check the .alarmIsActive flag. valve1 = SetAlarmFlag(valve1) IF valve1.alarmIsActive = 1 THEN PRINT "ALARM! We're all going to die!" Edited 2025-12-31 06:55 by PeteCotton |
||||
| bfwolf Senior Member Joined: 03/01/2025 Location: GermanyPosts: 131 |
@PeteCotton: You were faster than me.. I try to explain it this way:it's my fault if I don't understand the changes. is structured basic for large programs? I can't see the point and I think it makes code less easy to follow imho. it's said you don't have to use it but if it's a better way will all mmbasic now be structured? Hi Stan, maybe you read this post of mine?: https://www.thebackshed.com/forum/ViewTopic.php?TID=18519&P=2#248808 You shouldn't be afraid of the additional possibilities that MMBasic will offer with structs in the future! I think you also have a misunderstanding between structured programming and data structures - they are two different things: Structured programming is facilitated and supported through commands like IF <condition> <commands> ELSE <other commands> END IF or SUB subprogram-name [(parameter-list)] <commands> END SUB but not enforced, when commands like IF <condition> GOTO <label-or-line-number> or GOSUB <label-or-line-number> are still allowed, which has always been the case with MMBasic. You can even do structured programming with just GOTO and GOSUB, but it's much more difficult because you then quickly produce "spaghetti code" that others don't understand and after a short time you don't understand either. So you have the choice to program with GOTO and GOSUB, but "it is recommended" to use 'IF .. ELSE .. END IF' or 'SUB .. END SUB', because this makes it easier to write a program that is easier to understand. Getting these commands offered by the interpreter and using them is “Structured BASIC”. So now to the data structures: These offer a better opportunity to jointly manage different informations that belong together. That's all! The example I gave in the link above: You want to program a data logger that records weather data. Without data structs: Dim temperature_degC(1000) As integer Dim humidity_percent(1000) As integer Dim airpressure_mbar(1000) As integer Dim unix_time_sec(1000) As integer ' seconds since 1.1.1970 ' And now a Sub, that shall print the temperature and the time.. Sub PrintWeatherData(degC As integer, tUnix As integer) Print "We had "; degC; "°C at time"; tUnix; " (unix-sec)" End Sub ' We execute the Sub by: PrintWeatherData(temperature_degC(1), unix_time_sec(1)) And now with data structs: Type weatherData temperature_degC As integer humidity_percent As integer airpressure_mbar As integer unix_time As integer ' seconds since 1.1.1970 End Type Dim weatherDataRecordings(1000) As weatherData ' And now a Sub, that shall print the temperature and the time.. Sub PrintWeatherData(d As weatherData) Print "We had "; d.temperature_degC; "°C at time"; d.unix_time; " (unix-sec)" End Sub ' We execute the Sub by: PrintWeatherData(weatherDataRecordings(1)) ' But once later we decide to have a Sub, that shall print the temperature and the pressure and the time.. Sub PrintWeatherData2(d As weatherData) Print "We had "; d.temperature_degC; "°C and "; d.airpressure_mbar; "mbar at time"; d.unix_time; " (unix-sec)" End Sub ' We execute the Sub by: PrintWeatherData2(weatherDataRecordings(1)) Perhaps you have now seen and understood from this simple and small example how the functionality of the 'PrintWeatherData' sub can be extended without having to change anything in the list of passed parameters, because they are all connected and contained in the 'weatherData' struct type? Of course, you are still free to program as shown in the 1st example further above, without data structs! Greetings, bfwolf ![]() Edited 2025-12-31 07:10 by bfwolf |
||||
| LeoNicolas Guru Joined: 07/10/2020 Location: CanadaPosts: 555 |
This new data structure is super useful to organize complex data structures making the code more readable. A real example from my Knightmare game, taking these global variables: ' Supports 13 shots at the same time: 0: id | 1: x | 2: y | 3: GPR 1 | 4: GPR 2 | 5: GPR 3 ' The three first slots are for the player shots, the other ones for enemies dim g_shots(12,5) ' Object data: 0: obj id | 1: x | 2: y | 3: life | 4: GPR 1 | 5: GPR 2 | 6: shadow dim g_obj(20,6) It is required to remember which position of the array stores the value I want to access. If I want to access an object X and Y position: g_obj(0,1) and g_obj(0,2) Now imagine that in the middle of hundreds of lines of code. If a data type structure is much better. It will be something like this: g_obj(0).X g_obj(0).y g_obj(0).life Etc |
||||
| toml_12953 Guru Joined: 13/02/2015 Location: United StatesPosts: 540 |
I use option explicit and declare var types as. I'm willing to learn though. You may never need structures at all. It all depends on the type of programming you do. If you don't deal with records, then structures might not have much impact on you and you can ignore them. Us old COBOL programmers couldn't live without them! Don't confuse structures with structured programming. Rather think of structures as User Defined Datatypes. All it is is a way to define different datatypes. It's useful to organize data into records of related information. Suppose you have a business with 500 employees. You want to keep one record for each employee for tax purposes. You could create multiple arrays, each with one piece of data such as name, home address, DOB, SSN, spouse's name, home phone, cell phone, hourly rate, hire date. Do you see how this could create a lot of overhead to keep track of all these things? With structures, we can keep all the data in one record and deal with it all in a few statements. Type EmpRec EmpName as string * 20 HomeAddress as string * 60 DOB as string * 10 SSN as string * 10 SpouseName as string * 20 HomePhone as string * 10 CellNumber as string * 10 HourlyRate as float HireDate as string *10 END TYPE DIM EmployeeFile(500) as EmpRec Now, to access all the data for, say, employee # 47, all you have to deal with is EmployeeFile(47), not 9 different arrays. EmployeeFile(47).HireDate will give you the hire date of employee #47 Why not use integers for things like SSN and phone numbers? It's good programming practice and highly recommended to only define fields used for calculation as numeric. All other data, even if it consists of all digits should defined as character (string) data. Sure you could pack all the data into a single string and get at individual fields using MID$ but that code would be a lot harder to read. What field does MID$(EmployeeFile(47),81,10) refer to? Now, how about EmployeeFile(47).DOB? They access the same data but which is easier to read? Edited 2025-12-31 08:43 by toml_12953 |
||||
TassyJim![]() Guru Joined: 07/08/2011 Location: AustraliaPosts: 6426 |
This is an example of using structures. Written as a learning exercise for my own use but may help some. The same thing can be done using an extra dimension in the arrays but TYPEs are quicker. (One call instead of two) There are a few places where an intermediate variable is required. The LINE command is happy with line n*2,scalep(readings(n)).t,n*2+2,scalep(readings(n+1)).t,1,rgb(yellow) but LINE PLOT is not happy. You have to use a normal array. It is easy to extract just the "temperature" from the typed array using MEMORY COPY and that lets you use all the MATH functions. A command that lets you do the extraction with fewer steps and without the need to know the structure in detail would be nice to have. You can run the program without a DHT22 connected. ' OPTION EXPLICIT OPTION DEFAULT INTEGER OPTION BASE 0 TYPE room t AS FLOAT h AS FLOAT END TYPE DIM readings(144) AS room DIM n ' set up dummy data FOR n = 1 TO 144 READ readings(n).t,readings(n).h NEXT n SETTICK 10000, plotroom, 1 'every 10 seconds. *60 for 10 minutes = 1 day plotroom DO ' do other things LOOP FUNCTION thisreading(p AS INTEGER) AS room ' p = pin number for DHT22 LOCAL FLOAT tmpr, hmid DEVICE HUMID p, tmpr ,hmid thisreading.t = tmpr thisreading.h = hmid END FUNCTION SUB plotroom LOCAL n, fromaddr, toaddr, starttime AS FLOAT LOCAL ydata(144) AS FLOAT LOCAL byteSize = Struct(SIZEOF, "room") LOCAL pt1 AS room, pt2 AS room starttime = TIMER ' the slow way. even slower if we used a 2 dimension array 'for n = 1 to 143 'readings(n) = readings(n+1) 'next n ' it would be faster to use MEMORY COPY toaddr = PEEK(VARADDR readings()) fromaddr = toaddr + byteSize MEMORY COPY FLOAT fromaddr, toaddr, 144*2 readings(144) = thisreading(22) CLS ' the slow way: 'for n = 1 to 143 'pt1 = scalep(readings(n)) 'pt2 = scalep(readings(n+1)) 'line n*2,pt1.t,n*2+2,pt2.t,1,rgb(red) 'line n*2,pt1.h,n*2+2,pt2.h,1,rgb(cyan) 'next n 'the really slow way: 'for n = 1 to 143 'line n*2,scalep(readings(n)).t,n*2+2,scalep(readings(n+1)).t,1,rgb(yellow) 'line n*2,scalep(readings(n)).h,n*2+2,scalep(readings(n+1)).h,1,rgb(cyan) 'next n ' the fast way to plot data ' use memory copy to extract each member of the type ' LINE PLOT doesn't like typed arrays ' you can then use all the features of the MATH command fromaddr = PEEK(VARADDR readings()) toaddr = PEEK(VARADDR ydata()) MEMORY COPY FLOAT fromaddr, toaddr, 145,2 ' get the temperatures MATH SCALE ydata(),-4,ydata() MATH ADD ydata(),MM.VRES,ydata() LINE PLOT ydata(),144,,2,,,RGB(YELLOW) MEMORY COPY FLOAT fromaddr+8, toaddr, 145,2 ' get the humidity MATH SCALE ydata(),-3,ydata() MATH ADD ydata(),MM.VRES,ydata() LINE PLOT ydata(),144,,2,,,RGB(CYAN) struct PRINT readings(144) PRINT TIMER - starttime END SUB FUNCTION scalep(x AS room) AS room scalep.t = MM.VRES - x.t*4 scalep.h = MM.VRES - x.h*3 END FUNCTION dummydata: DATA 21.3,45.7 DATA 21.5,44.9 DATA 21.5,43.4 DATA 21.6,42.2 DATA 21.6,41.8 DATA 21.5,41.8 DATA 21.3,40.9 DATA 21 ,43 DATA 21.1,43.9 DATA 21.3,43.4 DATA 21.2,43.7 DATA 21.2,43.5 DATA 21.4,43.3 DATA 21.2,43 DATA 21.2,43.7 DATA 21.2,44.3 DATA 21.2,44.3 DATA 21.3,44.5 DATA 21.5,43.1 DATA 21.5,43.5 DATA 21.4,43.1 DATA 21.4,43.8 DATA 21.3,42.8 DATA 21.2,42.4 DATA 20.9,43.9 DATA 20.8,44.6 DATA 20.7,44.8 DATA 20.8,44.9 DATA 20.9,46 DATA 20.8,46.3 DATA 20.7,47 DATA 20.8,47.7 DATA 21.2,46.8 DATA 21.3,46.4 DATA 20.9,48.5 DATA 20.8,49.2 DATA 20.7,49.5 DATA 20.6,49.8 DATA 20.5,49.9 DATA 20.5,50 DATA 20.4,49.5 DATA 20.3,49.9 DATA 20.3,49.9 DATA 20.5,48.2 DATA 20.2,49.4 DATA 20.1,50.1 DATA 20 ,50.2 DATA 20 ,50.2 DATA 19.9,50.4 DATA 19.8,50.4 DATA 19.7,50.7 DATA 19.7,50.7 DATA 19.5,50.9 DATA 19.5,51 DATA 19.4,51 DATA 19.4,51.1 DATA 19.3,51.4 DATA 19.2,51.4 DATA 19.2,51.2 DATA 19.1,51.6 DATA 19.1,51.7 DATA 19 ,51.8 DATA 19 ,51.8 DATA 18.9,52.2 DATA 18.9,52.1 DATA 18.9,52.6 DATA 18.8,52.6 DATA 18.8,53 DATA 18.8,52.8 DATA 18.7,53.2 DATA 18.7,53.3 DATA 18.7,53.2 DATA 18.6,53.3 DATA 18.6,53.3 DATA 18.6,53.4 DATA 18.6,53.4 DATA 18.5,53.5 DATA 18.5,53.9 DATA 18.5,53.8 DATA 18.4,53.8 DATA 18.4,53.7 DATA 18.4,53.9 DATA 18.3,54.1 DATA 18.3,54.1 DATA 18.2,54 DATA 18.2,54.1 DATA 18.2,54.2 DATA 18.1,54.6 DATA 18, 54.6 DATA 18, 54.5 DATA 18, 54.4 DATA 18, 54.5 DATA 17.9,54.6 DATA 17.9,54.6 DATA 18.3,53.9 DATA 18.7,53 DATA 18.7,52.5 DATA 18.7,52.5 DATA 18.6,52.8 DATA 18.4,53.8 DATA 18.5,53.8 DATA 18.7,53.1 DATA 18.7,53.1 DATA 18.4,53.8 DATA 18.5,54.3 DATA 18.8,53.9 DATA 18.9,53.6 DATA 18.7,54.3 DATA 18.8,54.4 DATA 18.9,54.3 DATA 18.7,55 DATA 18.9,55.8 DATA 18.9,55.4 DATA 19, 55.2 DATA 19.3,54.8 DATA 19.2,54.9 DATA 19.3,55.2 DATA 19.3,55.4 DATA 19.4,55 DATA 19.5,54.9 DATA 19.5,54.9 DATA 19.7,54.5 DATA 19.7,54.6 DATA 19.8,54.5 DATA 19.9,54.4 DATA 20, 54.1 DATA 20.1,54.4 DATA 20.2,54.4 DATA 20.2,54.2 DATA 20.3,53.9 DATA 20.3,53.9 DATA 20.3,35.2 DATA 20.9,53.5 DATA 21, 53.4 DATA 21.2,53.1 DATA 21.5,53.2 DATA 21.5,52.9 DATA 21.7,52.7 DATA 21.8,52.4 DATA 21.7,52.6 DATA 21.7,52.4 DATA 21.8,52.4 DATA 22, 52.3 DATA 22.2,52 VK7JH MMedit |
||||
| The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2026 |