Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Is it possible (if so how) to use scanf / printf on your own input / output routine?

Status
Not open for further replies.

blueroomelectronics

Well-Known Member
Is it possible (if so how) to use scanf / printf on your own input / output routine or ring buffer?
Thanks in advance.
Yes, I'm very new to C and currently wrapping my head around pointers & strings.
 
Most compilers allow you to define std input and output... you just write your own putch() and getch() routines to override the original...

For example.... lets say you are outputting to an LCD

C:
void putch( char ch)
   {
   LCDdata(ch);
   }

The compiler should have this documented...
 
Thanks Ian, another possible answer was pointed out to me "sprintf" prints to a user defined buffer.

Problem with me I'm learning in a non linear way, probably not the fastest but it works for my old brain. Now I've got to look up putch (XC8 seems to want this defined before it'll allow printf to work, I'm guessing it's telling it where to print)

I'm really starting to enjoy using C (actually XC8) and trying to forget BASIC & Pascal.

Now I've got to wrap my brain around pointers.
 
Part two, how do I direct printf to a different output device? Since putch function controls the output and is automatically called by printf, how is it redefined?
 
From the XC8 manual (DS52053B-page 59):

You can get printf to send to one of several destinations by using a global variable to indicate your choice. Have the putch function send the byte to one of several destinations based on the contents of this variable.

An alternative would be to sprintf to a buffer and then have functions like send_buffer_uart / send_buffer_spi that work purely on a character array.
 
From the XC8 manual (DS52053B-page 59):



An alternative would be to sprintf to a buffer and then have functions like send_buffer_uart / send_buffer_spi that work purely on a character array.

This is the way I always do it...

My screen is usually 16 x 2 so I create a global 17 byte buffer.... The reason I use a global buffer is to use the screen buffer in any function.... I tried several local buffers but used up my stack too quickly..


C:
char LCDbuffer[17];

then use it with sprintf()

C:
int val = 1234;
sprintf(LCDbuffer," Value = %d ", val);E]

LCDprint(LCDbuffer);

The function is the same as above ( post #2)

C:
void LCDprint(char * buff)
   {
   while(*buff != 0)
      LCDdata(*buff++);
   }
 
You can switch the output for everything that prints using a function pointer called from the putch() function. e.g.
Code:
#include <stdio.h>

void putchLcd(char c)
{
    // do LCD putch here
}

void putchSerial(char c)
{
    // do serial putch here
}

void putchSevenSeg(char c)
{
    // print to 7seg here
}

void (*putchFunc)(char c) = putchLcd;       // default to printing to LCD
void putch(char c)
{
    putchFunc(c);   // call whatever function we've set the pointer to point to
}

int main()
{
    putchFunc = putchLcd;   // subsequent printf will print to LCD
    printf("hello from LCD");

    putchFunc = putchSerial;
    printf("hello from Serial port");

    putchFunc = putchSevenSeg;
    printf("\n005");

    return 0;
}

Or the more simply understood version, using conditional statements:
Code:
#include <stdio.h>

enum PutchMode{doLcdPutch, doSerialPutch, doSevSegPutch};

void putchLcd(char c)
{
    // do LCD putch here
}

void putchSerial(char c)
{
    // do serial putch here
}

void putchSevenSeg(char c)
{
    // print to 7seg here
}

enum PutchMode putchMode = doLcdPutch;
void putch(char c)
{
    switch(putchMode)
    {
    case doLcdPutch:
        putchLcd(c);
        break;

    case doSerialPutch:
        putchSerial(c);
        break;

    case doSevSegPutch:
        putchSevenSeg(c);
        break;
    }
}

int main()
{
    putchMode = doLcdPutch;   // subsequent printf will print to LCD
    printf("hello from LCD");

    putchMode = doSerialPutch;
    printf("hello from Serial port");

    putchMode = doSevSegPutch;
    printf("\n005");

    return 0;
}
 
@ dougy, edit, and Bill

Excellent examples but as it's Bill (no offence meant Bill) I'd change the return 0; to while(1); as returning from main on a pic is not a good idea.

Mike.
 
Most LCD devices have their own functions to write txt or characters. Sometime the compiler will already have built in functions for common displays. For instance on MikroC there are inbuilt functions for 16x2 text LED, and 128x64 GLCD.

Normally to write text to the display with those functions the syntax is something like this;
display_LCD_text(0,1,"blah");
where the text will be on line 0, starting from position 1, and will display the constant text "blah".

Or if you are using a buffer to hold and process your text before displaying (a good idea) then it more like this;
unsigned char txt[17]; // global buffer to hold 16 text chars + NULL

strcpy(txt,"foo"); // store temporary text into buffer
display_LCD_text(0,8,txt); // display the text in the middle of the top line

When you start downloading all the code projects for different LCDs etc you will see the coders usually implement a display text function for each LCD that is of very similar in use to that example.

On microcontrollers I have never used sprintf() or getc() putc() etc and looking in other people's LCD and GLCD code that would be a rare way to work with micros and displays.

The sprintf() is sometimes used, but is normally quite a large use (waste) of ROM just for that one function. It's common on smaller micros for people to use the smaller formatting functions CharToStr() or IntToStr() etc to turn a numerical variable into text. Those functions are small and fast. Then the static text can be added separately, simply by telling what position to display to.

like this;
display_LCD_text(0,0,"ADC="); // add static text
CharToStr(txt, ADC_value); // get the 0-255 value as text
display_LCD_text(0,4,txt); // display the number after the text tag (4 chars to the right)
 
@ dougy, edit, and Bill

Excellent examples but as it's Bill (no offence meant Bill) I'd change the return 0; to while(1); as returning from main on a pic is not a good idea.

Mike.

No offense taken. I'm just happy I can still absorb this stuff.

I took to sprintf as a string formatter that's great for getting data into a buffer, it does seem to readily gobble up resources though. I'll have to research strcpy and scanf.
 
I took to sprintf as a string formatter that's great for getting data into a buffer, it does seem to readily gobble up resources though.

What kind of data and what kind of buffer? Could you post the code you have so far? I have never needed sprintf (or other print-functions from the standard library) in 8-bit embedded systems. Usually it is very simple to write your own solution.
 
The code's a train-wreck at the moment, I'll probably avoid using sprintf and instead use strcpy as I don't really need the formatting.

I have three serial ports, one is used like a console the other two are connected to devices that control lights, sound etc for automation.
 
...
I have three serial ports, one is used like a console the other two are connected to devices that control lights, sound etc for automation.

So I guess you are using the hardware USART for RX/TX console comms, then the other two are software serial TX only (ie; two serial slaves)?

Depending how much data and how often you need to send it to the slaves, you could just manually bit bang it out to each slave in a function, without needing your multitasking interrupt you were suggesting using.

That makes things really easy (and reliable).

Another good option is to run all the slaves from a single TX output, and just include an addressing byte with each data message (to select which slave will act upon the data). That is simpler still and allows the option of connecting many slaves to the one TX output.
 
Actually it's a 18F46K22 with dual EUSARTs, the console will be fixed at 9600,N,8,1 and done in software with a fair amount of offloading by timers.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top