Convert Interger array to string(char array)

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hey guys,

This maybe a stupid question but, i want to convert a interger array to a string on my xmega.

I have been trying to do it with a for loop in different ways, but it isn't working.

So i made a temporary function that does it the dumb way

uint16_t adcSamples[SAMPLE_COUNT];
char ADCSamples2[5000];
void convert_array_to_string(void){
	snprintf(ADCSamples2,sizeof(ADCSamples2),"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \r\n ",
								adcSamples[0],adcSamples[1],adcSamples[2],adcSamples[3],adcSamples[4],adcSamples[5],adcSamples[6],adcSamples[7],adcSamples[8],adcSamples[9],adcSamples[10],
								adcSamples[11],adcSamples[12],adcSamples[13],adcSamples[14],adcSamples[15],adcSamples[16],adcSamples[17],adcSamples[18],adcSamples[19],adcSamples[20],
								adcSamples[21],adcSamples[22],adcSamples[23],adcSamples[24],adcSamples[25],adcSamples[26],adcSamples[27],adcSamples[28],adcSamples[29],adcSamples[30],
								adcSamples[31],adcSamples[32],adcSamples[33],adcSamples[34],adcSamples[35],adcSamples[36],adcSamples[37],adcSamples[38],adcSamples[39],adcSamples[40],
								adcSamples[41],adcSamples[42],adcSamples[43],adcSamples[44],adcSamples[45],adcSamples[46],adcSamples[47],adcSamples[48],adcSamples[49],adcSamples[50],
								adcSamples[51],adcSamples[52],adcSamples[53],adcSamples[54],adcSamples[55],adcSamples[56],adcSamples[57],adcSamples[58],adcSamples[59],adcSamples[60],
								adcSamples[61],adcSamples[62],adcSamples[63],adcSamples[64],adcSamples[65],adcSamples[66],adcSamples[67],adcSamples[68],adcSamples[69],adcSamples[70],
								adcSamples[71],adcSamples[72],adcSamples[73],adcSamples[74],adcSamples[75],adcSamples[76],adcSamples[77],adcSamples[78],adcSamples[79],adcSamples[80],
								adcSamples[81],adcSamples[82],adcSamples[83],adcSamples[84],adcSamples[85],adcSamples[86],adcSamples[87],adcSamples[88],adcSamples[89],adcSamples[90],
								adcSamples[91],adcSamples[92],adcSamples[93],adcSamples[94],adcSamples[95],adcSamples[96],adcSamples[97],adcSamples[98],adcSamples[99],adcSamples[100],
								adcSamples[101],adcSamples[102],adcSamples[103],adcSamples[104],adcSamples[105],adcSamples[106],adcSamples[107],adcSamples[108],adcSamples[109],adcSamples[110],
								adcSamples[111],adcSamples[112],adcSamples[113],adcSamples[114],adcSamples[115],adcSamples[116],adcSamples[117],adcSamples[118],adcSamples[119],adcSamples[120],
								adcSamples[121],adcSamples[122],adcSamples[123],adcSamples[124],adcSamples[125],adcSamples[126],adcSamples[127],adcSamples[128],adcSamples[129],adcSamples[130],
								adcSamples[131],adcSamples[132],adcSamples[133],adcSamples[134],adcSamples[135],adcSamples[136],adcSamples[137],adcSamples[138],adcSamples[139],adcSamples[140],
								adcSamples[141],adcSamples[142],adcSamples[143],adcSamples[144],adcSamples[145],adcSamples[146],adcSamples[147],adcSamples[148],adcSamples[149],adcSamples[150],
								adcSamples[151],adcSamples[152],adcSamples[153],adcSamples[154],adcSamples[155],adcSamples[156],adcSamples[157],adcSamples[158],adcSamples[159],adcSamples[160],
								adcSamples[161],adcSamples[162],adcSamples[163],adcSamples[164],adcSamples[165],adcSamples[166],adcSamples[167],adcSamples[168],adcSamples[169],adcSamples[170],
								adcSamples[171],adcSamples[172],adcSamples[173],adcSamples[174],adcSamples[175],adcSamples[176],adcSamples[177],adcSamples[178],adcSamples[179],adcSamples[180],
								adcSamples[181],adcSamples[182],adcSamples[183],adcSamples[184],adcSamples[185],adcSamples[186],adcSamples[187],adcSamples[188],adcSamples[189],adcSamples[190],
								adcSamples[191],adcSamples[192],adcSamples[193],adcSamples[194],adcSamples[195],adcSamples[196],adcSamples[197],adcSamples[198],adcSamples[199],adcSamples[200]);
}

