手把手教你用pcDuino的A10点灯

雨后的彩虹桥 发布于 2014/01/13 11:21
阅读 918
收藏 0

很多人问,我们板子上的arduino IDE或者c_environment做了什么让板子上的IO口有输入输出的功能。这篇文章将会告诉你,pcDuino是怎么工作的。

pcDuino板载的是嵌入式ubuntu或者android系统,这里必然要涉及到linux操作底层硬件的原理。大家都知道linux系统里面一切皆文件,那么linux系统怎么让硬件IO变成文件呢,请看下面一张图。

1

一,搭建环境

sudo apt-get update

sudo apt-get install  vim  pcduino-linux-headers-3.4.29+

两条命令就在pcDuino上面把嵌入式开发环境搭建好了。

二,看手册

这篇文章的目的是手把手教你将板子上面的RX,TX闪烁起来,首先要搞清楚板子RX和TX接在哪儿了,这个需要看原理图。

三,编写了linux LED驱

这里就不再啰嗦了,我尽量在程序里面注释的详细一些。

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/init.h>

#include <linux/delay.h>

#include <linux/device.h>

#include <asm/uaccess.h>

#include <asm/irq.h>

#include <asm/io.h>



/*根据芯片手册得到的宏定义*/

#define GPIO_BASE 0x01C20800

#define GPH_CFG1  (GPIO_BASE + 0×100)

#define GPH_CFG2  (GPIO_BASE + 0×104)

#define GPH15_CFG         (1 << 28)

#define GPH16_CFG         (1 << 0)

#define GPH_DATA  (GPIO_BASE + 0x10c)



/*自动创建设备节点结构体*/

static struct class *leddrv_class;

/*cfg1里面有PH15,cfg2里面有PH16*/

volatile unsigned  long  *gph_cfg1 = NULL;

volatile unsigned  long  *gph_cfg2 = NULL;

volatile unsigned  long  *gph_date = NULL;

/*设备打开函数,当你在应用程序里面对led执行open函数这个函数就会被执行*/

static int led_drv_open(struct inode *inode, struct file *file)

{

         /*将PH15_CFG位清零*/

         *gph_cfg1 &= ~(GPH15_CFG);

         /*将PH15_CFG位置1,即设置为输出模式*/

         *gph_cfg1 |= GPH15_CFG;

 

        *gph_cfg2 &= ~(GPH16_CFG);

        *gph_cfg2 |= GPH16_CFG;

         /*在内核里面打印要用printk*/

         printk(KERN_ALERT”led openi\n”);

        

         return 0;

}

/*设备写函数,当你在应用程序里面对led执行write函数这个函数就会被执行*/

static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

         printk(KERN_ALERT”led write\n”);

         int val ;

         /*内核空间和用户空间相互独立,两者之间数据交换要用这个函数*/

         copy_from_user(&val,buf,count);

         if(val == 1)

         {

                   /*置0,相当pin_write写0*/

                   *gph_date &= ~(0×03<<15);

         }

         else

         {       

                   /*置1,相当pin_write写1*/

                   *gph_date |= (0×03<<15);

         }

         return 0;

}

/*linux设备驱动里面每个设备都得要一个设备描述符,其实就可以结构体,有兴趣的可以看看他的原型*/

static struct file_operations led_drv_fops = {

    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

    .open   =   led_drv_open,     /*函数指针赋值*/

    .write  =          led_drv_write,             /*函数指针赋值*/

};

/*主设备号变量*/

int major;

/*当执行insmod命令的时候这个函数会被执行 */

static int led_drv_init(void)

{       

         /*注册一个LED设备,参数0表示让操作系统分配主设备号,分配好了之后返回给major */

         major = register_chrdev(0, “led_drv”, &led_drv_fops);

         /*创建设备节点,有了这两个函数,我们在文件系统里面就会看到/dev/led */

         leddrv_class = class_create(THIS_MODULE,”led_drv”);

         device_create(leddrv_class,NULL,MKDEV(major,0),NULL,”led”);

         /*linux系统里面都是虚拟地址 ioremap就是将虚拟地址转换为物理地址,然后我们可以对寄存器进行操作

          *第一个参数表示需要映射的基地址,第二个参数表示长度,即基地址+0×10*/

         gph_cfg1 = (volatile unsigned long*)ioremap(GPH_CFG1,16);

         /*0×104 = 0×100 +4*/

         gph_cfg2 = gph_cfg1 + 1;

         /*0×104 = 0×100 +4*3*/

         gph_date = gph_cfg1 + 3;

         printk(KERN_ALERT”register\n”);

         return 0;

}

/*当执行rmmod的时候会被执行*/

static void led_drv_exit(void)

{

         /*注销LED设备*/

         unregister_chrdev(major, “led_drv”); // 卸载

         /*释放申请的地址*/

         iounmap(gph_cfg1);

         /*销毁创建的设备节点*/

         device_destroy(leddrv_class,MKDEV(major,0));

         class_destroy(leddrv_class);

         printk(KERN_ALERT”unregister\n”);

}

/*linux设备驱动的两个修饰符*/

module_init(led_drv_init);

module_exit(led_drv_exit);

 

/*遵循GPL协议*/

MODULE_LICENSE(“GPL”);

编写Makefile

KERN_DIR = /usr/src/linux-headers-3.4.29+/

 

all:

    make -C $(KERN_DIR) M=`pwd` modules

 

clean:

    make -C $(KERN_DIR) M=`pwd` modules clean

    rm -rf modules.order

 

obj-m   += led.o

编译:make

加载:sudo insmod led.ko

卸载:sudo rmmod led

四,测试

根据驱动程序,只需要写一个简单的测试代码就可以了。

#include<stdio.h>

#include<stdlib.h>

int main()

{

    int fd;

    int val = 1;

    fd = open(“/dev/led”,0666);

    if(fd < 0)

    {  

        printf(“cannot open\n”);

        return 0;

    }  

    while(1)

    {  

        write(fd,&val,sizeof(int));

        sleep(1);

        val = 0;

        write(fd,&val,sizeof(int));

        val = 1;

        sleep(1);

    }  

    close(fd);

    return 0;

}



编译:gcc led_test.c

执行:sudo ./a.out

linksprite学习中心



加载中
0
leo-H
leo-H
求sources.list ,我连vim都装不上,我用的ubuntu12.4的sources.list是不是不行?
0
雨后的彩虹桥
雨后的彩虹桥
 deb  http://ports.ubuntu.com/ubuntu-ports/ precise main universe
deb-src  http://ports.ubuntu.com/ubuntu-ports/ precise main universe
deb  http://ports.ubuntu.com/ubuntu-ports/ precise-security main universe
deb-src  http://ports.ubuntu.com/ubuntu-ports/ precise-security main universe
deb  http://ports.ubuntu.com/ubuntu-ports/ precise-updates main universe
deb-src  http://ports.ubuntu.com/ubuntu-ports/ precise-updates main universe
deb  http://www.wiimu.com:8020/pcduino/ pcduino main
deb-src  http://www.wiimu.com:8020/pcduino/ pcduino main
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部