|
|
View previous topic :: View next topic |
Author |
Message |
pavelustinov
Joined: 09 Mar 2013 Posts: 20
|
7-segment display blinking |
Posted: Fri Sep 06, 2013 7:59 am |
|
|
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
|
|
Posted: Fri Sep 06, 2013 8:24 am |
|
|
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
|
|
Posted: Fri Sep 06, 2013 8:47 am |
|
|
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: 19520
|
|
Posted: Fri Sep 06, 2013 12:54 pm |
|
|
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: 19520
|
|
Posted: Fri Sep 06, 2013 1:17 pm |
|
|
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
|
|
Posted: Fri Sep 06, 2013 3:51 pm |
|
|
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: 19520
|
|
Posted: Sat Sep 07, 2013 12:58 am |
|
|
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
|
|
Posted: Sat Sep 07, 2013 4:28 am |
|
|
when temperature is negative - it does not work correctly. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Sat Sep 07, 2013 7:31 am |
|
|
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
|
|
Posted: Sat Sep 07, 2013 10:07 am |
|
|
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! |
|
|
|
|
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
|