Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 10:26 05 May 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Micromite MK2: IR receiver for NEC

     Page 1 of 2    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8592
Posted: 09:29am 26 Nov 2014
Copy link to clipboard 
Print this post

I don't think there is anything you can't do with a Micromite MK2
The very cheap IR remote controls available on ebay such as item 281489966317 (£0.99)

transmit using the NEC standard code which of course is completely incompatible with the Sony code that Geoff has included in the Micromite firmware.
However with a little bit of C it has proved easy to reliably receive the NEC code in a non-blocking interrupt routine.

The program uses pin 2 on the Micromite. It could be any pin with interrupt capability but the cFunction would need some changes.

The NEC standard starts with a 9ms pulse. This gives plenty of time for a negative edge triggered interrupt to call the IRreceive cFunction. The cFunction then starts hardware timer 5 and uses this to time all subsequent positive and negative pulses up to a maximum of 66 (32 bits, 2 edges on each, + 2 edges for an initial 4.5msec low period). There is a timeout built into the code in case of an invalid pulse train and to establish the end of the pulse sequence. Once the complete set of pulses is received the cFunction uses the measured length of the 4.5msec pulse to establish a cutoff period between "1" and "0" pulses. This makes the code independent of processor speed.

The cFunction then packs the data received into the 32-bit function return.
A return of &HFFFFFFFF means that a repeat pulse the same as the last one has been received. A return of 0 means an invalid sequence and should be ignored. Otherwise there will be a 32 bit number representing each key on the handset.

For the handset referenced above they are:
BA45FF00 CH-
B946FF00 CH
B847FF00 CH+
BB44FF00 <<
BF40FF00 >>
BC43FF00 Play/Pause
F807FF00 Vol-
EA15FF00 Vol+
F609FF00 EQ
E916FF00 0
E619FF00 100+
F20DFF00 200+
F30CFF00 1
E718FF00 2
A15EFF00 3
F708FF00 4
E31CFF00 5
A55AFF00 6
BD42FF00 7
AD52FF00 8
B54AFF00 9

