本工程设计的硬件有:
(1)nanopi s2(linux nanopi2 3.4.39)及其连接的继电器,5v转3.3v使用模块、光感设备、声感设备linux-3.4.y-nanopi2-lollipop-mr1.zip内核开发字符驱动程序
(2)tiny6410(linux FriendlyARM 2.6.38)使用连接的继电器和红外传感器linux-2.6.38-20110325.tar.gz内核开发字符驱动程序
将相应的交叉编译器分别编译,然后移植到相应的开发板加载驱动(如:insmod mic_driver.ko,前面的自动加载驱动体验好用)
不同内核的gpio操作函数不同,见之前发布的相关信息gpio驱动发展经验。需要注意的是阅读io下拉电阻设置在高低电平的驱动下,以确保io口电平状态稳定,否则会有数据跳动。
一、 nanopi s2的相关驱动
1.1 光感设备驱动及测试程序
#include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/uaccess.h> #include <linux/list.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> #include <mach/platform.h> #include <mach/devices.h> #include <mach/soc.h> #define DEVICE_NAME "4418_light" //nanopi2s -s5p4418 #define LGPIO PAD_GPIO_C 11 //模块GPIO脚 static int light_read(struct file *file, char * buffer, size_t count, loff_t * ppos) { unsigned tmp; unsigned long err; tmp = gpio_get_value(LGPIO); printk("==%d==\n",tmp); err = copy_to_user(buffer, &tmp, 1); return 1; } static struct file_operations dev_fops={ read:light_read, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init my_light_init(void) { int ret; gpio_direction_input(LGPIO);//设置io为输入 nxp_soc_gpio_set_io_pull_sel(LGPIO,0);//设置下拉电阻 ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit my_light_exit(void) { misc_deregister(&misc); } module_init(my_light_init); module_exit(my_light_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("cumtzd");
其测试程序
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #define DEV_FILE "/dev/4418_light" int main() { int fd_dev=-1; char dat; printf("nanoPi driver Test\n"); fd_dev = open(DEV_FILE,O_RDWR); if(fd_dev<0){ printf("open device err\n"); return 0; } while(1){ read(fd_dev,&dat,1); printf("Light status [%d]\n",dat); sleep(1); } return 0; }
1. 2 声学设备驱动及测试程序
#include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/uaccess.h> #include <linux/list.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/gpio.h> #include <mach/platform.h> #include <mach/devices.h> #include <mach/soc.h> #define DEVICE_NAME "4418_mic" //nanopi2s -s5p4418 #define LGPIO PAD_GPIO_C 13 //模块GPIO脚 static int mic_read(struct file *file, char * buffer, size_t count, loff_t * ppos) { unsigned tmp; unsigned long err; tmp = gpio_get_value(LGPIO); printk("mic==%d==\n",tmp); err = copy_to_user(buffer, &tmp, 1); return 1; } static struct file_operations dev_fops={ read:mic_read, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init my_mic_init(void) { int ret; gpio_direction_input(LGPIO);//设置io为输入 nxp_soc_gpio_set_io_pull_sel(LGPIO,0);//设置下拉电阻 ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit my_mic_exit(void) { misc_deregister(&misc); } module_init(my_mic_init); module_exit(my_mic_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("cumtzd");
其测试程序
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fctl.h>
#include <errno.h>
#define DEV_FILE "/dev/4418_mic"
int main()
{
int fd_dev=-1;
char dat;
int time=1000,ms,count=0;
printf("nanoPi driver Test\n");
fd_dev = open(DEV_FILE,O_RDWR);
if(fd_dev<0){
printf("open device err\n");
return 0;
}
printf("input ms:");//控制检测时间间隔多少ms
scanf("%d",&ms);
time = time * ms;
while(1){
read(fd_dev,&dat,1);
if(dat==0)
count++;//统计声响次数
printf("MIC status [%d],count=%d\n",dat,count);
usleep(time);
}
return 0;
}
1. 3 电压转换模块设备驱动及测试程序
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/devices.h>
#include <mach/soc.h>
#define DEVICE_NAME "4418_search"
//nanopi2S S5P4418
#define GPIO_MIC PAD_GPIO_B +30 //连接声音传感器的5-3.3v电压转换模块对应的GPIO脚
#define GPIO_LIGHT PAD_GPIO_B +31 //连接光感传感器的5-3.3v电压转换模块对应的GPIO脚
static int pir_read(struct file *file, char * buffer, size_t count, loff_t * ppos)
{
char tmp[2];
unsigned long err;
tmp[0] = gpio_get_value(GPIO_MIC);
tmp[1] = gpio_get_value(GPIO_LIGHT);
// printk("==%d==\n",tmp);
err = copy_to_user(buffer, &tmp, 2);
return 1;
}
static struct file_operations dev_fops={
read:pir_read,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_pir_init(void)
{
int ret;
gpio_direction_input(GPIO_MIC);//设置io为输入
nxp_soc_gpio_set_io_pull_sel(GPIO_MIC,0);//设置下拉电阻
gpio_direction_input(GPIO_LIGHT);//设置io为输入
nxp_soc_gpio_set_io_pull_sel(GPIO_LIGHT,0);//设置下拉电阻
ret = misc_register(&misc);
printk (DEVICE_NAME"\t initialized\n");
return ret;
}
static void __exit my_pir_exit(void)
{
misc_deregister(&misc);
}
module_init(my_pir_init);
module_exit(my_pir_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cumtzd");
其测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define DEV_FILE "/dev/4418_search"
int main()
{
int fd_dev=-1;
char dat[2];
printf("nanoPi 5-3.3v driver Test\n");
fd_dev = open(DEV_FILE,O_RDWR);
if(fd_dev<0){
printf("open device err\n");
return 0;
}
while(1){
dat[0]=0;
dat[1]=0;
read(fd_dev,dat,2);
printf("dat[0]=%d,dat[1]=%d\n",dat[0],dat[1]);
sleep(1);
}
return 0;
}
1. 4 继电器驱动及测试程序
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/devices.h>
#define DEVICE_NAME "4418_relay1"
//nanopi2s -s5p4418
#define J1_GPIO PAD_GPIO_C +7 //模块GPIO脚
#define J1_OFF 0x00
#define J1_ON 0x01
char drv_buf[2];
static int update_relay(void)
{
switch(drv_buf[0]) {
case J1_ON:
gpio_set_value(J1_GPIO, 0); //输出低电平,低电平触发,即磁铁和触点常闭状况
return 0;
case J1_OFF:
gpio_set_value(J1_GPIO, 1); //输出高电平
return 0;
default:
return -EINVAL;
}
}
static int relay_write(struct file *file, const char * buffer, size_t count, loff_t * ppos)
{
unsigned long err;
err = copy_from_user(drv_buf, buffer, 1);
update_relay();
return 1;
}
static struct file_operations dev_fops={
write:relay_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_relay_init(void)
{
int ret;
gpio_direction_output(J1_GPIO,1);//设置输出
//gpio_direction_output(J2_GPIO,1);//设置输出
ret = misc_register(&misc);
printk (DEVICE_NAME"\t#J1 J2 initialized\n");
return ret;
}
static void __exit my_relay_exit(void)
{
misc_deregister(&misc);
}
module_init(my_relay_init);
module_exit(my_relay_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CUMTZD");
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/platform.h>
#include <mach/devices.h>
#define DEVICE_NAME "4418_relay2"
//nanopi2s -s5p4418
#define J2_GPIO PAD_GPIO_C +8 //模块GPIO脚
#define J2_OFF 0x00
#define J2_ON 0x01
char drv_buf[2];
static int update_relay(void)
{
switch(drv_buf[0]) {
case J2_ON:
gpio_set_value(J2_GPIO, 0); //输出低电平
return 0;
case J2_OFF:
gpio_set_value(J2_GPIO, 1); //输出高电平
return 0;
default:
return -EINVAL;
}
}
static int relay_write(struct file *file, const char * buffer, size_t count, loff_t * ppos)
{
unsigned long err;
err = copy_from_user(drv_buf, buffer, 1);
update_relay();
return 1;
}
static struct file_operations dev_fops={
write:relay_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_relay_init(void)
{
int ret;
//gpio_direction_output(J1_GPIO,1);//设置输出
gpio_direction_output(J2_GPIO,1);//设置输出
ret = misc_register(&misc);
printk (DEVICE_NAME"\t#J1 J2 initialized\n");
return ret;
}
static void __exit my_relay_exit(void)
{
misc_deregister(&misc);
}
module_init(my_relay_init);
module_exit(my_relay_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CUMTZD");
其测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define RELAY1_DEV "/dev/4418_relay1"
#define RELAY2_DEV "/dev/4418_relay2"
#define J1_OFF 0x00
#define J1_ON 0x01
#define J2_OFF 0x00
#define J2_ON 0x01
int main()
{
int fd_dev1=-1;
int fd_dev2=-1;
char dat[2];
int cmd;
printf("nanoPi driver Test\n");
fd_dev1 = open(RELAY1_DEV,O_RDWR);
fd_dev2 = open(RELAY2_DEV,O_RDWR);
if(fd_dev1<0||fd_dev2<0){
printf("open device err\n");
return 0;
}
while(1)
{
printf("1:J1 OFF 2:J1 ON\n");
printf("Please input:");
scanf("%d",&cmd);
switch(cmd){
case 1:
dat[0] = J1_OFF;
break;
case 2:
dat[0] = J1_ON;
break;
default:
break;
}
write(fd_dev1,dat,1);
sleep(2);
printf("3:J2 OFF 4:J2 ON\n");
printf("Please input:");
scanf("%d",&cmd);
switch(cmd){
case 3:
dat[0] = J2_OFF;
break;
case 4:
dat[0] = J2_ON;
break;
default:
break;
}
write(fd_dev2,dat,1);
}
return 0;
}
二、 tiny6410的相关驱动
2.1 红外感应设备驱动及测试程序
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/hardware.h>
#include <plat/gpio-cfg.h>
#define DEVICE_NAME "6410_hongwai"
//nanopi2451
//#define LGPIO PAD_GPIO_C +28 //模块GPIO脚
//Tiny6410-s3c6410
#define LGPIO S3C64XX_GPB(1)
static int pir_read(struct file *file, char * buffer, size_t count, loff_t * ppos)
{
unsigned tmp;
unsigned long err;
tmp = gpio_get_value(LGPIO);
printk("==%d==\n",tmp);
err = copy_to_user(buffer, &tmp, 1);
return 1;
}
static struct file_operations dev_fops={
read:pir_read,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_pir_init(void)
{
int ret;
gpio_direction_input(LGPIO);//设置io为输入
//nxp_soc_gpio_set_io_pull_sel(LGPIO,0);//设置下拉电阻
s3c_gpio_setpull(LGPIO,S3C_GPIO_PULL_DOWN);//设置下拉电阻
ret = misc_register(&misc);
printk (DEVICE_NAME"\t initialized\n");
return ret;
}
static void __exit my_pir_exit(void)
{
misc_deregister(&misc);
}
module_init(my_pir_init);
module_exit(my_pir_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cumtzd");
其测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define DEV_FILE "/dev/6410_hongwai"
int main()
{
int fd_dev=-1;
char dat[8];
printf("Tiny6410 driver Test\n");
fd_dev = open(DEV_FILE,O_RDWR);
if(fd_dev<0){
printf("open device err\n");
return 0;
}
while(1){
dat[0]=0x55;
read(fd_dev,dat,1);
printf("dat=%x\n",dat[0]);
sleep(1);
}
return 0;
}
2.2 继电器驱动及测试程序
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <mach/hardware.h>
#include <plat/gpio-cfg.h>
#define DEVICE_NAME "6410_relay"
//nanopi 2s -s5p4418
//#define J1_GPIO PAD_GPIO_C +7 //模块GPIO脚
//Tiny6410-s3c6410
#define J1_GPIO S3C64XX_GPB(0)
#define J1_OFF 0x00
#define J1_ON 0x01
char drv_buf[2];
static int update_relay(void)
{
switch(drv_buf[0]) {
case J1_ON:
gpio_set_value(J1_GPIO, 0); //输出低电平,低电平触发,即磁铁和触点常闭状况
return 0;
case J1_OFF:
gpio_set_value(J1_GPIO, 1); //输出高电平
return 0;
default:
return -EINVAL;
}
}
static int relay_write(struct file *file, const char * buffer, size_t count, loff_t * ppos)
{
unsigned long err;
err = copy_from_user(drv_buf, buffer, 1);
update_relay();
return 1;
}
static struct file_operations dev_fops={
write:relay_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init my_relay_init(void)
{
int ret;
gpio_direction_output(J1_GPIO,1);//设置输出
//s3c_gpio_setpull(J1_GPIO,S3C_GPIO_PULL_DOWN);//设置下拉电阻
ret = misc_register(&misc);
printk (DEVICE_NAME"\t#J1 J2 initialized\n");
return ret;
}
static void __exit my_relay_exit(void)
{
misc_deregister(&misc);
}
module_init(my_relay_init);
module_exit(my_relay_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CUMTZD");
其测试程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define DEV_FILE "/dev/6410_relay"
#define J1_OFF 0x00
#define J1_ON 0x01
int main()
{
int fd_dev=-1;
char dat[2];
int cmd;
printf("Tiny6410 driver Test\n");
fd_dev = open(DEV_FILE,O_RDWR);
if(fd_dev<0){
printf("open device err\n");
return 0;
}
while(1){
printf("1:J1 OFF 2:J1 ON \n");
printf("Please input:");
scanf("%d",&cmd);
switch(cmd){
case 1:
dat[0] = J1_OFF;
break;
case 2:
dat[0] = J1_ON;
break;
default:
break;
}
write(fd_dev,dat,1);
}
return 0;
}