|
|
View previous topic :: View next topic |
Author |
Message |
Liam_85
Joined: 09 Nov 2014 Posts: 26 Location: Ireland
|
NEC decoding, weird UART problem |
Posted: Fri Feb 27, 2015 9:29 pm |
|
|
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
|
|
Posted: Fri Feb 27, 2015 10:27 pm |
|
|
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
|
|
Posted: Fri Feb 27, 2015 10:50 pm |
|
|
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: 19539
|
|
Posted: Sat Feb 28, 2015 1:57 am |
|
|
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: 9243 Location: Greensville,Ontario
|
|
Posted: Sat Feb 28, 2015 6:33 am |
|
|
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
|
|
Posted: Sat Feb 28, 2015 10:12 am |
|
|
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: 19539
|
|
Posted: Sat Feb 28, 2015 10:15 am |
|
|
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!...
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
|
|
Posted: Sat Feb 28, 2015 10:37 am |
|
|
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 |
|
|
|
|
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
|