In my example program the interrupt routine puts the received character into a circular buffer for processing in the main program (I haven't coded an overun check). In the case of the example code this then just prints out.

The IR receiver I have tested this with is the one available from the picaxe store LED020. I use a 4K7 pullup resistor but I have also enabled the Micromite pullup which would probably be sufficient although I haven't tested this.



cpu 48
option explicit
option default none
dim as integer IRreceived=0,IRread=0,IRbuffer(8);
setpin 2,intl,readpulses,pullup
do
do while IRreceived<>IRread
print hex$(IRbuffer(IRread),8)
IRread=(IRread+1) mod 8
loop
loop
end
'
readpulses:
IRbuffer(IRreceived)=NECreceive()
IRreceived=(IRreceived+1) mod 8
ireturn
'
CFunction NECreceive
00000000
27bdfee0 afbe011c 03a0f021 3c04bf80 34840e00 34058030 ac850000 afc00004
3c04bf88 34846020 8c840000 30840001 afc40000 10000004 00000000 3c04bf80
34840e10 ac800000 3c04bf88 34846020 8c840000 30840001 1080fff8 00000000
10000008 00000000 3c04bf80 34840e10 8c850000 3404ea60 00a4202b 10800011
00000000 3c04bf88 34846020 8c840000 30840001 308400ff 1080000b 00000000
3c04bf80 34840e10 8c850000 3404ea60 00a4202b 1480ffec 00000000 10000002
00000000 00000000 3c04bf80 34840e10 8c850000 8fc40004 00042080 03c42021
ac850010 3c04bf80 34840e10 ac800000 8fc40004 24840001 afc40004 10000008
00000000 3c04bf80 34840e10 8c850000 8fc40004 00042080 03c42021 ac850010
3c04bf88 34846020 8c840000 30840001 1080fff4 00000000 3c04bf80 34840e10
ac800000 8fc40004 24840001 afc40004 8fc50004 24040042 14a40007 00000000
8fc50004 24040002 10a40006 00000000 10000008 00000000 00000000 1000ffc1
00000000 2402ffff 00001821 10000032 00000000 8fc40004 2c840003 14800009
00000000 8fc40004 2c840042 10800005 00000000 00001021 00001821 10000026
00000000 afc00000 8fc40010 00042902 00a02021 00042040 00852021 afc40008
afc00004 10000016 00000000 8fc40004 24840001 00042040 afc4000c 8fc4000c
00042080 03c42021 8c850010 8fc40008 0085202b 10800007 00000000 8fc40004
24050001 00852004 8fc50000 00a42025 afc40000 8fc40004 24840001 afc40004
8fc40004 2c840020 1480ffe8 00000000 8fc20000 00001821 03c0e821 8fbe011c
27bd0120 03e00008 00000000
End CFunction



long long NECreceive(){
unsigned int p,i,j,bitlength,log[66];
#define tmr5con *(volatile unsigned int *)0xbf800e00 //timer 5 configuration register
#define tmr5 *(volatile unsigned int *)0xbf800e10 //timer 5 counter
#define porta *(volatile unsigned int *)0xbf886020 //port a
tmr5con=0x8030; //turn on with scale 256
i=0;
p=porta & 1;
while ((porta & 1)==0) //wait for A.0 (pin 2) to go high after the intial long low
tmr5=0; //reset the timer
while (1){
while (((porta&1)==1) && (tmr5<60000))
if (tmr5>=60000) break;
log=tmr5;
tmr5=0;
i++;
while ((porta&1)==0)
log=tmr5;
tmr5=0;
i++;
if (i==66) break;
}
if(i==2) return 0xFFFFFFFF; //Repeat code
if(i>2 && i<66) return 0; //invalid code
p=0;
bitlength=log[0]/16*3; //establish a test bit length
for (i=0;i<32;i++){
j=(i+1)*2;
if(log[j]>bitlength){
p=p | (1<<i);
}
}
return p;
}Edited by matherp 2014-11-27
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 09:53am 26 Nov 2014
Copy link to clipboard 
Print this post

Hi Peter

Absolutely superb !

Peter
The only Konstant is Change
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 02:07pm 26 Nov 2014
Copy link to clipboard 
Print this post

Brilliant.
Geoff Graham - http://geoffg.net
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1328
Posted: 02:29pm 26 Nov 2014
Copy link to clipboard 
Print this post

@matherp,
Great timing Peter - I looked at these a couple of days ago and decided they wouldn't work for me with the MicroMite - now they do! - and at that price I ordered two.

Greg
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2794
Posted: 04:39pm 26 Nov 2014
Copy link to clipboard 
Print this post

May be worth referring to this link - Using an Apple IR remote . . . .
For everything Micromite visit micromite.org

Direct Email: whitewizzard@micromite.o
 
viscomjim
Guru

Joined: 08/01/2014
Location: United States
Posts: 925
Posted: 06:10pm 26 Nov 2014
Copy link to clipboard 
Print this post

This is really cool. I have implemented WW apple remote code for many a project. The coolness factor of using an apple remote is obvious, and anyone that sees this is floored that it works so well. Thanks again to WW.

I have to say that since Geoff has introduced the C thing to MMbasic, I am absolutely lost when viewing the codes that you guys (Matherp, Peter, Geoff and a handful of others on this thread) crank out that work. I am sure that I can not be the only one who has absolutely no clue what is going on here while perusing your code, especially since the only programming experience I have (again, I'm sure I'm not alone here) is basic. The uMite has opened so many doors for me because of the use of basic, a non programmer that happens to get basic just enough to make my projects work to the point where I have been blessed with some paying gigs (major thanks to Geoff and this forum!). When I come across code like this, I am both excited that this new (to me) aspect of MMbasic seems to open up new avenues of control at much higher speeds that challenge a lot of what is out there, (arduino wise and other platforms) and at the same time, other than being able to copy and paste this kind of code in some of my programs, I wish there was something available to us "inexperienced programmers" that would allows us (me) to understand what in the world you are doing.

I know that I am pushing the limits of this particular thread, and I hope that I am not offending anyone here. Not my intention by any means.

I would like to pose the following... Imagine, (this is actually happening right now) someone came across MMbasic and the uMite and all of a sudden, the light bulb came on. A 32 bit microcontroller's "power" was available to a noob that never programmed anything but an egg timer by turning a knob. Now, things are rolling right along, MMbasic is getting better and better, more built in functions like keyboard input, LCD display, RTC support, Rotary encoders, etc. are at your fingertips and work flawlessly.

All of a sudden, C functions are introduced. Check out the OLED code, amazing! Check out this threads code for NEC IR protocol decoding, also amazing! How about the temp and pressure code. I can only see this getting better and better, however, I am getting more and more lost when viewing these threads. So this noob needs to figure out what to do to keep up with you experienced C guys. I am more than willing and eager to figure out what you are doing here with this "new" feature. Can you suggest a path to follow that could get me into this loop. Since the beginning of Geoff's uMite project, I was on board and have never looked back. I was excited that I could look at so many code submissions on this forum, and even though at times it took many tries to follow the code and what it was intended to do, most of the time it would eventually make sense and it would also "teach" how things were done logically. (Big props to guys like Geoff, Jman, White Wizard, TZ, Plasma, Grogster aka PCBster, Paceman, Boss, etc, etc...) I actually think I regained quite a few brain cells back by doing this. But looking at a bunch of bytes of code preceeded by "CFunction", I am lost.

Please, I am begging the experts that keep posting this type of excellent code, can you give a bit of direction and clarification of what in the world all those chunks of bytes do... or at least where to start to get a grip on what seems to be so easy for you experienced guys.

Thanks again to everyone on this forum!!!! Especially Geoff!



Edited by viscomjim 2014-11-28
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3165
Posted: 09:02pm 26 Nov 2014
Copy link to clipboard 
Print this post

Thanks for the kind words viscomjim. We do need an introduction to programming in C, preferably using CFunctions as the test example. The trouble is that this is a big subject and C can be cryptic and difficult to explain. Maybe someone has the spare time.

matherp, timer 5 is used by the COM2 serial port. So, if you had COM2 open at the same time strange things would happen. Timer 1 is used by the Sony IR receiver command so that would be a good option as I doubt that anyone would use that feature at the same time as your function. A better option is to use the core timer which is always free. The tutorial produced by Peter (G8JCF) contains the source to the SerialTx function which uses the core timer.

For anyone who is using matherp's function; note that pin 2 is on the 28-pin chip, on the 44-pin chip it is pin 19. Also note that this must be run with the CPU at 48MHz.

Geoff

Geoff Graham - http://geoffg.net
 
jman

Guru

Joined: 12/06/2011
Location: New Zealand
Posts: 711
Posted: 11:01pm 26 Nov 2014
Copy link to clipboard 
Print this post

Hi
At the risk of hijacking this thread (Glen please move it if required)

My thoughts are that I can understand the NEC code that WW posted this new NEC code
using CFunctions is completely foreign to me.
The one thing that attracted me to the Mite's was that were using basic and I
have a little understanding of basic so the examples and the great projects posted here are comprehendible to me. If I wanted to use C and I quote "C can be cryptic and difficult" I would have bought an Ardunio or something similar. I think the old timers like my self enjoy basic and the great features offered by the Mite's version of basic. This not to say that Cfunctions is not or will not be popular I am sure it will be. Some features (like not been able to use a string variable with the same name as an integer variable) were added or removed to make it easier for beginners to get started I don't see this as been one of those features.

Like I said just my thoughts and NOT intended to create a flame storm

Regards
Jman
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2794
Posted: 11:58pm 26 Nov 2014
Copy link to clipboard 
Print this post

jman, viscomjim, all

I too am totally lost when it comes to these CFunctions! As it stands now, there is a total reliance by me on using other peoples code - the reason I don't like Arduino, and C in general! I have tried C so many times and the last attempt I just gave up after not being able to do something quite 'basic'!!

I have spent most of the last week 'de-ciphering' matherp's brilliant OLED code which has proved invaluable (thanks to Plasma for rushing me a bi-colour OLED to run this on). I fully understand why CFunctions are required but hope that the people that write any 'general' blocks of code will comment the 'inputs & outputs' clearly enough so that us BASIC people can then use them too.

As jman and viscomjim have said - these are my thoughts and are in no way meant to be negative.

Great work by those who have created & developed CFunctions . But please do keep the use of them simple enough for all of us BASIC folk to follow!!

WW
For everything Micromite visit micromite.org

Direct Email: whitewizzard@micromite.o
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8592
Posted: 01:23am 27 Nov 2014
Copy link to clipboard 
Print this post

Please find attached an update.

I've changed the timer to timer-1 as per Geoff's suggestion.

I've fixed a bug in the repeat function.

Also I've found more about the NEC code. It sends 32 bits, The first 8 are the address, the second 8 are a ones-complement version of the address, the third 8 are the data, and the fourth 8 are a ones-complement version of the data. This means that the packet always has 32 ones and 32 noughts in it and is always the same length.

It also allows the data to be checked between the normal and inverse version.

The cFunction now makes the check and returns the address * 256 + data (or 0 if the check fails). As the address for these cheap remotes is zero that means we now just get a single byte representing the button pushed.

45 CH-
46 CH
47 CH+
44 <<
40 >>
43 Play/Pause
07 Vol-
15 Vol+
09 EQ
16 0
19 100+
0D 200+
0C 1
18 2
5E 3
08 4
1C 5
5A 6
42 7
52 8
4A 9

The code IS CPU speed independent as it self-calibrates using the initial 4.5msec pulse. I've tested it from 5-48 Mhz.


cpu 48
option explicit
option default none
dim as integer IRreceived=0,IRread=0,IRbuffer(8);
setpin 2,intl,readpulses,pullup
do
do while IRreceived<>IRread
print hex$(IRbuffer(IRread),8)
IRread=(IRread+1) mod 8
loop
loop
end
'
readpulses:
IRbuffer(IRreceived)=NECreceive()
IRreceived=(IRreceived+1) mod 8
ireturn
'
CFunction NECreceive
00000000
27bdfed8 afbe0124 03a0f021 afc00008 3c04bf80 34840600 34058010 ac850000
afc00000 10000004 00000000 3c04bf80 34840610 ac800000 3c04bf88 34846020
8c840000 30840001 1080fff8 00000000 1000004d 00000000 3c04bf80 34840610
8c850000 8fc40000 00042080 03c42021 ac850018 10000002 00000000 00000000
3c04bf88 34846020 8c840000 30840001 308400ff 10800008 00000000 3c04bf80
34840610 8c850000 34049c40 00a4202b 1480ffe9 00000000 3c04bf80 34840610
8c850000 34049c40 00a4202b 10800004 00000000 3c04bf80 34840610 ac800000
8fc40000 24840001 afc40000 10000008 00000000 3c04bf80 34840610 8c850000
8fc40000 00042080 03c42021 ac850018 3c04bf88 34846020 8c840000 30840001
14800008 00000000 3c04bf80 34840610 8c850000 34049c40 00a4202b 1480ffed
00000000 3c04bf80 34840610 8c850000 34049c40 00a4202b 10800004 00000000
3c04bf80 34840610 ac800000 8fc40000 24840001 afc40000 8fc50000 24040042
10a4000a 00000000 3c04bf80 34840610 8c850000 34049c40 00a4202b 1480ffb7
00000000 10000002 00000000 00000000 8fc50000 24040004 14a40005 00000000
240200ff 00001821 10000057 00000000 8fc40000 2c840005 14800009 00000000
8fc40000 2c840042 10800005 00000000 00001021 00001821 1000004b 00000000
8fc40018 00042902 00a02021 00042040 00852021 afc4000c afc00004 10000016
00000000 8fc40004 24840001 00042040 afc40010 8fc40010 00042080 03c42021
8c850018 8fc4000c 0085202b 10800007 00000000 8fc40004 24050001 00852004
8fc50008 00a42025 afc40008 8fc40004 24840001 afc40004 8fc40004 2c840020
1480ffe8 00000000 8fc40008 a3c40014 8fc40008 00042202 308400ff 00042027
a3c40015 8fc40008 00042402 a3c40016 8fc40008 00042602 308400ff 00042027
a3c40017 93c50014 93c40015 00a42026 0004202b 308500ff 93c60016 93c40017
00c42026 0004202b 308400ff 00a42025 308400ff 10800005 00000000 00001021
00001821 10000008 00000000 93c50016 93c40015 00042200 00a42021 00801021
000427c3 00801821 03c0e821 8fbe0124 27bd0128 03e00008 00000000
End CFunction


long long NECreceive(){
unsigned int i,j,k,buffer,bitlength,log[66];
unsigned char a,b,c,d;
buffer=0;
#define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register
#define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter
#define porta *(volatile unsigned int *)0xbf886020 //port a
tmr1con=0x8010; //turn on with scale 256
i=0;
while ((porta & 1)==0) //wait for A.0 (pin 2) to go high after the intial long low
tmr1=0; //reset the timer
while (tmr1<40000){
while (((porta&1)==1) && (tmr1<40000))
log=tmr1;
if (tmr1<40000) tmr1=0;
i++;
while (((porta&1)==0) && (tmr1<40000))
log=tmr1;
if (tmr1<40000) tmr1=0;
i++;
if (i==66) break;
}
if(i==4) return 0xFF; //Repeat code
if(i>4 && i<66) return 0; //invalid code
bitlength=log[0]/16*3; //establish a test bit length
for (k=0;k<32;k++){
j=(k+1)*2;
if(log[j]>bitlength) buffer=buffer | (1<<k);
}
a= buffer & 0xFF;
b= ~((buffer>>8) & 0xff);
c= (buffer>>16) & 0xff;
d= ~((buffer>>24) &0xff);
if ((a!=b) | (c!=d)) return 0;
return c+256*b;
}
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1328
Posted: 01:41am 27 Nov 2014
Copy link to clipboard 
Print this post


I have no idea about "C" either but I think the CFunctions stuff is excellent and pushes the whole Micromite envelope into areas it couldn't otherwise be - like @matherp's graphic's routines which in many cases would otherwise be too slow, and e.g. the NEC IR controller code above. It's also great that Peter gives the "C" code too so that those who might wish to look into it a bit can do so. Another obvious benefit of CFunctions is that other experienced "C" programmers can produce "extenions" to MMBasic and take the load off Geoff a bit. After all CFunctions are pretty much just the same as any of the 'standard' normal MMBasic functions that we have little idea of the internal workings therof.

About 18 months ago I bought a copy of De Jasio's "Programming 32 Bit Microcontrollers in C" that Geoff recommends on his site, intending to have a go at it. So far though I've been too busy building things with Maxi/Micro - Mite stuff to get into it, which has been great. I still intend to get into it, one day , and I think the CFunction command and libraries of them, will help to do that.

If someone did have time to produce a "C" primer using CFunctions as Geoff suggests above, it would be excellent but I recognise that this would be a pretty major effort. In the meantime we can still all use the great tool that we have, i.e. Micromite Basic to do no end of fun useful things.

One thing that I think we do need now is a library for functions that have been written by our "C" gurus. We haven't heard from Hugh for quite a while, (he oversees the MMBasic Maximite library for those who mightn't know) but an equivalent of that for Micromite MMBasic and CFunctions is needed - IMHO. If such is done then contributors should be encouraged to provide the "C" code along with the CFunction so that us "Basic only" fellas can go a step further. If those CFunctions could also be written in Micromite Basic (albeit in some cases perhaps running a bit slow to be useful) then it would be very helpful to provide that as well to allow modding (and maybe de-bugging) by the Basic-only crew.

