树莓派gpio驱动编写——不使用wiringPi

2023-05-16

一、相关概念

    • 总线地址

总线地址:cpu能够访问内存的范围

可以通过cat /proc/meminfo 来查看内存条大小

    • 物理地址

物理地址:硬件的实际地址或绝对地址

    • 虚拟地址

虚拟地址:逻辑(基于算法的地址(软件层面的地址,假地址))地址称为虚拟地址

  • 它可以用来加载程序数据(数据可能被加载到物理内存上,空间不够就加载到虚拟内存中)

  • 它对应着一段连续的内存地址,起始位置为 0。

  • 之所以说虚拟是因为这个起始的 0 地址是被虚拟出来的, 不是物理内存的 0 地址。

虚拟地址空间的大小也由操作系统决定,32位的操作系统虚拟地址空间的大小为 2^32 字节,也就是 4G,64 系统的操作系统虚拟地址空间大小为 2^64 字节

    • mmu与页表

mmu:MMU是Memory Management Unit的缩写,中文名是内存管理单元,有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件。虚拟地址和物理地址的映射关系存储在页表中

MMU位于CPU内,作用:

  • 程序中使用的地址均是虚拟内存地址,进程中的数据是如何进入到物理内存中的呢?

  • MMU完成虚拟内存到物理内存的映射,即虚拟地址映射为物理地址;

  • 流水线中预取指令取到的地址是虚拟地址,需要MMU转换以及设置访问权限

页表

  • 如物理地址为1M,虚拟地址为4M;虚拟地址可以从0-4M来表示物理地址0-1M,中间的算法叫做页表

  • 页表通过mmu来执行,把虚拟地址通过页表映射成物理地址。页表决定了1M在哪里被表示成4M

  • 其中是以页(4KB)为单位进行映射的

    • 设备号

  1. 设备号是用来区分硬件的

linux一切皆为文件,其设备管理同样是和文件系统紧密结合。各种设备都以文件的形式存在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。

在目录/dev下都能看到鼠标,键盘,屏幕,串口等设备文件,硬件要有相对应的驱动,那么open怎样区分这些硬件呢? 依靠文件名与设备号。

  1. 主设备号和次设备号

设备号分为:主设备号:用来区分不同种类的设备

次设备号:用来区分同种类型的多个设备

驱动链表:管理所有设备的驱动
1、添加:在我们编写完驱动程序,加载到内核
2、查找:调用驱动程序,用户空间去open
3、驱动插入链表的顺序由设备号检索
    • 当用户态调用open时,内核态发生了什么

  • 用户层调用open产生一个软中断(终端号为0x80),进入内核空间调用sys_call

  • sys_call调用sys_open,去内核的驱动链表根据主设备号与次设备号找驱动

  • 调用驱动中的open,去做相应的操作

二、gpio驱动编写

cat /proc/iomem  获取虚拟地址所对应的物理地址
pinout   获取对应芯片型号
    • 查看芯片手册

通过阅读芯片手册我们可以得知,写pin4的gpio驱动我们需要使用GPFSEL0、GPSET0、GPCLR0寄存器,且每个寄存器占4位

GPFSEL0:GPIO Function Select 功能选择 输出或输入(GPIO Function Select Registers)

000 = GPIO Pin 9 is an input

001 = GPIO Pin 9 is an output

由该部分可以得知,我们对pin4进行操作就是对FSEL4进行操作,也是对12-14位进行操作,并且为001时为输出模式。

GPSET0: GPIO Pin Output Set; gpio输出1设置

GPCLR0: GPIO Pin Output Clear;gpio输出0设置

    • 进行地址赋值及映射

因为代码操作的是虚拟地址,而我们需要对物理地址进行操作,所以我们需要使用ioremap函数进行物理地址和虚拟地址之间的相互转换

函数原型:void *ioremap(unsigned long phys_addr, unsigned long size)
phys_addr:要映射的起始的IO物理地址;
size:要映射的空间的大小;

因为程序在编译过程中会对程序进行优化,所以我们需要使用volatile关键字来避免程序对该操作的优化

