我正在使用最近购买的DragonBoard 410 C,运行Android5.1操作系统,并使用Android和Kotlin一起生成一个示例应用程序,该应用程序探索了一些硬件,比如40针低功耗连接器。
我的问题是如何使用Kotlin和Android访问带有GPIO引脚的40针低功耗连接器。
从我到目前为止的研究来看,mraa库似乎是通往成功的道路,但是我没有找到任何关于使用Kotlin库的文档。
如何开始使用Kotlin的mraa库来访问40针低功耗连接器?
还是有不同的方法?
我的第一个例子是一个简单的眨眼LED应用程序,但我不知道如何访问低功耗连接器的引脚使用Kotlin。
备注和资源
mraa文档页面
Libmraa是一个C/C++库,它绑定到Python、Javascript和Java,以便与伽利略、爱迪生和其他平台上的I/O接口,并使用结构化的、合理的API,其中端口名称/编号与您所在的板相匹配。使用libmraa并不会将您绑定到特定的硬件上,在运行时完成板检测,您可以创建跨支持平台工作的可移植代码。
UPM存储库为各种常用的传感器和执行器提供软件驱动程序。这些软件驱动程序通过调用MRAA与底层硬件平台(或微控制器)以及附加的传感器进行交互。
哪个Android运行哪个Linux内核?https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
Android Version |API Level |Linux Version in AOSP |Header Version
----------------------------------------------------------------------------------------
4.4 Kit Kat |19, 20 |(3.10) |2.6.18
5.x Lollipop |21, 22 |(3.16.1) |3.14.0
6.0 Marshmallow |23 |(3.18.10) |3.18.10sysfs死了!蜥蜴万岁!( linux和CircuitPython的libgpiod)
这基本上是将取代我们的Python驱动程序的代码,它的优点是可以与运行4.8+内核的任何其他Linux板向前兼容。我们将慢慢地替换其他CircuitPython代码来使用libgpiod,这样我们就可以在Raspberry、BeagleBone或Onion.io上广泛支持CircuitPython。 这里没有很多libgpiod代码,而且libgpiod还没有在Linux发行版上上市,这可能就是为什么它需要一段时间才能流行起来的原因。有C和Python的绑定。下面是一个脚本,可以通过为您编译https://github.com/adafruit/Raspberry-Pi-Installer-Scripts/blob/master/libgpiod.sh来帮助您入门
DragonBoard 410 C GPIO库是用Java编写的,使用GitHub GpioLibrary的"/sys/class/ GPIO“方法访问GPIO引脚。这看起来像是物联网课程库库中的一个存储库,其中一些使用DragonBoard 410 C。
这提供了Linux上GPIO访问约定的概述。 这些调用使用gpio_*命名前缀。任何其他调用都不应使用该前缀或相关的_gpio*前缀。
Android Studio和adb
Android是用于开发Android应用程序的应用程序。可以从https://developer.android.com/studio/releases下载以便安装。
此外,还有Android平台工具,这是一个单独的下载。adb外壳应用程序是这些工具的一部分。这些工具可以从SDK平台工具发布说明下载以进行安装。选择操作系统所需的特定版本(Windows、Linux、MacOS)。
Android Things
虽然安卓系统看起来很有帮助,但它似乎只有几块板实际上是支持的,而DragonBoard 410 C就不是其中之一。而且我也不确定Android系统是否能与Android5.1一起工作。
https://developer.android.com/things/get-started
然而,DragonBoard 410 C https://discuss.96boards.org/t/android-things-on-the-dragonboard/1128有一个Brillo (现在是Android的东西)端口。
Android Developers > Docs > Android Things > Guides > GPIO
为了打开到GPIO端口的连接,您需要知道唯一的端口名。在开发的最初阶段,或者在将应用程序移植到新硬件时,使用
PeripheralManager使用getGpioList()发现所有可用的端口名是很有帮助的:
安卓事物GitHub存储库https://github.com/androidthings/
还请参阅下面的堆栈溢出帖子,其中有一些关于这个主题的话要说。参见标记android-堆叠溢出中的东西。
发布于 2020-09-02 04:27:23
在回顾了许多替代方案之后,访问运行Android5.1的DragonBoard 410 C的GPIO引脚的最简单方法似乎是使用遗留的sysfs特殊设备文件方法。
我不确定这是否是唯一可行的解决办法。使用Android和libgpiod似乎都需要一个比Android5.1更新的Linux内核。
我写了一篇关于CodeProject.com的文章,详细介绍了如何解决这个问题。见用Windows10forDevelopmentwithDragonBoard 410 C和Android。
哪个Android运行哪个Linux内核?https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel
Android Version |API Level |Linux Version in AOSP |Header Version
----------------------------------------------------------------------------------------
4.4 Kit Kat |19, 20 |(3.10) |2.6.18
5.x Lollipop |21, 22 |(3.16.1) |3.14.0
6.0 Marshmallow |23 |(3.18.10) |3.18.10这个方法似乎也是最简单的,因为所使用的库也是用Kotlin编写的。
使用遗留的sysfs专用设备GPIO接口
请参阅这篇关于Linux伪文件和特殊设备文件的StackOverFlow文章,以及用于GPIO引脚、什么是/sys/class/gpio/export和`/sys/class/gpio/unexport机制,以及sysfs的基本功能是什么?的遗留sysfs接口。
我找到了一个用Java编写的简单的GPIO库,它提供了必要的源代码。Android有一个将Java转换为Kotlin的工具,我将其包含在我的项目中。源代码在Gpio.kt和GpioProcessor.kt文件中。
但是,为了使这一工作有效,我必须对我的DragonBoard启动脚本进行更改,以确保创建了必要的特殊设备文件并具有适当的权限,从而允许用户程序操作GPIO引脚。
以下过程来自古瑟尔类物联网:设备的感知和执行,第5a课:通过程序(Android)视频#2访问GPIO,修改引导脚本。程序是:
添加到/etc/init.qcom.post_boot.sh底部的附加shell代码如下所示。不过,这些特殊的设备文件只适用于Android5.1。 Linux使用不同的GPIO引脚名。
set -A pins 938 915 1017 926 937 930 914 971 901 936 935
for i in 0 1 2 3 4 5 6 7 8 9 10
do
echo ${pins[i]} > /sys/class/gpio/export;
chmod 777 /sys/class/gpio/gpio${pins[i]};
chmod 777 /sys/class/gpio/gpio${pins[i]}/value;
chmod 777 /sys/class/gpio/gpio${pins[i]}/direction;
done--关于sysfs设备属性的一个注记
下面是一些来自用于用户空间的GPIO Sysfs接口的kernel.org文档。除了我使用的两个属性,direction和value,还有其他几个属性,比如edge和active_low。
“方向”…读为“in”或“out”。此值通常可以写入。以“out”的形式写入默认值为low。为了确保无故障操作,可以编写“低”和“高”值,以便将GPIO配置为具有该初始值的输出。 注意,如果内核不支持更改GPIO的方向,或者它是由内核代码导出的,而内核代码没有显式地允许用户空间重新配置这个GPIO方向,那么这个属性就不存在。 “value”…读取为0(低)或1(高)。如果将GPIO配置为输出,则可以写入此值;任何非零值都被视为高值。 如果引脚可以配置为产生中断的中断,如果它被配置为生成中断(请参阅“edge”的描述),您可以对该文件进行轮询(2),每当中断被触发时,轮询(2)将返回。如果使用轮询(2),则设置事件POLLPRI和POLLERR。如果使用select(2),请将文件描述符设置为“除其他外”。在轮询(2)返回后,要么将After (2)返回sysfs文件的开头并读取新值,要么关闭该文件并重新打开它以读取该值。 “边缘”…读为“无”、“上升”、“下降”或“两者兼而有之”。编写这些字符串以选择将对“value”文件返回进行轮询(2)的信号边缘。 只有当引脚可以配置为生成输入引脚的中断时,此文件才存在。 “active_low”…读取为0 (false)或1 (true)。写入任何非零值,以反转用于读写的value属性。现有的和随后的投票(2)支持配置通过边缘属性的“上升”和“下降”边缘将遵循此设置。
Kotlin使用sysfs的源代码
在我的DragonBoard存储库410 c中有一个完整的测试应用程序,用于探索在Android中使用GitHub 410 C的主题。
文件Gpio.kt源文件
package com.example.myapplication
import java.io.*
/**
* Created by Ara on 7/21/15.
* From https://www.instructables.com/id/DragonBoard-How-to-Access-GPIOs-Using-Java/
* Java source from the article was converted to Kotlin using Android Studio.
*
* See as well https://github.com/IOT-410c/DragonBoard410c_GpioLibrary
*
*/
class Gpio(pin: Int) {
private val pin: Int
/*
* The GPIO pins are represented by folders in the Linux file system
* within the folder /sys/class/gpio. Each pin is represented by a folder
* whose name is the prefix "gpio" followed by the pin number.
* Within the folder representing the pin are two files, "value" used to
* set or get the value of the pin and "direction" used to set or get
* the direction of the pin.
*
* This function creates the path to the Linux file which represents a particular
* GPIO pin function, "value" or "direction".
*/
private fun MakeFileName(pin: Int, op: String): String {
return "/sys/class/gpio/gpio$pin$op"
}
/*
* Get or set the current direction of a pin.
* A pin may be either an Input pin or an Output pin.
*/
var direction: String
get() {
println("Getting Direction")
var line = ""
try {
val br = BufferedReader(FileReader(MakeFileName(pin, "/direction")))
line = br.readLine()
br.close()
} catch (e: Exception) {
println("Error: " + e.message)
}
return line
}
private set(direction) {
println("Setting Direction")
try {
val out = BufferedWriter(FileWriter(MakeFileName(pin, "/direction"), false))
out.write(direction)
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
/**
* Get or Set pin value.
* @param value Value of pin.
* 0 -> Low Level.
* 1 -> High Level
*/
var value: Int
get() {
println("Getting Value")
var line = ""
try {
val br = BufferedReader(FileReader(MakeFileName(pin, "/value")))
line = br.readLine()
br.close()
} catch (e: Exception) {
println("Error: " + e.message)
}
return line.toInt()
}
private set(value) {
println("Setting Value")
try {
val out = BufferedWriter(FileWriter(MakeFileName(pin, "/value"), false))
out.write(Integer.toString(value))
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
/**
* Set pin as high.
*/
fun pinHigh() {
value = HIGH
}
/**
* Set pin as low.
*/
fun pinLow() {
value = LOW
}
/**
* Set pin as output.
*/
fun pinOut() {
direction = "out"
}
/**
* Set pin as input.
* @param pin - Desirable pin.
*/
fun pinIn() {
direction = "in"
}
fun exportPin() {
println("Exporting Ping")
try {
val out = BufferedWriter(FileWriter("$PATH/export", false))
out.write(pin.toString())
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
/**
* Disable access to GPIO.
* @param pin GPIO pin to disable access.
*/
fun unexportPin() {
println("unExporting Ping")
try {
val out = BufferedWriter(FileWriter("$PATH/unexport", false))
out.write(pin.toString())
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
companion object {
const val HIGH = 1
const val LOW = 0
private const val PATH = "/sys/class/gpio"
}
/**
* Set desirable pin for the GPIO class.
*/
init {
println("Initializing pin $pin")
this.pin = pin
}
}GpioProcessor.kt的来源
package com.example.myapplication
import java.io.BufferedWriter
import java.io.FileWriter
import java.io.IOException
import java.util.*
/**
* Created by Ara on 7/21/15.
* From https://www.instructables.com/id/DragonBoard-How-to-Access-GPIOs-Using-Java/
* Java source from the article was converted to Kotlin using Android Studio.
*
* See as well https://github.com/IOT-410c/DragonBoard410c_GpioLibrary
*
* Simple example main()
*
* public class Main {
*
* public static void main(String[] args) {
* int count = 0;
* int buttonValue = 0;
*
* GpioProcessor gpioProcessor = new GpioProcessor();
*
* // Get reference of GPIO27 and GPIO29.
*
* Gpio gpioPin27 = gpioProcessor.getPin27();
* Gpio gpioPin29 = gpioProcessor.getPin29();
*
* // Set GPIO27 as output.Set GPIO29 as input.
* gpioPin27.pinOut();
* gpioPin29.pinIn();
*
* while(count<20){
* count++;
* // Read value of GPIO29.
* buttonValue=gpioPin29.getValue();
*
* if(buttonValue == 0){
* // Set GPIO27 as low level.
* gpioPin27.pinLow();
* } else{
* // Set GPIO27 as high level.
* gpioPin27.pinHigh();
* }
*
* try {
* Thread.sleep(1000);
* } catch(InterruptedException e){
* // TODO Auto-generated catch block
* e.printStackTrace();
* }
* }
*
* // Disable access GPIO27 and GPIO29.
* gpioProcessor.closePins();
* }
* }
*/ /*
This class abstracts the use of the gpio pins. This class can be utilized on any linux operating
system that has gpio pins defined in the /sys/class/gpio directory. It is required that the gpio
pins themselves are available for access by the user of this application, and may require a
change of permissions.
*/
class GpioProcessor {
private val PATH = "/sys/class/gpio"
private val pins: MutableList<Int> = ArrayList()
// mapping of physical pin number to GPIO file number.
// the mapping varies depending on the operating system
private val androidPin23 = 938
private val androidPin24 = 914
private val androidPin25 = 915
private val androidPin26 = 971
private val androidPin27 = 1017
private val androidPin28 = 901 // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
private val androidPin29 = 926 // (input only)
private val androidPin30 = 927
private val androidPin31 = 937
private val androidPin32 = 936
private val androidPin33 = 930
private val androidPin34 = 935
private val linuxPin23 = 36
private val linuxPin24 = 12
private val linuxPin25 = 13
private val linuxPin26 = 69
private val linuxPin27 = 115
private val linuxPin28 = 4 // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
private val linuxPin29 = 24 // (input only)
private val linuxPin30 = 25
private val linuxPin31 = 35
private val linuxPin32 = 34
private val linuxPin33 = 28
private val linuxPin34 = 33
private val physicalPin23 = androidPin23
private val physicalPin24 = androidPin24
private val physicalPin25 = androidPin25
private val physicalPin26 = androidPin26
private val physicalPin27 = androidPin27
private val physicalPin28 = androidPin28 // GPIO pin borrowed from MPP. supports PWM. support analog I/O.
private val physicalPin29 = androidPin29 // (input only)
private val physicalPin30 = androidPin30
private val physicalPin31 = androidPin31
private val physicalPin32 = androidPin32
private val physicalPin33 = androidPin33
private val physicalPin34 = androidPin34
/**
* Get function of specific pin.
* @param pin Desirable pin.
*/
fun getPin(pin: Int): Gpio {
exportPin(pin)
pins.add(pin)
return Gpio(pin)
}
/**
* Get pin 23;
* @returns {Gpio}
*/
val pin23: Gpio
get() = getPin(physicalPin23)
/**
* Get pin 24.
* @returns {Gpio}
*/
val pin24: Gpio
get() = getPin(physicalPin24)
/**
* Get pin 25.
* @returns {Gpio}
*/
val pin25: Gpio
get() = getPin(physicalPin25)
/**
* Get pin 26.
* @returns {Gpio}
*/
val pin26: Gpio
get() = getPin(physicalPin26)
/**
* Get pin 27.
* @returns {Gpio}
*/
val pin27: Gpio
get() = getPin(physicalPin27)
/**
* Get pin 28.
* @returns {Gpio}
*/
val pin28: Gpio
get() = getPin(physicalPin28)
/**
* Get pin 29.
* @returns {Gpio}
*/
val pin29: Gpio
get() = getPin(physicalPin29)
/**
* Get pin 30.
* @returns {Gpio}
*/
val pin30: Gpio
get() = getPin(physicalPin30)
/**
* Get pin 31.
* @returns {Gpio}
*/
val pin31: Gpio
get() = getPin(physicalPin31)
/**
* Get pin 32.
* @returns {Gpio}
*/
val pin32: Gpio
get() = getPin(physicalPin32)
/**
* Get pin 33.
* @returns {Gpio}
*/
val pin33: Gpio
get() = getPin(physicalPin33)
/**
* Get pin 34.
* @returns {Gpio}
*/
val pin34: Gpio
get() = getPin(physicalPin34)
/**
* Get all GPIO's pins.
* @return List of pins.
*/
val allPins: Array<Gpio?>
get() {
val allPins = arrayOfNulls<Gpio>(12) // android linux
allPins[0] = pin23 // GPIO 938 GPIO 36
allPins[1] = pin24 // GPIO 914 GPIO 12
allPins[2] = pin25 // GPIO 915 GPIO 13
allPins[3] = pin26 // GPIO 971 GPIO 69
allPins[4] = pin27 // GPIO 1017 GPIO 115
allPins[5] = pin28 // Reserved
allPins[6] = pin29 // GPIO 926 GPIO 24 (input only)
allPins[7] = pin30 // GPIO 927 GPIO 25
allPins[8] = pin31 // GPIO 937 GPIO 35
allPins[9] = pin32 // GPIO 936 GPIO 34
allPins[10] = pin33 // GPIO 930 GPIO 28
allPins[11] = pin34 // GPIO 935 GPIO 33
return allPins
}
/**
* Enable access to GPIO.
* @param pin GPIO pin to access.
*/
private fun exportPin(pin: Int) {
println("Exporting Ping")
try {
val out = BufferedWriter(FileWriter("$PATH/export", false))
out.write(pin.toString())
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
/**
* Disable access to GPIO.
* @param pin GPIO pin to disable access.
*/
private fun unexportPin(pin: Int) {
println("unExporting Ping")
try {
val out = BufferedWriter(FileWriter("$PATH/unexport", false))
out.write(pin.toString())
out.close()
} catch (e: IOException) {
println("Error: " + e.message)
}
}
fun closePins() {
for (pin in pins) {
unexportPin(pin)
}
pins.clear()
}
companion object {
const val TAG = "GpioProcessor"
}
}使用类的GpioProcessor示例源
通过将按钮按下链接到侦听器,我在片段内的Android应用程序中使用了GPIO接口库。我有两个按钮,一个通过驱动一个引脚高开LED,另一个通过把引脚低开来关闭LED。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById<Button>(R.id.button_second).setOnClickListener {
findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment)
}
val txtScroll = view.findViewById(R.id.LedStatus) as TextView
// find the button whose id is button_Location and then set an listener for
// any clicks on that button. In the following listener we are going to have
// the "Location" button, defined in the file fragment_first.xml, generate a
// list of the GPS service providers by creatinga LocationManager object to
// generate a list.
val gpioProcessor_x = GpioProcessor()
// Get reference of GPIO23.
val gpioPin23_x = gpioProcessor_x.pin23
gpioPin23_x.exportPin()
view.findViewById<Button>(R.id.button_led_off).setOnClickListener {
val gpioProcessor = GpioProcessor()
// Get reference of GPIO27.
val gpioPin23 = gpioProcessor.pin23
// Set GPIO23 as output.
gpioPin23.pinOut()
gpioPin23.pinLow() // drive pin low to turn off LED.
txtScroll.append("LED Off\n")
}
view.findViewById<Button>(R.id.button_led_on).setOnClickListener {
val gpioProcessor = GpioProcessor()
// Get reference of GPIO27.
val gpioPin23 = gpioProcessor.pin23
// Set GPIO23 as output.
gpioPin23.pinOut()
gpioPin23.pinHigh() // drive pin high to turn on LED
txtScroll.append("LED On\n")
}
}https://stackoverflow.com/questions/63653864
复制相似问题