AndroidThings系列之四:GPIO及点灯
终于到点灯了! 有人早就不耐烦了,不就点个灯,多大点事!在MCUer的眼里,点灯就屁大点事,虽然说在AndroidThings的世界里,点灯也就屁大点事。不过有些事得交待清楚才行! 第一个问题就是GPIO命名的事,像Arduino直接用编号,例如常见的13号就代表USER LED,ST的MCU有自己的命名规则,NXP也有自己的规格,当然AndroidThings也有自己的命名规则。
第一个问题就是GPIO命名的事,像Arduino直接用编号,例如常见的13号就代表USER LED,ST的MCU有自己的命名规则,NXP也有自己的规格,当然AndroidThings也有自己的命名规则。
AndroidThings使用字符串来命名GPIO,先看下i.MX7D的GPIO引脚图
i.MX7D中,纯粹用于GPIO的一共是12个引脚,命名形式采用GPIOx_IOxx形式,其中x代表的是数字,例如GPIO6_IO12就是编号为18的引脚。
其实是APP的权限设置问题,要使用GPIO外设,需要打开相关的权限,代码如下
<uses-permission android:name="com.google.android.things.permission.USE_PERIPHERAL_IO" />
AndroidThings使用PeripheralManager类来管理外设,不管是GPIO也好,I2C也好,统统都通过该类来进行管理,该类提供了getGpioList()方法来获取平台提供的GPIO引脚,另外openGpio()方法则用来打开指定的GPIO端口,该方法返回一个Gpio对象,Gpio类提供了所有与GPIO操作相关的方法,如读取/写入/关闭等操作。
另外还值得一提的是外设操作都有可能抛出异常,所以一般的外设操作都封装在
try {
...
} catch
块中。
使用的LED灯连接到GPIO6_IO12引脚上,下面是完整的代码
public class MainActivity extends Activity {
private static final String TAG = "TAG";
private static final String LED_NAME = "GPIO6_IO12";
private PeripheralManager mPeripheralManager;
private Gpio mGpio;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPeripheralManager = PeripheralManager.getInstance();
Log.d(TAG, "onCreate: " + mPeripheralManager.getGpioList());
try {
mGpio = mPeripheralManager.openGpio(LED_NAME);
mGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
mGpio.setActiveType(Gpio.ACTIVE_HIGH);
} catch (IOException e) {
e.printStackTrace();
}
mHandler.post(new Runnable() {
@Override
public void run() {
if(mGpio == null) {
return;
}
try {
mGpio.setValue(!mGpio.getValue());
//Log.d(TAG, "run: " + mGpio.getValue());
} catch (IOException e) {
e.printStackTrace();
}
mHandler.postDelayed(this, 500);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if(mGpio != null) {
try {
mGpio.close();
mGpio = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
代码2~7行是一些常量及变量的声明,如GPIO名称,PeripheralManager、Gpio等。
在onCreate()函数中,我们使用了如下代码来获取GPIO列表
Log.d(TAG, "onCreate: " + mPeripheralManager.getGpioList());
对应的输出如下
onCreate: [GPIO1_IO10, GPIO2_IO00, GPIO2_IO01, GPIO2_IO02, GPIO2_IO03, GPIO2_IO05, GPIO2_IO07, GPIO5_IO00, GPIO6_IO12, GPIO6_IO13, GPIO6_IO14, GPIO6_IO15]
这是Logcat中打印出来的内容,i.MX7D中所有可用的GPIO都列出来了,和官方给出的GPIO接口标注是一致的,至于具体的位置就只能参考官方的GPIO标注了。
下面一段代码的作用是打开GPIO端口并做初始化配置
try {
mGpio = mPeripheralManager.openGpio(LED_NAME);
mGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
mGpio.setActiveType(Gpio.ACTIVE_HIGH);
} catch (IOException e) {
e.printStackTrace();
}
首先使用PeripheralManager来打个一个端口,接下来的mGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)是设置GPIO的方向,OUT就是输出,后面的LOW指定初始化为低,mGpio.setActiveType(Gpio.ACTIVE_HIGH)的作用主要用来读取值,即高电平代表真,否则为假,如果这个地方指定Gpio.ACTIVE_LOW,则读取到高电平返回假,否则返加真。这段话读起来有点拗口,但是一定要搞清楚。
最后要注意的是这些GPIO操作都放在try...catch...块内,用来处理可能抛出的异常。
接下来的onDestroy()方法,这里执行资源释放相关问题。
一旦Activity被销毁,则要将申请的外设资源释放。虽然在AndroidThings中,Activity被销毁的情况相对来说比较少,但做为良好的编程习惯,还是要将这些代码添加进来。
至于代码中与Handler相关的操作,这是用来定时的,即控制LED灯闪烁。
Handler的post()方法是立即执行相关的代码,这里指定的是Runnable对象,而后面的postDelay()方法则在延迟指定的时间段(单位为毫秒)后开始执行Runnable对象。这样就实现了一般MCU中的定时操作。
Gpio的getValue()及setValue()用来读取及写入GPIO商品状态值,这些值是布尔类型,具体的含义则与Gpio.setActiveType()中指定的值息息相关。
编译、上传代码至开发板,LED灯开始闪烁
点灯完毕。
不过还有些事值得讨论,这里只说了GPIO的输出,GPIO也可以配置为输入,可以读取按键状态等信息,下面的代码片断演示了如何将GPIO配置为输入模式并使用中断来处理相关事件
public void configureInput(Gpio gpio) throws IOException {
// Initialize the pin as an input
gpio.setDirection(Gpio.DIRECTION_IN);
// Low voltage is considered active
gpio.setActiveType(Gpio.ACTIVE_LOW);
// Register for all state changes
gpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
gpio.registerGpioCallback(mGpioCallback);
}
private GpioCallback mGpioCallback = new GpioCallback() {
@Override
public boolean onGpioEdge(Gpio gpio) {
// Read the active low pin state
if (gpio.getValue()) {
// Pin is LOW
} else {
// Pin is HIGH
}
// Continue listening for more interrupts
return true;
}
@Override
public void onGpioError(Gpio gpio, int error) {
Log.w(TAG, gpio + ": Error event " + error);
}
};
GpioCallback类定义了回调相关操作,用来处理不同的状态。
下面的代码则演示了如何来注册及注销相关的回调
public class HomeActivity extends Activity {
private Gpio mGpio;
...
@Override
protected void onStart() {
super.onStart();
// Begin listening for interrupt events
mGpio.registerGpioCallback(mGpioCallback);
}
@Override
protected void onStop() {
super.onStop();
// Interrupt events no longer necessary
mGpio.unregisterGpioCallback(mGpioCallback);
}
}
补充一点,GPIO使用的是只是简单的状态检测,在处理按键时,有一个问题可能要考虑到,那就是抖动问题,如果没有硬件消抖,则需要用户使用代码来消除抖动。AndroidThings的三方库中包括一个button组件,可以直接使用,详情请参考https://github.com/androidthings/contrib-drivers。
GPIO库使用起来非常舒服,不止如此,只要掌握了GPIO的运行模式,后面的PWM、I2C等操作,基本模式是一致的。
下一节来点个1602屏。