As a fairly new student in C I am having diffictly with arrays. I have a string of numbers that I am tring to split up into smaller strings to convert them to integers. I have made the code as basic as possible but still get the errors.
#include <stdio.h> #include <stdlib.h> #include <reg52.h> xdata char Temperatures1[9]; xdata char Temperatures2[12]; xdata char Temperatures3[9]; void main(void) { char a[36] = "<<123456789012345678901234567890>>"; int s; SCON = 0x52; TMOD = 0x20; TCON = 0x69; TH1 = 0xF5; for(s=0; s < 9; s++) { Temperatures1[s] = a[s+2]; } for(s=0; s < 12; s++) { Temperatures2[s] = a[s+11]; } for(s=0; s < 9; s++) { Temperatures3[s] = a[s+23]; } printf("Temperatures1: %s\n", Temperatures1); printf("Temperatures2: %s\n", Temperatures2); printf("Temperatures3: %s\n", Temperatures3); }
Steve, The problem is you are trying to print null terminated strings but are using character arrays without null termination. Try terminating them;
#include <stdio.h> #include <stdlib.h> #include <reg52.h> xdata char Temperatures1[10]; xdata char Temperatures2[13]; xdata char Temperatures3[10]; void main(void) { char a[36] = "<<123456789012345678901234567890>>"; int s; SCON = 0x52; TMOD = 0x20; TCON = 0x69; TH1 = 0xF5; for(s=0; s < 9; s++) { Temperatures1[s] = a[s+2]; } Temperatures1[s] = 0; for(s=0; s < 12; s++) { Temperatures2[s] = a[s+11]; } Temperatures2[s] = 0; for(s=0; s < 9; s++) { Temperatures3[s] = a[s+23]; } Temperatures3[s] = 0; printf("Temperatures1: %s\n", Temperatures1); printf("Temperatures2: %s\n", Temperatures2); printf("Temperatures3: %s\n", Temperatures3); }
Scott, Thanks a lot thats worked a treat. Cheers Steve
You may want to consider using the library routines to do actually copy the strings.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <reg52.h> xdata char Temperatures1[10]; xdata char Temperatures2[13]; xdata char Temperatures3[10]; void main(void) { char a[36] = "<<123456789012345678901234567890>>"; SCON = 0x52; TMOD = 0x20; TCON = 0x69; TH1 = 0xF5; strncpy (Temperature1, &a[2], 9); Temperatures1[9] = 0; strncpy (Temperature2, &a[11], 9); Temperatures2[9] = 0; strncpy (Temperature3, &a[23], 9); Temperatures3[9] = 0; printf("Temperatures1: %s\n", Temperatures1); printf("Temperatures2: %s\n", Temperatures2); printf("Temperatures3: %s\n", Temperatures3); }
The 'C' initializer will probably clear the arrays before calling main() The C language requires this. All static duration variables must be zeroed before main is called.
The 'C' initializer will probably clear the arrays before calling main(), in which case the last character in each array would already be a null, but you should never rely on this. In C51, the startup code MUST BE configured by the user. The default setting is that DATA memory is cleared (from 0x00-0x7F) but DATA from 0x80-0xFF and XDATA are NOT cleared. You must make a single configuration change to enable that AND you must include the startup code in your project. Refer to http://www.keil.com/support/docs/1728.htm for a few more details about the startup code. Jon
"consider using the library routines" The library routines are written by the compiler vendor, and usually provide the most efficient implementation - certainly better than writing your own 'for' loop! Also, with C51, certain Library functions can take advantage of the extra DPTR(s)
"In C51, the startup code MUST BE configured by the user." Every time you start uVision, it puts up that annoying splash screen saying, "True Integration" In my book, if it really was True integration, the startup code configuration would be included in the uVision options forms! But then I wouldn't have been able to invent the term NEIDE - Not Entirely Integrated Development Environment ;-)
"if it really was True integration, the startup code configuration would be included in the uVision options forms!" The startup code is so "particular" to your chip and target that put all the available features and options into a kind of option form doesn't sound so good ( What are all the possible user's options!?? ). Almost every month there's a new fancy 8051 derivative on market that requires some kind of different startup code. Only trivial tasks could be put in a form ( common stuff to all chips ). The user is free to modify it whenever required and there will be always something to be changed. A really true integration would be some stuff like.: Hey, I don't need to program anymore because all my desired code is at form #3300293 :-) This guy was definitely born to be freely modified for any special or non-special purpose.
Well, I see your point. I s'pose I should clarify what I was thinking: In the particular case of 'C' initialisation in STARTUP.A51, many of the standard parameters which have to be manually set are already specified in the uVision options - principally the 'Target', and 'BL51 Locate' tabs: IDATALEN XDATASTART XDATALEN PDATASTART PDATALEN PPAGE I'm a great believer that things should be defined in one place only - currently these have to be defined in both the uVision forms and the STARTUP.A51 code. This is obviously asking for trouble as it's oh so easy for them to get out of step...! :-0 And the rest could easily be specified on a uVision form: IBPSTACK IBPSTACK XBPSTACK XBPSTACK PBPSTACK PBPSTACK PPAGEENABLE I think that uVision should at least make these definitions available; eg, via SET command-line options. Of course, you will still need your own target-specific initialisation stuff in addition to Keil's STARTUP.A51.
In the particular case of 'C' initialisation in STARTUP.A51, many of the standard parameters which have to be manually set are already specified in the uVision options - principally the 'Target', and 'BL51 Locate' tabs: IDATALEN XDATASTART XDATALEN PDATASTART PDATALEN PPAGE But, what if I have 32K of RAM (from 0x0000-0x7FFF) and 32K of battery-backed NVRAM (from 0x8000-0xFFFF) and I want the first 32K cleared to 0 but not the second 32K. Or, what if I have 32K of SRAM (from 0x0000-0x7FFF), and 8K of EEPROM (from 0xA000-0xBFFF), and 8K of NVRAM (from 0xE000-0xFFFF), and ... But, I guess you see the point there. :-) Jon
So what is the point of the 'BL51 Locate' tab, and the address-space fields in the 'Target' tab?
So what is the point of the 'BL51 Locate' tab, and the address-space fields in the 'Target' tab? The point of the locate tab is to specify the addresses and/or order of segments in the different memory areas. For example, you may prefer that segments use DATA or IDATA in a certain order. The point of the address-space fields in the target tab are to tell the linker what areas of memory it can use for your program code and your variables. Not every program's CODE and XDATA start at 0x0000. Jon
Can we create our own segments in C51/L51? In GCC and Diab DCC we can create a segment and then tell the compiler to place certain objects in these segments. These segments are unknown to the default C run-time and thus are left alone, e.g. not cleared and not initialized with compile time values. For example, for NVRAM I'd place all my NVRAM objects in a segment called .nvRam and create in a linker control file. Then, at the definition of my NVRAM objects I'd just indicate that the compiler should put these objects in the .nvRam segment. Hmm... maybe _at_ would take care of this just fine. Same net affect I guess. Regards, - Mark