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.

split a number by 3

Status
Not open for further replies.
Well it's still heaps slower than the way I posted, but if you want to use it you can improve it a bit by changing;

Code:
a = (num / 100 ) % 10;    //a = 2;

to;

Code:
a = (num / 100 );    //a = 2;
It's far more readable than what you posted.
The first way works if there is more than 3 digits eg. 4255. It's a common way of doing it. But yes, if there is only 3 digits, the second way works.
 
Last edited:
If readbility is an issue then it can be wrapped in a neat readable little function. :)

PICs have very limited ROM, RAM and usually limited time to execute code. How often is readability the top priority?? Good embedded C is going to be a lot different from "good" C taught in a class.
 
You use loops whearas all it takes is 3 simple statements.
If I were worried about the execution time difference between my simple code and yours, I'd be programming in assembly.
 
It's not black and white - assembly being the efficient path and C being the slow but maintainable/readable path. One can achieve very efficient code with C if he pays attention to what is produced behind the scenes. Balancing performance and readability is an art; you can't always get enough of both and sometimes you need to sway heavily to one side.

I would opt for RB's solution as it is indeed much quicker and very straightforward.
 
You use loops whearas all it takes is 3 simple statements.
If I were worried about the execution time difference between my simple code and yours, I'd be programming in assembly.

Loops? Have you checked your /100 /10 and %10 code in your compilers output? :eek:

All the PIC embedded C that I write is checked against the compiler output (the assembly). I programmed PICs in assembler for lots of years, with a little bit of asm skill you can write C-- code that will compile to something not much larger or slower than assembly. Just because you use C doesn't mean you are forced to be stuck with massive bloated slow code, there are better ways.

And "better ways" doesn't include using sprintf()... ;)
:D
 
I used 3 simple and commonly used statements, that are found in textbooks to achieve what the OP asked. If the output of a statement containing a simple modulo and divide operation is more bloated than your code using loops, so be it, I view it is a side effect of using C. Course, you can write efficient programs using C, but I simply disagree with using loops to achieve something that can performed using a single statement.
I wouldn't like to be one trying to maintain a C program of yours that actually does something, to be honest.

I write C programs for microcontrollers all the time, which are readable, easy to maintain and debug and are fast enough to do the job. As I say, I'd use assembly before I'd write
unnecessarily complicated C code.
 
Last edited:
And "better ways" doesn't include using sprintf()... ;)
:D

Ooohhh that one tickles. But my position is defensible. The majority of my applications are written on PIC24 and PIC32 platforms using a cooperative multitasking approach. I spend a LOT of time waiting in one particular while loop. I can easily afford to sprinkle a ton of sprintf and printf wherever I like.

main.h:
Code:
#define TASK1   0
#define TASK2   1
#define TASK3   2
#define TASK4   3
#define TASK5   4

#define FIRST_TASK   TASK1
#define LAST_TASK    TASK5

#define MAIN_LOOP_TIME   5  // 5 mS
#define TASK_DELAY_TIME  (MAIN_LOOP_DELAY * (LAST_TASK - FIRST_TASK + 1))

main.c:
Code:
void Sync_to_Real_Time( void )
{
// timer 2 is configured to set the T2IF flag every 5mS
   if (T2IF)
      printf("Sync error\r\n");

   while (T2IF == 0)
      ;

   T2IF = CLEAR_INT_FLAG;
}

void main( void )
{
Uint32 static task = FIRST_TASK; // this is from a PIC32, so a 32 bit value won't hurt me

   Init_Hardware();
   Show_Version();

   while (1)
   {
      Sync_to_Real_Time();
      Service_Display();

      switch (task)
      {
         case TASK1:
            Service_UI();
            Service_Sleep_Timer();
            break;

         case TASK2:
            Service_Temp_Sensors();
            Service_Application();
            break;

         case TASK3:
            Service_Debug_Port();
            Service_Backlight();
            break;

         case TASK4:
            Service_Sd_Card();
            Service_Beeper();
            break;

         case TASK5:
            Service_Rf_Module();
            break;
      }
      task++;
      if (task > LAST_TASK)
         task = FIRST_TASK;
   }
}