Greg
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 8592
Posted: 02:44am 27 Nov 2014
Copy link to clipboard 
Print this post

  Quote  I can only see this getting better and better, however, I am getting more and more lost when viewing these threads. So this noob needs to figure out what to do to keep up with you experienced C guys.


Viscomjim

Firstly let me state that I am a complete novice at C. I use a small subset of the language that maps 1:1 onto similar basic statements. I try to use few if any of the features that can make C very difficult to read. I don't work with Arduino because that uses an object-orientated version of C that I also find very difficult.

Let me lead you through the C code in this thread so you can see how easy it is.
long long NECreceive(){

This is the same as the Basic function definition. "long long" is just C speak for a Geoff's "as integer". The opening curly bracket marks the start of the code block that will be the function. There is a closing curly bracket at the end which is equivalent to "end function"
unsigned int i,j,k,buffer,bitlength,log[66];
unsigned char a,b,c,d;

These are my variable definitions as per DIM i,j etc. The "unsigned int" says they will be 32 bit integers that go from 0 - 2^32-1, char is a normal 8-bit byte. C statements terminate with a ";" character to indicate the end of the logical line.

#define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register
#define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter
#define porta *(volatile unsigned int *)0xbf886020 //port a

This bit is magic and copied from G8JCF's tutorial but the format is always the same. The first line is saying that the integer tmr1con is located at memory location 0xbf800600 in the pic's memory. This happens to be the location of the hardware register that controls timer1 so when I write to tmr1con I am actually writing to that specific hardware register.
tmr1con=0x8010; //turn on with scale 8
buffer=0;
i=0;

Now we are into standard code, // means the start of a comment, 0x8010 comes from the pic32 manual and is turning the timer on and setting a divide/8 pre-scale from the system clock.

while ((porta & 1)==0) //wait for A.0 (pin 2) to go high after the intial long low
tmr1=0; //reset the timer

Here we are just looking a bit 0 of the pic's hardware port A (pin 2 on the 28-pin part) and doing nothing until it stops being zero. Exactly the same as a DO WHILE, LOOP in basic with nothing in the loop just slightly more cryptic. Once the pin has gone high we reset the timer to zero

while (tmr1<40000){
while (((porta&1)==1) && (tmr1<40000))
log=tmr1;
if (tmr1<40000) tmr1=0;
i++;
while (((porta&1)==0) && (tmr1<40000))
log=tmr1;
if (tmr1<40000) tmr1=0;
i++;
if (i==66) break;
} // end of outer do while

This bit has an outer DO WHILE with two inner DO WHILEs inside it. The curly brackets define the code within the outer loop so the last closing bracket is the equivalent of a Basic "LOOP" statement. The outer loop says keep processing unless the timer has got to such a large value that there can't be any more data coming into the pin.
The top inner loop repeats doing nothing until the input pin stops being zero or a timeout occurs. Note that the logical equivalence operator is == rather than just = which is only used for assignment. && = logical AND, || = logical OR, != logical not equal.
Once the pin goes to zero we store the timer value in the array "log" at index "i" note the C syntax uses square brackets rather than round ones for array access and we then reset the timer unless it was a timeout.
i++ just means i=i+1. It is a unary operator similar to NOT in basic.
The next while loop waits, doing nothing, for the input pin to go high again unless a timeout occurs and again we store the time taken for the input to change. The "if(i==66)" statement checks if the array is now full and "break" is exactly the same as EXIT in Basic leaving the outer "while" loop if it is full.

if(i==4) return 0xFF; //Repeat code
if(i>4 && i<66) return 0; //invalid code
bitlength=log[0]/16*3; //establish a test bit length

The next bit of code runs once there has been a timeout or the array is full. It checks if the IR remote has sent a repeat code in which case i will be 4. If so it then sets the function return to 0xFF (=&HFF in Basic). "return =" is the same as "NECreceive=" if it was a Basic function.
If the data received was neither a repeat (i>4) or a full package (i<66) then I return an invalid return of 0.
The NEC format starts with a 4.5msec low pulse and I know I have stored the measured length of the pulse in the log array in position zero. "0"s in NEC are represented by 512usec pulses (4.5msec/8), "1"s by three times that length so I pick a time that is 1.5 times the "0" length to act as the differentiator between "1" and "0". This makes the test independent of processor speed.
for (k=0;k<32;k++){
j=(k+1)*2;
if(log[j]>bitlength) buffer=buffer | (1<<k);
}

I'm not interested in the negative pulse lengths - these should all be 512usec, so I start a "FOR" loop. The C code means "FOR k=0 to 31 step 1" and again the curly brackets enclose the code in the loop with the last one equivalent to "NEXT k"
j is just a counter that increments in steps of 2 starting at array position 2.
I then test if the stored pulse length was greater than my predetermined cutoff and if it is I bitwise OR (in C this is the | character) the output buffer with a 1 shifted into the requisite position. All this can be replicated 1:1 in Geoff's Basic.
Once this has run I have the NEC code in my output buffer.

a= buffer & 0xFF;
b= ~((buffer>>8) & 0xff);
c= (buffer>>16) & 0xff;
d= ~((buffer>>24) &0xff);
if ((a!=b) | (c!=d)) return 0;
return c+256*b;
}