The value can be up to +/-2000 for the ADC value. That would take about 6 char places per value.

I tried multiply thing. This is one of them.

uint8_t j,i;
char buffer[7];
			for (i=0; i<SAMPLE_COUNT;i++){
				snprintf(buffer,sizeof(buffer),"%d ",adcSamples[i]);
				
				//temp[sizeof(buffer)*i]=buffer;
				strcpy(ADCSamples1[(sizeof(buffer)*i)],buffer);
				//strcat(temp,buffer);
				printf("%s ",ADCSamples1[(sizeof(buffer)*i)]);
			}

The printf in the for loop gives the right output, but when i want to print the whole string outside of the for loop. It doesn't give any output

for(i=0;i<sizeof(adcSamples)*sizeof(uint16_t));i++){

    snprintf(adcSamples1*(sizeof(uint16_t)*i),sizeof(adcSamples1),"%d ", adcSamples);

}

Anyone got an idea how i could to this??blush

Thanks

Last Edited: Tue. May 12, 2015 - 02:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which AVr has enough RAM to hold a string like that - sounds like more than 1K?

 

Do you really need the entire string to be built before it's used anyway? If the ultimate output is just printf() or something can't you just output a bit at a time in a for() loop. Consider for example:

~$ cat test.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

uint16_t samples[200];

int main(void) {
        int i;
        for (i=0; i < 200; i++) {
                samples[i] = rand();
        }
// then later...

        for (i=0; i < 200; i++) {
                printf("%d ", samples[i]);
        }
}

~$ gcc test.c -o test
~$ ./test
17767 9158 39017 18547 56401 23807 37962 22764 7977 31949 22714 55211 16882 7931 43491 57670 124 25282 2132 10232 8987 59880 52711 17293 3958 9562 63790 29283 49715 55199 50377 1946 64358 23858 20493 55223 47665 58456 12451 55642 24869 35165 45317 41751 43096 23273 33886 43220 48555 36018 53453 57542 30363 40628 9300 34321 50190 7554 63604 34369 62753 48445 36316 61575 6768 56809 51262 54433 49729 63713 44540 9063 33342 24321 50814 10903 47594 19164 54123 30614 55183 42040 22620 20010 17132 31920 54331 1787 39474 52399 36156 36692 35308 6936 32731 42076 63746 18458 30974 47939 16635 9978 57002 49978 34299 42281 60881 16358 61445 49468 46972 51092 25973 4056 5566 43105 35977 59897 44892 9915 46760 15513 46607 16533 22449 13803 58609 20659 32261 24047 3063 48896 34025 60065 33338 2789 36810 28683 19147 32720 12616 583 18276 38589 4639 23843 16158 40616 18204 61051 50532 64965 11028 31603 15962 33477 45406 9035 54137 12131 33083 57200 61028 1572 51729 28830 4361 23004 57514 23508 55724 4594 24091 8464 43183 28731 32307 59341 3811 50512 54856 54343 49941 348 20411 367 33826 281 9402 22427 12413 42485 14091 7905 44058 284 36735 48419 23288 28713 
~$

EDIT: OK if you really want to build a "huge" string first this (not particularly elegant) code achieves that...

~$ cat test.c
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

uint16_t samples[200];
char huge[16384]; // the joy of owning a PC!