volatile的作用是作为指令关键字,确保本条 指令不会因编译器的优化而省略,且要求每次直接读值
volatile unsigned int *GPFSEL0 = (volatile unsigned int*)ioremap(0xfe200000,4);
volatile unsigned int *GPCLR0  = (volatile unsigned int*)ioremap(0xfe200028,4);
volatile unsigned int *GPSET0  = (volatile unsigned int*)ioremap(0xfe20001C,4);

进行了地址映射,我们还需要解除映射

void iounmap(void* addr)//取消ioremap所映射的IO地址
iounmap(GPFSEL0);  //放入exit函数中
iounmap(GPSET0);
iounmap(GPCLR0);
    • 进行输出设置

由芯片手册看出我们需要对32位中的其中几位,如果我们通过

GPSET0 = 0000000000000....0000..0

该方式进行赋值的话,这样对于我们的检查和编写都会造成很大的难度。所以我们使用位操作(|、&)。

将pin4引脚设置为输出模式
    *GPFSEL0 &= ~(0x6 << 12);//12-14  13、14置0 
    *GPFSEL0 |= (0x1 << 12);//12置1

将pin4引脚值1
    *GPSET0 |= (0x1 << 4);

将pin4引脚置0
    *GPCLR0 |= (0x1 << 4);

我们设置的是输出模式,所以我们需要获取上层的指令,可以通过copy_from_user函数

unsigned long copy_from_user(void * to, const void __user * from, unsigned long n)
第一个参数to是 内核空间的数据目标地址指针,
第二个参数from是 用户空间的数据源地址指针,
第三个参数n是 数据长度
此函数将from指针指向的用户空间地址开始的连续n个字节的数据产送到to指针指向的内核空间地址,简言之是用于将用户空间的数据传送到内核空间
    • 进行驱动模板编写以及测试

内核驱动框架

#include <linux/fs.h>         //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>     //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件
 
static struct class *pin4_class;  
static struct device *pin4_class_dev;
 
static dev_t devno;                //设备号
static int major = 231;             //主设备号
static int minor = 0;               //次设备号
static char *module_name = "pin4";   //模块名
 
//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
    printk("pin4_open\n");  //内核的打印函数和printf类似
      
    return 0;
}
 
//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
    printk("pin4_write\n");
    
    return 0;
}
 
//led_read函数 
static ssize_t pin4_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    printk("pin4_read\n");

    return 0;
}

static struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
    .read  = pin4_read,   
};
 
int __init pin4_drv_init(void)   //真实驱动入口
{
    int ret;
    devno = MKDEV(major, minor);  //创建设备号
    ret   = register_chrdev(major, module_name, &pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中
 
    pin4_class=class_create(THIS_MODULE, "myfirstdemo");        //用代码在dev自动生成设备
    pin4_class_dev =device_create(pin4_class, NULL, devno, NULL, module_name);  //创建设备文件
    
    return 0;
}
 
void __exit pin4_drv_exit(void)
{
    device_destroy(pin4_class, devno);
    class_destroy(pin4_class);  
    unregister_chrdev(major, module_name);  //卸载驱动
 
}
 
module_init(pin4_drv_init);  //入口,内核加载该驱动的时候,这个宏被使用,在insmod时候就会调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

上层应用程序

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
 
int main()
{
        int fd;
 
        fd = open("/dev/pin4",O_RDWR);
        if(fd < 0){
                printf("open failed\n");
                perror("reson");
        }else{
                printf("open success\n");
        }
 
        fd = write(fd,1,1);//写一个字符'1',写一个字节
        return 0;
}
 

驱动模块的编译以及测试

将我们写好的驱动放入/drivers/char/文件夹下,并且对Makefile进行添加驱动

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7l make -j4 modules
  • 通过该指令进行编译驱动生成xx.ko文件,该文件就为我们所需要的驱动文件。并且通过scp指令将xx.ko文件传到树莓派上

  • 在树莓派上通过insmod指令安装驱动

  • 通过lsmod检查驱动是否安装成功,此时如果我们直接对驱动进行操作,会提示权限不够

  • 通过chmod指令为该驱动增加权限

sudo chmod 666 /dev/pin4

此时就可以运行上层应用程序进行测试了,当程序运行结束后,通过dmesg进行驱动的输出检测

出现以上两行信息,及说明我们的模块是正确的、可以使用的。

三、进行pin4口的驱动编写

将以上我们所查阅的资料以及准备的模板进行整合

内核驱动

//字符设备驱动框架

#include <linux/fs.h>        //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>    //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件
 
static struct class *pin4_class;  
static struct device *pin4_class_dev;
 
static dev_t devno;                //设备号
static int major = 231;            //主设备号
static int minor = 0;              //次设备号
static char *module_name = "pin4";   //模块名
 
volatile unsigned int *GPFSEL0 = NULL;
volatile unsigned int *GPSET0  = NULL;
volatile unsigned int *GPCLR0  = NULL;

//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{
    //printk("pin4_open\n");  //内核的打印函数和printf类似

    *GPFSEL0 &= ~(0x6 << 12);//12-14  13、14置0 
    *GPFSEL0 |= (0x1 << 12);//12置1
    
    printk("pin4 set output success\n");

    return 0;
}
 