As per my post above the NEC format repeats the 8 bit address and 8 bit data in ones-complement form so I assign the individual bytes to my local variables a,b,c, and d. The "~" character is exactly the same as "NOT" in Basic. The bit shift operators >> and << are now available in Geoff's Basic but equally I could have written ">>8" as "/256" etc.
The if statement tests whether the now inverted ones-complement version is equal to the normal version for both the address and the data bytes. If it isn't something is wrong so I return 0. Otherwise I return the databyte + the address scaled by 256. NB the C if statement uses () to contain the conditional test rather then using THEN to end the conditional part. If we need multiple statements after the IF then we use curly brackets to contain them. Likewise an "else" clause can also be added.

I hope you can see there is nothing I'm doing that couldn't be written 1:1 in basic, just the syntax is rather more cryptic which makes it harder to read.

The gotchas in C for me are:
forgetting the ; character at the end of a line (bizarrely and I personally think incorrectly this is not required after a closing curly bracket)
forgetting that the equivalence operator is "==" and not "=". If(a=b) is valid and sets variable a to be the same as variable b whilst testing whether "a" is "true: <>0" or "false:=0"
code in C is case sensitive.

Don't be afraid of C. If you can program in Basic then you can certainly program in C at my level. Of course complex program logic will be complex in any language.

