分类: 嵌入式
2010-11-11 10:54:20
摘自:
忙忙碌碌有一天,终于实现自己想要的结果了,虽说是个普通的流水灯,但是也让我收获不小啊,对着原理图看了很长时间才找到自己想要的管脚的名字,晚上没什么事就写出来了,如有错误希望留言指正
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_MAJOR 242
//主设备号,先用cat /proc/devices看看自己的板子上那个主设备号没用。
#define LED_NAME "my2440_leds" //设备名称,可以起自己喜爱的名字
#define STOP 0
#define START 1
static unsigned long led_table [] = {
S3C2410_GPF0,
S3C2410_GPF2,
S3C2410_GPF4,
S3C2410_GPF6,
S3C2410_GPG1,
S3C2410_GPG5,
S3C2410_GPG7,
S3C2410_GPG10,
};
static unsigned int led_cfg_table [] = {
S3C2410_GPF0_OUTP,
S3C2410_GPF2_OUTP,
S3C2410_GPF4_OUTP,
S3C2410_GPF6_OUTP,
S3C2410_GPG1_OUTP,
S3C2410_GPG5_OUTP,
S3C2410_GPG7_OUTP,
S3C2410_GPG10_OUTP,
};
//上面是将管脚设置成普通的输出管脚,在Micro型板子上都是用..._GPIO_OUTP
//打开设备
static int led_open(struct inode *inode, struct file *file)
{
//
int i;
for (i = 0; i < 8; i++)
{
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
return 0;
}
//关闭设备
static int led_close(struct inode *inode, struct file *file)
{
return 0;
}
//对设备进行控制
static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
int i;
if(cmd==STOP)
{
printk("led stop\n");
for (i = 0;i < 8;i++)
{
s3c2410_gpio_setpin(led_table[i], !cmd);
}
}
else if (cmd==START)
{
printk("leds start\n");
for (i = 0;i < 8;i++)
{
s3c2410_gpio_setpin(led_table[i], !cmd);
msleep(500);
}
for (i = 0;i < 8;i++)
{
s3c2410_gpio_setpin(led_table[7-i],cmd);
msleep(500);
}
}
else
return -EINVAL;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_close,
.ioctl = led_ioctl,
};
static int __init led_init(void)
{
int ret;
ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
if(ret < 0)
{
printk(LED_NAME " register falid!\n");
}
}
static void __exit led_exit(void)
{
//注销设备
unregister_chrdev(LED_MAJOR, LED_NAME);
printk(LED_NAME " rmmodule\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("gaofeng");
MODULE_DESCRIPTION("my2440 led driver");
驱动就这么多了,接下来就是编译了,还是用老方法吧,编译成模块吧,先将驱动程序移到内核的驱动代码
/mini2440/linux2.6.29/drivers/char下,编译Makefile,添加如下
obj-m += 8leds.o//我的驱动代码保存的文件名实8led.c的
然后退到linux2.6.29目录下,输入命令make modules
没有错误的话就会生成8leds.ko,将该目标代码下载到开发板上。接下来就是创建设备如口和加载模块了
“这里说点别的,可能有的人在编译成模块文件时碰到过这样的问题,就是mknod...和insmod...都没有错误,但是执行rmmod时却提示说模块文件不存在,并且执行lsmod时明明看到自己加载的模块处于live状态,我刚开始就是这样,刚开始还以为是自己的系统有问题了,偶然在一个论坛中看到是因为自己缺少一个文件夹执行mkdir /mkdir/modules/2.6.29.4.FriendlyARM将编译好的模块文件放到该文件夹里就不会有这种问题了”
下面是测试程序:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define STOP 0
#define START 1
static int tmp;
static int fd;
static void set_leds(void)
{
ioctl(fd, tmp);
}
int main(int argc, char **argv)
{
//打开led设备
fd = open("/dev/8ledtest", O_RDWR);
if(fd < 0)
{
printf("Open LED Device Faild!\n");
exit(1);
}
//提示用户输入一个参数来对led进行控制,0表示停止工作,1表示开始
printf("please enter the cmd (0|1 is stop|Start):\n");
scanf("%d", &tmp);
while(1)
{
fd_set rdfds;
struct timeval tv;
int ret;
FD_ZERO(&rdfds);
FD_SET(0, &rdfds);//0是标准输入的句柄(1是标准输出的句柄、2是错误的句柄)
tv.tv_sec = 1;//设置timeout的值为1秒
tv.tv_usec = 0;
ret = select(1, &rdfds, NULL, NULL, &tv);
if(ret < 0) perror("select");
else if(ret == 0)
{
set_leds();
}
else
{
scanf("%d", &tmp);
printf("cmd = %d\n", tmp);
}
if(tmp < 0)
{
break;
}
}
//关闭设备
close(fd);
return 0;
}
因为想在程序运行起来之后还能从控制台输入控制信息,想了好长时间也没有想出一个好的方法,只好加了一个文件检测的select()函数,使测试程序写的有点长了。编译好后将测试程序下到板子上或是用mount命令都OK。
接下来需要自己焊个流水灯了,在流水灯负极最好焊个电阻,防止二极管被烧坏吗!焊好插到自己的板子上运行,就会看到流水的现象了。
下面是用QT编写的一个简单的图形界面
1.编写图形界面
打开QT 2.0,在里面进行编辑如下
将名字该为LEDBaseForm,因为在后面的程序中要把它当做是一个父类来继续的,所以此处的名字要和后面的.h文件中保持一致,保存成8led_base.ui格式的文件,因为下面的.h中要用。
2.编写.h文件
#ifndef MYHELLOFORM_H
#define MYHELLOFORM_H
#include "8led_base.h"//就是上面保存的.ui文件
#include
class MyLEDForm : public LEDBaseForm//要和前面的推行界面的名字保持一致
{
Q_OBJECT
public:
MyLEDForm( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );//带默认参数的构造函数
virtual ~MyLEDForm();
private slots:
void Onled();
void Offled();
};
#endif // MYHELLOFORM_H
保存成8led.h后面的程序要用
3.编写mian.cpp文件
#include "8led.h"
#include
QTOPIA_ADD_APPLICATION("8ledtest",MyLEDForm)
QTOPIA_MAIN
4.编写8led.cpp
#include "8led.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_START 1
#define LED_STOP 0
int fd;
MyLEDForm::MyLEDForm( QWidget* parent, const char* name, WFlags fl)
:LEDBaseForm(parent, name, fl)//要和前面建立的图形界面的名字保持一致
{
connect(PushButton1,SIGNAL(clicked()),this,SLOT(Onled()));
connect(PushButton2,SIGNAL(clicked()),this,SLOT(Offled()));
}
MyLEDForm::~MyLEDForm(){}
void MyLEDForm::Onled()
{
fd = ::open("/dev/8ledtest", 0);
::ioctl(fd, 1);
}
void MyLEDForm::Offled()
{
fd = ::open("/dev/8ledtest", 0);
::ioctl(fd, 0);
::close(fd); // 关闭设备
}
5.接下来时.pro文件
CONFIG += qtopiaapp
CONFIG -= buildQuicklaunch
HEADERS = 8led.h
SOURCES = 8led.cpp
SOURCES+=main.cpp
INTERFACES = 8led_base.ui
desktop.files = 8led.desktop
desktop.path = /apps/gaof
INSTALLS += desktop
pics.files=pics/*
pics.path=/pics/gaof/qpelogo
PICS_INSTALLS+=pics
TARGET = 8ledtest//生成的可执行程序
6.编写build文件
#!/bin/bash
source /opt/FriendlyARM/mini2440/arm-qtopia/qtopia-2.2.0-FriendlyARM/setQpeEnv
qmake -spec /opt/FriendlyARM/mini2440/arm-qtopia/qtopia-2.2.0-FriendlyARM/qtopia/mkspecs/qws/linux-arm-g++ -o Makefile *.pro
make clean
make
7.编写8leds.desktop
[Desktop Entry]
Comment=An Example Program
Exec=8ledtest
Icon=gaof/qpelogo
//需要先在opt/Qtopia/pics下建立一个自己的文件夹,我的当然就是gaof了将想要显示的图标放到里面
Type=gaof
//gaof是我自己建的最上层的图标,类似于友善的Games图标,具体的建立方法可以参考
Name=8led
9.上面的都做好后就可以运行./build生成可执行文件了。编译后将8led.desktop下载到开发办的/opt/Qtopia/apps/gaof目录里
将生成的可执行程序下载到/opt/Qtopia/bin里,这时通过图形界面上的ledstart和ledstop按钮就可以控制自己焊的流水灯的亮和灭了。
!!终于写完了,时间也差不多了,实验室要锁门了,写的有点仓促,如有错误,望指正!!