精华内容
下载资源
问答
  • 现在有一个序列,里面会包含大小写字符和空白符。 找到最后一个字符,计算它的长度。 思路就是从后往前找,直到碰到空白符。...唯一要注意的一是:原序列最后可能是空白符,我是用.trim()函数先把这些空白去掉。

    Given a string s consists of upper/lower-case alphabets and empty space characters ' ', return the length of last word in the string.

    If the last word does not exist, return 0.

    Note: A word is defined as a character sequence consists of non-space characters only.

    For example, 
    Given s = "Hello World",

    return 5.

    现在有一个序列,里面会包含大小写字符和空白符。

    找到最后一个字符,计算它的长度。

    思路就是从后往前找,直到碰到空白符。

    唯一要注意的一个点是:原序列最后可能是空白符,我是用.trim()函数先把这些空白去掉。

    运行时间:


    代码:

    public class LengthofLastWord {
        public int lengthOfLastWord(String s) {
            s = s.trim();
            int count = 0;
            for (int i = s.length() - 1; i >= 0; i--) {
                if (s.charAt(i) == ' ') {
                    return count;
                }
                count++;
            }
            return count;
        }
    }

    展开全文
  • 关注、星标嵌入式客栈,精彩及时送达[导读] 前篇文章,介绍了如何将个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成个LED灯设备驱动。点一个灯有什么好谈...
    关注、星标嵌入式客栈,精彩及时送达f7f64a815c79e7981fdeee81b91fef65.png

    [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一个LED灯设备驱动。点一个灯有什么好谈呢?况且Linux下有专门的leds驱动子系统。

    点灯有啥好聊呢?

    在很多嵌入式系统里,有可能需要实现数字开关量输出,比如:

    • LED状态显示
    • 阀门/继电器控制
    • 蜂鸣器
    • ......

    嵌入式Linux一般需求千变万化,也不可能这些需求都有现成设备驱动代码可供使用,所以如何学会完成一个开关量输出设备的驱动,一方面点个灯可以比较快了解如何具体写一个字符类设备驱动,另一方面实际项目中对于开关量输出设备就可以这样干,所以是具有较强的实用价值的。

    要完成这样一个开关量输出GPIO的驱动程序,需要梳理梳理下面这些概念:

    • 设备编号
    • 设备挂载
    • 关键数据结构

    设备编号

    字符设备是通过文件系统内的设备名称进行访问的,其本质是设备文件系统树的节点。故Linux下设备也是一个文件,Linux下字符设备在/dev目录下。可以在开发板的控制台或者编译的主Linux系统中利用ls -l /dev查看,如下图:

    6e3de82ccdf72ed035afbe0c5a01c8af.png

    对于ls -l列出的属性,做一个比较细的解析:

    841262a328c90c4edf11289288a5cfe4.png

    细心的朋友或许会发现设备号属性,在有的文件夹下列出来不是这样,这就对了!普通文件夹下是这样:

    c9b26696af64995a762fddc0eccbefa2.png

    差别在于一个是文件大小,一个是设备号。

    再细心一点的朋友或许还会问,这些/dev下的文件时间属性为神马都相差无几?这是因为/dev设备树节点是在内核启动挂载设备驱动动态生成的,所以时间就是系统开机后按次序生成的,你如不信,不妨重启一下系统在查看一下。

    1cbd1d69a2595e3eaa00a8727b54b0f9.png

    常见文件类型:

    • d: directory 文件夹
    • l: link  符号链接
    • p: FIFO pipe 管道文件,可以用mkfifo命令生成创建
    • s: socket 套接字文件
    • c: char 字符型设备文件
    • b: block 块设备文件
    • -:常规文件

    回到设备号,设备号是一个32位无符号整型数,其中:

    • 12位用来表示主设备号,用于标识设备对应的驱动程序。
    • 20位用来表示次设备号,用于正确确定设备文件所指的设备。

    这怎么理解呢,看下串口类设备就比较清楚了:

    27c67afc72301b8055b752b5bacb934a.png

    主设备号一样证明这些设备共用了一个驱动程序,而次设备号不一样,则对应了不同的串口设备。那么怎么得到设备号呢?

    /*下列定义位于./include/linux/types.h */
    typedef u32 __kernel_dev_t;
    typedef __kernel_dev_t dev_t;

    /* 下面宏用于生成主设备号,次设备号       */
    /* 下列定义位于./include/linux/Kdev_t.h */
    #define MINORBITS 20
    #define MINORMASK ((1U <#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))#define MKDEV(ma,mi) (((ma) <

    使用举例:

    /* 主设备号 */
    MAJOR(dev_t dev); 
    /* 次设备号 */
    MINOR(dev_t dev);

    设备挂载

    为简化问题,本文描述一下动态加载设备驱动模块,暂不考虑设备树。参考<>一书。可参照前文将驱动编译成模块,然后利用下面脚步动态加载模块。由前面描述,知道设备最终需要在/dev目录下生成一个设备文件,那么这个设备文件节点是怎么生成呢,看看下面的脚本:

    #!/bin/sh
    #-----------------------------------------------------------------------
    module="led"
    device="led"
    mode="664"
    group="staff"

    #
     利用insmod命令加载设备模块
    insmod -f $module.ko $* || exit 1
    # 获取系统分配的主设备号 
    major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`

    #
     删除旧节点
    rm -f /dev/${device} 

    #
    创建设备文件节点
    mknod /dev/${device} c $major 0
    #设置设备文件节点属性
    chgrp $group /dev/${device}
    chmod $mode  /dev/${device}

    这里要提一下/proc/devices,这是一个文件记录了字符和块设备的主设备号,以及分配到这些设备号的设备名称。比如使用cat命令来列出这个文件内容:

    1eec6e38309509d0cf03eb2e6f0faad1.png

    关键数据结构

    字符设备由什么关键数据结构进行抽象的呢,来看看:

    • file_operations定义在./include/linux/fs.h
    • cdev定义在./include/linux/cdev.h
    6bf1e49996944af2b34a9475d9d21b48.png

    cdev中与字符设备驱动编程相关两个数据域:

    • const struct file_operations *ops;
    • dev_t dev;设备编号

    文件操作符是一个庞大的数据结构,常规字符设备驱动一般需要实现下面一些函数指针:

    • read:用来实现从设备中读取数据
    • write:用于实现写入数据到设备
    • ioctl:实现执行设备特定命令的方法
    • open:用实现打开一个设备文件
    • release:当file结构被释放时,将调用这个接口函数

    点灯设备

    先上代码(可左右滑动显示):

    #include 
    #include 
    #include 
    #include   /* printk() */
    #include 
    #include 
    #include       /* everything... */
    #include 
    #include    /* copy_*_user */

    /*这里具体参考不同开发板的电路 GPIOC24 */
    #define LED_CTRL   (2*32+24)  

    static const unsigned int led_pad_cfg = LED_CTRL;

    struct t_led_dev{
     struct cdev cdev;
     unsigned char value; 
    };

    struct t_led_dev  led_dev;
    static dev_t led_major;
    static dev_t led_minor=0

    static int led_open(struct inode * inode,struct file * filp)
     filp->private_data = &led_dev; 
     
     printk ("led is opened!\n");          
     return 0;
    }

    static int led_release(struct inode * inode,
                           struct file * filp)
    {
     return 0;
    }

    static ssize_t led_read(struct file * file, char __user * buf,size_t count, loff_t *ppos){
     ssize_t ret=1;   
     if(copy_to_user(&(led_dev.value),buf,1))
      return -EFAULT;
     printk ("led is read!\n");
     return ret;
    }

    static ssize_t led_write(struct file * filp, const char __user *buf,size_t count,loff_t *ppos){
     unsigned char value; 
        ssize_t retval = 0;
     if(copy_from_user(&value,buf,1))
      return -EFAULT;
     
     if(value&0x01)
      gpio_set_value(led_pad_cfg, 1);
     else
      gpio_set_value(led_pad_cfg, 0);

        printk ("led is written!\n");
     return retval;
    }

    static const struct file_operations led_fops = {
     .owner = THIS_MODULE,
     .read  = led_read,
     .write = led_write,
     .open  = led_open,
     .release = led_release,
    };

    static void led_setup_cdev(struct t_led_dev * dev, int index)
        /* 初始化字符设备驱动数据域 */
     int err,devno = MKDEV(led_major,led_minor+index);
     cdev_init(&(dev->cdev),&led_fops);
     dev->cdev.owner = THIS_MODULE;
     dev->cdev.ops = &led_fops;
        /* 字符设备注册 */
     err = cdev_add(&(dev->cdev),devno,1);
     if(err)
      printk(KERN_NOTICE "Error %d adding led %d",err,index); 
    }

    static int led_gpio_init(void){
     if (gpio_request(LED_CTRL, "led") 0) {
      printk("Led request gpio failed\n");
      return -1;
     }
     
     printk("Led gpio requested ok\n");
     
     gpio_direction_output(LED_CTRL, 1); 
     gpio_set_value(LED_CTRL, 1);
     
     return 0;
    }
    /* 注销设备 */
    void led_cleanup(void)
     dev_t devno = MKDEV(led_major, led_minor); 
     gpio_set_value(LED_CTRL, 0); 
     gpio_free(LED_CTRL);

     cdev_del(&led_dev.cdev); 
     unregister_chrdev_region(devno, 1);    //注销设备号  
    }

    /* 注册设备 */
    static int led_init(void)
     int result;
     dev_t dev = MKDEV( led_major, 0 );
     /* 动态分配设备号 */
     result = alloc_chrdev_region(&dev, 01"led");      
     if(result<0)
      return result; 
     
     led_major = MAJOR(dev);
     
     memset(&led_dev,0,sizeof(struct t_led_dev));
     led_setup_cdev(&led_dev,0);

     led_gpio_init();
     printk ("led device initialised!\n"); 
     
     return result;
    }

    module_init(led_init);
    module_exit(led_cleanup);

    MODULE_DESCRIPTION("Led device demo");
    MODULE_AUTHOR("embinn");
    MODULE_LICENSE("GPL");

    来总结一下要点:

    • init函数,需要用module_init宏包起来,本例中即为led_init,module_init宏的作用就是选编译为模块或进内核的底层实现,建议刚开始不必深究。一般而言主要实现:

      • 申请分配主设备号alloc_chrdev_region
      • 为特定设备相关数据结构分配内存
      • 将入口函数(open read write等)与字符设备驱动的cdev抽象数据结构关联
      • 将主设备与驱动程序cdev相关联
      • 申请硬件资源,初始化硬件
      • 调用cdev_add注册设备
    • exit函数,一样需要用module_exit包起来,主要负责:

      • 释放硬件资源
      • 调用cdev_del删除设备
      • 调用unregister_chrdev_region注销设备号
    • 用户空间与驱动数据交换

      • copy_to_user,如其名一样,将内核空间数据信息传递到用户空间
      • copy_from_user,如其名一样,从用户空间拷贝数据进内核空间
    • 善用printk进行驱动调试,这是内核打印函数。

    • gpio相关操作函数,这里就不一一列举其作用了,比较容易理解。

    测试驱动

    #include 
    #include 
    #include 
    #include 

    #define READ_SIZE 10

    int main(int argc, char **argv){
     int fd,count;
     float value;
     unsigned char buf[READ_SIZE+1];
     printf"Cmd argv[0]:%s,argv[1]:%s,argv[2]:%s\n",argv[0],argv[1],argv[2] );
     
     if( argc<2 ){
      printf"[Usage: test device_name ]\n" );
      exit(0);
     }
        if(strlen(argv[2]!=1)
            printf"Invalid parameter\n" );
        
     if(( fd = open(argv[1],O_WRONLY  ))<0){
      printf"Error:can not open the device: %s\n",argv[1] );
      exit(1);
     }
        
        if(argv[2][0] == '1')
            buf[0] = 1;
        else if(argv[2][0] == '0')
            buf[0] = 0;
        else
            printf"Invalid parameter\n" );

     printf("write: %d\n",buf[0]);
     if( (count = write( fd, buf ,1 ))<0 ){
      perror("write error.\n");
      exit(1);  
     }
     
     close(fd);
     printf("close device %s\n",argv[1] );
     return 0;
    }

    编译成可执行文件,调用前面的脚本加载设备后,在/dev下就可以看到led设备了。比如测试代码编译成ledTest执行文件,则使用下面命令运行测试程序就可以看到led控制效果了:

    /*打开led 具体取决电路是高有效还是低有效*/
    ./ledTest /dev/led 1
    ./ledTest /dev/led 0

    这样就实现了用户空间驱动底层设备了,实际应用代码就可以这样去访问底层的字符型设备。

    总结一下

    本文总结了简单字符设备的驱动开发的一些要点,以及如何动态加载,在设备文件系统树上创建设备节点,并演示了驱动以及驱动使用的基本要点。

    本文辛苦原创,如喜欢请点赞/在看/分享支持,不胜感激!

    END

    结束语

        好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!

       如果有想加入公众号群聊共同讨论技术的小伙伴可以添加下方bug菌微信

    65a638c0d660b226b52fa51505d6286c.png

    推荐好文  点击蓝色字体即可跳转

    ☞【收藏】get这些技巧,HardFault_Handler排查只需要几分钟54cd57ddbceeb4f080ccb1b95aae6b84.gif

    ☞【C进阶】有了"链表"还用"数组"干嘛?被问懵了......54cd57ddbceeb4f080ccb1b95aae6b84.gif

    ☞【算法】"暴力"字符匹配算法的C语言实现54cd57ddbceeb4f080ccb1b95aae6b84.gif

    ☞【重磅】剖析MCU的IAP升级软件设计(设计思路篇)

    ☞【算法】高效"KMP"字符匹配算法就这么简单

    ☞【典藏】自制小型GUI界面框架(设计思想篇)

    ☞【C进阶】听说用 “ 逗号表达式 ” 仅仅为了秀技?

    ☞深度剖析"bit序"与"字节序"

    ☞【进阶】嵌入式编程技法之"数据驱动编程"

    展开全文
  • ORACLE数据库系统是美国ORACLE公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器(CLIENT/SERVER)或B/S体系结构的数据库之一。  拉里•埃里森  就业前景 从就业与择业的...
  • [导读] 前篇文章,介绍了如何将个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成个LED灯设备驱动。点一个灯有什么好谈呢?况且Linux下有专门leds驱动子...

    ab50c3daa9e307348e2b8c5a272480eb.png

    [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一个LED灯设备驱动。点一个灯有什么好谈呢?况且Linux下有专门的leds驱动子系统。

    点灯有啥好聊呢?

    在很多嵌入式系统里,有可能需要实现数字开关量输出,比如:

    • LED状态显示
    • 阀门/继电器控制
    • 蜂鸣器
    • ......

    嵌入式Linux一般需求千变万化,也不可能这些需求都有现成设备驱动代码可供使用,所以如何学会完成一个开关量输出设备的驱动,一方面点个灯可以比较快了解如何具体写一个字符类设备驱动,另一方面实际项目中对于开关量输出设备就可以这样干,所以是具有较强的实用价值的。

    要完成这样一个开关量输出GPIO的驱动程序,需要梳理梳理下面这些概念:

    • 设备编号
    • 设备挂载
    • 关键数据结构

    设备编号

    字符设备是通过文件系统内的设备名称进行访问的,其本质是设备文件系统树的节点。故Linux下设备也是一个文件,Linux下字符设备在/dev目录下。可以在开发板的控制台或者编译的主Linux系统中利用ls -l /dev查看,如下图:

    9fc715dc85eb2656ebc9d0416bbb3e3b.png

    对于ls -l列出的属性,做一个比较细的解析:

    c0f5bdbe6928a59a2cf45614c405ee22.png

    细心的朋友或许会发现设备号属性,在有的文件夹下列出来不是这样,这就对了!普通文件夹下是这样:

    17fc2a7754ae1358f4d5672e9237d4d1.png

    差别在于一个是文件大小,一个是设备号。

    再细心一点的朋友或许还会问,这些/dev下的文件时间属性为神马都相差无几?这是因为/dev设备树节点是在内核启动挂载设备驱动动态生成的,所以时间就是系统开机后按次序生成的,你如不信,不妨重启一下系统在查看一下。

    1ad29a4a92ea393f4f5bb2b8f0d93b8e.png

    常见文件类型:

    • d: directory 文件夹
    • l: link  符号链接
    • p: FIFO pipe 管道文件,可以用mkfifo命令生成创建
    • s: socket 套接字文件
    • c: char 字符型设备文件
    • b: block 块设备文件
    • -:常规文件

    回到设备号,设备号是一个32位无符号整型数,其中:

    • 12位用来表示主设备号,用于标识设备对应的驱动程序。
    • 20位用来表示次设备号,用于正确确定设备文件所指的设备。

    这怎么理解呢,看下串口类设备就比较清楚了:

    f526b296b8421d9e25a32eac47769642.png

    主设备号一样证明这些设备共用了一个驱动程序,而次设备号不一样,则对应了不同的串口设备。那么怎么得到设备号呢?

    /*下列定义位于./include/linux/types.h */
    typedef u32 __kernel_dev_t;
    typedef __kernel_dev_t dev_t;

    /* 下面宏用于生成主设备号,次设备号       */
    /* 下列定义位于./include/linux/Kdev_t.h */
    #define MINORBITS 20
    #define MINORMASK ((1U <#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))#define MKDEV(ma,mi) (((ma) <

    使用举例:

    /* 主设备号 */
    MAJOR(dev_t dev); 
    /* 次设备号 */
    MINOR(dev_t dev);

    设备挂载

    为简化问题,本文描述一下动态加载设备驱动模块,暂不考虑设备树。参考<>一书。可参照前文将驱动编译成模块,然后利用下面脚步动态加载模块。由前面描述,知道设备最终需要在/dev目录下生成一个设备文件,那么这个设备文件节点是怎么生成呢,看看下面的脚本:

    #!/bin/sh
    #-----------------------------------------------------------------------
    module="led"
    device="led"
    mode="664"
    group="staff"

    #
     利用insmod命令加载设备模块
    insmod -f $module.ko $* || exit 1
    # 获取系统分配的主设备号 
    major=`cat /proc/devices | awk "\\$2==\"$module\" {print \\$1}"`

    #
     删除旧节点
    rm -f /dev/${device} 

    #
    创建设备文件节点
    mknod /dev/${device} c $major 0
    #设置设备文件节点属性
    chgrp $group /dev/${device}
    chmod $mode  /dev/${device}

    这里要提一下/proc/devices,这是一个文件记录了字符和块设备的主设备号,以及分配到这些设备号的设备名称。比如使用cat命令来列出这个文件内容:

    626bc8d4d9733239df5b042f590b580b.png

    关键数据结构

    字符设备由什么关键数据结构进行抽象的呢,来看看:

    • file_operations定义在./include/linux/fs.h
    • cdev定义在./include/linux/cdev.h
    7ebc4a28dd1c515e2f8b4b6056a7ce39.png

    cdev中与字符设备驱动编程相关两个数据域:

    • const struct file_operations *ops;
    • dev_t dev;设备编号

    文件操作符是一个庞大的数据结构,常规字符设备驱动一般需要实现下面一些函数指针:

    • read:用来实现从设备中读取数据
    • write:用于实现写入数据到设备
    • ioctl:实现执行设备特定命令的方法
    • open:用实现打开一个设备文件
    • release:当file结构被释放时,将调用这个接口函数

    点灯设备

    先上代码(可左右滑动显示):

    #include 
    #include 
    #include 
    #include   /* printk() */
    #include 
    #include 
    #include       /* everything... */
    #include 
    #include    /* copy_*_user */

    /*这里具体参考不同开发板的电路 GPIOC24 */
    #define LED_CTRL   (2*32+24)  

    static const unsigned int led_pad_cfg = LED_CTRL;

    struct t_led_dev{
     struct cdev cdev;
     unsigned char value; 
    };

    struct t_led_dev  led_dev;
    static dev_t led_major;
    static dev_t led_minor=0

    static int led_open(struct inode * inode,struct file * filp)
     filp->private_data = &led_dev; 
     
     printk ("led is opened!\n");          
     return 0;
    }

    static int led_release(struct inode * inode,
                           struct file * filp)
    {
     return 0;
    }

    static ssize_t led_read(struct file * file, char __user * buf,size_t count, loff_t *ppos){
     ssize_t ret=1;   
     if(copy_to_user(&(led_dev.value),buf,1))
      return -EFAULT;
     printk ("led is read!\n");
     return ret;
    }

    static ssize_t led_write(struct file * filp, const char __user *buf,size_t count,loff_t *ppos){
     unsigned char value; 
        ssize_t retval = 0;
     if(copy_from_user(&value,buf,1))
      return -EFAULT;
     
     if(value&0x01)
      gpio_set_value(led_pad_cfg, 1);
     else
      gpio_set_value(led_pad_cfg, 0);

        printk ("led is written!\n");
     return retval;
    }

    static const struct file_operations led_fops = {
     .owner = THIS_MODULE,
     .read  = led_read,
     .write = led_write,
     .open  = led_open,
     .release = led_release,
    };

    static void led_setup_cdev(struct t_led_dev * dev, int index)
        /* 初始化字符设备驱动数据域 */
     int err,devno = MKDEV(led_major,led_minor+index);
     cdev_init(&(dev->cdev),&led_fops);
     dev->cdev.owner = THIS_MODULE;
     dev->cdev.ops = &led_fops;
        /* 字符设备注册 */
     err = cdev_add(&(dev->cdev),devno,1);
     if(err)
      printk(KERN_NOTICE "Error %d adding led %d",err,index); 
    }

    static int led_gpio_init(void){
     if (gpio_request(LED_CTRL, "led") 0) {
      printk("Led request gpio failed\n");
      return -1;
     }
     
     printk("Led gpio requested ok\n");
     
     gpio_direction_output(LED_CTRL, 1); 
     gpio_set_value(LED_CTRL, 1);
     
     return 0;
    }
    /* 注销设备 */
    void led_cleanup(void)
     dev_t devno = MKDEV(led_major, led_minor); 
     gpio_set_value(LED_CTRL, 0); 
     gpio_free(LED_CTRL);

     cdev_del(&led_dev.cdev); 
     unregister_chrdev_region(devno, 1);    //注销设备号  
    }

    /* 注册设备 */
    static int led_init(void)
     int result;
     dev_t dev = MKDEV( led_major, 0 );
     /* 动态分配设备号 */
     result = alloc_chrdev_region(&dev, 01"led");      
     if(result<0)
      return result; 
     
     led_major = MAJOR(dev);
     
     memset(&led_dev,0,sizeof(struct t_led_dev));
     led_setup_cdev(&led_dev,0);

     led_gpio_init();
     printk ("led device initialised!\n"); 
     
     return result;
    }

    module_init(led_init);
    module_exit(led_cleanup);

    MODULE_DESCRIPTION("Led device demo");
    MODULE_AUTHOR("embinn");
    MODULE_LICENSE("GPL");

    来总结一下要点:

    • init函数,需要用module_init宏包起来,本例中即为led_init,module_init宏的作用就是选编译为模块或进内核的底层实现,建议刚开始不必深究。一般而言主要实现:

      • 申请分配主设备号alloc_chrdev_region
      • 为特定设备相关数据结构分配内存
      • 将入口函数(open read write等)与字符设备驱动的cdev抽象数据结构关联
      • 将主设备与驱动程序cdev相关联
      • 申请硬件资源,初始化硬件
      • 调用cdev_add注册设备
    • exit函数,一样需要用module_exit包起来,主要负责:

      • 释放硬件资源
      • 调用cdev_del删除设备
      • 调用unregister_chrdev_region注销设备号
    • 用户空间与驱动数据交换

      • copy_to_user,如其名一样,将内核空间数据信息传递到用户空间
      • copy_from_user,如其名一样,从用户空间拷贝数据进内核空间
    • 善用printk进行驱动调试,这是内核打印函数。

    • gpio相关操作函数,这里就不一一列举其作用了,比较容易理解。

    测试驱动

    #include 
    #include 
    #include 
    #include 

    #define READ_SIZE 10

    int main(int argc, char **argv){
     int fd,count;
     float value;
     unsigned char buf[READ_SIZE+1];
     printf"Cmd argv[0]:%s,argv[1]:%s,argv[2]:%s\n",argv[0],argv[1],argv[2] );
     
     if( argc<2 ){
      printf"[Usage: test device_name ]\n" );
      exit(0);
     }
        if(strlen(argv[2]!=1)
            printf"Invalid parameter\n" );
        
     if(( fd = open(argv[1],O_WRONLY  ))<0){
      printf"Error:can not open the device: %s\n",argv[1] );
      exit(1);
     }
        
        if(argv[2][0] == '1')
            buf[0] = 1;
        else if(argv[2][0] == '0')
            buf[0] = 0;
        else
            printf"Invalid parameter\n" );

     printf("write: %d\n",buf[0]);
     if( (count = write( fd, buf ,1 ))<0 ){
      perror("write error.\n");
      exit(1);  
     }
     
     close(fd);
     printf("close device %s\n",argv[1] );
     return 0;
    }

    编译成可执行文件,调用前面的脚本加载设备后,在/dev下就可以看到led设备了。比如测试代码编译成ledTest执行文件,则使用下面命令运行测试程序就可以看到led控制效果了:

    /*打开led 具体取决电路是高有效还是低有效*/
    ./ledTest /dev/led 1
    ./ledTest /dev/led 0

    这样就实现了用户空间驱动底层设备了,实际应用代码就可以这样去访问底层的字符型设备。

    总结一下

    本文总结了简单字符设备的驱动开发的一些要点,以及如何动态加载,在设备文件系统树上创建设备节点,并演示了驱动以及驱动使用的基本要点。

    0584d2b3c29366f0d2dfe4d99799a16e.png

    1.芯师爷|2020硬核中国芯 重磅启动!

    2.【直播福利+预告】第三期“嵌入式与物联网开发技术”线上分享即将开始啦~

    3.使用ZYNQ实现复杂嵌入式系统,真的好用!

    4.工业互联网:嵌入式系统的机遇和挑战

    5.余承东签发内部文件:华为要造屏幕芯片!

    6.RTOS是如何实现多任务的?

    971f0d6ab9bfaece31e58d81fbc7cc0b.gif

    免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

    展开全文
  • 昨天,笔者写了个程序,慢步Python:输出word文档内每段前10个字,在编写中学习知识不是怎么高大上,但干货还是有。嗯,对于学习编程初学者来说。里面用到很多python编程知识。笔者觉得有必要解释一下。...

    昨天,笔者写了一个程序,慢步Python:输出word文档内每段前10个字,在编写中学习知识点不是怎么高大上,但干货还是有的。嗯,对于学习编程的初学者来说。

    里面用到很多python编程的知识点。笔者觉得有必要解释一下。

    编程需要大量数据,为了编程方便,数据就分成了不同的类型,不同的数据类型有不同的特性。

    Python两种基本数据类型

    python语言中,有两种最基本的数据类型:数值类型及字符串类型。

    读者可以参考书目

    数值类型的数据,和我们平时说的数学运算中的数字,1+1=2,里面的1和2,或者已知x=9,y=1,x和y也是数值类型数据。

    字符串,简单的理解就是字符、文字,写出来的文字符号,§№☆★○●◇◎◆□,这些都是符号,字符串的一个极端理解就是特殊符号。就是一个符号。

    能用来计算得到数值结果的是数值类型数据,用来显示、阅读的文字,是字符串。

    字符串的表示方式

    在python语言中,字符串通过引号来表示,如“我”、“这是一个字符串”、“1”。也可以用单引号表示‘这个’、‘字符’、‘字符串类型’

    python交互式运行环境

    在pycharm中,可以直接调用python交互式运行环境,打开pycharm的界面,看到左下角有个python console(python控制台)

    fc1f4134970a304ef3df912bb127db80cb175c53.jpeg?token=85d50f2978da77d5fef83afc9ca2607b

    点击python console即可进入python交互式运行环境。这是运行python的其中一种方式。

    对于python运行方式或者pycharm有疑问的,可以回看笔者的文章Python程序的编辑及运行,Pycharm的下载安装

    可进入python交互式运行环境的界面是这样的。

    314e251f95cad1c8f3fc414a1ed11b0fc83d5109.jpeg?token=b347537504ee8db3589d5fcb9d338ccd

    在这个交互式窗口,我们可以python代码,每输入一行代码,它便会立即执行这行代码。比如下图:

    bba1cd11728b4710132588b0a221bffbfd0323bd.jpeg?token=8ed9e7d07240b666f9ee5f7b8be5b32c

    在绿色>>>后面输入print("字符串"),按回车键结束这行代码,计算机立刻执行代码,结果是输出 字符串 。

    这里需要提一下的是,绿色>>>后面是python代码,无绿色>>>的是输出的结果。

    笔者定义了两个变量:a 和 b,分别给它们赋值,赋值为3 和 ‘3’,一个是数值,见上图的右上角a ={int} 3,int即整数类型数据,为数值类型的一种;一个是字符串,b = {str}'3',str即字符串类型数据。

    3 和‘3’之间的区别就是有没有引号。(需要注意的是,所有和格式有关的符号,例如这里的引号,都是英文输入法的符号。对于电脑来说,中文的引号和英文的引号是两种符号)

    然后输出a 和 b,结果输出两个3。说明输出语句print对数值和对字符串的输出是一样的。

    对于数据类型,我们还可以用type()函数去获取数据类型。

    8644ebf81a4c510fe8be976300b6592bd52aa542.jpeg?token=45d92a3b0450677f647762cd33e97817

    如上图,

    type(a)

    即可得到a即3的数据类型:整数类型,类似的得到b即‘3’的数据类型为:字符串类型。

    今天主要讲述python的基本数据类型,暂时到这里吧,慢步陪大家慢慢进步。

    展开全文
  • 本人小白,写了一串代码批量读取word,例如一个文件夹有1000多份, 代码循环挨个读取,第一份时候一般5分钟,但是越后面越慢,比如第 20份可能需要半小时,第50份可能需要1小时,第60份可能一个半小时。 我看...
  • Spark Streaming 提供wordcount有点太简单了,做...通过socket向Spark APP发送一串数字字符(“,“分割),然后将数字转换 Int格式并 进行计数, 如果输入不是数字,Spark APP报错并停止APP socket 文件 ...
  • 其实关键就在于字符如何判重,STL里的set可以搞,但是注意C里面没有这个东西,所以要么我们自己手写个红黑树来实现set(红黑树不好写!很麻烦),要么就使用字典树(这个确实相对来说好些得多)。写这个题其实也是...
  • <br />   ...比方说有个选择题四个选项是四个不同图片,又比如试题中有复杂公式,这样题用数据库字段去保存话,确实是个大问题了,毕竟数据库字段只能保存字符或二进制流嘛。  
  • 在UART库头文件,UART由个结构体进行维护: typedef struct { //波特率 uint32_t UART_BaudRate; //数据长度 uint16_t UART_WordLength; //停止位 uint16_t UART_StopBits; //校验位 uint1
  • 本文主要涉及以下内容:正则表达式基础什么是正则表达式不管是使用Windows搜索...正则表达式可以理解为超复杂通配符,可以比通配符匹配更为精准,正规一点说法就是使用单个字符来描述、匹配系列符合某个...
  • 宏:计算机科学里的宏(Macro),是种批量处理的称谓。一般说来,宏是种规则或模式,或称语法替换 ,用于说明某特定输入(通常是字符)如何根据预定义的规则转换成对应的输出(通常也是字符)。这种替换在预...
  • # TODO: 把qlist中个问题字符转换成tf-idf向量, 转换之后结果存储在X矩阵。 X大小是: N* D矩阵。 这里N是问题个数(样本个数), # D是字典库大小。 vectorizer = TfidfVectorizer() # ...
  • NLP实战(二)搭建个简单问答系统

    千次阅读 热门讨论 2020-06-04 16:33:48
    文本表示(tf-idf, word2vec) 4. 文本相似度计算 5. 文本高效检索 此项目需要数据: dev-v2.0.json: 这个数据包含了问题和答案pair, 但是以JSON格式存在,需要编写parser来提取出里面问题和答案。 glove...
  • 今天为大家分享函数是Excat函数,其实我第次了解到这个函数时候,我想到利用场景就是把word里面文字拿出来进行一致比较,这个想法算是比较大胆吧!问题如果真把两篇文章内容拿来做比较,即使发现了有...
  • 上面的代码是我在网上找到的一种java操作word的方法 java读取word文档时,虽然网上介绍了很多插件poi、java2Word、jacob、itext等等,poi无法读取格式(新的API估计行好像还在处于研发阶段,不太稳定,做项目不太...
  • 所以main.d也要作为个目标来生成,它的依赖应该是main.d里的每个依赖文件,也就是说make里要有这样的定义: main.d: main.c command.h 这时我们发现,main.d与main.o的依赖是完全相同的,可以利用make的多目标规则...
  • 我理解就和我们在word或者其他编辑软件里点的查找、替换作用是差不多,不过功能要强大多,当然使用起来也稍微复杂一些。书上定义差不多是这样:正则表达式就是一个表达式(也是一串字符),它定义了某种...
  • 不可能被撑开table和div

    千次阅读 2011-12-15 11:52:38
    div, table 经常会现让内容给撑开情况, 大部分原因就是里面有连续字母数字, 因为没有空格和换行, 浏览器不知怎么将其断开, 所以让它宽度无限延伸了。 table还好一点,用了上面样式基本上不可能
  • 我理解就和我们在word或者其他编辑软件里点的查找、替换作用是差不多,不过功能要强大多,当然使用起来也稍微复杂一些。 书上定义差不多是这样:正则表达式就是一个表达式(也是一串字符),它...
  • 对KMP算法理解

    2018-12-19 21:59:42
    这篇文章本来写在了word文档,两天仓促写了这些东西,但不知不觉就搞了16页的word,为了留存劳动成果,发遍存到博客上。文章几乎一直在用失配后如何选择新合适起点来说这个算法,总之就是为了减少不必要...
  • 我理解就和我们在word或者其他编辑软件里点的查找、替换作用是差不多,不过功能要强大多,当然使用起来也稍微复杂一些。 书上定义差不多是这样:正则表达式就是一个表达式(也是一串字符),它定义了某种...
  • excel使用

    2012-11-25 17:06:01
    合并不同单元格内容,还有种方法是利用CONCATENATE函数,此函数作用是将若干文字合并到个字串中,具体操作为“=CONCATENATE(B1,C1)”。比如,假设在某河流生态调查工作表中,B2包含“物种”、B3包含...
  • js第二天

    2018-10-16 11:30:00
    a这个变量是字符了,对于里面个字母来说,他是字节。里面有11个字节。字节总数用length表示 4.符号运算 +字符拼接 . 表示“” 对于前面叫对象 后面叫属性和方法 属性和...
  • 1.在得到word时,要把下划线'_'和字母数字作为word的一部分考虑 2.忽略字符常量中的出现的关键词信息,或者说字符常量里的文本信息统统过滤掉 3.注释内容全部过滤掉 4.不考虑预处理器控制指令中的文本信息(这...
  • ctf 2019 re

    2021-01-29 12:40:11
    这边这个if语句判断很明显啊,就进去看了看,就是乘法 思路: 很简单,除回去就出来了, 这个数量很大,我是用word查找替换做 中间少了个[6],因为只有个数,就从0开始个个试,是1, 脚本 #include <...
  • 读取时区别:二进制可以每个字符为位,不会出现中文字符需要占据多位问题,但是需要进行encode才能知道具体字符。 在pythonload_word2vec_format函数里面有具体区别代码: gensim.models....
  • LeetCode079——单词搜索

    千次阅读 2018-08-13 08:38:14
    LeetCode代码仓:https://github.com/617076674/LeetCode 原题链接:https://leetcode-cn.com/problems/word-search/description/ 题目描述: ...我们在board数组首先定位到word字符...
  • 第二行,是吧个网址和ticker起来,因为google finance上网址都有规律,所以如果你要搜索googleoption今天报价, 有图为证:   所以在执行当中,已经有了个string 变量url,它指向goog finance网址: 然后...
  • Linux常用命令

    2014-09-21 19:43:32
    将许多包关联,使包可以一起安装不需要用rpm 装 ldap:统一名字(在服务器上) authconfig-tui 打开ldap 空格键 确定选中 用图形用户打开ldap: system-config-authentication /etc/init.d/...

空空如也

空空如也

1 2 3 4 5
收藏数 94
精华内容 37
关键字:

word里的一串点