Infrared Sending Part 1
Sending IR signals is difficult when using a device that is expected to be wall or shelf mounted. You have to create a strong enough signal for it to bounce around the room and be received by the target under less than ideal conditions.
To accomplish this, you have to use quite a bit of power. In my original project, I tied a couple of I/O pins together and drove the LED by sinking current in parallel. That worked if the LED was a foot or two away from the unit, but failed when trying to bounce off of walls. I also tried different LED’s and finally found one that works better than others.
One manufacturer of remotes wired two led’s in series to get the signal range with the smallest amount of power consumed in the unit. It worked, but I wanted something easier to tinker with.
Since the IR signal was recorded on time, it has to be played out in the time domain. When the IR signal was recorded, it was recorded at 500 ns (1/2 microsecond) accuracy, but was divided by two to remove some jitter. On playback, the signal is played back at a 500 ns rate, so it is shifted before it it put into the playback timer. This gives us at most a 1 us (microsecond) inaccuracy in playback from the hardware. The CPU is then interrupted, and the next value is loaded into the counter. This takes around 2 microseconds, so the total inaccuracy is around 3 microseconds (or longer if another interrupt is executing). Total is around 3 to 7 microseconds jitter for a 48 mHz processor. This is well within tolerances for IR, whose 38 kHz modulation of the light gives you a 26 microsecond jitter based on when you start the signal relative to the 38 kHz clock.
The Circuitry Description
Sending a “1” in IR means turning the light on. However, it has to be modulated at a 38 kHz rate. In addition, we don’t want any spurious IR leaking out, so we need an easy control mechanism. I chose to use a 3 input AND gate. When all 3 inputs are high, its output is high. This high level drives the gate of an FET or the base of a darlington transistor and turns the light on. When the signal is a “1”, and the control is a “1”, the 38 kHz clock modulates the IR signal outs at the proper frequency to be “seen” by the remotely controlled device.
I went from parallel I/O’s to an FET. That worked better, but the drain resistance was high enough to limit the current through the LED. I then switched to a Darlington Transistor, and that provided the lowest on resistance for the LED. Placing a 5 ohm resistor between the LED and the 5 volt power supply provided enough current to bounce off the walls and still send a message to the A/C unit (except when the sun is directly shining through the window into the room).
Here is the final schematic. Note that I used P12_4 to snoop on the enable/disable signal. That made it easier to troubleshoot while the circuitry was in its early stages of development:
Configurations:
There are three configurations to be done. The first is the number of control signals and the name. The IR_OUT_START sends a pulse to the reset line of Timer_IR_OUT. This pulse is handled by the hardware of the control register. The Timer is a One Shot configuration, which means it has to be physically reset each time it runs. There are the configuration dialogs:
The Code
Note: In main.h, add the following line just below the last #include in the file:
#include "playIR.h"
PlayIR.h:
#ifndef _PLAYIR_H_
#define _PLAYIR_H_
/* ========================================
* Copyright Wade Maxfield, 2020
* All Rights Reserved
* LICENSED SOFTWARE.
* Under the GPL v3 license
* This license does not override previous licenses
* Some information may be Proprietary to
* Cypress (http://www.cypress.com) for their
* PSoC 5LP®--Cypress Semiconductor and
* only usable on their devices.
* PROPERTY OF Wade Maxfield.
* Commercial license available
* ========================================
*/
#include "main.h"
extern enum equipEnum CurrentEquipmentID;
void init_playIR();
void addPlayIRToQueue(enum captureTypesEnum playID, enum equipEnum equipID);
int16 IR_is_playing();// return 1 if ir signal is being played out
void playIRSignal(enum captureTypesEnum playID, enum equipEnum equipID);
void handle_playIR() ;
int16 playNextIR();
#endif
/* [] END OF FILE */
playIR.c:
Note: See the next post for the playIRFlag information and location in Milliseconds.h and Milliseconds.c.
/* ========================================
* Copyright Wade Maxfield, 2020
* All Rights Reserved
* LICENSED SOFTWARE.
* Under the GPL v3 license
* This license does not override previous licenses
* Some information may be Proprietary to
* Cypress (http://www.cypress.com) for their
* PSoC 5LP®--Cypress Semiconductor and
* only usable on their devices.
* PROPERTY OF Wade Maxfield.
* Commercial license available
* ========================================
*/
#include "main.h"
enum equipEnum CurrentEquipmentID;
enum captureTypesEnum captureType;
const uint16 powerGE[] =
{ 8578, 4278, 555, 1596, 522, 1603, 557, 1595, 555,
534, 525, 1600, 549, 566, 504, 1595, 555, 1596, 553,
4228, 553, 1598, 552, 1573, 556, 533, 557, 1594, 524,
539, 552, 537, 554, 562, 497, 539, 657, 22505
};
const enum captureTypesEnum modeSequenceGE[] =
{
heatType,
coolType,
energySaverType,
fanOnlyType
};
const uint16 modeGE[] =
{ 8564, 4286, 548, 1602, 527, 1597, 553, 1598, 552,
537, 523, 1601, 549, 566, 503, 1594, 556, 1595, 545,
4234, 548, 1603, 547, 1576, 553, 563, 527, 561, 520,
542, 527, 562, 529, 559, 522, 540, 624, 19372, 8565,
4286, 548, 1603, 547, 1577, 552, 1599, 551, 564, 495,
1603, 547, 568, 523, 1574, 555, 1596, 554, 4226, 556,
1595, 555, 1597, 521, 541, 550, 566, 525, 564, 495,
567, 524, 565, 526, 563, 602, 6861
};
const uint16 fanOnlyFRIGIDAIRE[] =
{ 9005, 4432, 601, 510, 601, 537, 575, 537, 574,
1630, 593, 544, 567, 519, 603, 509, 603, 535, 576,
1628, 595, 543, 568, 1636, 598, 540, 572, 1632, 601,
1629, 594, 1636, 598, 1632, 601, 1629, 594, 1636, 597,
1633, 600, 538, 574, 538, 573, 539, 573, 539, 573,
538, 573, 539, 573, 513, 598, 514, 598, 1632, 601,
1629, 594, 1636, 598, 1632, 601, 1621, 601, 40612, 8978,
2175, 592, 62490
};
const uint16 fanSlowerGE[] =
{ 8568, 4253, 548, 1602, 547, 1603, 524, 1600, 549,
539, 551, 1573, 555, 533, 557, 1594, 523, 1601, 548,
4258, 522, 540, 550, 538, 552, 1599, 529, 533, 546,
542, 548, 541, 529, 533, 546, 542, 632, 19385, 8569,
4281, 520, 1603, 556, 1595, 553, 1571, 547, 542, 548,
1602, 526, 536, 554, 1597, 551, 1599, 529, 4250, 551,
563, 496, 566, 523, 1600, 549, 539, 530, 532, 548,
567, 523, 539, 520, 542, 632, 45466
};
const uint16 fanFasterGE[] =
{ 8567, 4248, 552, 1597, 552, 1597, 521, 1602, 547,
541, 549, 1574, 554, 561, 529, 1593, 524, 1599, 550,
4253, 527, 1596, 553, 535, 555, 1594, 523, 538, 553,
535, 555, 533, 526, 535, 554, 534, 630, 19375, 8569,
4276, 577, 1545, 552, 1597, 552, 1597, 520, 568, 522,
1600, 581, 480, 547, 1602, 547, 1603, 525, 4251, 550,
1599, 529, 559, 521, 1602, 546, 568, 502, 533, 557,
558, 522, 566, 503, 558, 605, 62822
};
const uint16 fanAutoGE[] =
{ 8567, 4278, 554, 1595, 554, 1570, 548, 1601, 547,
568, 502, 1595, 554, 561, 518, 1579, 549, 1601, 548,
4229, 551, 564, 526, 1597, 520, 568, 522, 1601, 548,
567, 502, 559, 521, 567, 523, 565, 599, 19357, 8566,
4279, 553, 1596, 522, 1601, 547, 1602, 547, 568, 501,
1596, 553, 561, 519, 1577, 551, 1599, 550, 4226, 553,
562, 528, 1594, 523, 565, 525, 1598, 551, 564, 494,
567, 523, 565, 525, 563, 601, 34215
};
const uint16 upGE[] =
{ 8559, 4294, 564, 1559, 537, 1614, 542, 1581, 545,
571, 512, 1611, 535, 554, 509, 1615, 541, 1610, 516,
4263, 535, 580, 483, 579, 514, 575, 517, 1606, 510,
579, 514, 575, 508, 580, 483, 579, 594, 19402, 8554,
4297, 542, 1608, 518, 1606, 540, 1611, 534, 555, 509,
1615, 540, 576, 507, 1590, 536, 1615, 541, 4239, 540,
576, 517, 571, 492, 571, 512, 1612, 543, 572, 492,
571, 512, 577, 515, 574, 589, 19383, 8562, 4291, 537,
1613, 513, 1611, 545, 1606, 540, 549, 514, 1610, 536,
580, 483, 1615, 540, 1611, 535, 4245, 543, 573, 510,
579, 484, 579, 514, 1611, 535, 580, 483, 579, 514,
575, 508, 581, 591, 19378, 8558, 4293, 535, 1614, 512,
1613, 543, 1607, 509, 580, 513, 1612, 545, 570, 483,
1615, 541, 1610, 536, 4243, 536, 580, 512, 576, 488,
574, 519, 1605, 541, 548, 515, 574, 509, 579, 514,
548, 614, 18173
};
const uint16 downGE[] =
{ 8556, 4271, 537, 1613, 543, 1609, 517, 1607, 539,
576, 517, 1581, 545, 571, 512, 1612, 514, 1611, 535,
4272, 517, 1607, 539, 577, 515, 574, 490, 1608, 538,
578, 515, 547, 516, 572, 510, 579, 594, 19405, 8562,
4290, 508, 1616, 540, 1610, 536, 1589, 537, 552, 541,
1610, 516, 547, 536, 1615, 541, 1610, 516, 4263, 536,
1588, 538, 578, 515, 574, 509, 1589, 537, 552, 541,
574, 509, 553, 510, 579, 593, 19405, 8561, 4292, 516,
1608, 538, 1613, 513, 1611, 545, 571, 512, 1612, 514,
548, 535, 1615, 541, 1582, 544, 4263, 566, 1558, 538,
550, 543, 573, 490, 1607, 539, 550, 543, 546, 517,
545, 538, 551, 622, 19400, 8559, 4266, 542, 1608, 539,
1612, 514, 1610, 536, 580, 513, 1584, 543, 573, 510,
1614, 512, 1612, 544, 4262, 517, 1608, 538, 577, 516,
573, 490, 1608, 538, 577, 507, 555, 518, 571, 512,
577, 595, 43738
};
const uint16 powerFRIGIDAIRE[] =
{ 8922, 4442, 601, 510, 601, 510, 602, 510, 601,
1629, 594, 517, 595, 516, 595, 517, 595, 516, 595,
1635, 598, 540, 572, 1632, 601, 510, 601, 1629, 594,
1636, 597, 1633, 600, 1630, 593, 1636, 597, 515, 597,
514, 597, 515, 596, 1634, 599, 512, 600, 512, 599,
512, 599, 513, 598, 1632, 602, 1627, 595, 1635, 598,
514, 597, 1632, 601, 1629, 594, 1628, 595, 40617, 8920,
2229, 601, 4179
};
const uint16 upFRIGIDAIRE[] =
{ 9004, 4441, 594, 557, 567, 558, 567, 558, 566,
1650, 599, 553, 572, 552, 572, 553, 572, 553, 571,
1645, 593, 558, 567, 1648, 600, 525, 600, 1642, 596,
1646, 603, 1640, 598, 1644, 594, 558, 566, 1649, 600,
1642, 596, 1647, 602, 549, 575, 550, 574, 550, 575,
550, 574, 1641, 598, 554, 570, 555, 570, 554, 570,
1646, 593, 1649, 599, 1644, 595, 1648, 600, 40674, 9001,
2202, 593, 31525
};
const uint16 downFRIGIDAIRE[] =
{ 9004, 4441, 593, 532, 592, 533, 592, 532, 592,
1651, 598, 527, 597, 528, 596, 529, 596, 528, 596,
1647, 601, 524, 601, 1641, 597, 528, 596, 1646, 593,
1650, 598, 1645, 594, 1649, 600, 1643, 595, 530, 595,
1647, 601, 1642, 597, 528, 596, 529, 595, 530, 595,
530, 594, 530, 594, 1649, 600, 525, 599, 526, 598,
1643, 595, 1648, 601, 1642, 596, 1647, 602, 40674, 8999,
2204, 591, 30399
};
const uint16 heatFRIGIDAIRE[] =
{ 9002, 4449, 596, 530, 594, 531, 594, 532, 592,
1651, 598, 528, 597, 528, 596, 530, 595, 530, 594,
1649, 600, 526, 599, 1644, 594, 532, 593, 1650, 599,
1645, 594, 1650, 599, 1645, 593, 1651, 598, 1646, 593,
1651, 598, 1645, 593, 560, 575, 1642, 597, 1647, 602,
1642, 596, 556, 569, 530, 594, 532, 593, 558, 566,
1651, 598, 554, 570, 529, 596, 556, 568, 40706, 9003,
2205, 600, 61548
};
const uint16 fanAutoFRIGIDAIRE[] =
{ 8932, 4438, 604, 508, 603, 509, 602, 510, 601,
1631, 602, 537, 574, 538, 573, 539, 572, 541, 570,
1635, 597, 541, 570, 1636, 597, 541, 570, 1636, 596,
1636, 597, 1634, 598, 1634, 598, 1634, 599, 1632, 601,
1631, 601, 1631, 602, 536, 575, 537, 574, 513, 598,
514, 597, 515, 596, 543, 578, 534, 577, 536, 575,
1630, 603, 1629, 603, 1629, 604, 1619, 602, 40650, 8926,
2230, 600, 57484
};
const uint16 fanFasterFRIGIDAIRE[] =
{ 9001, 4447, 596, 528, 596, 529, 596, 529, 595,
1648, 601, 524, 600, 525, 599, 526, 598, 527, 598,
1645, 603, 523, 603, 1642, 598, 528, 596, 1647, 601,
1642, 596, 1647, 602, 1641, 597, 1646, 593, 532, 603,
522, 602, 523, 601, 524, 601, 524, 600, 525, 599,
526, 599, 526, 598, 1645, 593, 1650, 599, 1645, 593,
1650, 599, 1644, 594, 1650, 599, 1644, 594, 40695, 9002,
2203, 602, 30202, 9001, 2206, 599, 5029
};
const uint16 fanSlowerFRIGIDAIRE[] =
{ 9002, 4447, 597, 528, 596, 529, 595, 530, 595,
1649, 599, 526, 599, 526, 598, 527, 597, 529, 595,
1648, 601, 524, 600, 1644, 594, 531, 594, 1649, 599,
1645, 593, 1651, 598, 1646, 592, 533, 602, 523, 601,
1643, 595, 530, 595, 531, 593, 532, 592, 533, 602,
523, 601, 1643, 596, 1648, 600, 525, 599, 1644, 595,
1649, 599, 1644, 595, 1649, 600, 1643, 595, 40698, 9008,
2200, 596, 30225, 9003, 2204, 592, 6542
};
const uint16 energySaverFRIGIDAIRE[] =
{ 8993, 4435, 596, 514, 597, 515, 596, 515, 596,
1633, 600, 538, 573, 512, 599, 538, 573, 538, 573,
1631, 602, 535, 576, 1628, 594, 543, 568, 1635, 598,
1632, 600, 1629, 604, 1626, 596, 541, 570, 1634, 598,
539, 572, 513, 598, 539, 572, 539, 573, 539, 572,
539, 572, 1631, 601, 537, 574, 1629, 593, 1637, 596,
1633, 599, 1631, 602, 1627, 595, 1627, 595, 40619, 8969,
2175, 603, 41835
};
const uint16 coolFRIGIDAIRE[] =
{ 8999, 4429, 601, 536, 575, 537, 574, 538, 573,
1631, 601, 537, 574, 538, 573, 539, 572, 539, 572,
1633, 599, 539, 572, 1632, 600, 538, 574, 1631, 601,
1630, 602, 1628, 595, 1636, 596, 1635, 597, 541, 570,
542, 569, 1636, 596, 542, 569, 543, 568, 544, 567,
545, 576, 535, 576, 1629, 603, 1628, 594, 544, 577,
1628, 594, 1637, 595, 1636, 597, 1626, 595, 40642, 8970,
2179, 598, 26369
};
static int16 playIndex;
static int16 maxPlayIndex;
static uint16 *playPtr;
static int16 playLevel;
int16 minumTimeBetweenIRCommands;
#define MAX_NUMBER_OF_PLAY_COMMANDS 64 // should never have this much stacked up.
int16 irHead,irTail;
uint16 irTimeout; // up to 1 second between plays
enum equipEnum irEquipment[MAX_NUMBER_OF_PLAY_COMMANDS];
enum captureTypesEnum irIDs[MAX_NUMBER_OF_PLAY_COMMANDS];
//------------------------------------------
//------------------------------------------
CY_ISR(isr_IR_OUT){
// if playIndex>maxPlayindex, we are through.
if (playPtr ){
if (playIndex++ < maxPlayIndex) {
Timer_IR_OUT_ReadStatusRegister();
Timer_IR_OUT_WritePeriod(*playPtr++<<1);// the time of the output
playLevel = !playLevel;
cr_IR_OUT_Level_Write(playLevel);// tell it to send/not send
cr_IR_OUT_START_Write(1);// send start pulse
return;
}
}
cr_IR_OUT_Level_Write(0);// tell it to send/not send
}
//------------------------------------------
// initialize for playing IR signals
//------------------------------------------
void init_playIR(){
isr_IR_OUT_CounterFinished_StartEx(isr_IR_OUT);
Timer_IR_OUT_Start();
}
//------------------------------------------
//------------------------------------------
void handle_playIR() {
playNextIR();
}
//------------------------------------------
// play the next ir if one is to be played
// by pulling it from the queue
// which is in the form of a ring buffer
// return 0 if not playing, 1 if playing
//------------------------------------------
int16 playNextIR() {
static int16 wasPlaying;
// borrow the playIRFlag from the Milliseconds code
// to give us a 1 millisecond counter under our control
// This is only approximate, as other routines can hog
// the CPU time, but the overall code is tight enough
// to not worry about this.
if (playIRFlag){
playIRFlag=0;
if(irTimeout){
irTimeout--;
}
}
if (irHead==irTail){
if (wasPlaying){
wasPlaying=0;
//sendTextToNextion("main.rbSending.val=0");
}
return 0 ; // not playing
}
if (!wasPlaying){
wasPlaying=1;
//sendTextToNextion("main.rbSending.val=1");
}
if (irTimeout)
return 1; // playing (sort of)
if (CurrentEquipmentID==FRIDGIDAIRE_ID)
minumTimeBetweenIRCommands=100; //was 50 may make this incrementable by nextion later
else
minumTimeBetweenIRCommands=400;
// play the next, set irTimeout
irTimeout = minumTimeBetweenIRCommands; // minimum time between ir commands <-- make settable later
playIRSignal(irIDs[irTail],irEquipment[irTail]);
// increment tail (removes the item from the ring buffer
if (++irTail >= MAX_NUMBER_OF_PLAY_COMMANDS)
irTail=0;
return 1;// playing a command
}
//------------------------------------------
// return a 1 if IR is playing now, 0 if not
//------------------------------------------
int16 IR_is_playing() {
if (playIndex<maxPlayIndex)
return 1;
return 0;
}
//------------------------------------------
// start the playing of the IR signal
//------------------------------------------
void doPlayIR(uint16 *lPlayPtr,int16 numItems){
playIndex=1;
playLevel=1; // send IR out at 1, don't send at 0.
maxPlayIndex=numItems;
playPtr = lPlayPtr;
Timer_IR_OUT_WritePeriod(*playPtr++<<1);// correct speed
cr_IR_OUT_Level_Write(playLevel);// tell it to send/not send
cr_IR_OUT_START_Write(1);// send start pulse
}
//------------------------------------
// add the signal to play to the
// ir Queue
//------------------------------------
void addPlayIRToQueue(enum captureTypesEnum playID,enum equipEnum equipID){
irIDs[irHead]=playID;
irEquipment[irHead]=equipID;
// ignore collision in ring buffer
// if that happens, too much is going on and
// ring buffer needs increasing
if (++irHead >= MAX_NUMBER_OF_PLAY_COMMANDS)
irHead=0;
}
//------------------------------------------
// play the IR signal
//------------------------------------------
void playIRSignal(enum captureTypesEnum playID, enum equipEnum equipID){
if (equipID==GE_ID){
switch (playID){
default:
break; // do nothing
case upType:
doPlayIR((uint16 *)upGE,sizeof(upGE)/sizeof(uint16));
break;
case downType:
doPlayIR((uint16 *)downGE,sizeof(downGE)/sizeof(uint16));
break;
case powerType:
doPlayIR((uint16 *)powerGE,sizeof(powerGE)/sizeof(uint16));
break;
case modeType:
doPlayIR((uint16 *)modeGE,sizeof(modeGE)/sizeof(uint16));
break;
case fanSlowerType:
doPlayIR((uint16 *)fanSlowerGE,sizeof(fanSlowerGE)/sizeof(uint16));
break;
case fanFasterType:
doPlayIR((uint16 *)fanFasterGE,sizeof(fanFasterGE)/sizeof(uint16));
break;
case fanAutoType:
doPlayIR((uint16 *)fanAutoGE,sizeof(fanAutoGE)/sizeof(uint16));
break;
/*
case coolType:
doPlayIR((uint16 *)coolGE,sizeof(coolGE)/sizeof(uint16));
break;
case heatType:
doPlayIR((uint16 *)heatGE,sizeof(heatGE)/sizeof(uint16));
break;
case energySaverType:
doPlayIR((uint16 *)energySaverGE,sizeof(energySaverGE)/sizeof(uint16));
break;
*/
}
} else {
switch (playID){
default:
break; // do nothing
case upType:
doPlayIR((uint16 *)upFRIGIDAIRE,sizeof(upFRIGIDAIRE)/sizeof(uint16));
break;
case downType:
doPlayIR((uint16 *)downFRIGIDAIRE,sizeof(downFRIGIDAIRE)/sizeof(uint16));
break;
case coolType:
doPlayIR((uint16 *)coolFRIGIDAIRE,sizeof(coolFRIGIDAIRE)/sizeof(uint16));
break;
case heatType:
doPlayIR((uint16 *)heatFRIGIDAIRE,sizeof(heatFRIGIDAIRE)/sizeof(uint16));
break;
case energySaverType:
doPlayIR((uint16 *)energySaverFRIGIDAIRE,sizeof(energySaverFRIGIDAIRE)/sizeof(uint16));
break;
case powerType:
doPlayIR((uint16 *)powerFRIGIDAIRE,sizeof(powerFRIGIDAIRE)/sizeof(uint16));
break;
case fanOnlyType:
doPlayIR((uint16 *)fanOnlyFRIGIDAIRE,sizeof(fanOnlyFRIGIDAIRE)/sizeof(uint16));
break;
case fanSlowerType:
doPlayIR((uint16 *)fanSlowerFRIGIDAIRE,sizeof(fanSlowerFRIGIDAIRE)/sizeof(uint16));
break;
case fanFasterType:
doPlayIR((uint16 *)fanFasterFRIGIDAIRE,sizeof(fanFasterFRIGIDAIRE)/sizeof(uint16));
break;
case fanAutoType:
doPlayIR((uint16 *)fanAutoFRIGIDAIRE,sizeof(fanAutoFRIGIDAIRE)/sizeof(uint16));
break;
}
}
}
/* [] END OF FILE */
main.c:
Modify main.c to call the code you just added to the project:
int main(void)
{
// the following two variables are for USBSerial/Command Parser
int16 bufNum;
USBSerialMessage *USBRxPtr;
init_milliseconds();
init_leds();
CyGlobalIntEnable; /* Enable global interrupts. */
initUSBSerial();// setup the USB serial interface.
init_parse();
init_capture();// set up the I/R Capture hardware
init_playIR(); // initialize the ir playback <-------------playIR
for(;;)
{
handle_playIR(); // handles scheduling of IR cmds <-----playir
BlinkLed1(100); // blink 10 times per second (every 100ms)
//======================
// usb serial port
//======================
if ((bufNum=handleUSBSerial())>=0){
USBRxPtr=&USBRxBuffer[bufNum];
parse((char*)(USBRxPtr->msg),(uint16*)&(USBRxPtr->size)); // handle possible command
}
temperature=getTemperatureF(&TemperatureReadingAvailable);
if (TemperatureReadingAvailable) {
// write your code here to do something
}
//===========================
// if the user has chosen to
// read the I/R controller.
//===========================
handle_capture();
handle_playIR(); // handles scheduling of ir commands
}
}
Code Explanation:
To facilitate sending arbitrary IR, I created a queue system where the signals are played out of a list. This allows fairly complex command sequences to be sent. The codes shown were captured and then placed into an array in code. These arrays reside in flash memory. The contents were placed into the flash by using the const keyword and initializing the array immediately. Without both, the arrays is initialized each time the PSOC boots, and can be overwritten by accidental memory writers.
To make it easier to put the codes in memory, I wrote a formatter that became part of parseCommands.c file. It became a matter of copy and paste from the terminal program. I’ll give you that code snippet here. Review the earlier posts to see where to put the command.
case 'f': case 'F':{
sprintf(outMsg,"Captured %d readings\n\r{ ",capCounter);
printMessage(outMsg);
index1=0;
for (index =0; index < capCounter; index++){
result = SendTimes[index];
sprintf(outMsg," %5ld",result);
if (++index1>9){
index1=0;
printMessage("\n\r");
}
printMessage(outMsg);
if (index < capCounter-1)
printMessage(", ");
}
// printMessage(", 0");// terminate array
printMessage("\n\r};\n\r");
} goto printSignon;
Parting Words
If you have followed the posts from the beginning, you should be able to create this part of the project with the information given. Cut open an old remote and steal the LED if you wish. The Darlington can be purchased on Amazon, search for Darlington Transistor. For a few dollars, you can get kits which will let you experiment.
Next time, I will give some photos, and sources for the LED and other parts used, along with some code to start tying things together. The Nextion display will rear its head sometime in the future.
Enjoy!