CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

NEC decoding, weird UART problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Liam_85



Joined: 09 Nov 2014
Posts: 26
Location: Ireland

View user's profile Send private message

NEC decoding, weird UART problem
PostPosted: Fri Feb 27, 2015 9:29 pm     Reply with quote

Hi everybody. I have a weird problem with a UART that is baffling me. I am using a PIC12F1840 to decode NEC IR and send the decoded info to a PIC24HJ128GP502. There is seven buttons on the IR remote and all of them are decoded and sent to the PIC24 immediately. What is received at the PIC24 is -
select, play/pause, menu, left, right, up & down.
So then i decided to just send one char for each button instead of a string or multiple chars so i send -
s, m, p, l, r, u, d (select, menu, play/pause, left, right, up, down). All of them work fine except s and p. For some reason when i press either of these two buttons it sends the corresponding char and then the uC wont respond for approx 13 seconds for each case.
This is a basic version of the program;
Code:
#fuses INTRC_IO       // INTOSC oscillator: I/O function on CLKIN pin
#fuses PROTECT        // Code protected from reading
#fuses MCLR           // MCLR/VPP pin function is MCLR; Weak pull-up enabled
#fuses NOIESO         // Internal/External Switchover mode is disabled
#fuses NOLVP          // High-voltage on MCLR must be used for programming
#fuses NOFCMEN        // Fail-Safe Clock Monitor is disabled
#fuses NOCLKOUT       // CLKOUT function is disabled. I/O function on the CLKOUT pin
#fuses NOPUT          // Power up timer disabled
#fuses NODEBUG        // In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins
#fuses BORV19         // Brown-out Reset voltage set to 1.9V
#fuses NOSTVREN       // Stack Overflow or Underflow will not cause a Reset


#use delay(internal=4MHz)                   // 4MHz xtal
#use rs232(UART1, baud = 19200, xmit = PIN_a4, rcv = PIN_a5, bits=8, errors)

void decode(){
   for (i=16; i<=23; i++) {
      if ((ONE_MIN <= irframes[i]) && (ONE_MAX >= irframes[i]))
         bits[i] = 0x01;
      if ((ZERO_MIN <= irframes[i]) && (ZERO_MAX >= irframes[i]))
         bits[i] = 0x00;
      //printf("%4u", bits[i]);
   }
   mask = 0x01;
   for (i=16; i<=23; i++) {
      if (bits[i])
         data = data | mask;
      mask <<= 1;
   }
}


And the send function;
Code:

void send_code(){
   if(data == 0x02)
      putc('m');
   else if(data == 0x5E)
      putc('p');
   else if(data == 0x5D)
      putc('s');
   else if(data == 0x08)
      putc('l');
   else if(data == 0x07)
      putc('r');
   else if(data == 0x0B)
      putc('u');
   else if(data == 0x0D)
      putc('d');     
}

The weird part is if I change putc('s'); or printf("s"); to printf("Select"); and putc('p'); or print("p"); to printf("Play/pause"); they print immediately. Also if i un-comment the line
Code:
printf("%4u", bits[i]);

it prints bits[i] and 's' or 'p' immediately. Any thoughts because this is really annoying me. Thanks in advance for the help.
_________________
Liam Hanmore


Last edited by Liam_85 on Sat Feb 28, 2015 10:13 am; edited 1 time in total
Liam_85



Joined: 09 Nov 2014
Posts: 26
Location: Ireland

View user's profile Send private message

PostPosted: Fri Feb 27, 2015 10:27 pm     Reply with quote

