En 0755-86038900
公司新闻

4412开发板android入门篇_GPIO控制

发布时间:2015-03-13

 

基于UT4412BV03开发板的gpio驱动及应用程序设计

 

想必大家在学生时代都学过单片机,在我们学习51单片机和STM32单片机时,学习的第一个例程就是控制单片机的GPIO口来实现led灯的程序,那么我们在学习嵌入式linux时,我们可以根据自己的职业发展方向去学习,因为嵌入式开发是一个庞大的任务,涉及的知识面广泛,我们写的入门级例程偏重于linux驱动,仅仅从linux驱动程序开始,涉及到android的硬件抽象层和框架层,应用层也会涉及到相对简单的测试程序。所有程序都基于友坚恒天UT4412BV03开发板验证通过。

 

本课程目标:

※ 熟悉Exynos 4412GPIO口的使用方法

※ 写一个控制板子上4LED灯的驱动程序

※ 写一个测试LED的应用程序

 

一.熟悉并掌握linux内核中GPIO控制的一些常用函数

 

    我们在使用GPIO时虽然可以不用申请,而直接操作GPIO,但这样操作不是最好的,一般情况下我们使用时先申请GPIO口,用完再释放GPIO口。

 

GPIO控制常用的函数所在的文件位置

    linux/arch/arm/plat-s3c/gpio-config.c

    linux/arch/arm/mach-exynos/include/mach/gpio-exynos4.h

    arch/arm/mach-u300/gpio.c

GPIO引脚控制常用函数介绍

 1.分配GPIO控制引脚的函数:gpio_request()

intgpio_request(unsigned gpio, const char *label)

返回值:如果返回0,则申请成功,返回非零值GPIO申请失败。

 

 2.释放GPIO控制引脚的函数:gpio_free()

  voidgpio_free(unsigned gpio);

 

 3.设置IO口的方向为输入、输出

int   gpio_direction_input(unsigned gpio); 

int   gpio_direction_output(unsigned gpio, int value);

返回值:返回0,代表success,返回负数,代表错误

 

4.获取I/O口的当前值

Int  gpio_get_value(unsigned gpio);

 

5.设置 I/O口输出的值

  void gpio_set_value(unsigned gpio, int value);

6.设置GPIO口的初始状态

   int s3c_gpio_cfgpin(unsigned int  pin, unsigned int  config)

config可以取值如下

  linux/arch/arm/plat-s3c/include/plat/gpio-cfg.h中定义的config取值

#define S3C_GPIO_INPUT    (S3C_GPIO_SPECIAL(0))

#define S3C_GPIO_OUTPUT   (S3C_GPIO_SPECIAL(1))

#define S3C_GPIO_SFN(x)    (S3C_GPIO_SPECIAL(x))

 

7.GPIO引脚有无上拉设置

   int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull)

 

linux/arch/arm/plat-s3c/include/plat/gpio-cfg.h中定义的pull取值

  #define S3C_GPIO_PULL_NONE ((__force s3c_gpio_pull_t)0x00)

  #define S3C_GPIO_PULL_DOWN ((__force s3c_gpio_pull_t)0x01)

  #define S3C_GPIO_PULL_UP ((__force s3c_gpio_pull_t)0x02)

 

二.LED驱动编写须知的硬件接口

  在编写前我们需要知道LEDGPIO口的硬件连接。根据硬件连接我们知道要点亮LED需要控制相应引脚为高点平,熄灭LED需要控制相应引脚为低电平。IO口为1时将使三极管导通,LED点亮。IO口为0时将使三极管截止,LED熄灭。

UT4412LED跟芯片的连接:

       EINT5--------GPX0_5

       EINT7--------GPX0_7

       EINT20-------GPX2_4

       EINT21-------GPX2_5

 

 

 

 

 

当知道硬件连接后,需要查阅4412芯片用户手册了解引脚的控制方法。


根据数据手册可以知道要使用GPIO管脚控制LED需要将对应GPIO设为输出模式

设置方法:假设设置GPX0_7为输出有下面两种方式

法一:s3c_gpio_cfgpin(EXYNOS5_GPX0(7), S3C_GPIO_SFN(1));

   法二:s3c_gpio_cfgpin(EXYNOS5_GPX0(7), S3C_GPIO_OUTPUT);