//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{
    //printk("pin4_write\n");
    char cmd_user;

    copy_from_user(&cmd_user,buf,count);

    printk("get value\n");

    if(cmd_user == 1){
        *GPSET0 |= (0x1 << 4);
        printk("pin4 set high\n");
    }
    if(cmd_user == 0){
        *GPCLR0 |= (0x1 << 4);
        printk("pin4 set low\n");
    }

    return 0;
}
 
//led_read函数 
static ssize_t pin4_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    printk("pin4_read\n");

    return 0;
}

static struct file_operations pin4_fops = {
    .owner = THIS_MODULE,
    .open  = pin4_open,
    .write = pin4_write,
    .read  = pin4_read,   
};
 
int __init pin4_drv_init(void)   //真实驱动入口
{
    int ret;
    devno = MKDEV(major, minor);  //创建设备号
    ret   = register_chrdev(major, module_name, &pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中
 
    pin4_class=class_create(THIS_MODULE, "myfirstdemo");        //用代码在dev自动生成设备
    pin4_class_dev =device_create(pin4_class, NULL, devno, NULL, module_name);  //创建设备文件
    
    GPFSEL0 = (volatile unsigned int*)ioremap(0xfe200000,4);
    GPCLR0  = (volatile unsigned int*)ioremap(0xfe200028,4);
    GPSET0  = (volatile unsigned int*)ioremap(0xfe20001C,4);

    printk("pin4driver success\n");

    return 0;
}
 
void __exit pin4_drv_exit(void)
{
    iounmap(GPFSEL0);
    iounmap(GPSET0);
    iounmap(GPCLR0);

    device_destroy(pin4_class, devno);
    class_destroy(pin4_class);  
    unregister_chrdev(major, module_name);  //卸载驱动
 
}
 
module_init(pin4_drv_init);  //入口,内核加载该驱动的时候,这个宏被使用,在insmod时候就会调用
module_exit(pin4_drv_exit);
MODULE_LICENSE("GPL v2");

上层应用

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
 
int main()
{
        int fd;
        int cmd;
 
        fd = open("/dev/pin4",O_RDWR);
        if(fd < 0){
                printf("open failed\n");
                perror("reson");
        }else{
                printf("open success\n");
        }
 
        printf("请输入0 / 1\n 0:设置pin4为低电平\n 1:设置pin4为高电平\n");
        scanf("%d",&cmd);
 
        if(cmd == 0){
                printf("pin4设置成低电平\n");
        }else if(cmd == 1){
                printf("pin4设置成高电平\n");
        }
 
        fd = write(fd,&cmd,1);//写一个字符'1',写一个字节
        return 0;
}
 

当我们编写、编译、加载完成后,可以通过wiringPi中的gpio readall指令进行检查驱动是否正常运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

树莓派gpio驱动编写——不使用wiringPi 的相关文章

  • STM32F103笔记(二)——GPIO原理

    GPIO的工作原理与两个实验实例 一 STM32F103 GPIO说明1 stm32 GPIO引脚的主要功能2 GPIO相关配置寄存器的简介3 STM32F103 GPIO的8种工作方式4种输入模式4种输出模式 二 点亮LED实例 xff0
  • LINUX 操作GPIO口

    两种方法 1 写驱动的方式 缺 2 通过linux提供的用户空间 终端控制 通过在用户空间上来操作GPIO xff0c 控制入口在 xff1a sys class gpio 首先确认内核里是否已选择上gpiolib的sysfs接口功能 默认
  • 树莓派GPIO控制

    树莓派GPIO 控制 陈拓 2018 06 09 2018 06 10 0 概述 本文介绍树莓派 Zero W的GPIO控制 xff0c 并用LED看效果 也适宜于树莓派3B 43 0 1 树莓派GPIO编号方式 功能物理引脚 从左到右 x
  • GPIO简介

    1 什么是GPIO xff1f GPIO是General Purpose Input Output xff0c 即通用输入输出端口 xff0c 简称GPIO 作用 xff1a 负责采集外部器件的信息或者控制外部器件工作 xff0c 即输入输
  • stm32简介+gpio的C语言封装

  • void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)的一些理解

    GPIO TypeDef GPIOA BASE 表示将GPIOA BASE强制转换为指针类型的结构体 xff0c define GPIOA GPIO TypeDef GPIOA BASE 表示用 GPIO TypeDef GPIOA BAS
  • GPIO的速度的理解

    一 GPIO模式配置 1 输入 输出模式 参考stm32手册 2 GPIO输出模式下 几种速度的区别 1 GPIO 引脚速度 GPIO Speed 2MHz 10MHz 50MHz 又称输出驱动电路的响应速度 芯片内部在I O口的输出部分安
  • 【STM32F4】二、I/O引脚的复用和映射

    目录 一 基本概念 1 什么是I O引脚 2 什么是I O引脚的复用 二 如何配置I O引脚复用 1 复用器 GPIOx AFRL GPIOx AFRH 和复用功能 AF 2 程序编写 2 1 打开I O时钟和复用功能对应外设时钟 2 2
  • 零基础玩转树莓派(四)—GPIO端口控制(LED灯)

    一 GPIO介绍 树莓派3B 和普通电脑不一样的地方在于它还带了40个可编程的GPIO General Purpose Input Output 可以用来驱动各种外设 如传感器 步进电机等 GPIO General Purpose I O
  • 品味树莓派:GPIO Zero库使用入门

    文章目录 目的 基础说明 入门使用 LED PWMLED Button 更多入门例程 类基础说明 注意事项 总结 目的 树莓派有很多GPIO口可供用户使用 官方同时也提供了一些方式来操作这些IO口 其中目前主要推荐的是基于Python的GP
  • 【树莓派】error: command ‘/usr/bin/arm-linux-gnueabihf-gcc‘ failed with exit code 1(已解决)

    输入以下命令 export CFLAGS fcommon pip3 install RPi GPIO 参考网址 https askubuntu com questions 1290037 error while installing rpi
  • 学习笔记:STM32的ACD

    STM32f103系列有3个ADC ADC1 ADC2 ADC3 通道 ADC1和ADC2都有16个外部通道 2个内部通道 连接到温度传感器和内部参考电压 VREFINT 1 2V ADC3有8个外部通道 通道列表 通道顺序转换 使用多个通
  • 如何在Python中运行后一段时间内禁用Raspberry Pi GPIO事件?

    每当我的 Raspberry Pi 的 GPIO 引脚出现下降沿时 我就会创建一个事件 但是 我想在每次运行后禁用此事件一段时间 例如 5 秒 我希望在该时间段之后再次启用该事件 我的第一个想法就是使用sleep 5 在实际的事件函数中 但
  • 使用 Node.js 通过 Raspberry Pi 3 model B 进行 GPIO

    我正在尝试使用树莓派 3 B 型让 LED 闪烁 我的机器上安装了所有必需的模块 即 npm nodejs pi gpio 修复了检测 gpio 的微小更改 代码是 var gpio require pi gpio gpio open 16
  • linux GPIO C API

    我有一个 powerpc 板 上面运行着 3 2 内核 使用 sysfs 访问 GPIO 按预期工作 例如 gt echo 242 gt sys class gpio export gt cat sys class gpio gpio242
  • Sphinx:如何排除自动模块中的导入?

    我有一个用 Python 编写的 Raspberry Pi 项目 它使用 RPi GPIO 模块 代码上的所有工作都是在 Windows 机器上完成的 其中 RPi GPIO 不会安装 每次我尝试运行 autodoc 时 它都会崩溃 说它无
  • gpiod - 在设备树中使用标签

    我想用libgpiod通过自定义板上的用户空间控制一些 GPIO 我有一个 i MX6UL 处理器 它有数百个引脚 我将只使用其中 8 个 作为 GPIO 我读到了关于libgpiod因为它正在取代旧的 sysfs API 我很高兴您可以为
  • Beaglebone GPIO 输入不起作用

    我正在使用 beaglebone 通过 sysfs 接口访问特定引脚的数字输入 我可以更改输出状态 但不能更改输入 我所做的是 我有两个引脚 pinA 和 pinB pinA 我将其输出 pinB 我将其输入 将 pinA 连接到 pinB
  • Python使用sudo启动时找不到模块

    我有一个使用 Google Assistant 库的脚本 并且必须从那里导入一些模块 我发现这只适用于 Python 虚拟环境 这真的很奇怪 在同一个文件夹中 我有一个使用 GPIO 引脚并且必须使用 root 的脚本 它们相互交互 因此当
  • 通过单个 GPIO 引脚转储闪存

    我正在使用 Infineon 的 XMC4500 Relax Kit 并尝试通过单个 GPIO 引脚提取固件 我非常天真的想法是通过 GPIO 引脚一次转储一位 然后用逻辑分析仪以某种方式 嗅探 数据 伪代码 while word by w

