S3C2440 开发板实战(10):signal & async 异步通信

发布者:静逸心境最新更新时间:2022-07-15 来源: csdn关键字:S3C2440  开发板  signal  异步通信 手机看文章 扫描二维码
随时随地手机看文章

进程之间发送信号

这里我们使用 kill 命令,在进程与进程之间进行传输信号。

比如杀死一个进程也是通过进程之间发送信号:


#kill -9 pid

相对应的如果要发送信号,则要注册信号处理函数(和注册中断服务函数类似),并且编写一个信号服务函数,然后写一个一直休眠的函数就ok了。应用程序 signal.c 代码如下:


#include

#include


void mysignal_fun(int signum){

    static int count = 0;

    printf("signal = %d, %d timesn", signum, count++);

}


int main(int argc, char **argv){

    signal(SIGUSR1, mysignal_fun);// input: "kill -10(-USR1) pid" 

    while(1)        

        sleep(1000);

    return 0;

}


通过“&”在后台运行之后,利用进程kill对后台运行的signal进行传递信号。


#ps     //获得PID

#kill -USR1 signal_pid     //从ps中获得的pid      


从以上可以看出在这种方法中还得手动获取pid号,在后续的实验中会使用函数获取pid号。

运行结果为:


# kill -USR1 752

signal = 10, 0 times

# kill -USR1 752

signal = 10, 1 times

# kill -10 752

signal = 10, 2 times

# kill -USR1 752

signal = 10, 3 times

# kill -10 752

signal = 10, 4 times


驱动向应用程序发送信号

要点:


注册信号函数 使用signal 函数在应用程序中国注册信号处理函数

谁发送信号函数 从驱动中发送

这个信号发送给哪个函数 发送给app app要告诉驱动pid

怎么发kill_fasyn 函数发送

按下按键时驱动程序通知应用程序


驱动向应用程序发送信号的方法和中断类似,有以下四块问题:


注册信号函数

初始化信号函数

由驱动发送信号函数

这个信号由驱动发送给应用程序,即应用程序应该告诉信号进程的PID号

step1: 注册信号处理函数

这一步是通过signal()函数进行对信号处理函数进行初始化,其功能为设置某一信号的对应动作。对signal函数的声明如下:


#include

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t sig_handler);


signum的取值如下表所示:

image.png

image.png

image.png

handler描述了与信号关联的动作,它可以取以下三种值:

SIG_IGN 这个符号表示忽略该信号。例如:

#include

#include

int main(int argc, char *argv[]){    

    signal(SIGINT, SIG_IGN);    

    while(1)

        sleep(1000);

    return 0;

}


SIGINT信号代表由InterruptKey产生,通常是CTRL +C 或者是DELETE 。执行上述代码时,按下CTRL + C程序没有反应。这就对了,如果我们想结束该程序可以按下CTRL +来结束,当我们按下CTRL +组合键时,产生了SIGQUIT信号,此信号并没有被忽略。


SIG_DFL 这个符号表示恢复对信号的系统默认处理。不写此处理函数默认也是执行系统默认操作。例如:

#include

#include

int main(int argc, char *argv[]){    

    signal(SIGINT, SIG_DFL);    

    while(1)

        sleep(1000);

    return 0;

}


这时就可以按下CTRL +C 来终止该进程了。把signal(SIGINT, SIG_DFL);这句去掉,效果是一样的


sighandler_t类型的函数指针,即我们的信号处理函数。照着上两个例子:

#include

#include

typedef void (*signal_handler)(int); 