三.LED驱动源代码分析

LED驱动源码ut4412led.c分析

/*

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation

 */

#include <linux/module.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/sched.h>

#include <linux/delay.h>

#include <linux/platform_device.h>

#include <mach/hardware.h>

#include <asm/mach-types.h>

#include <linux/gpio.h>

#include <asm/gpio.h>

#include <asm/delay.h>

#include <linux/clk.h>

#include <plat/gpio-cfg.h>

staticint ut4412_led_status[4] = { 0 };  //led控制的状态标志位

static void led_probe(void)

{

int ret;

ret = gpio_request(EXYNOS4_GPX0(5), "GPX05");//GPIO引脚申请

if(ret)

printk("GPX05 requese fail!");

s3c_gpio_setpull(EXYNOS4_GPX0(5), S3C_GPIO_PULL_UP);//设置上拉输出

gpio_direction_output(EXYNOS4_GPX0(5),0 );//设置引脚输出低电平

ret = gpio_request(EXYNOS4_GPX0(7), "GPX07");

if(ret)

printk("GPX07 requese fail!");

s3c_gpio_setpull(EXYNOS4_GPX0(7), S3C_GPIO_PULL_UP);

gpio_direction_output(EXYNOS4_GPX0(7),0);

ret = gpio_request(EXYNOS4_GPX2(4), "GPX24");

if(ret)

printk("GPX24 requese fail!");

s3c_gpio_setpull(EXYNOS4_GPX2(4), S3C_GPIO_PULL_UP);

gpio_direction_output(EXYNOS4_GPX2(4),0 );

ret = gpio_request(EXYNOS4_GPX2(5), "GPX25");

if(ret)

printk("GPX25 requese fail!");

s3c_gpio_setpull(EXYNOS4_GPX2(5), S3C_GPIO_PULL_UP);

gpio_direction_output(EXYNOS4_GPX2(5), 0);

ut4412_led_status[0] = 0;  //LED状态标志

ut4412_led_status[1] = 0;

ut4412_led_status[2] = 0;

ut4412_led_status[3] = 0;

}

static  void  led_remove(void)

{

gpio_free(EXYNOS4_GPX0(5));//释放GPIO引脚

gpio_free(EXYNOS4_GPX0(7));

gpio_free(EXYNOS4_GPX2(4));

gpio_free(EXYNOS4_GPX2(5));

}

staticssize_t  ut4412_led_read(struct device *dev, structdevice_attribute *attr, char *buf)

{

if(!strcmp(attr->attr.name, "led1"))

{

if(ut4412_led_status[0] != 0)

return   strlcpy(buf, "1 ", 3);

else

return   strlcpy(buf, "0 ", 3);

}

else if(!strcmp(attr->attr.name, "led2"))

{

if(ut4412_led_status[1] != 0)

return   strlcpy(buf, "1 ", 3);

else

return  strlcpy(buf, "0 ", 3);

}

else if(!strcmp(attr->attr.name, "led3"))

{

if(ut4412_led_status[2] != 0)

return  strlcpy(buf, "1 ", 3);

else

return  strlcpy(buf, "0 ", 3);

}

else if(!strcmp(attr->attr.name, "led4"))

{

if(ut4412_led_status[3] != 0)

return  strlcpy(buf, "1 ", 3);

else

return  strlcpy(buf, "0 ", 3);

}

        return   strlcpy(buf, " ", 3);

}

 

staticssize_t ut4412_led_write(struct device *dev, structdevice_attribute *attr, const char *buf, size_t count)

{

unsigned long on = simple_strtoul(buf, NULL, 10);

 

if(!strcmp(attr->attr.name, "led1"))

{

if(on)

{

gpio_direction_output(EXYNOS4_GPX0(5), 1);

ut4412_led_status[0] = 1;

}

else

{

gpio_direction_output(EXYNOS4_GPX0(5),0);

ut4412_led_status[0] = 0;

}

}

else if(!strcmp(attr->attr.name, "led2"))

{

if(on)

{

gpio_direction_output(EXYNOS4_GPX0(7), 1);

ut4412_led_status[1] = 1;

}

else

{

gpio_direction_output(EXYNOS4_GPX0(7), 0);

ut4412_led_status[1] = 0;

}

}

else if(!strcmp(attr->attr.name, "led3"))

{

if(on)

{

gpio_direction_output(EXYNOS4_GPX2(4), 1);

ut4412_led_status[2] = 1;

}

else

{

gpio_direction_output(EXYNOS4_GPX2(4), 0);

ut4412_led_status[2] = 0;

}

}

else if(!strcmp(attr->attr.name, "led4"))

{

if(on)

{

gpio_direction_output(EXYNOS4_GPX2(5), 1);

ut4412_led_status[3] = 1;

}

else

{

gpio_direction_output(EXYNOS4_GPX2(5), 0);

ut4412_led_status[3] = 0;

}

}

 

return count;

}

