CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

7-segment display blinking

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
pavelustinov



Joined: 09 Mar 2013
Posts: 20

View user's profile Send private message

7-segment display blinking
PostPosted: Fri Sep 06, 2013 7:59 am     Reply with quote

Hello everybody!
I use PIC16F877A, 4-digits 7-segment display, DS18B20 temp sensor.
My program compiles successfully, display on my real hardware show current temperature.
But it blinks. I think, I need to change delays in timer, but I don't know how. I tried, but I have no result.
Code:

#include <16F877A.h>
#device *=16
#device adc=8

#FUSES NOWDT, HS, PUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT     
#use delay(clock=4000000)

#include <1wire.c>
#include <ds1820.c>

float temperature;
int16 del;
int16 tens;
int16 units;
int16 hundreds;
int16 floor;

#INT_TIMER0
void segment_mux_isr()
{
   int16 k;
   int j = 10;
   for(del=0; del<20; del++)
      {
         output_A(indexNumber(1));
         output_B(myDecode(hundreds));
         for(k=0; k<j; k++) {}
         output_A(indexNumber(2));
         output_B(myDecode(tens));
         for(k=0; k<j; k++) {}
         output_A(indexNumber(3));
         output_B(myDecode(units));
         for(k=0; k<j; k++) {}
         output_A(indexNumber(4));
         output_B(myDecode(floor));
         for(k=0; k<j; k++) {}
      }
}

void main()
{
   float temperature;
   
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
      temperature = ds1820_read();
     
      hundreds = temperature / 100;
      tens = (temperature - hundreds * 100) / 10;
      units = temperature - hundreds * 100 - tens * 10;
      floor = (temperature - hundreds * 100 - tens * 10 - units) * 10;
   }
}
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Fri Sep 06, 2013 8:24 am     Reply with quote

Would you care to:-

1) Show a schematic
2) Provide code which is complete and compilable.
3) Explain how you think the display works.

Mike
pavelustinov



Joined: 09 Mar 2013
Posts: 20

View user's profile Send private message

PostPosted: Fri Sep 06, 2013 8:47 am     Reply with quote

Mike Walne wrote:
Would you care to:-

1) Show a schematic
2) Provide code which is complete and compilable.
3) Explain how you think the display works.

Mike


You can download here http://www.sokol-media.ru/data.zip
C code, Proteus File, PDF with schematic.
Note: Proteus and real hardware works different.
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Fri Sep 06, 2013 12:54 pm     Reply with quote

The approach is flawed in a number of ways:

The interrupt is called every 65536 processor cycles (256*256) = 15 times per second.
The interrupt routine, then sits, and updates the display 20 times. Now a quick 'guess', gives a total time for this, of about:
15 cycles to get the first number
3 cycles to output
15 cycles for the next value
3 cycles to output
80 cycles for the 'delay' loop

Repeat all these four times

Then repeat the whole thing 20 times.

So perhaps 10000 cycles.
Then the display update stops till the next interrupt.

So the display stops being refreshed for about 5/6th the time.

Then a further problem. The display can be called when only some of the values have been updated. Result, momentary garbage.

Now the display update needs to be much more evenly distributed in time:
Code:

#include <16F877A.h>
#device *=16
#device adc=8

#FUSES NOWDT, XT, PUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT     
#use delay(clock=4000000)
//Note at 4MHz should be XT oscillator

#include <1wire.c>
#include <ds1820.c>
#include <stdlib.h>

struct tval {
   int8 tens;
   int8 units;
   int8 hundreds;
   int8 floor;
} t_val;

#INT_TIMER0
void segment_mux_isr()
{
   static int state=0;
   switch (state)
   {
   case 0:
      output_A(indexNumber(1));
      output_B(myDecode(t_val.hundreds)); 
      state++;
      break;
   case 1:
      output_A(indexNumber(2));
      output_B(myDecode(t_val.tens));
      state++;
   case 2:
      output_A(indexNumber(3));
      output_B(myDecode(t_val.units));
      state++;
   case 3:
      output_A(indexNumber(4));
      output_B(myDecode(t_val.floor));
      state=0;
  }
}

