Embedded C - timer0 and ADC problem

Thread Starter

anon1

Joined Jan 25, 2018
13
Language: C.

Info:

PicKit 3.

PIC18F1220.

Master clock is 10 MHz.

10-bit ADC.

Using timer0 (16-bit mode). The maximum number of combinations on timer0 is 65536.

RB2/INT2 is set as an input.

A potentiometer is connected to RA0/AN0.

RB1 is generating a waveform on a display segment.

The PIC18F1220 that I'm programming is connected to a PIC16F684 that has a built-in program that has a toothed wheel simulator and generates sync pulses once per the revolution of the toothed wheel. The RPM can be adjusted with switches, thus changing the intervals at which the sync pulses go high.

Goals:

1. (achieved) Detect the rising edge of incoming sync pulse that is generated by the other PIC (PIC16F684 with built-in program). This is being detected on input pin RB2/INT2.

2. (partially achieved) Every time a rising edge is detected on RB2, the display segment that is connected to RB1 should light up and stay high for X ms, then stay turn off until the next time a rising edge is detected on RB2. This duration X is to be adjustable depending on the potentiometer that is connected to RA0/AN0. The range should be between 0.25 ms and 4 ms depending on the setting of the potentiometer.

Result:
According to an oscilloscope, my program seems to detect each incoming rising edge on RB2 and the time that the display segment stays high for is adjustable depending on the pot setting, but it is adjustable between about 4.4 ms and 0.75 ms instead of between 4 ms down to 0.25 ms. It works in principle but I need to get the correct range.

When I tried to get the 0.25 ms delay by bypassing the AD conversion, and feeding the corresponding number directly into tmr0, it does stay on for 0.25 ms, as expected. I suspect that the problem might have something to do with the AD conversion currently only reading ADRESH and supposedly ignoring whatever is in ADRESL and the problem seems to become more noticeable the shorter a delay I'm trying to achieve here (adding 0.4 ms to 4 ms is not as noticeable as adding it to 0.25 ms). Unless I use larger delays, it seems to add/remove something that causes the number that is fed into the timer not to match up with the range - when I check my calculations in Excel, they do match up with the desired range. I have previously tried to use While loops to detect the incoming rising edges instead of interrupts and the result was the same, inaccurate, range. However, when I change the calculations so that the smallest duration X is 250 ms instead of 0.25 ms, it does seem to get the range that would be expected. This suggests that it could be something to do with the least significant bits as when the desired delay is 250 ms or higher, to have 0.4 ms added in the background won't make a noticeable difference, but adding 0.4 ms to 0.25 ms does make a big difference. Any idea how I could solve this problem and get a more precise range between 4 ms and 0.25 ms (or 0.25 ms to 4 ms, depending on whether I want to go from high to low or low to high)?
 
Last edited:

Thread Starter

anon1

Joined Jan 25, 2018
13
I will try this out with the MPLABX simulator but it won't be until Friday afternoon if you can wait that long?
Thanks but hoping someone will be able to take a look sooner than that.

Do you, or anyone else reading this, know how, rather than just reading the MSBs from the ADC, as currently, I could also include what's in ADRESL and hopefully get a more accurate reading that way? It might not solve my problem, but worth a try if there's a way to do read all 10 bits of the ADC.
Normally the 8 MSBs would suffice but seemingly not in this particular case, as the consequences of dropping the LSBs seem to be more noticeable now that the shortest delay needs to be so small. Is there an easy way to include whatever is stored in ADRESL as it's currently only returning the value that's in ADRESH?
 

danadak

Joined Mar 10, 2018
4,057
Hopefully the compiler interprets the *256 as

analog_reading= ADRESL + (ADRESH<<8);

You may need to cast both to int16....before addition.


Regards, Dana.
 

Thread Starter

anon1

Joined Jan 25, 2018
13
After further analysis, I have found that the value that the interrupt writes into timer0 seems to add between 253 and 293 [i.e. WriteTimer0((65536-timer_value))+293)]. I don't think the fact I've been ignoring ADRESL would explain this. It seems that the variable is picking up another reading at some point and adding it, but where might this be coming from? If the difference was always 293, I would simply have subtracted it from the variable but unfortunately the difference between the expected result and the actual result varies between 253 and 293 and then goes down to 255.

0.00025 s - calculated result: 65527, actual number fed into timer0 to cause this delay (based on tests): 65275.
0.0004 s - calculated result: 65520, actual number fed into timer0 to cause this delay: 65265.
0.0015 s - calculated result: 65477, actual number fed into timer0 to cause this delay: 65185. Difference: -292 (presumably this means that it adds this in the background).
0.004 s - calculated result: 65438, actual number fed into timer0 to cause this delay: 65125.
 
Last edited:

danadak

Joined Mar 10, 2018
4,057
Sounds like a mix of signed and unsigned variables getting
mixed. Possibly mixing uint8 and uint16 as well.

Cast everything to make sure sign bits and type are preserved. Or
at minimum look at header files for type definition to make sure
you do not rely on compiler doing the right thing with various variable
types. You can do some quick tests to check compiler consistency.


Regards, Dana.
 

Thread Starter

anon1

Joined Jan 25, 2018
13
Sounds like a mix of signed and unsigned variables getting
mixed. Possibly mixing uint8 and uint16 as well.

Cast everything to make sure sign bits and type are preserved. Or
at minimum look at header files for type definition to make sure
you do not rely on compiler doing the right thing with various variable
types. You can do some quick tests to check compiler consistency.
Regards, Dana.
Thanks. Seems to be working now.
 
Top