ARM40-A5D27应用程序——脉冲计数

ARM40-A5D27应用程序——脉冲计数

2020.6.10

 在工业控制中,经常需要获取脉冲信号计数值、频率、周期等参数。本文为实现外部输入脉冲信号的计数、频率、周期测量的实例。
 主要功能: 读取1s时间内的外部输入脉冲信号计数值,通过/proc/flowmeter可以查看结果。

一、脉冲计数

 (1)C语言源码
  文件包含 flow_meter.c,Makefile,代码见附录(1)。

 (2)交叉编译

make

 (3)执行程序与测试
  将交叉编译得到的flowmeter.ko文件拷贝到ARM40-A5D27板中,执行程序:

# insmod flowmerter.ko
flowmeter: loading out-of-tree module taints kernel.
# cat /proc/flowmeter
1972 1972 0 0 0 0 0 0 0 0 0 0

参考文章:

《Linux Device Drivers Development: Develop customized drivers for embedded Linux》
《ARM40-A5应用——W1LED的使用说明》
荟聚计划:共商 共建 共享 Grant

附:

(1)flow_meter.c 的代码

/*
 * PC09~PC18, PC21, PC22, 共12路DIx信号,其中DI1,DI2为高速数字输入,
 * 脉冲计数范围2Hz~2kHz;其余10路DIx脉冲计数范围2HZ~500HZ。
 * 计数范围仅为示例,最大频率以实测为准。
 * 原理:PB10提供1HZ的定时信号;在PB10中断响应函数中,统计这1s时间
 * 内,其它DIx共产生多少个中断,因而得到DIx上的脉冲个数。
 */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

#define GPIO_TOTAL      13
#define GPIO_HZ_REF     42      //PB10 is 1HZ
//GPIO_DI: PC09~PC18, PC21, PC22 (73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86)
int GPIO_DI[GPIO_TOTAL] = {GPIO_HZ_REF, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 85, 86};
int irq_sum[GPIO_TOTAL] = {0, };

typedef struct
{
        int gpio;
        int irq;
        int irq_rate;
        char name[6];
} gpio_info_t;

gpio_info_t *gpio_info = NULL;

static irqreturn_t flowmeter_isr(int irq, void *dev_id)
{
        unsigned long flags = 0;
        int i;
        gpio_info_t *data = dev_id;
        local_irq_save(flags);

        //printk("%s %s\tgpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq);

        data->irq_rate ++;

        if(data == gpio_info) {         //if GPIO_HZ_REF, the 1HZ irq is coming, restore the irq_sum
                for(i = 1; i < GPIO_TOTAL; i++) {
                        irq_sum[i] = (data + i)->irq_rate;
                        (data + i)->irq_rate = 0;
                }
        }
        local_irq_restore(flags);
        return IRQ_HANDLED;
}

static int flowmeter_proc_show(struct seq_file *m, void *v)
{
        seq_printf(m, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
                        irq_sum[1], irq_sum[2], irq_sum[3], irq_sum[4], irq_sum[5], irq_sum[6],
                        irq_sum[7], irq_sum[8], irq_sum[9], irq_sum[10], irq_sum[11], irq_sum[12]);
        return 0;
}

static int __init flowmeter_init(void)
{
        int ret;
        int i;

        proc_create_single("flowmeter", 0, NULL, flowmeter_proc_show);

        gpio_info = kzalloc(GPIO_TOTAL * sizeof(*gpio_info), GFP_KERNEL);
        if (!gpio_info)
                return -ENOMEM;

        //DI_0 is GPIO_HZ_REF
        for (i = 0; i < GPIO_TOTAL; i++) {
                sprintf(gpio_info[i].name, "DI_%d", i);
                gpio_info[i].gpio = GPIO_DI[i];
                gpio_info[i].irq_rate = 0;
                gpio_info[i].irq = gpio_to_irq(gpio_info[i].gpio);
                if(gpio_info[i].irq < 0) {
                        printk("gpio_to_irq %d failed\n", gpio_info[i].gpio);
                        return -1;
                }

                ret = request_irq(gpio_info[i].irq, flowmeter_isr, IRQ_TYPE_EDGE_FALLING, gpio_info[i].name, gpio_info+i);
                if(ret < 0) {
                        printk("request_irq %d failed\n", gpio_info[i].gpio);
                        return -1;
                }
        }

        return 0;
}