The C bible is still Kernighan and Richie - "The C programming language". This is widely available on the web as a PDF. It does get into much more complex constructs that I use but it is readable and has exercises.

One of the limitations of cFunctions that actually makes them much easier is that we can't use lots of external library routines. I just treat it as compiled basic with a slightly different syntax.

Hope this helps

Best regards

Peter

 
Philbo
Newbie

Joined: 05/11/2014
Location: Australia
Posts: 1
Posted: 02:52am 27 Nov 2014
Copy link to clipboard 
Print this post

I want to thank matherp for all his hard work. I really appreciate people who contribute not only their intellectual output but also their time. I also appologise for going off-topic. Please excuse.

I'm in a similar situation as the other Basic only guys here. I have only dabbled in one low-level language, Pascal and that was many years ago.
Taking Paceman's idea in another direction (for discussion only) I think a well documented library is almost mandatory. Down the track when potentially dozens of libraries exist, a Basic coder could browse through, looking at the summaries for each and decide which function or functions in a library may and may not fit their needs.
I think with libraries most programmers use them and few would dissect them to see how they work unless there was a need. Rather, a library is selected because it can get a particular job done. There isn't a real need to know how it works, just that it does.
If memory serves, I think that's how I used libraries. I read somewhere that one doesn't need to reinvent the wheel when coding; use a segment or whole library that is already trimmed to be fast and efficient and usually written by someone else rather than kludge out something that is buggy, slow and unnecessarily large. I remember I needed some critical timing when handling stepper motors and Pascal couldn't handle it (intel 386) as it isn't as quick as C. I had to insert C routines into the program to drive the steppers.
Sometimes ML is required or was back then. Maybe now with Gigahertz CPUs it might not be necessary; we can overcome bad programming or slow languages with V8 engines.
If I have that right, then all I need to know is how to insert a selected function (part of a library perhaps?) into my Basic code and that is all that is needed. A "How to" on inserting/using libraries would be the duckz gutz imo.
I do not want to give people the wrong ideas here and if I need correcting, please do that and maybe let me/us know how it does work.
philEdited by Philbo 2014-11-28
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1328
Posted: 03:42am 27 Nov 2014
Copy link to clipboard 
Print this post


