This is part of my final project of ME461 at UIUC. In this project, I'm interested in remotely control the control gain of the Segbot we built, and I found I may use an IR sensor to achieve that. A detailed description of the whole project and the connection of the IR sensor can be found here. Here's how to read the signal with F28379D Launchpad.
Understand the signalTo read the signal, we first need to understand the signal received by the IR sensor. I used a digital oscilloscope to see the pattern of the output from the IR receiver.
After examining the signal pattern, I found that the signal will always stay high when there's no button pressed. And after receiving a signal from the TV remote, the IR receiver's output will change to low and stay for 9ms, change back to high for 4.6ms, and followed by 32 short and long pulses. The short pulses are about 640us; the long pulses are about 1.74ms.
Another interesting fact is that if we kept pressing a key, there would appear a different pattern that only consists of a series of "short" pulses shown in the above picture.
Capture the signalKnowing the pattern, I decided to use a sample rate of 0.1ms to capture the signal. This could help us to distinguish the difference between different patterns. I used CPUTimer 2, and the initialization is as follows.
int16_t state = 0;
uint16_t idle_time = 0;
uint16_t countlow = 0;
uint16_t counthigh = 0;
uint32_t store = 0;
uint32_t savestore[100];
uint16_t storeindex = 0;
ConfigCpuTimer(&CpuTimer2, 200, 100);//This makes cputimer2 to be called every 0.1ms
I used a 3-state state machine to extract the signal. State 0 is the "ignore" state. In this state, we prevent the case that if we hold a key for too long, it will mess up the readings. I set the waiting time to be 180ms, which is long enough for the user to release the TV remote's button.
//ignore state
//to prevent holding a key for too long and receive invalid signal
if (state == 0) {
idle_time++; //count the number of time entered the the timer
if (idle_time > 1800) {
state = 1;//wait for signal
idle_time = 0;
}
}
After staying in state 0 for 180ms, it will go into state 1, the "wait for signal" state. This is the state that we will stay for most of the time. Whenever a button is pushed, it first makes sure there is a low signal lasting for more than 8ms, then it will go to state 2 when another high signal is received.
//wait for signal state
//there should be a 9ms low follow by a 4.6ms high, then the signal started
else if (state == 1) {
//when the signal is low, increase the countlow number
if (GpioDataRegs.GPADAT.bit.GPIO1 == 0){
countlow++;
}
//passed the 9ms low
if (countlow > 80){
//entered the high
if (GpioDataRegs.GPADAT.bit.GPIO1 == 1) {
state = 2;// go to the read signal state;
store = 0;
counthigh = 1;
state2 = 1;
countstate2 = 0;
countlow = 0;
}
}
}
State 2 is the "read signal" state. In this state, there's another state machine that checks the receiving signal. When entered state 2, the state2
value is set to 1, which corresponds to having a high signal at the current reading. If the next bit received is still high, it will stay in state 1 of state2
. Otherwise, it will go into state 0 of state2.
This state will check the number of high signals it just received and add it to a variable called store
. When there are 32 bits in store
, the state machine will return to state 0. The store
value will be stored in savestore
.
//read signal
else if (state == 2) {
//if sees high signal, increse the number of counthigh
if (state2 == 1) {
if (GpioDataRegs.GPADAT.bit.GPIO1 == 1) {
counthigh++;
}
if (GpioDataRegs.GPADAT.bit.GPIO1 == 0) {
state2 = 0;
if (counthigh > 40){
}//do nothing
//case 2 receive a 1 (shorter)
else if(counthigh < 10){//0.64ms "1"
store = (store<<1)|1;//add a 1 at the end of the store variable
countstate2++;
} else { ///1.74ms "0"
store = store<<1 ;//add a zero to the end
countstate2++;
}
if (countstate2 == 32) {
state = 0;// back to ignore state
savestore[storeindex] = store;
storeindex = (storeindex +1) % 100;
countstate2 =0;
}
}
} else if (state2 == 0) {//when entered low, check the signal just received
//case 1 recognize the first long high signal
if (GpioDataRegs.GPADAT.bit.GPIO1 == 1) {
state2 = 1;
counthigh = 0;
}
}
}
Interpret the signalAfter having this code, we can use the expression window of Code Composer Studio to get the value of different button on our TV remote.
We can then set the actions when each button is pressed.
if (store == 0x9E5F9768) {
turnrate = turnrate - 0.2;
} else if (store == 0x9E5F57A8) {//1 turn right
turnrate = turnrate + 0.2;
} else if (store == 0x9E5FBD42) {//2 forward
FwdBackOffset = FwdBackOffset - 0.2;
} else if (store == 0x9E5F3DC2) { //3 backward
FwdBackOffset = FwdBackOffset + 0.2;
} else if (store == 0x9E5F27D8){//jump left
turnrate = 0;
turnref = turnref-3;
turnref_1 = turnref_1 - 3;
} else if (store == 0x9E5F17E8){ //jump right
turnrate = 0;
turnref = turnref+3;
turnref_1 = turnref_1 +3;
} else { //all the other button is a "reset"
turnrate = 0;
FwdBackOffset = 0;
}
CreditsThanks to Professor Dan Block's help in figuring out how to set up the state machine and read the signal.
Comments
Please log in or sign up to comment.