![]() |
Forum Index : Microcontroller and PC projects : NEC IR Transmission?
Page 1 of 2 ![]() ![]() |
|||||
Author | Message | ||||
Frank N. Furter Guru ![]() Joined: 28/05/2012 Location: GermanyPosts: 949 |
Hi to all! Is there a way to send a NEC IR-protocol with our Micromite? I know we can receive it and we can send Sony-protocol but I need NEC as transmitter to control my Pioneer CD changer... THANKS! Frank |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
Matherp! Your're up! ![]() Not sure if this can be done with a Cfunction,but perhaps? Smoke makes things work. When the smoke gets out, it stops! |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
This really would be an excellent 'feature' (even to the firmware). Only thing is though, there maybe too many 'standards' (from my early days when playing with the Apple IR remote). Be interesting to see how this thread develops! |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Your wish is my command ![]() NECSend pin_number, device, code e.g NECsend 2,255,1 Note: if you send the above to a Micromite it will report "255,128". I'm pretty sure that Geoff has got the bit order the wrong way round but await his comments ![]() And then we get onto the tricky bit about the device address. There are two versions of the NEC code , one sends a 8-bit address and then the inverse of the address as a check byte. The other sends a 16-bit address. Geoff's code assumes a 16-bit address. I have implemented the send function such that addresses <256 are send in normal mode, addresses > 256 are sent in extended addressing mode. The code should run on any flavour of Micromite and at any clock speed although slow speeds may produce poor results as the timings will not be very precise. Just connect your IR LED to any DOUT serial port. The -ve connection on the LED should be connected ground and the +ve to the Micromite port via a resistor (330ohm works for me) i.e. positive logic. The code will automatically set the chosen pin as an output. Enjoy Csub NECSend 0000001A 'high 00001021 40824800 0045102B 10400008 00804021 40024800 0048182B 1460FFFD 0045102B ACC70000 1440FFFA 01044021 03E00008 00000000 'low ACA60000 00001021 40824800 0044102B 10400005 00000000 40024800 0044102B 1440FFFD 00000000 03E00008 00000000 'main 27BDFFB0 AFBF004C AFBE0048 AFB70044 AFB40038 AFB30034 AFB20030 AFB1002C AFB00028 AFB60040 3C109D00 AFB5003C 8E02009C 00809821 3C044795 24844E00 00C0A021 0040F809 00A08821 AFA20020 8E02009C 3C0444DE 0040F809 248438E4 0040B821 8E02009C 3C044414 0040F809 248425ED 0040F021 8E02009C 3C04435E 0040F809 248438E4 AFA2001C 8E02009C 3C0442DE 0040F809 248438E4 AFA20024 8E640000 8E020024 24050007 0040F809 24120001 AFA20018 8E640000 8E020024 0040F809 24050005 AFA20014 8E020028 0040F809 8E640000 8E230000 8E240004 00529004 306500FF 14800006 8E870000 54800005 38A300FF 2C620100 54400002 38A300FF 7C633A00 8FA20014 3C159D00 00078C00 AC520000 8E640000 8EA20010 38E700FF 00073E00 02258825 02278825 00003021 24050008 00031A00 0040F809 02238825 8FA30018 8EA20004 24044E20 0040F809 AFA30010 8EA20000 3C040008 3C03BF88 AC641064 3C03BF88 AC601068 8C440000 8EA20080 00002821 0040F809 8EB30064 00408021 8EA2009C 3C044000 0040F809 8FB40014 00402821 0260F809 02002021 0040B021 8EA20064 8EB0007C 02E02821 0040F809 02C02021 0200F809 00402021 00409821 8EA20064 8EB0007C 03C02821 0040F809 02C02021 0200F809 00402021 0040F021 8FA5001C 8EA20064 8EB0007C 0040F809 02C02021 0200F809 00402021 AFA2001C 8FA50024 8EA20064 8EB0007C 0040F809 02C02021 0200F809 00402021 0040B821 8FA50020 8EA20064 8EB0007C 0040F809 02C02021 0200F809 00402021 8FA60018 00402021 02E02821 02403821 0040A821 0411FF4F 00000000 8FA4001C 8FA50014 02403021 00008021 0411FF57 00000000 24160020 8FA60010 02A02021 02602821 02403821 0411FF42 00000000 32220001 03C02021 02802821 02403021 10400005 0260B821 0411FF48 00000000 10000007 26100001 02602021 02802821 02403021 0411FF41 00000000 26100001 1616FFE9 00118842 8FA60018 02A02021 02E02821 02403821 0411FF2A 00000000 8FA30014 3C020008 AC720000 8FBF004C 3C03BF88 AC621064 3C03BF88 8FBE0048 8FB70044 8FB60040 8FB5003C 8FB40038 8FB30034 8FB20030 8FB1002C 8FB00028 AC621068 03E00008 27BD0050 end csub C source for those interested #define _SUPPRESS_PLIB_WARNING #include <plib.h> #include "../cfunctions.h" void high(unsigned int dwell, int duration, int portinv, int mypin){ unsigned int next_clock=dwell; unsigned int current_ticks=0; asm volatile("mtc0 %0, $9": "+r"(current_ticks)); //set the current number of ticks to 0 while(current_ticks<duration){ //send leading pulse do{ asm volatile("mfc0 %0, $9" : "=r"(current_ticks));//get the time in ticks since zeroed }while(current_ticks<next_clock); *(volatile unsigned int *)portinv=mypin; next_clock+=dwell; } } void low(int duration, int portclr, int mypin){ unsigned int current_ticks=0; *(volatile unsigned int *)portclr=mypin; asm volatile("mtc0 %0, $9": "+r"(current_ticks)); //set the current number of ticks to 0 while(current_ticks<duration){ asm volatile("mfc0 %0, $9" : "=r"(current_ticks));//get the time in ticks since zeroed } } void main(long long *pin, unsigned long long *devin, unsigned long long *codein){ float IRfreq=LoadFloat(0x47954E00); //38.222KHz * 2 float us562 =LoadFloat(0x44DE38E4); //562.5 usec float us1687=LoadFloat(0x441425ED); //1.6875 ms float ms4=LoadFloat(0x435E38E4); // 4.5 msec float ms9=LoadFloat(0x42DE38E4); //9 msec float tick_rate; unsigned int us562i,us1687i,ms4i,ms9i,dwell; unsigned int portinv=(int)(volatile unsigned int *)GetPortAddr(*pin,LATINV); unsigned int portclr=(int)(volatile unsigned int *)GetPortAddr(*pin,LATCLR); int mypin=1<<GetPinBit(*pin); unsigned int devinv,dev=*devin & 0xFF; unsigned int code=*codein; if(*devin>0xff){ devinv=(*devin>>8) & 0xFF; //extended address mode } else { devinv= dev ^ 0xFF; // normal invert of single address } unsigned int codeinv= code ^ 0xFF; // get the inverse of *dev int j; unsigned int transmit = dev | (devinv<<8) | (code <<16) | (codeinv<<24); *(volatile unsigned int *)portclr=mypin; ExtCfg(*pin,EXT_DIG_OUT,0); uSec(20000); mT4IntEnable(0); // disable clock interrupt tick_rate = FDiv(IntToFloat(CurrentCpuSpeed),LoadFloat(0x40000000)); //get the number of clock ticks per second us562i=FloatToInt(FDiv(tick_rate,us562)); us1687i=FloatToInt(FDiv(tick_rate,us1687)); ms4i=FloatToInt(FDiv(tick_rate,ms4)); ms9i=FloatToInt(FDiv(tick_rate,ms9)); dwell=FloatToInt(FDiv(tick_rate,IRfreq)); high(dwell, ms9i, portinv, mypin); low(ms4i, portclr, mypin); for(j=0;j<32;j++){ high(dwell, us562i, portinv, mypin); if(transmit & 1){ low(us1687i,portclr, mypin); } else { low(us562i,portclr, mypin); } transmit = transmit >> 1; } high(dwell, us562i, portinv, mypin); *(volatile unsigned int *)portclr=mypin; mT4IntEnable(1); // enable clock interrupt } |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
![]() THANK YOU! This is brilliantly useful ![]() |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
I realised belatedly the CFunction was somewhat over engineered so here is a simpler (and smaller version) [code]CSUB NECSend 0000000E 'high 00001021 40824800 0045102B 10400008 00804021 40024800 0048182B 1460FFFD 0045102B ACC70000 1440FFFA 01044021 03E00008 00000000 'main 27BDFFB0 AFBF004C AFBE0048 AFB70044 AFB5003C AFB30034 AFB20030 AFB1002C AFB00028 AFB60040 3C109D00 AFB40038 8E02009C 00808821 3C044795 24844E00 00C09821 0040F809 00A09021 AFA2001C 8E02009C 3C0444DE 0040F809 248438E4 0040B821 8E02009C 3C0442DE 0040F809 248438E4 AFA20020 8E240000 8E020024 24050007 0040F809 24150001 AFA20018 8E240000 8E020024 0040F809 24050005 0040F021 8E020028 0040F809 8E240000 8E430000 8E440004 0055A804 306500FF 14800006 8E670000 54800005 38A300FF 2C620100 54400002 38A300FF 7C633A00 3C169D00 AFD50000 8E240000 8EC20010 00079400 38E700FF 00073E00 02459025 02479025 00003021 00031A00 24050008 0040F809 02439025 8EC20004 240407D0 0040F809 AFB50010 8EC30000 8EC20080 8ED30064 8C640000 8FA30018 00002821 00008821 0040F809 AFA30014 00408021 8EC2009C 0040F809 3C044000 00402821 0260F809 02002021 0040A021 8EC20064 8ED0007C 02E02821 0040F809 02802021 0200F809 00402021 00409821 8FA50020 8EC20064 8ED0007C 0040F809 02802021 0200F809 00402021 0040B821 8FA5001C 8EC20064 8ED0007C 0040F809 02802021 0200F809 00402021 8FA60018 00402021 3C030008 0040A021 3C02BF88 AC431064 02E02821 3C02BF88 02A03821 AC401068 0411FF75 00000000 AFD50000 8EC20004 24041194 0040F809 3C109D00 24160020 8FA60014 02602821 02A03821 02802021 0411FF69 00000000 8FA20010 24040232 26310001 AFC20000 8E020004 0040F809 0260B821 32420001 10400004 00000000 8E020004 0040F809 24040465 1636FFEC 00129042 8FA60018 02802021 02E02821 02A03821 0411FF54 00000000 AFD50000 8FBF004C 3C020008 3C03BF88 AC621064 3C03BF88 8FBE0048 8FB70044 8FB60040 8FB5003C 8FB40038 8FB30034 8FB20030 8FB1002C 8FB00028 AC621068 03E00008 27BD0050 end CSUB [/code] Geoff believes that the Micromite NEC receive code may well be reporting the wrong codes as I suspect so here is a little program that can be used to test the NECSend function. This will report exactly the codes sent and also correctly evaluate normal (8-bit) and extended (16-bit) device addressing. Frank: If you run the following receive program on a Micromite you can read correctly the codes from your existing controller to use in the NECSend function option explicit
option default none Dim integer dev,key IR dev,key,irint Do pause 1000 Loop irint: If (dev And &HFF) = ((dev>>8) Xor &HFF) Then ' normal address Print brv((dev>>8),8) ,brv(key,8) Else ' extended address Print brv(dev,16),brv(key,8) EndIf IReturn Function brv(x As integer, k As integer) As integer Local integer n brv=0 For n=1 To k If x And (1<<(n-1)) Then brv=brv Or (1<<(k-n)) EndIf Next n End Function C source of the update #define _SUPPRESS_PLIB_WARNING
#include <plib.h> #include "../cfunctions.h" void high(unsigned int dwell, int duration, int portinv, int mypin){ unsigned int next_clock=dwell; unsigned int current_ticks=0; asm volatile("mtc0 %0, $9": "+r"(current_ticks)); //set the current number of ticks to 0 while(current_ticks<duration){ //send leading pulse do{ asm volatile("mfc0 %0, $9" : "=r"(current_ticks));//get the time in ticks since zeroed }while(current_ticks<next_clock); *(volatile unsigned int *)portinv=mypin; next_clock+=dwell; } } void main(long long *pin, unsigned long long *devin, unsigned long long *codein){ float IRfreq=LoadFloat(0x47954E00); //38.222KHz * 2 float us562 =LoadFloat(0x44DE38E4); //562.5 usec float ms9=LoadFloat(0x42DE38E4); //9 msec float tick_rate; unsigned int us562i,ms9i,dwell; unsigned int portinv=(int)(volatile unsigned int *)GetPortAddr(*pin,LATINV); unsigned int portclr=(int)(volatile unsigned int *)GetPortAddr(*pin,LATCLR); int mypin=1<<GetPinBit(*pin); unsigned int devinv,dev=*devin & 0xFF; unsigned int code=*codein; if(*devin>0xff){ devinv=(*devin>>8) & 0xFF; //extended address mode } else { devinv= dev ^ 0xFF; // normal invert of single address } unsigned int codeinv= code ^ 0xFF; // get the inverse of *dev int j; unsigned int transmit = dev | (devinv<<8) | (code <<16) | (codeinv<<24); *(volatile unsigned int *)portclr=mypin; ExtCfg(*pin,EXT_DIG_OUT,0); uSec(2000); tick_rate = FDiv(IntToFloat(CurrentCpuSpeed),LoadFloat(0x40000000)); //get the number of clock ticks per second us562i=FloatToInt(FDiv(tick_rate,us562)); ms9i=FloatToInt(FDiv(tick_rate,ms9)); dwell=FloatToInt(FDiv(tick_rate,IRfreq)); mT4IntEnable(0); // disable clock interrupt high(dwell, ms9i, portinv, mypin); *(volatile unsigned int *)portclr=mypin; uSec(4500); for(j=0;j<32;j++){ high(dwell, us562i, portinv, mypin); *(volatile unsigned int *)portclr=mypin; uSec(562); if(transmit & 1) uSec(1125); transmit = transmit >> 1; } high(dwell, us562i, portinv, mypin); //stop bit *(volatile unsigned int *)portclr=mypin; mT4IntEnable(1); // enable clock interrupt } |
||||
Frank N. Furter Guru ![]() Joined: 28/05/2012 Location: GermanyPosts: 949 |
Hi Peter, you are amazing! ![]() ![]() ![]() THANK YOU VERY, VERY MUCH!!! ...it's very difficult to find a special CD in a 301 capacity disc changer! Now I can built a intelligent IR-Remote to find my CD's! That's really great! ![]() Frank P.S.: ...is it possible that you are related to DATA from the StarTrek Next Generation? ![]() |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
He is Lore...... ![]() Smoke makes things work. When the smoke gets out, it stops! |
||||
Frank N. Furter Guru ![]() Joined: 28/05/2012 Location: GermanyPosts: 949 |
No, no, no - Lore was a bad guy! ![]() ...and Peter is a genius!!! ![]() |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Been Searching a bit on this topic. Not sure what Peter's Functions capabilities are, but is the able function to send ANY command from ANY remote possible? If this was paired with a Read or learn Function, it would let users the MM to control any device with an IR remote. Obviously there may be limitations. Cheers Phil. PS my main understanding of IR remotes is that some types tend to go missing more than others, while certain ones gravitate to one of several known locations. |
||||
Geoffg![]() Guru ![]() Joined: 06/06/2011 Location: AustraliaPosts: 3292 |
There are many, many different IR protocols and it would be impossible to implement them all. My guess is that most learning remote controls do their learning by measuring the timing of the IR signal and then replicating that, ie they do not know what the content means. This is no good for the Micromite and far too messy to implement. Geoff Geoff Graham - http://geoffg.net |
||||
piclover Senior Member ![]() Joined: 14/06/2015 Location: FrancePosts: 134 |
In my very own view, none of the IR protocols should even be part of the MM2 firmware (since none of those protocols are predominant on the market: there are also Philips' RC5/6, Toshiba's, etc...). Now that CFunctions exist, they should be implemented as such (especially since using a remote protocol in a project is not the most common occurrence). It's of course, my own opinion. |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2944 |
Totally agree with the above statement - and IMHO it is good to leave at least the Sony protocol in MMBasic's Firmware as it gives 'beginners' the option to very easily add in IR functionality into a project using cheap Remotes available on eBay with just the addition (in terms of hardware) of a single IR detector. Put another way, Low hardware Cost, Simple Code, and potentially a Powerful end Solution. I wrote & published some early code to decode the NEC protocol purely because I loved the styling of the Apple remote. Now that this is also implemented in the firmware I would say leave this in too. But to add other protocols I totally agree that these should be performed by user code (whether it be pure Basic code or as a CFunction). To remove all IR decoding software from the MMBasic firmware would be a bad move IMHO as not everyone can write CFunctions. Geoff has it bang on in terms of two 'basic' protocols that can be used with just a couple of lines of code. Try doing that on a RPi, or an Arduino, or a . . . . . . |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
My guess is that most learning remote controls do their learning by measuring the timing of the IR signal and then replicating that. Geoff Looks like between Sony & NEC protocols seem to cover just about everything in this house. From what I see with most of the universals I've played with here (cheap ones), they seem to rely on a brand code table, usually printed. I assume that then tells the remote which device code to use & what keycode to assign the buttons. Some have a discover mode, where they try the different band codes until you acknowledge that the device has been turned on. At that point you can test other button, and if happy accept that brand code, or continue to scan others. Once you've found the brand code you can accept that, and some then offer a learn function to correct or add buttons. As the remote now knows the brand code & device code, I'd assume they are decoding in their learn mode, as they already know the correct device code, it's only a key code that needs to be corrected. The Logitech's I have are setup by their web app, using a database of device & keycodes for various appliances. The one big exception to what can be controlled by my universal remotes is the Air Conditioners. They all use a totally different approach, sending the entire status the Air conditioner is required to be in; Heat/Cool mode, Fan Speed, Temp, swing etc, etc. Obviously this is required to ensure the Air Con is in sync with the display on the remote. The remotes seem to send a string of bytes, using various blocks of bits to control the various functions. There is an interesting looking Universal Air Con Remote listed here, along with a table of brand codes. Found an interesting Thesis done recently regarding Air Con controls; Universal infrared adapter for air conditioners All a bit over my head, but matherp, would be more at home reading it & knowing if the knowing the feasibility of doing something similar with a MM external function. I'd hazard a guess that there's be users that would like to drive their Air Cons with a MicroMite. Cheers Phil |
||||
robert.rozee Guru ![]() Joined: 31/12/2012 Location: New ZealandPosts: 2442 |
the aircon remote control is certainly an interesting one, as many units come with extremely poorly designed remotes. single buttons for each mode, on/off and temperature would suffice most users. particularly the elderly, who struggle to read the miniscule icons on many displays. i seem to remember someone long ago on the forums tinkering with using the micromite to learn IR codes. you might care to have a dig around. it may even be possible to write something that uses matherp's micro-second timing routines that were posted recently. cheers, rob :-) |
||||
MicroBlocks![]() Guru ![]() Joined: 12/05/2012 Location: ThailandPosts: 2209 |
My eyesight is stil pretty ok, but even i hate to use these aircon remotes. This asks for an aircon remote challenge. :) Microblocks. Build with logic. |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
A friend of mine is embarking on just such a project. Air Con control for the elderly. His intention is to have the micro take control of the air con. Provide a pass thru function so a degree of control is still available. The primary purpose is to have the micro monitor the humidity level & then use the air con in the appropriate mode to keep it below a required level. Should be interesting to see how the remote decoding goes. First hiccup is the fact that the TSOP4840 I happen to have hear, don't seem to respond to any of my remotes. (Waiting on some 38kHz ones). Is that to be expected? Page 23 mentions that the 38kHz receivers will generally respond to 40kHz remotes, but the 40kHz one won't see my Panasonic TV remote at all. Cheers Phil |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Looks like between Sony & NEC protocols seem to cover just about everything in this house. Looks like my above statement was a fail.... Panasonic TV's seem to use Phillips RC5. Has anyone written anything for that? Thanks Phil. |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
You can do it using this routine using the circuit in the last post |
||||
Frank N. Furter Guru ![]() Joined: 28/05/2012 Location: GermanyPosts: 949 |
@Peter: It looks like your test program of the first page contains an error regarding the extended NEC code. I used it with remotes that use the "normal" NEC code - everything works as desired. However, I failed with a remote control using the "extended" code! I read 256 as address with the program from a remote control. When I sent this address my receiver did not respond. With the oscilloscope I read and decoded 65025 from the original remote (using the document linked on the first page) If I send this address now everything works! The transmission routine works perfectly (many thanks to Peter!!!) Frank |
||||
Page 1 of 2 ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |