1. 程式人生 > >tiny4412開發板LED燈驅動寫法

tiny4412開發板LED燈驅動寫法

簡介

led燈成本很低,操控簡單,在嵌入式產品中不可或缺,可以作為除錯標識,狀態指示等等,高階用法還可以作為呼吸燈進一步增強其美觀性。本章介紹只控制led燈的亮滅,tiny4412開發板有四個LED燈在核心板上供使用者操作,led燈亮滅靠cpu IO口輸出電平,具體操控看實際電路。

電路圖

在tiny4412開發板上,led燈電路如下:
這裡寫圖片描述
與CPU連線如下:
這裡寫圖片描述
可以看到CPU相應引腳輸出相關電平,就可以控制燈的亮滅,cpu引腳輸出低電平led燈亮,接下來就是操作相關暫存器,這些暫存器與GPM4相關,一個是控制暫存器,一個是資料暫存器。
命令暫存器
這裡寫圖片描述
資料暫存器
這裡寫圖片描述

驅動程式碼

//驅動程式碼
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>

#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/kdev_t.h>
#include<linux/slab.h>
#include<linux/device.h> //增加自動建立裝置標頭檔案
#include<linux/uaccess.h> //定義字元裝置結構體 static struct cdev *leddriver_cdev; //定義裝置號(包含主次) static dev_t leddriver_num=0; //定義裝置類 static struct class *leddriver_class; //定義裝置結構體 static struct device *leddriver_device; //定義錯誤返回型別 static int err; //定義裝置名稱 #define LEDDRIVER_NAME "myled" #define GPM4CON_ADDR 0x110002E0
#define GPM4DAT_ADDR 0X110002E4 static volatile unsigned long *gpm4con=NULL; static volatile unsigned long *gpm4dat=NULL; #define GPM4CON *gpm4con #define GPM4DAT *gpm4dat static ssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft) { unsigned char LED_STATUE; copy_from_user(&LED_STATUE,usr,1); printk("leddriver read is %d\r\n",LED_STATUE); switch(LED_STATUE) { case 10:GPM4DAT |= (0x1<<0);break; case 11:GPM4DAT &=~(0X1<<0);break; case 20:GPM4DAT |= (0x1<<1);break; case 21:GPM4DAT &=~(0X1<<1);break; case 30:GPM4DAT |= (0x1<<2);break; case 31:GPM4DAT &=~(0X1<<2);break; case 40:GPM4DAT |= (0x1<<3);break; case 41:GPM4DAT &=~(0X1<<3);break; } return 0; } ssize_t leddriver_write (struct file *file, const char __user *usr, size_t size, loff_t *loft) { printk("leddriver write is ok\r\n"); return 0; } int leddriver_open (struct inode *node, struct file *file) { printk("files open is success\r\n"); return 0; } int leddriver_release (struct inode *node, struct file *file) { printk("leddriver close is success\r\n"); return 0; } //檔案操作函式結構體 static struct file_operations leddriver_fops={ .owner=THIS_MODULE, .open=leddriver_open, .release=leddriver_release, .read=leddriver_read, .write=leddriver_write, }; static __init int ldedriver_init(void) { //分配字元裝置結構體,前面只是定義沒有分配空間 leddriver_cdev=cdev_alloc(); //判斷分配成功與否 if(leddriver_cdev==NULL) { err=-ENOMEM; printk("leddriver alloc is err\r\n"); goto err_leddriver_alloc; } //動態分配裝置號 err=alloc_chrdev_region(&leddriver_num, 0, 1, LEDDRIVER_NAME); //錯誤判斷 if(err<0) { printk("alloc leddriver num is err\r\n"); goto err_alloc_chrdev_region; } //初始化結構體 cdev_init(leddriver_cdev,&leddriver_fops); //驅動註冊 err=cdev_add(leddriver_cdev,leddriver_num,1); if(err<0) { printk("cdev add is err\r\n"); goto err_cdev_add; } //建立裝置類 leddriver_class=class_create(THIS_MODULE,"led_class"); err=PTR_ERR(leddriver_class); if(IS_ERR(leddriver_class)) { printk("leddriver creat class is err\r\n"); goto err_class_create; } //建立裝置 leddriver_device=device_create(leddriver_class,NULL, leddriver_num,NULL, "leddevice"); err=PTR_ERR(leddriver_device); if(IS_ERR(leddriver_device)) { printk("leddriver device creat is err \r\n"); goto err_device_create; } //led燈暫存器配置 gpm4con=ioremap(GPM4CON_ADDR, 4); gpm4dat=ioremap(GPM4DAT_ADDR, 4); GPM4CON &= ~(0XFFFF<<0); GPM4CON |= (0x1111<<0); GPM4DAT |= (0XF<<0); printk("leddriver init is success\r\n"); return 0; err_device_create: class_destroy(leddriver_class); err_class_create: cdev_del(leddriver_cdev); err_cdev_add: unregister_chrdev_region(leddriver_num, 1); err_alloc_chrdev_region: kfree(leddriver_cdev); err_leddriver_alloc: return err; } static __exit void leddriver_exit(void) { //取消對映 iounmap(gpm4con); iounmap(gpm4dat); device_destroy(leddriver_class,leddriver_num); class_destroy(leddriver_class); cdev_del(leddriver_cdev); unregister_chrdev_region(leddriver_num, 1); printk("leddriver is exit\r\n"); } module_init(ldedriver_init); module_exit(leddriver_exit); MODULE_LICENSE("GPL");

app程式碼

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc,char *argv[])
{
  unsigned char LED_STATUE,shi;
  int ge;

  int led_fp;

  led_fp = open(argv[1],O_RDWR);
 // LED_STATUE=(unsigned char)atoi(argv[2]);
 while(1)
    {
  for(shi=1;shi<=4;shi++)
    {
      for(ge=1;ge>=0;ge--)
        {
      LED_STATUE=shi*10+ge;
      read(led_fp,&LED_STATUE,1);
      sleep(1);
    }
    }
    }
  close(led_fp);
}

Makefile

KERN_DIR = /zhangchao/linux3.5/linux-3.5
all:
    make -C $(KERN_DIR) M=`pwd` modules
cp:
    cp ./* /zhangchao/rootfs/zhangchao
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order
obj-m += led.o

說明
雖然呼叫read write函式,來實現對燈的控制,並不符合函式操作規範,這裡的led燈並不能看做是一個檔案操作,並沒有體現出linux一切皆檔案,並不符合標準的檔案操作方法,規範化寫法將在後面給出。