static DEVICE_ATTR(led1, 0666, ut4412_led_read, ut4412_led_write);

static DEVICE_ATTR(led2, 0666, ut4412_led_read, ut4412_led_write);

static DEVICE_ATTR(led3, 0666, ut4412_led_read, ut4412_led_write);

static DEVICE_ATTR(led4, 0666, ut4412_led_read, ut4412_led_write);

 

staticstruct attribute *ut4412_led_sysfs_entries[] = {

&dev_attr_led1.attr,

&dev_attr_led2.attr,

&dev_attr_led3.attr,

&dev_attr_led4.attr,

NULL,

};

staticstructattribute_group ut4412_led_attr_group = {

.name = NULL,

.attrs = ut4412_led_sysfs_entries,

};

staticint ut4412_led_probe(structplatform_device *pdev)

{

led_probe();

returnsysfs_create_group(&pdev->dev.kobj, &ut4412_led_attr_group);

}

staticint ut4412_led_remove(structplatform_device *pdev)

{

led_remove();

 

sysfs_remove_group(&pdev->dev.kobj, &ut4412_led_attr_group);

return 0;

}

staticstructplatform_driver ut4412_led_driver = {

.probe  = ut4412_led_probe,

.remove  = ut4412_led_remove,

.driver  = {

.name = "ut4412-led",

},

};

staticstructplatform_device ut4412_led_device = {

.name      = "ut4412-led",

.id        = -1,

};

staticint __devinit ut4412_led_init(void)

{

int ret;

printk("---------ut4412_led_init-----------");

ret = platform_device_register(&ut4412_led_device);

if(ret)

printk("ut4412 led device register error ");

ret = platform_driver_register(&ut4412_led_driver);

if(ret)

printk("ut4412 led driver register error ");

return ret;

}

static void ut4412_led_exit(void)

{

platform_driver_unregister(&ut4412_led_driver);

printk("---------ut4412_led_exit-----------");

}

module_init(ut4412_led_init);