void signal_handler_fun(int signum) {

    printf("catch signal %dn", signum);

int main(int argc, char *argv[]) {

    signal(SIGINT, signal_hander_fun);

    while(1)

        sleep(1000);

    return 0;

}


这样我们就能在信号来的时候执行特定的函数。次程序在输入ctrl+c时会执行信号处理函数,输出:


catch signal 2

由于使用的是异步通信,所以信号选择SIGIO,并且在信号服务函数中进行read操作(虽然我的按键值的打印在中断函数中完成了,这里就打印一个read走走过场):


int fd;

void my_fasyn_signal_fun(int signum){

    unsigned char key_val;

    read(fd, &key_val, 1);

    printf("read!n");

}

int main(int argc, char **argv)

{

    signal(SIGIO, my_fasyn_signal_fun);    

    fd = open("/dev/buttons", O_RDWR);

    while(1)

        sleep(1000);

    return 0;

}


step2: 驱动发送信号函数

驱动通过kill_fasync(&async, SIGIO, POLL_IN); 发SIGIO信号给应用程序,应用程序就调用自己安装的响应函数去处理。其中async为信号序列结构体,需要进行定义以及初始化(初始化部分在step3中操作,这里假设已经初始化完毕)。POLL_IN表示的是可以写数据。

所以驱动在发送部分的程序的修改很简单。只需要在中断函数中进行通信即可:


static irqreturn_t button_irq(int irq, void *dev_id)

{

    struct pin_desc *pindesc = (struct pin_desc *)dev_id;

    key_val = ((*(pindesc -> key_Register)) & (1<<(pindesc -> key_pin))) ? 0 : 1;

    if(key_val){

    //    printk("%d", pindesc -> key_num);

    }     

    printk("%d  ",key_val);

    printk("%dn",pindesc->key_num);

    ev_press = 1;                  /* 表示中断发生了 */

    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

    

    kill_fasync(&button_async_queue, SIGIO, POLL_IN);  // async signal to APP

 

    return IRQ_HANDLED;

}


step3: 初始化

这个是异步通信中最重要的一步。


初始化由两个部分组成:


button_async_queue的初始化(step2中的坑)

需要告诉内核应用程序的PID

总的来说一下三行命令就可以概括这两个部分:


fcntl(fd, F_SETOWN, getpid()); // acquire the PID & tell kernal the PID

oflags = fcntl(fd, F_GETFL);   

fcntl(fd, F_SETFL, oflags | FASYNC); // change fasync_flag to call frv_fasync


对于fcntl()函数的功能为根据文件描述词来操作文件的特性。其定义如下:


#include

#include  

int fcntl(int fd, int cmd); 

int fcntl(int fd, int cmd, long arg); 

int fcntl(int fd, int cmd, struct flock *lock);


fcntl()针对(文件)描述符提供控制。参数fd是被参数cmd操作的描述符。针对cmd的值,fcntl能够接受第三个参数int arg。

cmd值可以取为以下宏定义:

image.png

录锁是fcntl的一个重要的功能!这里使用的是异步通信的设置只是获取设置文件状态的标志。


了解了fcntl函数之后,就不难分析这三行分别的作用,以下图所示:

在这里插入图片描述

button_async_queue 的初始化


这个结构体的定义如下:


static struct fasync_struct  *button_async_queue;

内核中有专门的函数对其进行初始化:fasync_helper()。这个函数作用包括分配内存和设置属性,最后在驱动的release里把fasync_helper初始化的东西free掉。


由上文分析,初始化时会调用驱动中的drv_fasync()函数,所以对于button_async_queue 的初始化的操作放在此函数进行。对应于文件结构体中的 .fasync 进行执行,所以驱动文件改写如下:


int button_drv_fasync(struct file *fd, struct file *filp, int on){

    printk("dirver: Initialize fasyncn");

    return fasync_helper(fd, filp, on, &button_async_queue); // Initialize button_async_queue

}

static struct file_operations button_drv_fops = {

    .owner   =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

    .open    =   button_drv_open,     

    .read    =   button_drv_read,

    .release =   EINTkey_close,

    .poll    =   botton_drv_poll,

    .fasync  =   button_drv_fasync,

};


驱动向应用程序发送信号总代码

驱动程序

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

//#include

#include

#include

#include


#define DEV_NAME "button_drv"  // device name


static struct class *buttondrv_class;

static struct class_device    *buttondrv_class_dev;


static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

/* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */

static volatile int ev_press = 0;


/* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */

/* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */

static unsigned char key_val;


static struct fasync_struct  *button_async_queue;


volatile unsigned long *gpfcon = NULL;

volatile unsigned long *gpfdat = NULL;

volatile unsigned long *gpgcon = NULL;

volatile unsigned long *gpgdat = NULL;


struct pin_desc{

    volatile unsigned long *key_Register;

    int key_pin;

    int key_num;

};


struct pin_desc pins_desc[4] = {

    {0x01, 0,  1},

    {0x02, 2,  2},

    {0x03, 3,  3},

    {0x04, 11, 4},

};


static irqreturn_t button_irq(int irq, void *dev_id)

{

    struct pin_desc *pindesc = (struct pin_desc *)dev_id;

    key_val = ((*(pindesc -> key_Register)) & (1<<(pindesc -> key_pin))) ? 0 : 1;

    if(key_val)

    {


    //    printk("%d", pindesc -> key_num);

    }

        

    printk("%d  ",key_val);

    printk("%dn",pindesc->key_num);

    ev_press = 1;                  /* 表示中断发生了 */

    wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

     

    kill_fasync(&button_async_queue, SIGIO, POLL_IN);  // asyn signal to APP

    

    return IRQ_HANDLED;

}


static int button_drv_open(struct inode *inode, struct file *file)

{

    pins_desc[0].key_Register = gpfdat;

    pins_desc[1].key_Register = gpfdat;

    pins_desc[2].key_Register = gpgdat;

    pins_desc[3].key_Register = gpgdat;


    request_irq(IRQ_EINT0,  button_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);

    request_irq(IRQ_EINT2,  button_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);

    request_irq(IRQ_EINT11, button_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);

    request_irq(IRQ_EINT19, button_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);

    return 0;

}

ssize_t button_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)