Given the structure of main(), I know (as long as I don't see sync errors spitting out of my port) that every task item will be called every 25mS and Service_Dsiplay() will be called every 5mS. The difficulty comes in when things are slooooowwww such as writing to a 320x240 color graphic LCD without a graphics accelerator. So any function that takes longer than 5 mS to execute gets cut down to a state machine. A short example:

Code:
Uint32* last_display_screen;  // used to remember what screen is drawn on the display

void Service_Display( void )
{
   switch (app_state)
   {
      case APP_SD_UTILITIES:
         Draw_Sd_Utilities_Screen();
         break;
    
      case ...:
         break;
   }
}

void Draw_Sd_Utilities( void )
{
static Uint32 draw_state;
static Uint32 i;
 
      if (last_dispaly_screen != (void*)Draw_Sd_Utilities)
      {
         draw_state = DRAW_BLANK_SCREEN;
         i = 0;         
      }

      switch (draw_state)
      {
          case DRAW_BLANK_SCREEN:
            SetColor(BACKGROUND_COLOR);
            Bar(GetMinX(), i, GetMaxX(), i+16);
            i+=16;
            if (i >= GetMaxY())
               draw_state = CREATE_GRAPHIC_OBJECTS;
            break;

         case CREATE_GRAPHIC_OBJECTS:
            ...
            break;
      }
}

That format, while it makes the code more complex to read in the case of servicing the display, allows me to keep the display updated quite well, keep the UI snappy, scan for SD card being inserted/removed, read files on the SD card, communicate over RF, create an RS-232 debug menu, read adc/temperature sensors and digitally filter them with known time constants.

temp_sensor.c
Code:
void Service_Temp_Sensors( void )
{
// Device has two temp sensors, each one takes 380 mS to complete a conversion
// Read one every 200 mS and alternate between the two

#define TEMP_SENSOR_DELAY      200/TASK_DELAY_MS
static Uint32 delay_timer = 0;
static Uint32 sensor_number = 0;
Uint32 temp_sensor_result;

   delay_timer++;
   if (delay_timer >= TEMP_SENSOR_DELAY)
   {
      delay_timer = 0;
      if (sensor_number == 0)
      {
         temp_sensor_result = Read_Temp_Sensor( 0 );
         Update_Digital_Filter( &temp_sensor_0, temp_sensor_result );
         sensor_number = 1;
      }
      else
      {
         temp_sensor_result = Read_Temp_Sensor( 1 );
         Update_Digital_Filter( &temp_sensor_1, temp_sensor_result );
         sensor_number = 0;
      }
   }
}

My digital filter acts similar to an RC filter...
Code:
void Update_Digital_Filter( filter_type* filter, Uint32 new_val )
{
static Uint32 init_flag = 0;

   if (init_flag == 0)
   {
      filter->output = new_val;
      filter->accumulator = new_val << filter->shift_value;
      init_flag = 1;
   }
   else
   {
      filter->accumulator -= filter->output;
      filter->accumulator += new_val;
      filter->output = filter->accumulator>>filter->shift_value;
   }
}

Since I know how often Update_Digital_Filter() is called, I can calculate and adjust the actual time constant of the filter easily using an Excel spreadsheet to set filter.shift_vaule at uC init.

All of this results in me sitting in my Sync_to_Real_Time() function, so I have plenty of cycles left over for printf and sprintf :) and I can easily time events with a static counter.

Edit: That is a lot of typing to defend my use of sprintf :D

Edit2: On the handful of PIC12 projects I've done, I don't use this method... and I avoid printf and floats like the plague as well
 
Last edited:
Roman (Mr RB),

I'm afraid there are very few of us who actually look at or care about the compiler output. While I often spend hours modifying C source and studying the output in order to come up with small, simple, elegant, and efficient algorithm, it seems to me that many programmers just don't care about the size and speed of their code. If they run out of memory they'll move up to a bigger chip. If the code doesn't run fast enough they'll use a faster clock. And that's perfectly acceptable.

Please save your arguments. There are only a few of us who understand or care about the concepts and disciplines you're describing and I suspect you'll agree that those concepts and disciplines aren't absolutely necessary for writing "good" code. It's just "good" code that we would do differently.

Kind regards, Mike
 
Roman (Mr RB),

I'm afraid there are very few of us who actually look at or care about the compiler output. While I often spend hours modifying C source and studying the output in order to come up with small, simple, elegant, and efficient algorithm, it seems to me that many programmers just don't care about the size and speed of their code. If they run out of memory they'll move up to a bigger chip. If the code doesn't run fast enough they'll use a faster clock. And that's perfectly acceptable.

Please save your arguments. There are only a few of us who understand or care about the concepts and disciplines you're describing and I suspect you'll agree that those concepts and disciplines aren't absolutely necessary for writing "good" code. It's just "good" code that we would do differently.

Kind regards, Mike

Software quality is a big topic and decided on many factors. Here are four:

1. Readability
2. Ease of maintenance, testing, debugging, fixing, modification and portability
3. Low complexity
4. Low resource consumption: memory, CPU

It's not always necessary to code the fastest code wherever and whenever possible trying to achieve number 4, butchering numbers 1,2 and 3 in the process.
 
Last edited:
Nice application Noggin! :)

Well the way I see it the beauty of C is that you can write really powerful code (ie smaller and faster) and THEN wrap it in a neat, readable function call that satisfies all of colin_mac's criteria for readability and ease of maintainance. So you get to have your cake and eat it too.

Mike_KL8H- it's shame that more people DON'T realise what their compiler is doing, and/or don't have the benefit of experience doing the same tasks in assembler in code 20 times smaller. Maybe we should be raising that point... And maybe the lecturers should too. But like you said I'm probably wasting my breath (fingers?). :)
 
Software quality is a big topic and decided on many factors. Here are four:

1. Readability
2. Ease of maintenance, testing, debugging, fixing, modification and portability
3. Low complexity
4. Low resource consumption: memory, CPU

It's not always necessary to code the fastest code wherever and whenever possible trying to achieve number 4, butchering numbers 1,2 and 3 in the process.

Colin,

You shouldn't need to defend your programming style to anyone or critisize others for their programming styles.

There are hundreds of different ways to code a task and I don't think we should force our opinions and styles on each other.

We've got a few young "rising stars" on the Forum and I've offered suggestions to a couple of them in the past to try and help them think about methods and styles differently but I also tried to be careful not to suggest that one way was better then another.

Have a great day.

Regards, Mike
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top