S3C2410——LED灯实验

写在最前面:嵌入式实验,ping不通时一定要先看看网线有没有接通,一般接通都是会有黄绿色色闪烁。

一、S3C2410输入/输出的原理

Linux主要有字符设备、块设备和网络设备3类驱动程序,我们一般编写的驱动都是字符设备驱动程序。

二、程序部分

编写程序控制3个LED灯,代码分为2个部分:控制LED的驱动程序、调用驱动程序的应用程序

1. 控制LED的驱动程序

(1) 常量和结构体的定义:

//定义设备名字,分配设备号时使用
#define DEVICE_NAME "UP-LED"
//定义次设备号
#define LEDRAW_MINOR 0
//定义端口C配置寄存器
#define GPCCON (*(volatile unsigned int *)S3C2410_GPCCON)
//定义端口C数据寄存器
#define GPCDAT (*(volatile unsigned int *)S3C2410_GPCDAT)
//定义字符设备结构体
struct cdev *mycdev;
//定义设备号变量,由主设备号和次设备号组成
dev_t devno;
//文件操作结构体定义使用设备的文件操作
static struct file_operations led_fops = {
    owner: THIS_MODULE,
    ioctl: led_ioctl, //只定义ioctl一个
};

(2) 驱动加载时的代码:

//定义加载驱动时执行的函数
module_init(led_init);
static int __init led_init(void)
{
    int result,err;
    //分配字符设备号
    result=alloc_chrdev_region(&devno,LEDRAW_MINOR,1,DEVICE_NAME);
    if(result < 0)
        printk(KERN_ERR "can't get device number \n");
    else
        printk("get device number\n");
    //设置GPC5、GPC6、GPC7为输出状态
    GPCCON=(GPCCON|0x5400)&0xffff57ff;
    //分配字符设备结构体
    mycdev = cdev_alloc();
    //初始化结构体,关联文件操作
    cdev_init(mycdev,&led_fops);
    //将字符设备驱动注册到内核
    err=cdev_add(mycdev,devno,1);
    if (err < 0)
        printk(KERN_ERR "can't add led device");
    return 0;
}

(3) 定义控制LED的文件操作:

static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 
unsigned long arg)
{    switch(cmd){
        case 1:
            if(arg==1) GPCDAT=GPCDAT&0xffffffdf;//第一个led亮
            if(arg==0) GPCDAT=GPCDAT|0x20;      //第一个led灭
            break;
        case 2:
            if(arg==1) GPCDAT=GPCDAT&0xffffffbf;//第二个led亮
            if(arg==0) GPCDAT=GPCDAT|0x40;      //第二个led灭
            break;
        case 3:
            if(arg==1) GPCDAT=GPCDAT&0xffffff7f;//第三个led亮
            if(arg==0) GPCDAT=GPCDAT|0x80;      //第三个led灭
            break;
        default:
            printk("error cmd number\n");break;
      }
      return 0;
}

2. 调用驱动程序的应用程序

//相关头文件的引用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{   //相关常量变量定义
    int on;
    int led_number;
    int fd;
    //读入命令行参数
    sscanf(argv[1], “%d”, &led_number);
    sscanf(argv[2],"%d", &on);
    //打开设备文件
    fd = open("/dev/leds", 0);
    if (fd < 0) { 
        perror("open device /dev/leds");
        exit(1);
    }
    //根据参数操作设备
    ioctl(fd, led_number, on);
    usleep(1000);
    //关闭设备文件
    close(fd);
    return 0;
}

3. makefile文件

ARGET = test_led
CROSS_COMPILE = arm-linux
CC            = $(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE),)
  KERNELDIR ?= /root/kernel/linux-2.6.24.4
  PWD := $(shell pwd)
all:   $(TARGET) modules
$(TARGET):
      $(CC) -o $(TARGET) $(TARGET).c
modules:
      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
      rm -rf *.o *~ *.ko Module.symvers *.mod.c $(TARGET)
.PHONY:modules clean
else
obj-m := led.o
endif

三、实验过程

在主机(虚拟机)上进行交叉编译:

根据makefile编译得到可执行文件test_led。

在主机上输入下面两行代码,将下面的两个文件上传到tftp服务器

cp led.ko /tftpboot/
cp test_led /tftpboot/

利用xshell超级终端,在目标机上接收led.ko和test_led文件,并且加载驱动程序

手动创建led设备节点,并给test_led文件可执行权限

实验现象:


posted @ 2022-05-07 16:41  静候佳茵  阅读(949)  评论(0编辑  收藏  举报