int main(void) {
        int i;
        for (i=0; i < 200; i++) {
                samples[i] = rand();
        }

	huge[0] = 0;
        for (i=0; i < 200; i++) {
                sprintf(&huge[strlen(huge)], "%d ", samples[i]);
        }
	printf("%s", huge);
}

~$ gcc test.c -o test
~$ ./test
17767 9158 39017 18547 56401 23807 37962 22764 7977 31949 22714 55211 16882 7931 43491 57670 124 25282 2132 10232 8987 59880 52711 17293 3958 9562 63790 29283 49715 55199 50377 1946 64358 23858 20493 55223 47665 58456 12451 55642 24869 35165 45317 41751 43096 23273 33886 43220 48555 36018 53453 57542 30363 40628 9300 34321 50190 7554 63604 34369 62753 48445 36316 61575 6768 56809 51262 54433 49729 63713 44540 9063 33342 24321 50814 10903 47594 19164 54123 30614 55183 42040 22620 20010 17132 31920 54331 1787 39474 52399 36156 36692 35308 6936 32731 42076 63746 18458 30974 47939 16635 9978 57002 49978 34299 42281 60881 16358 61445 49468 46972 51092 25973 4056 5566 43105 35977 59897 44892 9915 46760 15513 46607 16533 22449 13803 58609 20659 32261 24047 3063 48896 34025 60065 33338 2789 36810 28683 19147 32720 12616 583 18276 38589 4639 23843 16158 40616 18204 61051 50532 64965 11028 31603 15962 33477 45406 9035 54137 12131 33083 57200 61028 1572 51729 28830 4361 23004 57514 23508 55724 4594 24091 8464 43183 28731 32307 59341 3811 50512 54856 54343 49941 348 20411 367 33826 281 9402 22427 12413 42485 14091 7905 44058 284 36735 48419 23288 28713

If nothing else my reply here shows it is MUCH easier to test this kind of thing on a real PC then just migrate your solution to AVR when you know it works.

Last Edited: Tue. May 12, 2015 - 03:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Which AVr has enough RAM to hold a string like that - sounds like more than 1K?

+1

Quote:
Do you really need the entire string to be built before it's used anyway?

+1

Quote:
If the ultimate output is just printf() or something can't you just output a bit at a time

+1

 

But if you really do need it all in one string, and you really do have enough RAM for that:

 

Consider that the return value from snprintf() is the number of characters written into the string - so, after writing one item to the string, you can use this to determine the index at which to start writing the next item...

 

See: http://www.cplusplus.com/referen... - and note the proviso on the return value.

 

As this has nothing to do with the AVR, it's probably easier to get it working in a PC program first...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thx for the reply.

I'm using a XmegaA3Bu xplained board to do this.

 

I fill an array with ADC values.

After a certaint amount of samples i want to write these values to a SD-card with a time value and some other stuff. The function for the SD card needs a string to write to the SD card.

 

So i need to convert the interger array to a string.

sprintf(&huge[strlen(huge)], "%d ", samples[i]);

This functions does the job.

So thanks for the help laugh

PS: The string isn't 5000 char long, But around 500 cheeky, was a typo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Glad to hear it's working.

 

For future reference:

rgamer145 wrote:
The function for the SD card needs a string to write to the SD card.

But it shouldn't need to have the whole string in one go - it should be possible to append individual value strings to the file...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

But it shouldn't need to have the whole string in one go

+1

 

I'm sort of assuming you are talking about f_puts() or f_printf() in FatFs if it is SD cards?

 

In either case the two simple test programs I showed above demonstrate that you can either produce the output (printf() in this case) piecemeal or in one chunk and the result is actually the same. I'm sure that the "print" function you use to the SD card does not care if it's sent a short string 200 times or one very big one. the nature of SD is that everything happens in 512 byte sectors anyway. So if you print() just 6 characters the chances are nothing actually happens, the FAT software will just cache the data in a sector buffer. It's only after the 85th time you send 6 characters it will spot "oh the 512 byte sector buffer is full, I had better write that one to the storage then start over"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't have the standard library for the FatFs system.

Because i could get it to work like i wanted it to.

 