module_exit(ut4412_led_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("urbetter_fae");

MODULE_DESCRIPTION("ut4412BV03 platform led driver");

 

四.将LED驱动加入到kernel中编译

UT4412BV03开发板配套的例程放在光盘中:Demo目录下

led_demodriver目录下的led文件夹复制到kernelkerneldriverschar目录

 

 

打开char目录下的Makefile文件键入如下:

obj-y  +=  led/

 

打开char目录下的Kconfig文件键入如下:

Source  driver/char/led/Kconfig

代码添加后就可以执行:make  j2 编译出kernel镜像文件

 

注:-jn表示用几个线程来编译程序,如果只用make单线程编译,速度较慢,因此,我们可以根据电脑的配置来决定,我的笔记本电脑是四核的,所以我还可以运行4个线程来编译:make  --j4

 

利用fastboot命令烧写kernel镜像:fastboot  flash kernel  zImage 

 

五.编写LED驱动的测试程序

1.新建Android应用程序,点击“NEXT

2.多次点击“NEXT”如下图点击“Finish”完成Android应用工程的创建

 

 

  3.创建完工程后,进行Android UI界面的设计

复制led_demo目录下的图片bg1android工程的/res/drawable目录下,

activity_utled_test.xml目录下引用图片资源作为UI界面的背景

在其中加入如下语句:android:background="@drawable/bg1"

 

 

 

 

  界面布局文件代码如下:

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:background="@drawable/bg1"

android:gravity="center_horizontal"

android:orientation="vertical">

<TableLayout

android:layout_width="match_parent"

android:layout_height="wrap_content">

<TableRow

android:id="@+id/tableRow1"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<Button

android:id="@+id/btn1on"

android:layout_marginLeft="230dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:width="300dp"

android:textColor="#00FF00"

android:layout_marginTop="150dp"

android:text="@string/led1_on"/>

<Button

android:id="@+id/btn1off"

android:layout_marginLeft="20dp"

android:width="300dp"

android:textColor="#00FF00"

android:layout_marginTop="150dp"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led1_off"/>

</TableRow>

<TableRow

 

android:id="@+id/tableRow2"

android:layout_width="match_parent"

android:layout_height="wrap_content">

<Button

android:id="@+id/btn2on"

android:layout_marginLeft="230dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led2_on"/>

<Button

android:id="@+id/btn2off"

android:layout_marginLeft="20dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led2_off"/>

</TableRow>

<TableRow

android:id="@+id/tableRow3"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<Button

android:id="@+id/btn3on"

android:layout_marginLeft="230dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led3_on"/>

<Button

android:id="@+id/btn3off"

android:layout_marginLeft="20dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led3_off"/>

</TableRow>

<TableRow

android:id="@+id/tableRow4"

android:layout_width="wrap_content"

android:layout_height="wrap_content">

<Button

android:id="@+id/btn4on"

 

android:layout_marginLeft="230dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led4_on"/>

<Button

android:id="@+id/btn4off"

android:layout_marginLeft="20dp"

android:textColor="#00FF00"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/led4_off"/>

</TableRow>

</TableLayout>

</LinearLayout>

 

4.编辑Androidjava代码

 

  //定义LED控制用到的Button

Button btn1on,btn1off;

Button btn2on,btn2off;

Button btn3on,btn3off;

Button btn4on,btn4off;

  //Button资源的引用

btn1on=(Button)findViewById(R.id.btn1on);

btn1off=(Button)findViewById(R.id.btn1off);

btn2on=(Button)findViewById(R.id.btn2on);

btn2off=(Button)findViewById(R.id.btn2off);

btn3on=(Button)findViewById(R.id.btn3on);

btn3off=(Button)findViewById(R.id.btn3off);

btn4on=(Button)findViewById(R.id.btn4on);

btn4off=(Button)findViewById(R.id.btn4off);

  //定义button的监听事件

btn1on.setOnClickListener(btn1onListener);

btn1off.setOnClickListener(btn1offListener);

btn2on.setOnClickListener(btn2onListener);

btn2off.setOnClickListener(btn2offListener);

btn3on.setOnClickListener(btn3onListener);

btn3off.setOnClickListener(btn3offListener);

btn4on.setOnClickListener(btn4onListener);

btn4off.setOnClickListener(btn4offListener);

 

 

 

 //实现button事件的函数调用

privateButton.OnClickListenerbtn1onListener = newButton.OnClickListener(){

publicvoidonClick(View v) {

UTledcontrol(1,"1");

}

};

注:button实现代码未完全写出,完整代码见光盘资料led_demoAPK

LED控制函数的编写:

privatevoidUTledcontrol(intcmd,Stringstr)

{

try

{

switch(cmd)

{

case 1 :{

FileOutputStreamutled1=newFileOutputStream("/sys/devices/platform/ut4412-led/led1");

utled1.write(str.getBytes("iso-8859-1"));

utled1.close();

                 };break;

case 2:{     //打开驱动程序中的了的设备节点,并向该节点写入控制命令

FileOutputStreamutled2=newFileOutputStream("/sys/devices/platform/ut4412-led/led2");

utled2.write(str.getBytes("iso-8859-1"));

utled2.close();

               };break;

case 3:{

FileOutputStreamutled3=newFileOutputStream("/sys/devices/platform/ut4412-led/led3");

utled3.write(str.getBytes("iso-8859-1"));

utled3.close();

               };break;

case 4:{

FileOutputStreamutled4=newFileOutputStream("/sys/devices/platform/ut4412-led/led4");

utled4.write(str.getBytes("iso-8859-1"));

utled4.close();

               };break

default:   

}

}

catch(Exception e){

Toast.makeText(UTledTest.this"led open devices error!", Toast.LENGTH_SHORT).show();

}

 }

}

 

 

Android程序编译完毕后,可以执行程序并将APP下载到开发板上,然后通过此应用程序测试

 LED驱动是否编写成功:

Android应用程序UI界面如图所示:

   到这你可以点击按键试试效果啦!