@matherp,
Thanks for all that Peter - you obviously type, and probably think, a whole lot faster than I do. It's 12:30 a.m. here now - I'll hit the sack and try to digest it a bit tomorrow.

Greg
 
Dylan
Regular Member

Joined: 17/06/2013
Location: Netherlands
Posts: 81
Posted: 09:46am 27 Nov 2014
Copy link to clipboard 
Print this post

  matherp said  

#define tmr1con *(volatile unsigned int *)0xbf800600 //timer 1 configuration register
#define tmr1 *(volatile unsigned int *)0xbf800610 //timer 1 counter
#define porta *(volatile unsigned int *)0xbf886020 //port a

This bit is magic and copied from G8JCF's tutorial but the format is always the same. The first line is saying that the integer tmr1con is located at memory location 0xbf800600 in the pic's memory. This happens to be the location of the hardware register that controls timer1 so when I write to tmr1con I am actually writing to that specific hardware register.


Good explanation, except that pointers aren't magic ;) There are three parts to the 'magic':

First of all, #define is used by the C pre-processor to replace every instance of tmr1con, etc, with the tokens after it (perhaps recursively, but not here).

The second is the volatile keyword. The hardware register can change at any time, so no optimization is allowed.

Third, putting it all together, is a cast and a dereference thereof. 0xbf8blabla is cast to the type "pointer to a volatile unsigned int" (the last * being the pointer) and then immediately derefenced with the very first *.