{

    if(size == -1)

        return -EINVAL;    


    /* 如果没有按键动作, 休眠 */

    wait_event_interruptible(button_waitq, ev_press);


    /* 如果有按键动作, 返回键值 */

    copy_to_user(buf, &key_val, 1);

    ev_press = 0;


    return 1;

}


static int EINTkey_close(struct inode *inode, struct file *file)

{

    // FREE IRQ 

    free_irq(IRQ_EINT0, &pins_desc[0]);

    free_irq(IRQ_EINT2, &pins_desc[1]);

    free_irq(IRQ_EINT11, &pins_desc[2]);

    free_irq(IRQ_EINT19, &pins_desc[3]);

    return 0;

}


unsigned int botton_drv_poll(struct file *fd, struct poll_table_struct *wait)

{

    unsigned int mask = 0;

    poll_wait(fd, &button_waitq, wait); // 不会立即休眠


    if (ev_press)

        mask |= POLLIN | POLLRDNORM;


    return mask;

}


int button_drv_fasync(struct file *fd, struct file *filp, int on)

{

    printk("dirver: Initialize fasyncn");

    return fasync_helper(fd, filp, on, &button_async_queue); // Initialize button_async_queue

[1] [2]
关键字:S3C2440  开发板  signal  异步通信 引用地址:S3C2440 开发板实战(10):signal & async 异步通信

上一篇:S3C2440 开发板实战(11):同步互斥
下一篇:S3C2440 开发板实战(9):poll机制

推荐阅读最新更新时间:2024-11-11 10:41

【JZ2440】【记录】【如何学习一个新的芯片:S3C2440
1、基础介绍 : 虽然以前学过51和430单片机,但是,总结的少,也很盲目,随便看看书和视频后就开始读代码,写代码。虽然最开始读51的例程代码确实让我对单片机编程有了一个入门级的理解,作用还是很大。但是,毕竟是C语言写的,后续也没有继续的学习芯片的资源,所以对51、430内部结构、资源、操作方式完全不了解,只会对已经看过的程序做最基本的照葫芦画瓢式编程。现在学习S3C2440,用JZ2440开发板,希望把这些东西都梳理一遍。 2、对嵌入式系统性的认识: 做了很长时间地准备工作了,总算把一些基本的东西弄明白:嵌入式是什么、ARM指令集架构、ARM家族、S3C2440芯片和ARM920T指令集架构的区别、操作系统的结构(boot
[单片机]
4412开发板图像识别实战项目-移植jsoncpp库(四)
图像识别: 通过百度AI的快速入门手册,我们可以知道,如果要调用百度AI的接口,我们需要移植依赖库libcurl,openssl和jsincpp库。 环境:迅为提供的ubuntu16.04 编译器:arm-2014.05-29-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2 平台:迅为4412开发板 一.jsoncpp库简介 JSON全称为JavaScript ObjectNotation,它是一种轻量级的数据交换格式,易于阅读、编写、解析。jsoncpp是c++解析JSON串常用的解析库之一。 二.移植 1,解压压缩包进进入解压后的目录 tar -vxf jsoncp
[单片机]
4412<font color='red'>开发板</font>图像识别实战项目-移植jsoncpp库(四)
为AT91SAM9X5-EK开发板建立linux目标文件
一、最新版本 1.从网上获得linux的源码 输入:git clone git://github.com/linux4sam/linux-at91.git 安装完成后输入: cd linux-at91,切换到对应的目录下。 2.设置交差编译环境 之前已经安装过gcc-arm-linux-gnueabi,所以只需要定义一下环境变量: export CROSS_COMPILE=arm-linux-gnueabi- 3.配置默认设置,默认配置文件保存在:arch/arm/configs/at91_dt_defconfig文件中。 输入: make ARCH=arm at91_dt_defconfig 4.根据实际需要修改
[单片机]
为AT91SAM9X5-EK<font color='red'>开发板</font>建立linux目标文件
OK6410A 开发板 (九) 4 buildroot-2021.02 OK6410A rootfs 中的动态链接库
rootfs中动态链接库的来源 来自于 交叉编译链 rootfs 中 libc.so.6 来源猜想 suws@ubuntu:~/ok6410/system-new/buildroot/output$ sudo find . -name libc.so.6 | xargs ls -l lrwxrwxrwx 1 suws suws 12 May 30 2014 ./host/arm-buildroot-linux-gnueabi/sysroot/lib/libc.so.6 - libc-2.18.so lrwxrwxrwx 1 root root 12 Apr 15 15:21 ./images/rootfs/lib/libc.
[单片机]
OK6410A <font color='red'>开发板</font> (九) 4 buildroot-2021.02 OK6410A rootfs 中的动态链接库
S3C2440 SDRAM寄存器初始化设置
板子是s3c2440,使用两片容量为32MB、位宽16bit的EM63A165TS-6G芯片拼成容量为64M、32bit的SDRAM存储器。根据2410datasheet,要使用SDRAM需配置13个寄存器,以下逐个来看: 1、 BWSCON:Bus width & wait status control register总线位宽和等待状态控制寄存器。 此寄存器用于配置BANK0 – BANK7的位宽和状态控制,每个BANK用4位来配置,分别是: ● ST(启动/禁止SDRAM的数据掩码引脚。对于SDRAM,此位置0;对于SRAM,此位置1) ● WS(是否使用存储器的WAIT信号,通常置0为不使用) ● DW(两位,设置位宽。此
[单片机]
S3C2440 I2C实现
/***************************************************** *说 明:S3C2440 I2C实现 *****************************************************/ 1:I2C原理 总线的构成及信号类型 I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器
[单片机]
<font color='red'>S3C2440</font> I2C实现
Microsemi SmartFusion2 创客开发板由 Digi-Key 在全球独家发售
美国明尼苏达州锡夫里弗福尔斯市——Microsemi 与全球电子元器件分销商 Digi-Key Electronics 合作,为 Digi-Key 的全球客户群独家供应 SmartFusion™2 片上系统 (SoC) 现场可编程门阵列 (FPGA) 创客开发板 。这个低成本的评估平台降低了硬件和固件工程师为 SmartFusion2 器件中的 ARM Cortex™-M3 和 12K 逻辑元件 (LE) FPGA 开发嵌入式应用时的门槛。产品包含全新的 SmartFusion2 开发板、用于供电、编程和通信的 USB 电缆和《快速入门指南》。 这款开发板是一个理想的开发平台,可以使用 Microsemi SmartFusi
[嵌入式]
Microsemi SmartFusion2 创客<font color='red'>开发板</font>由 Digi-Key 在全球独家发售
移植qtopia到ARM开发板
前言: 说实话,以前只作过51,而且用的是汇编,C都没有怎么用过。最近才有机会接触到linux,说起来也算是落后分子了。多亏北理论坛里各位大侠的帮忙,还算顺利的把qtopia移植到了ARM开发板上。现整理了下文,抛砖引玉,希望能对大家有所帮助,当然也希望大家多提宝贵意见,mail to ahha1998@126.com即可。当然更希望大家的经验也能告诉我 一、所用的资源: 硬件:华恒HHARM9328MXL-R1 软件:cross-2.95.3.tar.bz2 qt-embedded-2.3.10.tar.gz qt-x11-2.3.2.tar.gz qt-x11-3.3.4.tar.gz qtopia-free-2.1.1.
[单片机]
热门资源推荐
热门放大器推荐
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved