|
|
View previous topic :: View next topic |
Author |
Message |
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
Need logical help for Seven segment display |
Posted: Thu Sep 26, 2013 2:00 am |
|
|
Hi,
I'm using PIC18F2520, Oscillator: Internal 1Mhz,
I'm designing a low power seven segment display(SSD) where i can feed current only about 1.5mA. Using POV technique, i'm displaying a number on the display. i.e, switching 'a' segment, some delay, switching 'b' segment, delay, goes on.... below is the sample code:
Not displaying '0' in the SSD,
Code: |
#include "18F2520.h"
#include "f2520_regs.h"
#fuses INTRC
#use delay(clock=1000000)
const char DIGIT_ZERO[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11101110, // d
0b11011110, // e
0b10111110, // f
0b11111110 // g
};
unsigned int16 value = 0, temp_value = 0, value1 = 0, count = 0, segment = 0;
unsigned int16 temp_variable = 0;
unsigned int16 digit_variable = 0;
unsigned int16 i = 0;
unsigned int16 increment = 0, DIGIT_VALUE = 0;
int1 interrupt_flag = 1;
#INT_TIMER1
void timer1_isr()
{
if(TMR1IF == 1)
{
interrupt_flag = 0;
if(count > 6)
{
count = 0;
}
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xFF; // 100us for 1Mhz
TMR1L = 0xE6;
}
}
void main()
{
TRISA = 0b00000000;
TRISB = 0b00000000;
T1CON = 0b10000000;
TMR1H = 0xFF; // 100us for 1Mhz
TMR1L = 0xE6;
TMR1ON = 1;
TMR1IF = 0;
TMR1IE = 1;
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
count=0;
INCREMENT = 0;
DIGIT_VALUE = 0;
while(1)
{
if(interrupt_flag == 0)
{
value1 = (0b00000001 << INCREMENT);
PORTA = value1; // Digit ON
if(DIGIT_VALUE == 0)
{
temp_value = (DIGIT_ZERO[count] >> 1);
value = temp_value | 0b00000000;
PORTB = value; // segment ON
}
interrupt_flag = 1;
}
}
}
|
When i change the program as below, it displays 0 in SSD.
Code: | #INT_TIMER1
void timer1_isr()
{
if(TMR1IF == 1)
{
count++;
if(count > 6)
{
count = 0;
}
value1 = (0b00000001 << INCREMENT);
PORTA = value1;
if(DIGIT_VALUE == 0)
{
temp_value = (DIGIT_ZERO[count] >> 1);
value = temp_value | 0b00000000;
PORTB = value;
}
TMR1IF = 0;
TMR1IE = 1;
TMR1H = 0xFF; // 100us for 1Mhz
TMR1L = 0xE6;
}
}
|
Why the program doesn't execute the code in while loop?
Please help |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 26, 2013 2:10 pm |
|
|
Your interrupt rate is too high, compared to your PIC's instruction cycle
speed. You said you have the Timer1 isr set to run every 100 usec.
But with your very low PIC oscillator speed of 1 MHz, an instruction cycle
is 4 usec. So you have the Timer1 isr running every 25 instruction cycles.
100 usec / 4 usec per instr. cycle = 25 instr. cycles.
But, the Timer1 isr does not get executed instantly. Always remember
this. There is a overhead cost to get in and out of the isr. With just one
isr running, the overhead is about 50 instruction cycles. The program
has to "save the state of the machine" before it enters the isr, and the
it has to restore it when it exits the isr. That takes 50 instruction cycles.
Because you have Timer1 set to overflow after 25 instruction cycles, and
it takes 50 for the overhead alone (not counting user code inside the isr),
what this means is that as soon as the PIC exits the isr, another new
Timer1 interrupt is already waiting and is triggered right away. You're back
in the isr again almost instantly. And this happens continuously. There
is almost no time available to run your main code. The processor is tied
up running the isr over and over again. Your main code (the while loop)
will execute very slowly. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Thu Sep 26, 2013 11:54 pm |
|
|
Great help PCM programmer ... I have changed the isr to execute from 100us to 1ms. Now it displays '0' in the SSD.
Thank you very much.
If possible, can you please post any reference documents about how to calculate instruction cycle.
I'll work on my project and if i'm stuck at any portion, ill post the problem here rather than creating a new thread.
Thank you once again. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Fri Sep 27, 2013 1:51 am |
|
|
How to configure PORT A - pin RA4, pin RA6, RA7 as digital output? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Fri Sep 27, 2013 2:32 am |
|
|
hemnath wrote: | How to configure PORT A - pin RA4, pin RA6, RA7 as digital output? |
You know that surely? Otherwise you wouldn't have included TRISA = 0b00000000;
...But that is not how it is is it? You don't yet understand I/O direction setting and just included the TRISA = 0b00000000; because you saw it somewhere, or someone told you to put it in, which you did, but without understanding why, or what it actually does.
In the same way, you've got timer interrupt flag bit setting in your ISR. Do you understand what that does too? I doubt it.
In fact ALL of the tris and bit setting stuff in your code is either not needed, is redundant or, in the ISR, and much worse, causes real problems.
CCS C normally doesn't need the user to do any tris setting, the compiler will handle that for you. Also you don't need to do any interrupt flag/enable setting, the compiler will do all that for you. All you need is the enable_interrupts(INT_XXXX); for each individual interrupt source followed by enable_interrupts(GLOBAL); to enable interrupts. You've got these, which is good, but only after your bit setting stuff has already enabled timer1 interrupt!
Look at the CCS manual. Learn how it, by default, automatically sets IO direction for you. Massive hint: IO bits are input by default, they are set to output the first time you try to output to them. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Fri Sep 27, 2013 2:46 am |
|
|
It's the 'trying to write assembler in C' style of programming.....
There are so many things:
setup_adc_ports(ALL_ANALOGS);
replaces all the ANSEL stuff.
set_timer_1(value);
replaces the TMR1H/L stuff, etc. etc.
What's posted could be done in less than ten lines, and done better (more likely to actually work...).
However major 'thinking' problems like the interrupt rate, are the other killers...
Best Wishes |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Fri Sep 27, 2013 9:25 pm |
|
|
Hi RF developer,
Thanks for your suggestion.
Yes i know why tris bit settings are used. Actually my problem is, when i configure TRISA = 0b00000000; ... pins - RA4, RA6 are not set as digital output. That's my problem. setting tris bit as 0 for output, 1 - input. Am i right?
@Ttelmah:
I will try to change my code as you suggested and post the results soon. Thank you so much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Sep 27, 2013 10:40 pm |
|
|
Quote: |
How to configure PORT A - pin RA4, pin RA6, RA7 as digital output?
#fuses INTRC
|
Look at the programs posted on this board. You will rarely, if ever, see
this fuse used.
The correct fuse is INTRC_IO. It makes the crystal oscillator pins into
normal i/o pins. This should fix RA6 and RA7.
With regard to RA4, tell us how you are testing this problem. How do you
know that RA4 isn't working as a digital i/o pin ? Make a small test
program and put an LED (with series resistor) on pin RA4 and try to
make it blink.
Also, what is your CCS compiler version ?
------------
Edit: Fixed a typo
Last edited by PCM programmer on Sun Sep 29, 2013 10:46 pm; edited 1 time in total |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Sun Sep 29, 2013 10:43 pm |
|
|
Thanks PCM programmer.
I have changed the fuses to INTRC_IO. Now it is working properly.
my compiler version is 4.114. I'm testing on the hardware.
I have another doubt. I have connected a button to PIN_B0. and B4-B7 to SSD for digit drive.
sample code:
Code: |
int1 DIGIT_FLAG = 1;
int1 UP_FLAG = 1;
#INT_EXT
void ext_interrupt_isr()
{
DIGIT_FLAG = 0;
// clear_interrupt(INT_EXT);
}
#INT_EXT1
void ext_interrupt_isr1()
{
UP_FLAG = 0;
// clear_interrupt(INT_EXT1);
}
void main
{
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT1);
#priority TIMER1, EXT, EXT1
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(1)
{
value1 = (0b00010000 << INCREMENT);
output_b(value1);
if(DIGIT_FLAG == 0)
{
DIGIT_FLAG = 1;
// do something
}
}
} |
When i press the button, DIGIT_FLAG should set as zero and testing a loop in 'while loop'. But nothing happening when i press the button. I know where the logic is wrong. In the line, output_b(value1), i have set pin_b0 as zero which makes the pin permanently low. am i right?
how to use pin B0 as external interrupt and send some other data to output_b() without affecting the PIN B0.
Please help. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Mon Sep 30, 2013 8:45 am |
|
|
Ok.
This is the 'downside' of the default port behaviour.
Basically in CCS, in default mode, if you perform 'output_b', then the whole of port B gets set as an output, which would override the input behaviour wanted for INT_EXT, and INT_EXT1.
There are three basic ways to use the ports in CCS.
1) standard_io. Easy, works 99% of the time. Means you don't have to do anything with TRIS.
2) fast_io. This makes the compiler work like assembler, with the compiler not doing any control of the TRIS, and you having to do it all.
3) fixed_io. Behaves like standard_io, but _you_ specify once what you want the pins to do, and the compiler listens to this.
So if you add the statement:
#use fixed_io(b_outputs=PIN_B4,PIN_B5,PIN_B6,PIN_B7)
near the top of your code (below the processor defines and clock, but before any code), B0, to B3, will be set as inputs, while B4 to B7 will be set as outputs, and this setting will remain in force, allowing the interrupts to work.
Best Wishes |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Mon Sep 30, 2013 10:17 pm |
|
|
Thanks Ttlemah.
#use fixed_io(b_outputs=PIN_B4,PIN_B5,PIN_B6,PIN_B7)
After using this line in the code, i can use external interrupts and also sending output data to port b.
Thank you very much. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Wed Nov 20, 2013 4:45 am |
|
|
when i start to display all 4 digits, LED's are blinking.
Present isr routine takesplace for every 1 ms
I have reduced it to 500us to reduce the blinking action of LEDs. But the problem remains the same.
Do i have to increase the crystal frequency?
Thanks. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Wed Nov 20, 2013 6:49 am |
|
|
You should post your complete program for us as you've probably made several changes.
It's impossible to tell you why 'blinks'. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Wed Nov 20, 2013 9:36 pm |
|
|
segments connected to PORT A. Digits connected to PORT B4 to B7.
Complete code:
Code: | #include "18F2520.h"
#fuses INTRC_IO
#use delay(clock=1000000)
#use fixed_io(b_outputs=PIN_B4,PIN_B5,PIN_B6,PIN_B7)
const char DIGIT_ZERO[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11101110, // d
0b11011110, // e
0b10111110, // f
0b11111110 // g
};
const char DIGIT_ONE[] = {
// gfedcba
0b11111110, // a
0b11111010, // b
0b11110110, // c
0b11111110, // d
0b11111110, // e
0b11111110, // f
0b11111110 // g
};
const char DIGIT_TWO[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11111110, // c
0b11101110, // d
0b11011110, // e
0b11111110, // f
0b01111110 // g
};
const char DIGIT_THREE[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11101110, // d
0b11111110, // e
0b11111110, // f
0b01111110 // g
};
const char DIGIT_FOUR[] = {
// gfedcba
0b11111110, // a
0b11111010, // b
0b11110110, // c
0b11111110, // d
0b11111110, // e
0b10111110, // f
0b01111110 // g
};
const char DIGIT_FIVE[] = {
// gfedcba
0b11111100, // a
0b11111110, // b
0b11110110, // c
0b11101110, // d
0b1111110, // e
0b10111110, // f
0b01111110 // g
};
const char DIGIT_SIX[] = {
// gfedcba
0b11111100, // a
0b11111110, // b
0b11110110, // c
0b11101110, // d
0b11011110, // e
0b10111110, // f
0b01111110 // g
};
const char DIGIT_SEVEN[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11111110, // d
0b11111110, // e
0b11111110, // f
0b11111110 // g
};
const char DIGIT_EIGHT[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11101110, // d
0b11011110, // e
0b10111110, // f
0b01111110 // g
};
const char DIGIT_NINE[] = {
// gfedcba
0b11111100, // a
0b11111010, // b
0b11110110, // c
0b11111110, // d
0b11111110, // e
0b10111110, // f
0b01111110 // g
};
unsigned int16 value = 0, temp_value = 0, value1 = 0, count = 0;
unsigned int16 increment = 0, DIGIT_VALUE = 0;
int1 interrupt_flag = 1;
int1 DIGIT_FLAG = 1;
int1 UP_FLAG = 1;
unsigned int disp_value1, disp_value2, disp_value3, disp_value4;
unsigned int16 DIGIT_VAL;
void display_value();
void digit(int16 DIGIT_VALUE);
#INT_TIMER1
void timer1_isr()
{
if(interrupt_active(INT_TIMER1))
{
interrupt_flag = 0;
count++;
if(count > 6)
{
INCREMENT++;
count = 0;
}
if(INCREMENT > 3)
{
INCREMENT = 0;
}
set_timer1(0xFF05); // 1ms for 1Mhz
clear_interrupt(INT_TIMER1);
}
}
#INT_EXT
void ext_interrupt_isr()
{
DIGIT_FLAG = 0;
}
#INT_EXT1
void ext_interrupt_isr1()
{
UP_FLAG = 0;
}
void main()
{
setup_comparator(NC_NC_NC_NC);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
set_timer1(0xFF05); // 1ms for 1Mhz
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts(INT_EXT1);
#priority TIMER1, EXT, EXT1
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
count=0;
INCREMENT = 0;
DIGIT_VALUE = 0;
while(1)
{
// To display 1234 in Seven segment display
DIGIT_VAL = 1234;
disp_value1 = (DIGIT_VAL%10);
disp_value2 = ((DIGIT_VAL/10)%10);
disp_value3 = ((DIGIT_VAL/100)%10);
disp_value4 = ((DIGIT_VAL/1000)%10);
if(interrupt_flag == 0)
{
if(INCREMENT == 0)
{
value1 = (0b00010000 << 0); // 1st digit
output_b(value1); // power digit 1
DIGIT(disp_value4); //
}
if(INCREMENT == 1)
{
value1 = (0b00010000 << 1);
output_b(value1);
DIGIT(disp_value3);
}
if(INCREMENT == 2)
{
value1 = (0b00010000 << 2);
output_b(value1);
DIGIT(disp_value2);
}
if(INCREMENT == 3)
{
value1 = (0b00010000 << 3);
output_b(value1);
DIGIT(disp_value1);
}
}
}
}
void DIGIT(int16 DIGIT_VALUE)
{
if(DIGIT_VALUE == 0)
{
temp_value = (DIGIT_ZERO[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 1)
{
temp_value = (DIGIT_ONE[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 2)
{
temp_value = (DIGIT_TWO[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 3)
{
temp_value = (DIGIT_THREE[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 4)
{
temp_value = (DIGIT_FOUR[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 5)
{
temp_value = (DIGIT_FIVE[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 6)
{
temp_value = (DIGIT_SIX[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 7)
{
temp_value = (DIGIT_SEVEN[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 8)
{
temp_value = (DIGIT_EIGHT[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
if(DIGIT_VALUE == 9)
{
temp_value = (DIGIT_NINE[count] >> 1);
value = temp_value | 0b00000000;
output_a(value);
}
} |
Display is blinking. How to resolve this issue? Please help!!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Thu Nov 21, 2013 1:30 am |
|
|
Though 'different', using a simple 7segment display, instead of the more complex update approach you are using, look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=51452>
The point made is the same.
You should be updating the segments, in your interrupt. The display wants to update at a steady rate, whatever your main code is doing.
Best Wishes |
|
|
|
|
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
|