K&R C is really close to the metal(loid), and the pre-processor allows this kind of idiom without cluttering the compiler or the language all that much.

Being able to read K&R C gets you a long way with the various derivatives (C++, Java, C#), none of which are of much interest to me in themselves, mind.

See if http://microchip.wikidot.com/tls2101:start does a better job than me ;)Edited by Dylan 2014-11-28
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 5913
Posted: 10:40am 27 Nov 2014
Copy link to clipboard 
Print this post

One option is to treat the CFUNCTIONS provided by others as just another built-in function. As long as you know what the inputs and outputs are, the under-the-hood workings are not important.

On the other hand, the source code in C is there to look at and gradually get to understand some of it.

I know very little C but I often look at the source code provided by Geoff to understand how things work. I will never be a 'C programmer' but I can read it a bit now and I am willing to adapt some CFUNCTIONS to suit my purposes. Making small changes to working code is easier than starting from scratch.

I expect I will only resort to CFUNCTIONS if needed for speed.

Jim

VK7JH
MMedit   MMBasic Help
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1328
Posted: 07:36pm 27 Nov 2014
Copy link to clipboard 
Print this post

  matherp said  Firstly let me state that I am a complete novice at C. I use a small subset of the language that maps 1:1 onto similar basic statements. I try to use few if any of the features that can make C very difficult to read. I don't work with Arduino because that uses an object-orientated version of C that I also find very difficult.


Again thanks for that explanation of the C code Peter, I've just spent a couple of hours going through it and having a look at the link that @Dylan posted. I see what you mean about the "1:1 mapping to similar Basic statements" and it does make it relatively straight forward to follow. I can't see myself writing CFunctions anytime soon though but I will certainly be using those generously produced by others.

@Dylan,
That MicroChip "C" primer link looks pretty good. It has a good introduction about using their IDE which is definitely worth a look. It was quite understandable and took me back to when I was involved in Fortran projects back in the '60's , no doubt the rest of it would be good too but that'll have to wait a bit. I might have to invest in a copy of K&R though so that I can take it along for summertime reading .

Greg
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 01:44pm 29 Nov 2014
Copy link to clipboard 
Print this post

Hi

I've read through this thread carefully, and I do sympathise with the 'basic-only' fellas. I only ever take to CFunctions when I need speed. Like everybody else who discovered uMites, the approachability, immediacy, simplicity and low-cost of MMBasic was what attracted me to the environment and keeps me there, but the more I used the uMite, the more I needed to push the performance boundaries and hence the need for CFunctions arose.

Without a compiler for MMBasic, there is very little which can be done to speed up MMBasic enough to take on the tough jobs.

MMBasic 4.6 without CFunctions is a much more powerful environment than previous versions of MMBasic, and for many people the extra power of 4.6 is 'plenty sufficient' as we say up here in Aberdeen.

With CFunctions, MMBasic can take on those previously unapproachable areas. We never expected everyone who uses MMBasic to start writing CFunctions, but amongst the MMBasic community there must be many people who will code up 'useful' functions in CFunctions and share them for wider use.

Revision 2 of the CFunction tutorial document - http://www.g8jcf.dyndns.org/mmbasicmkii/MMBasicCFunctions.pd f - is in progress, and I will now in the light of the various comments also include some basic C tutorial material, and links to reference material.

I think the biggest area of difficulty with C is pointers, and since everything is passed into CFunctions as pointers, unless one really 'gets' pointers and the whole '*' thing it can seem very daunting. What I will do is write a chapter all about MMBasic, CFunctions and pointers to try and clear up any possible confusion.

As for a common CFunction library, I am more than happy to act as editor for CFunctions, and to provide a repository for them. If one refers to page 63,64,65 of the CFunction tutorial document, it describes how CFunctions could be published.

Perhaps I should open up a new thread specifically dedicated to the topic of CFunctions ?

In the meantime, please feel free to PM me.

Peter
The only Konstant is Change
 
viscomjim
Guru

Joined: 08/01/2014
Location: United States
Posts: 925
Posted: 02:25pm 29 Nov 2014
Copy link to clipboard 
Print this post

A big thanks to mathrep and G8JCF (Peter & Peter) for all this info. I know this is a lot of work to get this info out to us and is greatly appreciated!!! I will slowly work my way into this and hopefully gain a bit of working knowledge in the process.

The actual subject of this thread, the NEC remote, has anyone tried this with the apple remote (WW?) yet?
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1328
Posted: 08:55pm 29 Nov 2014
Copy link to clipboard 
Print this post

  G8JCF said  Revision 2 of the CFunction tutorial document - http://www.g8jcf.dyndns.org/mmbasicmkii/MMBasicCFunctions.pd f - is in progress, and I will now in the light of the various comments also include some basic C tutorial material, and links to reference material.

That's very generous of you Peter. I've read through your Tutorial a couple of times and I follow what you're doing - sort of. Expanded info about what's going on in the "C" code can only be a plus even though the Tutorial is already pretty extensive.

  Quote  
I think the biggest area of difficulty with C is pointers, and since everything is passed into CFunctions as pointers, unless one really 'gets' pointers and the whole '*' thing it can seem very daunting. What I will do is write a chapter all about MMBasic, CFunctions and pointers to try and clear up any possible confusion.

Yes, pointers are confusing, a chapter as you're suggesting above would be great. How do you find the time to do this stuff? - Scottish weather?
  Quote  As for a common CFunction library, I am more than happy to act as editor for CFunctions, and to provide a repository for them. If one refers to page 63,64,65 of the CFunction tutorial document, it describes how CFunctions could be published.

Sounds excellent to me, and having an "editor" that understands the process would be a major plus. What do others think, and I wonder what Geoff feels about this? There's already the MMBasic library that Hugh Buckle maintains on Geoff's website for the Maximite programs, but this would be a pretty different sort of animal.

  Quote  Perhaps I should open up a new thread specifically dedicated to the topic of CFunctions ?

I think a single thread on how CFunctions are produced, which could include discussion about the Tutorial, would be a good idea but not for the whole range of CFunctions. A single "CFunction" thread would have to have, sort of, subsections to cover the threads for different functions and would just complicate the board.

What might work to separate CFunction threads from the normal MMBasic threads (if that's needed at all) is to put, say (CF) as a prefix to the thread's subject heading as we used to do with (MM) or (DM) to designate a Maximite or Duinomite thread. That way people will immediately know that it will contain some "C" discussion. (Note: we don't use that MM/DM thing anymore because the whole issue has faded away, but Glenn introduced it for good reason a couple of years ago.)

I don't think we need to separate CFunction threads. There's a lot of information that's important in them anyway (or just plain interesting) for those who will never want to write one but probably will want to use them.

What do others think?

Greg
 
     Page 1 of 2    
Print this page
© JAQ Software 2024