1
\$\begingroup\$

I'm using such code on PIC18F25K80 compiled with xc8 compiler:

unsigned long kline_kw1281_byte_time = 0;

void sendKline(void) {
  klineWrite(0x9);
  while (klineBusy());
  kline_kw1281_byte_time = millis();
  while (!klineAvailable()) {
      if (kline_kw1281_byte_time_out()) {
          mStatus = DISCONNECTED;
          while(Busy1USART());
          Write1USART(0x00);
          return;
      }
  }
}


bit kline_kw1281_byte_time_out(void) {
    unsigned long time_out = millis() - kline_kw1281_byte_time;

    if (time_out > 20){
        while(Busy1USART());
        Write1USART(time_out);
        return 1;
    } else
        return 0;
}

and I have strange issue. In kline_kw1281_byte_time_out() function I have true statement for time_out > 20 but Write1USART(time_out) prints me lower number than 20. This happens random. The function most of the time works correctly.

this is millis() code:

#include <p18cxxx.h>
#include "timer0.h"

volatile unsigned long runtime_millis;

void initialize_timer0() {
    T0CON = 0b11000011;
    INTCONbits.TMR0IE = 1;
    INTCON2bits.TMR0IP = 1; //set timer0 interrupt priority high
    INTCONbits.TMR0IF = 0; //reset timer0 interrupt flag
}

void timer0(void) {
    runtime_millis++;
    TMR0L = 8;
    INTCONbits.TMR0IF = 0;
}

unsigned long millis(void) {
    return runtime_millis;
}

void delay(unsigned long ms) {
    unsigned long cTime = runtime_millis;
    while (runtime_millis - cTime < ms);
}
\$\endgroup\$
2
  • \$\begingroup\$ I can't see the problem you stated but I can see one in delay() which can fail when the runtime_millis counter wraps. A compiler can include code that tests the overflag and gives you the wrong answer. Better to use a stepping stone do elapsed = runtime_millis - cTime; while (elapsed < ms);. Also be careful when reading a value which is altered under interrupt, that is larger than a processor register, lest it changes between the multiple memory reads required. Better to disable the interrupt while you read the counter into another variable. \$\endgroup\$
    – Weather Vane
    Commented Feb 13, 2015 at 11:18
  • 1
    \$\begingroup\$ the value of time_out could be changing (perhaps by code in an interrupt thread or similar). Try saving the value of time_out to another variable so that you're sure the value is the same at the time the 'if' test is evaluated as it as when you send the value to the UART. Also if the value is 4 it could be an ASCII '4' which is 52 when it's an integer. '4' > 20 is true in the same way that 'A' > 20. \$\endgroup\$
    – Will
    Commented Feb 19, 2015 at 16:41

1 Answer 1

4
\$\begingroup\$
if (time_out > 20){
    while(Busy1USART());
    Write1USART(time_out);

This writes time_out as ASCII character to the USART module. If you see '4' over the USART, that means the ASCII character '4', real value 0x34, is sent. And 0x34, 52 decimal, is greater than 20.

If you want to print the decimal value as a string to the USART, you can do this:

#define putch Write1USART 

printf("%ul", time_out);

The printf() function formats time_out as an unsigned long (hence %ul) and writes it byte by byte to putch(). putch() should therefore have the signature:

void putch(unsigned char);

The #define in the example above makes sure Write1USART() is used for putch().

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.