Thank you PCM programmer for your reply. The capital letters just happened to be the way i wrote it. I have tried lower case, capitalized numbers all sorts and its always them two that causes the problem. I was just looking at what gets decoded, for m, l, r, u and d is all low numbers, 0x02, 0x08, 0x07, 0x0b and 0x0d respectively and for p and s, 0x5e & 0x5d respectively. I am wondering if this might have anything to do with the problem by I cant see why this may be.
I placed a printf(" ") in this bit of code and it worked perfectly
Code:

   for (i=16; i<=23; i++) {
      if ((ONE_MIN <= irframes[i]) && (ONE_MAX >= irframes[i])){
         bits[i] = 0x01;
      }
      if ((ZERO_MIN <= irframes[i]) && (ZERO_MAX >= irframes[i])){
         bits[i] = 0x00;
      }
      printf(" ");


which baffles me why it makes it work correct.
_________________
Liam Hanmore
Liam_85



Joined: 09 Nov 2014
Posts: 26
Location: Ireland

View user's profile Send private message

PostPosted: Fri Feb 27, 2015 10:50 pm     Reply with quote

Sorry PCM programmer i must of deleted your post by accident, I really should go to sleep!!! Anyways I used
Code:

   for (i=16; i<=23; i++) {
      printf("%Lu ", irframes[i]);
   }

to print out what comes in every time just before
Code:

   for (i=16; i<=23; i++) {
      if ((ONE_MIN <= irframes[i]) && (ONE_MAX >= irframes[i])){
         bits[i] = 0x01;
      }
      if ((ZERO_MIN <= irframes[i]) && (ZERO_MAX >= irframes[i])){
         bits[i] = 0x00;
      }

and also printed the result in the send_code() function. This is what i got;

551 1625 557 533 527 527 527 527 m
521 1649 551 557 551 557 533 527 m
527 1625 557 551 551 527 527 557 m

533 521 521 1631 527 527 527 533 l
557 551 527 1625 527 533 527 521 l
551 527 527 1631 527 527 527 527 l

1625 1625 527 1625 557 551 551 557 u
1631 1631 533 1655 551 551 527 527 u
1655 1655 521 1655 557 533 527 527 u

1631 1631 1625 527 533 527 527 533 r
1631 1631 1631 533 527 527 533 527 r
1625 1631 1631 551 527 533 527 527 r

1625 527 1625 1655 551 557 551 557 d
1655 557 1631 1655 527 533 527 527 d
1631 527 1625 1625 527 527 527 527 d

1625 527 1631 1631 1631 527 1625 527 S
1625 557 1631 1631 1631 533 1631 527 S
1619 551 1655 1625 1631 527 1625 527 S
1625 527 1631 1625 1625 551 1655 557 S

527 1631 1619 1625 1625 521 1625 533 P
533 1631 1625 1655 1625 527 1631 527 P
533 1631 1631 1631 1619 551 1655 527 P
527 1625 1631 1631 1631 533 1631 527 P

You can see every time it decodes the correct char. But when printf("%Lu ", irframes[i]); is removed its back to 'p' and 's' not working.
_________________
Liam Hanmore
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Sat Feb 28, 2015 1:57 am     Reply with quote

You don't post enough to be really sure what is going wrong, but notice the pattern. The two characters giving you the problem, are the only ones that have bits set in the high nibble of the value. Suggests that the decode is going wrong when this is the case. Possibly starting the 'next' decode at the wrong level for example, and the delays associated with adding extra printing are allowing it to recover.
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Feb 28, 2015 6:33 am     Reply with quote

just jumping in here....but...

..then the uC wont respond for approx 13 seconds for each case.


some ideas...

I don't see a NOWDT fuse option at the top, maybe the default is WDT enabled and it's timing out, resetting the PIC ?

13 seconds sounds like the secondary oscillator is running( if the PIC has one),maybe cause the WDT tripped ,so PIC goes slow,then regular speed?


just thinking out loud....


Jay
Liam_85



Joined: 09 Nov 2014
Posts: 26
Location: Ireland

View user's profile Send private message

PostPosted: Sat Feb 28, 2015 10:12 am     Reply with quote

Thanks Temtronic and Ttelmah for your replies. Temtronic I actually forgot to put in that fuse but I checked the assembly file and NOWDT was in the fuses at the end. Also I am not using any external oscillator just internal.
Ttelmah I was thinking about what you said about the decode process going wrong with just these two key presses. So I went back searching online and I think I came across the problem, https://hifiduino.wordpress.com/apple-aluminum-remote/ states that when the buttons are pressed this is what is received;
Menu EE 87 02 59
Right EE 87 07 59
Left EE 87 08 59
Down EE 87 0D 59
Up EE 87 0B 59

Select EE 87 5D 59 followed by EE 87 04 59 and
Play/pause EE 87 5E 59 followed by EE 87 04 59.

I didn't realize that the select and play/pause had extra info until now so I am just using a small delay after the first 4 bytes has been received to discard the next 4 bytes.
Anyhow, I don't like uploading a long list of code but I am uploading it so that maybe I can help somebody in decoding NEC IR since there was not a lot of info about it. Although there is tons of info about SIRC or RC5 this is slightly different. Also Apples version of this NEC IR is a slightly different version to what can be found on Google but it can easily be modified for your application.

Code:

#include <12f1840.h>

#fuses NOWDT
#fuses INTRC_IO       // INTOSC oscillator: I/O function on CLKIN pin
#fuses PROTECT        // Code protected from reading
#fuses MCLR           // MCLR/VPP pin function is MCLR; Weak pull-up enabled
#fuses NOIESO         // Internal/External Switchover mode is disabled
#fuses NOLVP          // High-voltage on MCLR must be used for programming
#fuses NOFCMEN        // Fail-Safe Clock Monitor is disabled
#fuses NOCLKOUT       // CLKOUT function is disabled. I/O function on the CLKOUT pin
#fuses NOPUT          // Power up timer disabled
#fuses NODEBUG        // In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins
#fuses BORV19         // Brown-out Reset voltage set to 1.9V
#fuses NOSTVREN       // Stack Overflow or Underflow will not cause a Reset


#use delay(internal=4MHz)                   // 4MHz xtal
#use rs232(UART1, baud = 19200, xmit = PIN_a4, rcv = PIN_a5, bits=8, errors)

#byte T1CON = getenv("SFR:T1CON")            // Get T1CON address
#bit  TMR1ON = T1CON.0                       // Set T1CON run/stop bit
#byte TMR1H = getenv("SFR:TMR1H")            // Get timer 1 addr

#define timer1_start() TMR1ON = 1;  // Define TMR1ON start
#define timer1_stop() TMR1ON = 0;   // Define TMR1ON stop
#define lead_max  9250              // NEC lead condition is 9ms
#define lead_min  9250
#define start_max 4750              // NEC start condition is 4.5ms
#define start_min 4250

#define ONE_MAX   1850              // '1' high time is 1.675ms
#define ONE_MIN   1550
#define ZERO_MAX  700         // '0' high time is 0.562ms
#define ZERO_MIN  400   

int16 IRframes[32];        // 4 bytes received, only the 3rd byte containing data
int16 x = 0, y = 0, lead, space;
int8 i=0;                  // irframes counter
int8 bits[8];              // Array to hold 1s or 0s before decoding
int8 data;                 // Decoded data
int8 mask;                 // Mask for shifting in data

void init(){               // Reset all variables
   delay_ms(100);
   lead=0;
   space=0;
   data=0;
   mask=0;
   i=0;
   x=0;
}

void wait_for_high_to_low() {
   while(!input(PIN_A2)) ;       // If it's low, wait for a high
   delay_us(3);                  // Account for rise time */
   while(input(PIN_A2));         // Wait for signal to go low
}

void wait_for_high() {
   delay_us(3);                 /* account for rise time */
   while(!input(PIN_A2));        /* wait for signal to go high */
}

int16 detect_lead(){
   int16 lead;
   wait_for_high_to_low();
   set_timer1(0);
   wait_for_high();
   timer1_stop();
   y = get_timer1();
   lead=y;
   timer1_start();
   return lead;
}

int16 detect_space(){
   wait_for_high_to_low();
   timer1_stop();
   x = get_timer1();
   return (x-y);
}

void detect_bits(){
   while(i < 32){                // Get all 32 bits
      wait_for_high();           // Wait for next low to high transition
      set_timer1(0);             // Initialise timer to 0
      timer1_start();            // Start the timer
      wait_for_high_to_low();    // Wait for next high to low transition
      timer1_stop();             // Stop the timer
      irframes[i] = get_timer1();   // Get the timer ticks value and store it in irframes[i]
      i++;                       // Increment i
   }
}

void decode(){
   for (i=16; i<=23; i++)           // Discard all info except the data, the 3rd byte
      if ((ONE_MIN <= irframes[i]) && (ONE_MAX >= irframes[i])){     // Check if the value from timer is approx 1.675ms
         bits[i] = 0x01;                                             // If it is then it was a '1'
      }
      if ((ZERO_MIN <= irframes[i]) && (ZERO_MAX >= irframes[i])){   // Check if the value from timer is approx 0.562ms
         bits[i] = 0x00;                                             // If it is then it was a '1'
      }
   }
   delay_ms(60);           // Discard Select & play/pause second round of 4bytes
   mask = 0x01;                  // Set mask = 1
   for (i=16; i<=23; i++) {     
      if (bits[i])               // If the data in bits[i] = 1 then add a '1' in this position else just skip this position leaving a 0 in it
         data = data | mask;
      mask <<= 1;                //
   }
}

void send_code(){         
   if(data == 0x5E)   // If data decoded is 0x5E (play/pause) send 'p'
      putc('p');
   else if (data == 0x5D)  // If data decoded is 0x5D (select) send 's'
      putc('S'); 
   else if(data == 0x02)        // If data decoded is 0x02 (menu) send 'm'
      putc('m');
   else if(data == 0x08)   // If data decoded is 0x08 (left) send 'l'
      putc('l');
   else if(data == 0x07)   // If data decoded is 0x07 (right) send 'r'
      putc('r');
   else if(data == 0x0B)   // If data decoded is 0x0B (up) send 'u'
      putc('u');
   else if(data == 0x0D)   // If data decoded is 0x0D (down) send 'd'
      putc('d');
}

void main(){
   disable_peripherals();
   enable_peripherals();
   VREGPM=1;      // Low Power Sleep mode enabled in Sleep
   SETUP_TIMER_1(T1_INTERNAL | T1_DIV_BY_1);       // Use timer 1 div by 1 to count ticks
   while(true)
   { 
      init();                                      // Reset variables
      lead = detect_lead();                        // Detect lead condition
      if(lead_min <= lead <= lead_max){            // If lead is approx 9ms enter
         space = detect_space();                   // Detect space condition
         if(start_min <= space <= start_max){      // If space is approx 4.5ms then IR frame received so detect and decode
            detect_bits();                         // Detect the 4 bytes of info,
            decode();                              // Decode the data
            send_code();                           // Send the data

         }
      }     
   }
}

_________________
Liam Hanmore
Ttelmah



Joined: 11 Mar 2010
Posts: 19518

View user's profile Send private message

PostPosted: Sat Feb 28, 2015 10:15 am     Reply with quote

Well done. Glad I was on the right lines, it was just a 'pattern' I saw in what was happening, and extra data would of course explain it!... Smile

On the watchdog, this is a 'be careful' one, with some chips defaulting to watchdog on, and others defaulting to off. Designed to catch you....
Liam_85



Joined: 09 Nov 2014
Posts: 26
Location: Ireland

View user's profile Send private message

PostPosted: Sat Feb 28, 2015 10:37 am     Reply with quote

Thanks Thelmah, NOWDT would normally be the first fuse I declare but somehow I just missed it. Thanks also to PCM programmer and Temtronic, all of your (and others) comments on this forum have helped me numerous times with PICs and CCS C.
_________________
Liam Hanmore
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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