So i converted this library made for atmega to my xmega project.

http://www.roland-riegel.de/sd-reader/

 

This one worked for me, so i have gone further with this library. Haven't done anything with the FatFs from atmel anymore.
 

[EDIT:]

I have tried to write the each value separately.

But the writing is very slow then. Comparing to write a large string with values. :/

So i have to make the large string to let the program go at a proper speed.

Last Edited: Wed. May 13, 2015 - 12:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But the writing is very slow then.

Interesting - have you analysed where the delay is? Like I say a well written FAT library will simply be tacking most small writes onto the end of a 512 byte buffer. It's only when the buffer fills that it would then need to make the actual write one sector to the card.

 

I guess an inefficient implementation of FAT might read 512 bytes, add the 6 new bytes then write the updated 512 back again on each 6 byte write. That would be a very bad implementation !

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I haven't look in the it before, but it seems that indeed it read first 512bytes and add the data to write ir back again. But i'm not sure. I ain't that good with understanding someones code quickly

#if DOXYGEN || SD_RAW_WRITE_SUPPORT
/**
 * \ingroup sd_raw
 * Writes raw data to the card.
 *
 * \note If write buffering is enabled, you might have to
 *       call sd_raw_sync() before disconnecting the card
 *       to ensure all remaining data has been written.
 *
 * \param[in] offset The offset where to start writing.
 * \param[in] buffer The buffer containing the data to be written.
 * \param[in] length The number of bytes to write.
 * \returns 0 on failure, 1 on success.
 * \see sd_raw_write_interval, sd_raw_read, sd_raw_read_interval
 */
uint8_t sd_raw_write(offset_t offset, const uint8_t* buffer, uintptr_t length)
{
    if(sd_raw_locked())
        return 0;

    offset_t block_address;
    uint16_t block_offset;
    uint16_t write_length;
    while(length > 0)
    {
        /* determine byte count to write at once */
        block_offset = offset & 0x01ff;
        block_address = offset - block_offset;
        write_length = 512 - block_offset; /* write up to block border */
        if(write_length > length)
            write_length = length;
        
        /* Merge the data to write with the content of the block.
         * Use the cached block if available.
         */
        if(block_address != raw_block_address)
        {
#if SD_RAW_WRITE_BUFFERING
            if(!sd_raw_sync())
                return 0;
#endif

            if(block_offset || write_length < 512)
            {
                if(!sd_raw_read(block_address, raw_block, sizeof(raw_block)))
                    return 0;
            }
            raw_block_address = block_address;
        }

        if(buffer != raw_block)
        {
            memcpy(raw_block + block_offset, buffer, write_length);

#if SD_RAW_WRITE_BUFFERING
            raw_block_written = 0;

            if(length == write_length)
                return 1;
#endif
        }

        /* address card */
        select_card();

        /* send single block request */
#if SD_RAW_SDHC
        if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, (sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC) ? block_address / 512 : block_address)))
#else
        if(sd_raw_send_command(CMD_WRITE_SINGLE_BLOCK, block_address))
#endif
        {
            unselect_card();
            return 0;
        }

        /* send start byte */
        sd_raw_send_byte(0xfe);

        /* write byte block */
        uint8_t* cache = raw_block;
        for(uint16_t i = 0; i < 512; ++i)
            sd_raw_send_byte(*cache++);

        /* write dummy crc16 */
        sd_raw_send_byte(0xff);
        sd_raw_send_byte(0xff);

        /* wait while card is busy */
        while(sd_raw_rec_byte() != 0xff);
        sd_raw_rec_byte();

        /* deaddress card */
        unselect_card();

        buffer += write_length;
        offset += write_length;
        length -= write_length;

#if SD_RAW_WRITE_BUFFERING
        raw_block_written = 1;
#endif
    }

    return 1;
}
#endif

I think this is the function that handels the writing of the SD card

Last Edited: Wed. May 13, 2015 - 01:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would put a bit of effort into making FatFs work. I really don't think it can be beaten. It does this kind of thing properly!