|
|
View previous topic :: View next topic |
Author |
Message |
cobfan Guest
|
printf problem on 16f819(maybe general) |
Posted: Thu May 26, 2005 4:11 pm |
|
|
hi all,
first of all i must say i am almost new to programming the pic in c(used to do it on assembler before but the floating point math made me turn to c!).
Anyway my problem is that the following code doesn't print numbers correctly!
Code: |
#byte SW=0x70
#byte SS=0x71
int IPC=0,ADCNT=125,dotpos=0,dspout[4]={0,0,0,0};
int sts=0,dsp_cnt=0;
int const digits[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
#bit rst=sts.0
int init(void);
void putc_7sg(char);
void main(void)
{
int cal;
float result;
cal=init();
while(1)
{
result=read_adc(ADC_READ_ONLY);
result*=0.707;
printf(putc_7sg,"%05.1f",result);
rst=1;
while(!go_done);
}
}
int init(void)
{
int ee_val;
set_tris_a(0x21);
set_tris_b(0xC0);
port_b_pullups(TRUE);
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
SSPCON=0;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,125,1);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
ee_val=read_eeprom(0);
if(ee_val==0xFF)
{
printf(putc_7sg,"0123");
rst=1;
while(ra5);
ee_val=read_adc(ADC_START_AND_READ);
write_eeprom(0,ee_val);
}
read_adc(ADC_START_ONLY);
}
void putc_7sg(char c)
{
int i;
if(c!='.')
dspout[dsp_cnt++]=digits[c-48];
else
{
dotpos=1;
for(i=dsp_cnt-1;i>0;i--)
dotpos<<=1;
}
if(rst==1)
{
dsp_cnt=0;
dotpos=0;
rst=0;
}
}
|
The contents of dspout string are printed to 4-7seg displays by the tmr2 interrupt which is written in assembler and to long and nothing important to mention here. It occurs every 2 msecs and prints dspout[0] to first 7seg, dspout[1] to second 7seg... in order and one at a time everytime it occurs and also starts the adc everytime after the 4 digits are printed.
The printf(putc_7sg,"0123"); in function init which occurs first in execution of the program prints everyting ok. The numbers 0123 are displayed on 7seg displays correctly. But the printf in main prints float variable result like this:
if result is 241.2 for example it is printed like 2241.
and when i tried to print with "%05.2f" the result is like that:
if result is 36.47 for example it is printed like 736.4
everytime the last number is printed first. My version is 3.222 and I don't think this is a compiler bug but i also can't find my own bug. How can the first printf print ok but the last don't if it is my own bug.
I don't have any avaible pin on pic and hardware at the time to try it on rs232. Any help is appreciated, thnx to you all for your time... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 26, 2005 4:40 pm |
|
|
I didn't look at your main problem, but I immediately see a potential
problem at the top of your code. You have got these two values:
Code: | #byte SW=0x70
#byte SS=0x71 |
I'm not sure what those are, because in the 16F819 those are RAM
locations, near the end of bank 0.
If those are supposed to be globals, you probably should have
just used int8 to declare them.
The problem is that #byte does not protect the specified RAM address
from use by the compiler. The compiler could assign other variables
to addresses 0x70 and 0x71. To prevent this, you should use #locate
instead of #byte.
Look at the program below. If I compile it with PCM vs. 3.224 and look
at the symbol map, the variable "c" is at 0x21. Now if I add "byte SW =
0x21", recompile and look at the symbol map, SW and "c" share the
same location. If you do this, you risk unexpected program behavior.
Code: | #include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#byte SW = 0x21
//===================
void main()
{
char c;
c = 0x55;
SW = 0xAA;
while(1);
} |
|
|
|
bfemmel
Joined: 18 Jul 2004 Posts: 40 Location: San Carlos, CA.
|
|
Posted: Thu May 26, 2005 4:51 pm |
|
|
Well let me try. Inside the putc_7sg() routine you have the test for rst==1 after you put the first byte into dspout[] so you won't reset dsp_cnt until after you have used it as an index into the array. Only the first time through the routine will dsp_cnt be the correct value of 0;
You also have init() retuning an int value and even assign it to the vairable "cal" but there is no return statement in the init() routine. so what gets returned?
Tell me if I win the cupie doll or if I just goofed.
- Bruce |
|
|
cobfan Guest
|
|
Posted: Thu May 26, 2005 7:23 pm |
|
|
thnx to u all for your replies.
SW & SS are save registers for the interrupt routine. SW for work and SS for status. I wanted them to be on 0x70 & 0x71 because I wanted them to be accessible from all banks as the int routine may need to use them at any bank. But as I said before I'm new to programming pic in c so I couldn't realise that i should use the #locate preprocessor to declare them. Thnx for that very important detail pcm_programmer. But that didn't solve my problem.
Before, I tried resetting the dsp_cnt by something like
printf(putc_7sg,"%05.1f\n");
and trying to detect the '\n' character but '\n' didn't seem detectable so I declared a reset bit to check and detect that printf is finished. I'm sorry I didn't understand what you meant bfemmel. dsp_cnt should be 0 everytime after the printf function does its job.
Also I pasted the code from the .bak file so my correction for init function wasn't included. Sorry for this mistake of mine. Init returns the value ee_val.
And also adc is used as 10bit but is equelled to an int8 value but I know the upper byte read is lost and that's what I needed.
thnx again for your replies.
Best wishes... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu May 26, 2005 7:40 pm |
|
|
Quote: | And also adc is used as 10bit but is equelled to an int8 value but I
know the upper byte read is lost and that's what I needed. |
You should read the forum daily when you're learning CCS.
This question or a related one is asked about once a week.
http://www.ccsinfo.com/forum/viewtopic.php?t=23040&highlight=device+adc |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu May 26, 2005 8:33 pm |
|
|
cobfan wrote: | thnx to u all for your replies.
SW & SS are save registers for the interrupt routine. SW for work and SS for status. I wanted them to be on 0x70 & 0x71 because I wanted them to be accessible from all banks as the int routine may need to use them at any bank. But as I said before I'm new to programming pic in c so I couldn't realise that i should use the #locate preprocessor to declare them. Thnx for that very important detail pcm_programmer. But that didn't solve my problem.
Before, I tried resetting the dsp_cnt by something like
printf(putc_7sg,"%05.1f\n");
and trying to detect the '\n' character but '\n' didn't seem detectable so I declared a reset bit to check and detect that printf is finished. I'm sorry I didn't understand what you meant bfemmel. dsp_cnt should be 0 everytime after the printf function does its job.
Also I pasted the code from the .bak file so my correction for init function wasn't included. Sorry for this mistake of mine. Init returns the value ee_val.
And also adc is used as 10bit but is equelled to an int8 value but I know the upper byte read is lost and that's what I needed.
thnx again for your replies.
Best wishes... |
The compiler handles saving the status and Wreg unless you write you own interrupt handler. I didn't see any interrupt code so if you wrote you own, chances are that you are not saving enough registers. |
|
|
cobfan Guest
|
|
Posted: Thu May 26, 2005 8:35 pm |
|
|
This wasn't a question. I'm sorry if I wrote it like a question but I just wanted to give information in case that somebody realises that I use an int8 for a 10bit adc. That isn't anything important nevermind.
Anyway I replaced the following code for the putc_7sg function and got some progress.
Code: |
void putc_7sg(char c)
{
if(c=='.')
dotpos<<=dsp_cnt-1;
else if(c=='\n') {
dsp_cnt=0;
dotpos=1;
}
else
dspout[dsp_cnt++]=digits[c-48];
}
|
and using printf function like
printf(putc_7sg,"%05.1f\n",result);
I still don't know what was the problem with my previous code but this code solved the sequence problem. But I can't still get dot to correctly appear on the display. The dotpos variable should contain the dot position as a 1 on it like
dotpos=b'00000100'
adresses to the third 7seg display to print it but I don't know whats wrong with dotpos. thnx...
Best wishes... |
|
|
bfemmel
Joined: 18 Jul 2004 Posts: 40 Location: San Carlos, CA.
|
|
Posted: Fri May 27, 2005 8:49 am |
|
|
Quote: | I still don't know what was the problem with my previous code but this code solved the sequence problem. |
The problem was with the way that you reset the dsp_cnt array index. Since you used a post increment on the assignment and started the program with the variable set to 0, then the first time you printed your "0123" the variable dsp_cnt gets left at a value of 4, one past the end of your array! Then you don't reset it until after you have used the index in the putc_7sg(char c) to make the first index assingment into your array so that number is actually placed outside of your array somewhere at dspout[4] , where ever that is! By changing the code to use the line feed, you automatically reset the dsp_cnt variable after you are done with it instead of waiting. You could have done the same thing by moving the test for rst to the front of the old routine.
I am not sure of the problem with the radix yet.
Good Luck on this.
- Bruce |
|
|
cobfan Guest
|
|
Posted: Fri May 27, 2005 5:55 pm |
|
|
Now I got the point bfemmel. You're right the index is cleared after the 2. printf's first call. I should have checked the rst flag first. Anyway this way is much better I think. Also I have solved the radix problem by directly manipulating the output data.
By the end thank to you all for your replies and time.
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
|