基于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 : 源代码中有许多是我在调试的时候修改的,所以有一些源码注释没删除,呵呵。。。也说明了还有一些问题存在呢,不过,在板子上我已经测试过整个程序,没有问题,运行情况良好。

 


  以前在广嵌上培训的时候没有把arm+linux的内容学好,今天可终于自食其果了,一个在Qt Gui 里边通过调用内核驱动程序来控制mini2440板子Led灯的小程序,搞我接近十来天的时间——可能是有点懒的缘故,上周基本都在玩,这周才开始折腾,C++面向对象程序设计不过关,内核驱动写得一塌糊涂,对自己真那个失望!幸好公司的头头对我还是蛮有耐心的,知道一个毕业生刚出来都有些生手,来问情况的时候总是"兄弟"前,"兄弟"——连我都那么难接受的学习能力,他居然还是....不时搞到我惭愧,很惭愧。哦,还有,必须感谢网友卡卡罗特,逐浪,古月行云,直升飞机T的技术支持,是你们给了我思路,要知道,思路问题就是最大的问题,程序调不出来我可以调到凌晨四点多,可是没有思路,我可不敢轻举妄动。直升飞机T甚至还给我提供了他写的一个源码,功能相似,但是板子是天嵌公司的一个2440的板子,当然,还少不了我最好的大学同学兆华兄的提醒——不晓得为啥,被兆华一骂,我就变得醒目了好多个等级,哈哈。。。不扯啦,大家看过的,有觉得我理解得不合理或者是需要补充的地方,很希望可以一一指出,你们的意见,将是我进步的最大支持!

posted on 2012-03-16 05:44  风行雪舞  阅读(1355)  评论(0编辑  收藏  举报
无觅相关文章插件,快速提升流量