原文地址:https://blog.csdn.net/luhanglei/article/details/82496986
原理:當紅外發射管以38KHz頻率閃爍時,紅外接收端可以接收到信號。通過閃爍時長的不同,可以解析出不同的信號。
因爲時間精度高,不可能通過Thread.sleep()
實現。
AndroidThings支持的幾種通信協議中,SPI(AT關於SPI的官方文檔)比較合適(輸出信號爲例:CLK輸出時鐘,MOSI輸出0/1數據),因爲可以自主控制MOSI端口的高低電平,配置好對應的發射頻率,就可以實現紅外發射。
故使用SPI協議的輸出端,修改輸出頻率爲38KHz的整數倍,控制高低電平達到發射紅外信號的目的。
以樂高PF的紅外文檔爲模板(圖片截圖自樂高文檔,侵刪):
建立一個工具類,配置參數:
import com.google.android.things.pio.SpiDevice
object Util {
/**
* 每字節代表一次閃爍,當紅外發射管以38KHz閃爍的時候,接收管才能收到信號
* one byte per cycle, 1/38K second
*/
val frequency = 38000 * 8
val bitsPerWord = 8
val bitJustification = SpiDevice.BIT_JUSTIFICATION_MSB_FIRST
/**
* 一次閃爍的信號,時長1/38K秒
* one cycle of IR
* 11110000
*/
val IR = 0xf0.toByte()
/**
* 一次不閃爍的信號,時長1/38K秒
* one cycle of PAUSE
* 00000000
*/
val PAUSE = 0.toByte()
/**
* 在樂高PF的文檔裏,一次低位(0)由6個IR和10個pause組成
* In LEGO Power Functions RC document, Low bit consists of 6 cycles of IR and 10 “cycles” of pause
*/
val LOW_BIT: ArrayList<Byte> = ArrayList<Byte>().apply {
for (i in 1..6) {
add(IR)
}
for (i in 1..10) {
add(PAUSE)
}
}
/**
* 在樂高PF的文檔裏,一次高位(1)由6個IR和21個pause組成
* In LEGO Power Functions RC document, high bit of 6 cycles IR and 21 “cycles” of pause
*/
val HIGHT_BIT: ArrayList<Byte> = ArrayList<Byte>().apply {
for (i in 1..6) {
add(IR)
}
for (i in 1..21) {
add(PAUSE)
}
}
/**
* 在樂高PF的文檔裏,開始或停止位由6個IR和39個pause組成
* In LEGO Power Functions RC document, start bit of 6 cycles IR and 39 “cycles” of pause
*/
val START_AND_STOP_BIT: ArrayList<Byte> = ArrayList<Byte>().apply {
for (i in 1..6) {
add(IR)
}
for (i in 1..39) {
add(PAUSE)
}
}
}
然後組裝命令發射即可:
import android.app.Activity
import android.content.ContentValues.TAG
import android.os.Bundle
import android.util.Log
import com.google.android.things.pio.PeripheralManager
import com.google.android.things.pio.SpiDevice
import java.io.IOException
/**
* 使用SPI的MOSI口作爲輸出
* Use the MOSI port of the SPI as the output
*/
class MainActivity : Activity() {
private val SPI_DEVICE_NAME: String = "SPI0.0"
private lateinit var mSPIDevice: SpiDevice
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
val manager: PeripheralManager = PeripheralManager.getInstance()
mSPIDevice = manager.openSpiDevice(SPI_DEVICE_NAME)
configureSpiDevice(mSPIDevice)
//init and send order
val order = initOrder()
mSPIDevice.write(order, order.size)
} catch (e: IOException) {
Log.w(TAG, "Unable to access SPI device", e);
}
}
/**
* 拼接命令DEMO,樂高的命令由開始標誌+3段命令+校驗位+結束標誌組成
* Lego's order consists of START_BIT + Nibble1 + Nibble2 + Nibble3 + LRC + STOP_BIT
* LRC(4 bit) = 0xF xor Nibble 1 xor Nibble 2 xor Nibble 3
*/
private fun initOrder(): ByteArray {
val nibble1 = 0b0100
val nibble2 = 0b1010
val nibble3 = 0b0000
val lrc = 0xff.xor(nibble1).xor(nibble2).xor(nibble3)
val signal = ArrayList<Byte>()
signal.addAll(Util.START_AND_STOP_BIT)
signal.addAll(if (nibble1.and(0b1000) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble1.and(0b0100) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble1.and(0b0010) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble1.and(0b0001) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble2.and(0b1000) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble2.and(0b0100) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble2.and(0b0010) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble2.and(0b0001) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble3.and(0b1000) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble3.and(0b0100) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble3.and(0b0010) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (nibble3.and(0b0001) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (lrc.and(0b1000) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (lrc.and(0b0100) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (lrc.and(0b0010) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(if (lrc.and(0b0001) != 0) Util.HIGHT_BIT else Util.LOW_BIT)
signal.addAll(Util.START_AND_STOP_BIT)
return signal.toByteArray()
}
override fun onDestroy() {
super.onDestroy()
try {
if (::mSPIDevice.isInitialized) {
mSPIDevice.close()
}
} catch (e: IOException) {
Log.w(TAG, "Unable to access SPI device", e);
}
}
@Throws(IOException::class)
fun configureSpiDevice(device: SpiDevice) {
device.setMode(SpiDevice.MODE0)
device.setFrequency(Util.frequency)
device.setBitsPerWord(Util.bitsPerWord)
device.setBitJustification(Util.bitJustification)
}
}
接線圖(我用的樹莓派3B):
完整代碼包:https://github.com/Yangwoqizuo/Android-Things-IR
原文地址:https://blog.csdn.net/luhanglei/article/details/82496986