static void __exit flowmeter_exit(void)
{
        int i;
        for (i = 0; i < GPIO_TOTAL; i++) {
                free_irq(gpio_info[i].irq, gpio_info+i);
        }
        remove_proc_entry("flowmeter", NULL);
}

module_init(flowmeter_init);
module_exit(flowmeter_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FENGWEI");

(2)Makefile 的代码

MODULE_NAME:=flowmeter
  
obj-m += $(MODULE_NAME).o
$(MODULE_NAME)-objs :=flow_meter.o

PWD := $(shell pwd)
KDIR = /home/arm40_a5d2/arm40_a5d2_kernel/linux-5.4-at91

all:
        make ARCH=arm \
        CROSS_COMPILE=/home/arm40_a5d2/arm40_armgcc/gcc-linaro-7.3.1-2018.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- \
        -C $(KDIR) M=$(PWD) modules

        rm -rf *.o *.mod.c *.symvers *.order
clean:
        rm *.ko

(3)仅测量高速数字输入通道示例

/*
 * PC09~PC10为2路高速DIx信号,脉冲计数范围2Hz~2kHz;
 * 计数范围仅为示例,最大频率以实测为准。
 * 原理:PB10提供1HZ的定时信号;在PB10中断响应函数中,统计这1s时间
 * 内,DI1、DI2上共产生多少个中断,因而得到DI1、DI2上的脉冲个数。
 */
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

#define GPIO_TOTAL      3
#define GPIO_HZ_REF     42      //PB10 is 1HZ
//GPIO_DI: PC09~PC10 (73, 74)
int GPIO_DI[GPIO_TOTAL] = {GPIO_HZ_REF, 73, 74};
int irq_sum[GPIO_TOTAL] = {0, };

typedef struct
{
        int gpio;
        int irq;
        int irq_rate;
        char name[6];
} gpio_info_t;

gpio_info_t *gpio_info = NULL;

static irqreturn_t flowmeter_isr(int irq, void *dev_id)
{
        unsigned long flags = 0;
        int i;
        gpio_info_t *data = dev_id;
        local_irq_save(flags);

        //printk("%s %s\tgpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq);

        data->irq_rate ++;

        if(data == gpio_info) {         //if GPIO_HZ_REF, the 1HZ irq is coming, restore the irq_sum
                for(i = 1; i < GPIO_TOTAL; i++) {
                        irq_sum[i] = (data + i)->irq_rate;
                        (data + i)->irq_rate = 0;
                }
        }
        local_irq_restore(flags);
        return IRQ_HANDLED;
}

static int flowmeter_proc_show(struct seq_file *m, void *v)
{
        seq_printf(m, "%d %d\n", irq_sum[1], irq_sum[2]);
        return 0;
}

static int __init flowmeter_init(void)
{
        int ret;
        int i;

        proc_create_single("flowmeter", 0, NULL, flowmeter_proc_show);

        gpio_info = kzalloc(GPIO_TOTAL * sizeof(*gpio_info), GFP_KERNEL);
        if (!gpio_info)
                return -ENOMEM;

        //DI_0 is GPIO_HZ_REF
        for (i = 0; i < GPIO_TOTAL; i++) {
                sprintf(gpio_info[i].name, "DI_%d", i);
                gpio_info[i].gpio = GPIO_DI[i];
                gpio_info[i].irq_rate = 0;
                gpio_info[i].irq = gpio_to_irq(gpio_info[i].gpio);
                if(gpio_info[i].irq < 0) {
                        printk("gpio_to_irq %d failed\n", gpio_info[i].gpio);
                        return -1;
                }

                ret = request_irq(gpio_info[i].irq, flowmeter_isr, IRQ_TYPE_EDGE_FALLING, gpio_info[i].name, gpio_info+i);
                if(ret < 0) {
                        printk("request_irq %d failed\n", gpio_info[i].gpio);
                        return -1;
                }
        }

        return 0;
}

static void __exit flowmeter_exit(void)
{
        int i;
        for (i = 0; i < GPIO_TOTAL; i++) {
                free_irq(gpio_info[i].irq, gpio_info+i);
        }
        remove_proc_entry("flowmeter", NULL);
}

module_init(flowmeter_init);
module_exit(flowmeter_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FENGWEI");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值