随机推荐

  • Java short数据类型

    短 short 整型数据类型是16位有符号Java原始整数数据类型 其范围是 32768至32767 或 2 15至2 15 1 short整型数据类型没有字面量 但是 xff0c 可以将任何位于short 32768到32767 范围内的
  • Java面试题内容聚合

    往期内容聚合 设计模式内容聚合 面试技术文 Java岗 面试考点精讲 xff08 基础篇01期 xff09 Java岗 面试考点精讲 xff08 基础篇02期 xff09 Java岗 面试考点精讲 xff08 网络篇03期 xff09 Ja
  • JVM原理和优化

    JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java exe来完成 通过下面4步来完成JVM环境 1 创建JVM装载环境和配置 2 装载JVM dll 3 初始化JVM dll并挂界到JNIENV JNI调用接口 实例 4
  • 抽象类与接口

    抽象方法 xff1a 只有行为的概念 xff0c 没有具体的行为实现 1 使用 xff1a abstract 关键字修饰 xff0c 并且没有方法体 2 包含抽象方法的类 xff0c 就一定是抽象类 3 抽象类不能直接创建实例 可以定义引用
  • Linux 下查看java进程

    Linux下查看和停止所有java进程 1 ps ef grep java 在Linux下查看所有java进程命令 xff1a ps ef grep java 停止特定java进程命令 xff1a kill 9 java进程序号 停止所有j
  • SpringCloud + Oauth2.0 + ShiroRedis + JWT + Gateway + Nacos + Nginx + ant-design-vue 电商 java 项目

    该项目是一套电商系统 xff0c 包括前台商城系统及后台管理系统 xff0c 基于SpringBoot 43 MyBatis实现 xff0c 采用Docker容器化部署 前台商城系统 xff1a 首页 商品推荐 商品搜索 商品展示 购物车
  • JavaEE进阶 - Spring Boot 日志文件 - 细节狂魔

    文章目录 1 志有什么 xff1f 2 志怎么 xff1f 3 自定义日志打印 准备工作 xff1a 创建一个 Spring Boot 项目 并在其中创建一个UserController类 xff0c 用来演示 在程序中得到 志对象 常 的
  • Spring注解详解

    一 Spring注解驱动开发入门 spring在2 5版本引入了注解配置的支持 xff0c 同时从Spring 3版本开始 xff0c Spring JavaConfig项目提供的许多特性成为核心Spring框架的一部分 因此 xff0c
  • hadoop启动HDFS命令

    启动命令 xff1a hadoop sbin start dfs sh 停止命令 xff1a hadoop sbin stop dfs sh
  • 女生学java开发难吗?女生适合学java吗?

    女生学java开发 xff1f Java开发看上去是一项系统性很强 入门很难的 高大上 学科 xff0c 前端 代码这些普通人基本不会接触到的名词 xff0c 吓怕了众多初学者 大部分人对于Java程序员都有一个既定印象 xff0c 那就是
  • 女生学java软件开发怎么样?就业前景如何?

    学java目前现状是男生多于女生 xff0c 从事java工作的也是男生多于女生 xff0c 那么这种现状是说女生学java不好找工作吗 一 女生适合从事java吗 在很多人的潜意识里 xff0c 认为女生是不适合从事java工作的 xff
  • 【 Docker Desktop stopped...】--------已经解决

    windows10系统 xff0c 安装docker 4 6 1版本 xff0c 提示Docker Desktop stopped xff0c 如图所示 在Stackoverflow有此问题 xff0c 底下给出的解决方案是卸载4 6 1版
  • JVM参数配置详解

    JVM调优总结 默认设置 Xms为JVM启动时申请的最小内存 xff0c 默认为操作系统物理内存的1 64但小于1G Xmx为JVM可申请的最大内存 xff0c 默认为物理内存的1 4但小于1G xff0c 默认当空余堆内存小于40 时 x
  • 认识MyBatis与Mybatis-plus及两者的区别

    一 认识Mybatis MyBatis 是持久层框架 xff0c 它支持定制化 SQL 存储过程以及高级映射 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集 MyBatis 可以使用简单的 XML 或注解来配置
  • 线程

    创建线程 xff1a 方法一 xff09 继承Thread类 实现步骤 xff1a 继承Thread类 覆盖run 方法 提供并发运程的过程 创建这个类的实例 使用start 方法启动线程 xff08 方法二 xff09 实现Runnabl
  • Linux中实现cp命令

    一 main函数的原型 main int argc char argv argc是所有参数的总数量 argv为参数 如该程序所示 xff1a 程序运行结果如图所示 xff1a 二 实现cp指令的思路 1 打开src c 2 通过lseek函
  • Linux系统编程—进程

    一 相关概念 1 进程与程序 xff1a 程序是一个静态的概念 如gcc xxx c o pro xff0c 磁盘中生成的Pro文件 xff0c 叫做程序 进程就是程序运行起来 xff0c 系统中就多了一个进程 2 查看进程的方法 xff1
  • Linux系统编程——进程间通信

    目录 一 无名管道 相关概念 相关函数介 相关说明 实战 二 有名管道 有名管道和无名管道的区别 有名管道和无名管道的相同点 有名管道的相关函数 实战 三 消息队列 消息队列的介绍 消息队列的特点 相关函数 实战 四 共享内存 共享内存优缺
  • 树莓派——初级编程

    一 没有屏幕的树莓派如何使用 通过串口连接树莓派 通过官方给的相关文件和软件 xff0c 对树莓派进行刷系统 设备破解 默认情况 xff0c 树莓派的串口和蓝牙连接 想办法断开蓝牙连接 xff0c 把串口用来数据通信 默认账号 xff1a
  • 树莓派gpio驱动编写——不使用wiringPi

    一 相关概念 总线地址 总线地址 xff1a cpu能够访问内存的范围 可以通过cat proc meminfo 来查看内存条大小 物理地址 物理地址 xff1a 硬件的实际地址或绝对地址 虚拟地址 虚拟地址 xff1a 逻辑 xff08