This doesn't answer your question, but might make the code a little easier for you to debug. The case statements are really long and may not be the best way to explain what you are doing with your outputs. I make no guarantees that the code is operational (I have not run it at all), but this should get you thinking about file size and readability.
Your singleminutes case statement has a truth table like this:
// | out
// in| 0 1 2 3 4
// ---------------
// 0 | 0 0 0 0 0
// 1 | 0 1 0 0 0
// 2 | 0 1 1 0 0
// 3 | 0 1 1 1 0
// 4 | 0 1 1 1 1
which might be better represented with output-centric code like this:
if (singleminutes >= 1)
PPEins = 1;
else
PPEins = 0;
if (singleminutes >= 2)
PPZwei = 1;
else
PPZwei = 0;
if (singleminutes >= 3)
PPDrei = 1;
else
PPDrei = 0;
if (singleminutes >= 4)
PPVier = 1;
else
PPVier = 0;
The nfminutes is a little more complicated, but here is the Truth Table:
// | MHUhr PMFuenf PMZehn PMViertel PMZwanzig PMVor PMNach PMHalb | |
// --|--------------------------------------------------------------|--------|-----
// 0 | 1 0 0 0 0 0 0 0 | 1000 0 | 000
// 1 | 0 1 0 0 0 0 1 0 | 0100 0 | 010
// 2 | 0 0 1 0 0 0 1 0 | 0010 0 | 010
// 3 | 0 0 0 1 0 0 1 0 | 0001 0 | 010
// 4 | 0 0 0 0 1 0 1 0 | 0000 1 | 010
// 5 | 0 1 0 0 0 1 0 1 | 0000 0 | 101
// 6 | 0 0 0 0 0 0 0 1 | 0000 0 | 001
// 7 | 0 1 0 0 0 0 1 1 | 0100 0 | 011
// 8 | 0 0 0 0 1 1 0 0 | 0000 1 | 100
// 9 | 0 0 0 1 0 1 0 0 | 0001 0 | 100
//10 | 0 0 1 0 0 1 0 0 | 0010 0 | 100
//11 | 0 1 0 0 0 1 0 0 | 0100 0 | 100
and again some output-centric code:
// MHUhr PMFuenf PMZehn PMViertel PMZwanzig
if( nfminutes == 0 )
MHUhr = 1;
else
MHUhr = 0;
if(( nfminutes == 1 ) || (nfminutes == 5) || (nfminutes == 7) || (nfminutes == 11))
PMFuenf = 1;
else
PMFuenf = 0;
if(( nfminutes == 2 ) || (nfminutes == 10) )
PMZehn = 1;
else
PMZehn = 0;
if(( nfminutes == 3 ) || (nfminutes == 9) )
PMViertel = 1;
else
PMViertel = 0;
if(( nfminutes == 4 ) || (nfminutes == 8) )
PMZwanzig = 1;
else
PMZwanzig = 0;
// PMVor PMNach PMHalb
if( ((nfminutes >= 1 ) && (nfminutes <= 4 )) || (nfminutes == 7))
PMNach = 1;
else
PMNach = 0;
if( (nfminutes >= 5) && (nfminutes <= 7 )
PMHalb = 1;
else
PMHalb = 0;
if(nfminutes >=8)
PMVor = 1;
else
PMVor = 0;
The code above might do well with some #defines too
#define UHR 0
#define PHUENF_NACH 1
#define ZEHN_NACH 2
...
if(nfminutes == UHR)
Again for hours. Truth Table:
| 12 1 2 3 4 5 6 7 8 9 10 11
//----|------------------------------------
// 0 | 1 0 0 0 0 0 0 0 0 0 0 0
// 1 | 0 1 0 0 0 0 0 0 0 0 0 0
// 2 | 0 0 1 0 0 0 0 0 0 0 0 0
// 3 | 0 0 0 1 0 0 0 0 0 0 0 0
// 4 | 0 0 0 0 1 0 0 0 0 0 0 0
// 5 | 0 0 0 0 0 1 0 0 0 0 0 0
// 6 | 0 0 0 0 0 0 1 0 0 0 0 0
// 7 | 0 0 0 0 0 0 0 1 0 0 0 0
// 8 | 0 0 0 0 0 0 0 0 1 0 0 0
// 9 | 0 0 0 0 0 0 0 0 0 1 0 0
// 10 | 0 0 0 0 0 0 0 0 0 0 1 0
// 11 | 0 0 0 0 0 0 0 0 0 0 0 1
and code. Slightly different structure with all outputs being cleared, then only the correct output turned on.
// one-hot, clear all will not cause a glitch
PHZwoelf = 0;
PHEins = 0;
PHZwei = 0;
PHDrei = 0;
PHVier = 0;
PHFuenf = 0;
PHSechs = 0;
PHSieben = 0;
PHAcht = 0;
PHNeun = 0;
PHZehn = 0;
PHElf = 0;
if( hours == 0 )
PHZwoelf = 1;
if( hours == 1 )
PHEins = 1;
if( hours == 2 )
PHZwei = 1;
if( hours == 3 )
PHDrei = 1;
if( hours == 4 )
PHVier = 1;
if( hours == 5 )
PHFuenf = 1;
if( hours == 6 )
PHSechs = 1;
if( hours == 7 )
PHSieben = 1;
if( hours == 8 )
PHAcht = 1;
if( hours == 9 )
PHNeun = 1;
if( hours == 10 )
PHZehn = 1;
if( hours == 11 )
PHElf = 1;
All this also allows you to do your input calculations together before your case statements.
// update single minutes
int singleminutes = (int) (unbcd(tm.min)%5); // 1, 2, 3, 4
// update 5 minutes
int nfminutes = (int) (unbcd(tm.min)/5); // Fuenf Nach, Zehn Nach, ...
// update hours
int hours = (int) (unbcd(tm.hour)%12); // 12, 1, 2, 3, 4...
if(nfminutes>=5) hours++; // 7:25 = Fuenf Vor Halb Acht (8)
Even when using a compiler, you need to read the PIC datasheet. If I remember right, the C18 compiler considers the access bank NEAR and banked memory FAR. Whether a variable is in near or far memory should have no effect on the logic of the program, but accessing near memory can take less cycles and instruction words.
Your statement "I did allocation additional memory for udata DATA on the PIC 18F4520 linker" makes no sense. First, the english is so bad it's unclear what you really mean. Second, messing with the linker file is only for when you know exactly what you are doing. You can't magically make more memory by lying to the linker. That will only make it so the linker can't tell that you've overflowed a memory region. The PIC still has the memory regions it has no matter what you tell the linker. The default linker file should contain memory regions that cover all of useful memory.
Another pitfal when messing with RAM layout in the linker file is that if you let a memory region cross a bank boundary, some multi-byte structure or variable can then get placed accross that bank boundary. If the compiler assumes the structure is wholly on one bank, it could produce incorrect code for accessing parts of it. There are ways around this if you need large arrays, but that's a advanced concept not worth getting into unless that is actually your problem.
Also, do you really need double precision floating point? Unless you have a very unusual application, the answer is no.
Best Answer
You are not setting the clock signal of the ADC to 32MHz. The parameter
ADC_FOSC_32
divides the clock by 32 (see page 225 of the datasheet). This ensures, together with the aquisition time select bits (ADC_4_TAD
in your case), the minimum (/maximum) A/D aquisiton time (see page 359). When you hurt these requirements you will not get valid/accurate results.With the equations given on page 228 you can do the math and verify, that the requirements are met.
Some other points:
ConvertADC
.a
as output by settingTRISA = 0x0;
but you want it to be configured as input (as your comment is saying).TRISA = 0xFF;
would configure all pins on port a as input.To expand a bit on the aquisiton time (\$T_{AD}\$): This time is needed for the internal circuitry to probably charge. When this time is too short, you will get no/bad results.
For 32Mhz (without divisor) \$T_{AD}\$ would be 31ns. That is too fast. At least 0.7us are required for the ADC to work probably. So you select a proper divisor to get \$T_{AD}\$ above 0.7us. A divisor of 32 will do it here, \$T_{AD} = 1\$us > 0.7us.