void main()
{
   float temperature;
   int16 itemp;
   ldiv_t temp;
   struct tval l_val;
     
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16); //Note change of speed
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);

   while(TRUE)
   {
      temperature = ds1820_read();
      itemp=temperature;
      //integer part
      temp=ldiv(itemp,10);
      l_val.units=temp.rem;
      temp=ldiv(temp.quot,10);
      l_val.tens=temp.rem;
      l_val.hundreds=temp.quot;
      l_val.floor=(temperature-itemp)*10;
      //Now this will be a lot quicker than the repeated
      //multiplications/divisions. Takes advantage of the ldiv
      //function that returns quotient, and remainder from an
      //integer division.
      //At this point we have the new values
      disable_interrupts(INT_TIMER0);
      t_val=l_val;
      enable_interrupts(INT_TIMER0);  //transfer values   
   }
}


I have removed the duplicate 'temperature' declarations (you have it declared both as a global, and local variable).

Note no delays in the ISR. Instead it outputs just one digit, and exits immediately. The next ISR call sends the next digit. The ISR is called 16* faster, so the display is being continuously refreshed. The refresh is stopped for a moment, while the value to be shown is updated. Each digit is updated about 250*/second, while the whole display is updated 64*/second.

Haven't 'proof read' the code, so likely to be some typing errors.

Best Wishes
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Fri Sep 06, 2013 1:17 pm     Reply with quote

As a further comment:
Code:

const int digits[]={0b1000000,0b1111001,0b0100100,0b0110000,0b0011001,0b0010010,0b0000010,0b1111000,0b0000000,0b0010000};


Then using:
Code:

   case 0:
      output_A(1);
      output_B(digits[t_val.hundreds]);
      state++;
      break;
   case 1:
      output_A(2);
      output_B(digits[t_val.tens]);
      state++;
   case 2:
      output_A(4);
      output_B(digits[t_val.units]);
      state++;
   case 3:
      output_A(8);
      output_B(digits[t_val.floor]);
      state=0;


Codes as over forty instructions shorter than using the subroutines.

Best Wishes
pavelustinov



Joined: 09 Mar 2013
Posts: 20

View user's profile Send private message

PostPosted: Fri Sep 06, 2013 3:51 pm     Reply with quote

Ttelmah wrote:
The approach is flawed in a number of ways:

The interrupt is called every 65536 processor cycles (256*256) = 15 times per second.
...

Great! Display don't blink!
But now I have another problem. Temperature sometimes set to 0000.
I thought I had bad connection. No. This result sometimes I have in Proteus and in real hardware.
I used this driver DS18B20 with my LCD, temp shows successfully.
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Sat Sep 07, 2013 12:58 am     Reply with quote

I think you probably need to disable interrupts momentarily round the 'core' bits of the one wire read and write routines.

One wire is timing dependent, so the change in time when the interrupt occurs will bu&&er things up.....

Only the core though, So something like:
Code:

 for (count=0; count<8; ++count)
 {
  disable_interrupts(INT_TIMER0);
  output_low(ONE_WIRE_PIN);
  delay_us( 2 ); // pull 1-wire low to initiate read time-slot.
  output_float(ONE_WIRE_PIN); // now let 1-wire float high,
  delay_us( 8 ); // let device state stabilise,
  shift_right(&data,1,input(ONE_WIRE_PIN)); // and load result.
  enable_interrupts(INT_TIMER0);
  delay_us( 120 ); // wait until end of read slot.
 }

and the same for the write routine.

This way the display updates will only occur in the parts of the cycle, that are 'timing flexible'....

Best Wishes
fkl



Joined: 20 Nov 2010
Posts: 44

View user's profile Send private message

PostPosted: Sat Sep 07, 2013 4:28 am     Reply with quote

when temperature is negative - it does not work correctly.
Ttelmah



Joined: 11 Mar 2010
Posts: 19551

View user's profile Send private message

PostPosted: Sat Sep 07, 2013 7:31 am     Reply with quote

Several things needed for -ve.

1) You'd have to add an ability to display '-' to your display.
2) Test if the temperature number is -ve before converting to digits. If is is turn on the -ve in the display, and then make temperature=-temperature.

Best Wishes
pavelustinov



Joined: 09 Mar 2013
Posts: 20

View user's profile Send private message

PostPosted: Sat Sep 07, 2013 10:07 am     Reply with quote

Ttelmah wrote:
Several things needed for -ve.

1) You'd have to add an ability to display '-' to your display.
2) Test if the temperature number is -ve before converting to digits. If is is turn on the -ve in the display, and then make temperature=-temperature.

Best Wishes

Ttelmah, thank you very much! It works great! I am happy!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group