基于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 如下 :
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define IOCTL_GPIO_ON 0
#define IOCTL_GPIO_OFF 1
#define DEVICE_NAME "leds"
static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
static int sbc2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
// 设置指定引脚的输出电平为0,即低电平,灯亮
case IOCTL_GPIO_ON:
s3c2410_gpio_setpin(led_table[arg], cmd);
return 0;
// 设置指定引脚的输出电平为1,即高电平,灯灭
case IOCTL_GPIO_OFF:
s3c2410_gpio_setpin(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
//.open = sbc2440_leds_open,
//.release= sbc2440_leds_close,
.ioctl = sbc2440_leds_ioctl,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
ret = misc_register(&misc);
printk (DEVICE_NAME"/tinitialized/n");
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
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
#ifndef LED_H
#define LED_H
#include
class Led : public QObject
{
Q_OBJECT
public:
explicit Led(QObject *parent = 0);
public:
int fd;
int on[4];
public:
// Led();
~Led();
public:
void led1_on();
void led2_on();
void led3_on();
void led4_on();
};
#endif // LED_H
led.cpp
#include "led.h"
#include
#include
#include
#include
#include
#include
#include
Led::Led(QObject *parent) :
QObject(parent)
{
on[0] = 0;
on[1] = 0;
on[2] = 0;
on[3] = 0;
fd = open("/dev/leds",0);
// cout<<"fd = "<
必需要说明的是,在调用驱动程序ioctl()接口之前,必须包含怎么一个头文件#include
第三,GUI的设计。
在这里我们只设置4个按钮和一个退出按钮,并且附上一个提示面板,当然,必须在这一部分对Led进行实例化,并且加以应用才能完成对应用程序的功能,必须提醒的是,定义一个Led *ledobj对象指针以后,必须对其进行分配内存操作,否则程序将会出现不可预料完成的终止提示。源码如下:
leddialog.h
#ifndef LEDDIALOG_H
#define LEDDIALOG_H
#include
#include
#include "led.h"
class LedDialog : public QDialog
{
Q_OBJECT
private :
QLabel *label;
QPushButton *led1Button;
QPushButton *led2Button;
QPushButton *led3Button;
QPushButton *led4Button;
QPushButton *exitButton;
Led *ledobj;
private slots :
void Light_style1(void);
void Light_style2(void);
void Light_style3(void);
void Light_style4(void);
void Light_style_exit(void);
void Light_delay(int times);
public:
LedDialog(QWidget *parent = 0);
~LedDialog();
};
#endif // LEDDIALOG_H
leddialog.cpp
#include "leddialog.h"
#include
//Construction Function
LedDialog::LedDialog(QWidget *parent)
: QDialog(parent)
{
// init component
label= new QLabel(tr("Set Led"));
led1Button = new QPushButton(tr("Led1"));
led2Button = new QPushButton(tr("Led2"));
led3Button = new QPushButton(tr("Led3"));
led4Button = new QPushButton(tr("Led4"));
exitButton = new QPushButton(tr("Exit"));
ledobj = new Led();
//layout component
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(label,Qt::AlignTop);
layout->addWidget(led1Button);
layout->addWidget(led2Button);
layout->addWidget(led3Button);
layout->addWidget(led4Button);
layout->addWidget(exitButton);
setLayout(layout);
//resize(200,230);
//setFixedSize(200,230);
// this->setFixedSize( this->width (),this->height ());
setMinimumSize(200, 230);
setMaximumSize(200, 230);
// signal-slots connect
QObject::connect(led1Button, SIGNAL(clicked()), this, SLOT(Light_style1()));
QObject::connect(led2Button, SIGNAL(clicked()), this, SLOT(Light_style2()));
QObject::connect(led3Button, SIGNAL(clicked()), this, SLOT(Light_style3()));
QObject::connect(led4Button, SIGNAL(clicked()), this, SLOT(Light_style4()));
QObject::connect(exitButton, SIGNAL(clicked()), this, SLOT(Light_style_exit()));
}
//self-declaration function implement
void LedDialog::Light_style1(void)
{
ledobj->led1_on();
Light_delay(100);
}
void LedDialog::Light_style2(void)
{
ledobj->led2_on();
Light_delay(2000);
}
void LedDialog::Light_style3(void)
{
ledobj->led3_on();
Light_delay(2000);
}
void LedDialog::Light_style4(void)
{
ledobj->led4_on();
Light_delay(2000);;
}
void LedDialog::Light_style_exit(void)
{
exit(0);
}
void LedDialog::Light_delay(int times)
{
int i;
int j;
for (i = 0;i < times; i++)
for (j = 0; j < times; j++)
{
// Null function
}
}
LedDialog::~LedDialog()
{
}
最后附上main.cpp的内容,其实是完全没有做任何修改,QtCreator2.0自动生成。哈
#include
//#include
#include "led.h"
#include "leddialog.h"
#include "leddialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LedDialog w;
// QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
w.show();
return a.exec();
}
PS : 源代码中有许多是我在调试的时候修改的,所以有一些源码注释没删除,呵呵。。。也说明了还有一些问题存在呢,不过,在板子上我已经测试过整个程序,没有问题,运行情况良好。