转载地址: http://www.cnblogs.com/elect-fans/archive/2012/03/16/2408576.html
基于arm + linux的嵌入式软件开发,基本上的内容主要是:u-boot的移植,kernel的裁剪和相关驱动程序的设计,root-fs的制作,应用程序的设计,其中,应用程序主要包含两方面的内容:Gui的设计和逻辑控制程序的实现。在整个开发中,具有相当代码量的部分也就这么两个方面:驱动程序、应用程序。一般的开发板都有相关配套的底层驱动程序例程,开发者可稍加修改在工程项目中加以使用(其实我不知道这样是不是会触犯什么只是产权之类的东东,先凑着用吧)。
第一,驱动程序的设计。
很容易想到,Led在板子上是直接与CPU的GPIO引脚相接,即对相应GPIO的控制也就是对外设Led的控制,以下是Led作为一个外设在板子上的详细资源占用表。
图1.0 mini2440 开发板上Led灯的资源占用表
板子Led的原理图如下 :
图1.1 LED原理图
分析:LED灯只有两种状态,亮与不亮。查看用户手册可以知道,当GPIO被赋予低电平的时候,LED灯被点亮,否则将处于熄灭的状态,因此,只要设置好管脚高低电平两个状态就可以完成驱动程序连接底层硬件和应用程序的功能了。
源码 mini2440_leds.c 如下 :
1 #include <linux/miscdevice.h> 2 #include <linux/delay.h> 3 #include <asm/irq.h> 4 #include <mach/regs-gpio.h> 5 #include <mach/hardware.h> 6 #include <linux/kernel.h> 7 #include <linux/module.h> 8 #include <linux/init.h> 9 #include <linux/mm.h> 10 #include <linux/fs.h> 11 #include <linux/types.h> 12 #include <linux/delay.h> 13 #include <linux/moduleparam.h> 14 #include <linux/slab.h> 15 #include <linux/errno.h> 16 #include <linux/ioctl.h> 17 #include <linux/cdev.h> 18 #include <linux/string.h> 19 #include <linux/list.h> 20 #include <linux/pci.h> 21 #include <asm/uaccess.h> 22 #include <asm/atomic.h> 23 #include <asm/unistd.h> 24 25 #define IOCTL_GPIO_ON 0 26 #define IOCTL_GPIO_OFF 1 27 #define DEVICE_NAME "leds" 28 29 static unsigned long led_table [] = { 30 S3C2410_GPB5, 31 S3C2410_GPB6, 32 S3C2410_GPB7, 33 S3C2410_GPB8, 34 }; 35 36 static unsigned int led_cfg_table [] = { 37 S3C2410_GPB5_OUTP, 38 S3C2410_GPB6_OUTP, 39 S3C2410_GPB7_OUTP, 40 S3C2410_GPB8_OUTP, 41 }; 42 43 static int sbc2440_leds_ioctl( 44 struct inode *inode, 45 struct file *file, 46 unsigned int cmd, 47 unsigned long arg) 48 { 49 switch(cmd) { 50 // 设置指定引脚的输出电平为0,即低电平,灯亮 51 case IOCTL_GPIO_ON: 52 s3c2410_gpio_setpin(led_table[arg], cmd); 53 return 0; 54 // 设置指定引脚的输出电平为1,即高电平,灯灭 55 case IOCTL_GPIO_OFF: 56 s3c2410_gpio_setpin(led_table[arg], !cmd); 57 return 0; 58 59 default: 60 return -EINVAL; 61 } 62 } 63 64 static struct file_operations dev_fops = { 65 .owner = THIS_MODULE, 66 //.open = sbc2440_leds_open, 67 //.release= sbc2440_leds_close, 68 .ioctl = sbc2440_leds_ioctl, 69 }; 70 71 static struct miscdevice misc = { 72 .minor = MISC_DYNAMIC_MINOR, 73 .name = DEVICE_NAME, 74 .fops = &dev_fops, 75 }; 76 77 static int __init dev_init(void) 78 { 79 int ret; 80 81 int i; 82 83 for (i = 0; i < 4; i++) { 84 s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]); 85 s3c2410_gpio_setpin(led_table[i], 0); 86 } 87 88 ret = misc_register(&misc); 89 90 printk (DEVICE_NAME"/tinitialized/n"); 91 92 return ret; 93 } 94 95 static void __exit dev_exit(void) 96 { 97 misc_deregister(&misc); 98 } 99 100 module_init(dev_init); 101 module_exit(dev_exit); 102 MODULE_LICENSE("GPL"); 103 MODULE_AUTHOR("chenxiaomai");
为了编译此驱动程序,必须编写一个Makefile 文件,其内容如下 :
# If KERNELREEASE is defined ,we've been invoked from the kernel # build system and can use its language ifneq ($(KERNELRELEASE),) obj-m := mini2440_leds.o # Otherwise we were called directly from the command line # invoke the kernel build sysstem else KERNELDIR=/root/build_kernel/linux-2.6.29 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif all:mini2440_leds.c -o mini2440_leds.o $(CC) mini2440_leds.c -o mini2440_leds clean: rm -rvf *.o *.ko *.mod.c *.order *.symvers
把驱动程序和Makefile 放同一目录,在终端进行#make,如果不出问题,将会产生一些中间文件,但是,只有.ko文件才是我们想要的,你知道,那是我们在超级终端的主角。 make以后在终端输入#file mini2440_leds.ko,就可以看见驱动模块的详细信息啦。
[root@localhost Led]# file mini2440_leds.ko
mini2440_leds.ko: ELF 32-bit LSB relocatable, ARM, version 1 (SYSV), not stripped
到这里,你就可以把.ko文件送到板子的超级终端上直接insmod 和rmmod,这个,就不多说啦。。。
第二,逻辑控制设计。
基于逻辑与GUI分离的原则,这里把逻辑控制部分设置成每一个方法设置一个灯的熄灭状态。源码如下 :
led.h
1 #ifndef LED_H 2 #define LED_H 3 4 #include <QObject> 5 6 class Led : public QObject 7 { 8 Q_OBJECT 9 public: 10 explicit Led(QObject *parent = 0); 11 12 public: 13 int fd; 14 int on[4]; 15 16 public: 17 // Led(); 18 ~Led(); 19 20 public: 21 void led1_on(); 22 void led2_on(); 23 void led3_on(); 24 void led4_on(); 25 }; 26 27 #endif // LED_H
================================================
led.cpp
1 #include "led.h" 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 #include <stdio.h> 7 #include <sys/ioctl.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 11 Led::Led(QObject *parent) : 12 QObject(parent) 13 { 14 on[0] = 0; 15 on[1] = 0; 16 on[2] = 0; 17 on[3] = 0; 18 19 fd = open("/dev/leds",0); 20 // cout<<"fd = "<<fd<<endl; 21 if ( fd < 0 ) 22 { 23 perror("Error : fd < 0"); 24 } 25 } 26 27 void Led::led1_on() 28 { 29 on[0] = (~on[0]) & 1; 30 ioctl(fd,on[0],0); 31 } 32 33 void Led::led2_on() 34 { 35 on[1] = (~on[1]) & 1; 36 ioctl(fd,on[1],1); 37 } 38 39 void Led::led3_on() 40 { 41 on[2] = (~on[2]) & 1; 42 ioctl(fd,on[2],2); 43 44 } 45 46 void Led::led4_on() 47 { 48 on[3] = (~on[3]) & 1; 49 ioctl(fd,on[3],3); 50 } 51 52 Led::~Led() 53 { 54 //close(fd); 55 }
必需要说明的是,在调用驱动程序ioctl()接口之前,必须包含怎么一个头文件#include <sys/ioctl.h>,否则,编译器将会提示找不到该接口——这个问题也郁闷了三天的时间,后来是我们Qt群的一个老同志提醒我的,人生啊!
第三,GUI的设计。
在这里我们只设置4个按钮和一个退出按钮,并且附上一个提示面板,当然,必须在这一部分对Led进行实例化,并且加以应用才能完成对应用程序的功能,必须提醒的是,定义一个Led *ledobj对象指针以后,必须对其进行分配内存操作,否则程序将会出现不可预料完成的终止提示。源码如下:
leddialog.h
1 #ifndef LEDDIALOG_H 2 #define LEDDIALOG_H 3 4 #include <QtGui/QDialog> 5 #include <Qt/QtGui> 6 #include "led.h" 7 8 class LedDialog : public QDialog 9 { 10 Q_OBJECT 11 12 private : 13 QLabel *label; 14 QPushButton *led1Button; 15 QPushButton *led2Button; 16 QPushButton *led3Button; 17 QPushButton *led4Button; 18 QPushButton *exitButton; 19 Led *ledobj; 20 21 private slots : 22 void Light_style1(void); 23 void Light_style2(void); 24 void Light_style3(void); 25 void Light_style4(void); 26 void Light_style_exit(void); 27 void Light_delay(int times); 28 29 public: 30 LedDialog(QWidget *parent = 0); 31 ~LedDialog(); 32 }; 33 34 #endif // LEDDIALOG_H
=========================================================================================
leddialog.cpp
1 #include "leddialog.h" 2 #include <QtGui> 3 4 //Construction Function 5 LedDialog::LedDialog(QWidget *parent) 6 : QDialog(parent) 7 { 8 // init component 9 label= new QLabel(tr("Set Led")); 10 led1Button = new QPushButton(tr("Led1")); 11 led2Button = new QPushButton(tr("Led2")); 12 led3Button = new QPushButton(tr("Led3")); 13 led4Button = new QPushButton(tr("Led4")); 14 exitButton = new QPushButton(tr("Exit")); 15 ledobj = new Led(); 16 17 //layout component 18 QVBoxLayout *layout = new QVBoxLayout; 19 layout->addWidget(label,Qt::AlignTop); 20 layout->addWidget(led1Button); 21 layout->addWidget(led2Button); 22 layout->addWidget(led3Button); 23 layout->addWidget(led4Button); 24 layout->addWidget(exitButton); 25 setLayout(layout); 26 //resize(200,230); 27 //setFixedSize(200,230); 28 // this->setFixedSize( this->width (),this->height ()); 29 setMinimumSize(200, 230); 30 setMaximumSize(200, 230); 31 32 // signal-slots connect 33 QObject::connect(led1Button, SIGNAL(clicked()), this, SLOT(Light_style1())); 34 QObject::connect(led2Button, SIGNAL(clicked()), this, SLOT(Light_style2())); 35 QObject::connect(led3Button, SIGNAL(clicked()), this, SLOT(Light_style3())); 36 QObject::connect(led4Button, SIGNAL(clicked()), this, SLOT(Light_style4())); 37 QObject::connect(exitButton, SIGNAL(clicked()), this, SLOT(Light_style_exit())); 38 39 } 40 41 //self-declaration function implement 42 void LedDialog::Light_style1(void) 43 { 44 ledobj->led1_on(); 45 Light_delay(100); 46 } 47 48 void LedDialog::Light_style2(void) 49 { 50 51 ledobj->led2_on(); 52 Light_delay(2000); 53 } 54 55 void LedDialog::Light_style3(void) 56 { 57 ledobj->led3_on(); 58 Light_delay(2000); 59 } 60 61 void LedDialog::Light_style4(void) 62 { 63 ledobj->led4_on(); 64 Light_delay(2000);; 65 } 66 67 void LedDialog::Light_style_exit(void) 68 { 69 exit(0); 70 } 71 72 void LedDialog::Light_delay(int times) 73 { 74 int i; 75 int j; 76 for (i = 0;i < times; i++) 77 for (j = 0; j < times; j++) 78 { 79 // Null function 80 } 81 } 82 83 LedDialog::~LedDialog() 84 { 85 86 }
最后附上main.cpp的内容,其实是完全没有做任何修改,QtCreator2.0自动生成。哈
1 #include <QtGui/QApplication> 2 //#include <QTextCodec> 3 #include "led.h" 4 #include "leddialog.h" 5 6 #include "leddialog.h" 7 8 int main(int argc, char *argv[]) 9 { 10 QApplication a(argc, argv); 11 LedDialog w; 12 // QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); 13 w.show(); 14 return a.exec(); 15 }
PS : 源代码中有许多是我在调试的时候修改的,所以有一些源码注释没删除,呵呵。。。也说明了还有一些问题存在呢,不过,在板子上我已经测试过整个程序,没有问题,运行情况良好。