嵌入式Linux驱动开发(I2C专题)(五)

I2C系统驱动程序模型

参考资料:

  • Linux内核文档:
    • Documentation\i2c\instantiating-devices.rst
    • Documentation\i2c\writing-clients.rst
  • Linux内核驱动程序示例:
    • drivers/eeprom/at24.c

1. I2C驱动程序的层次

在这里插入图片描述
I2C Core就是I2C核心层,它的作用:

  • 提供统一的访问函数,比如i2c_transfer、i2c_smbus_xfer等
  • 实现I2C总线-设备-驱动模型,管理:I2C设备(i2c_client)、I2C设备驱动(i2c_driver)、I2C控制器(i2c_adapter)

2. I2C总线-设备-驱动模型

在这里插入图片描述

2.1 i2c_driver

i2c_driver表明能支持哪些设备:

  • 使用of_match_table来判断
    • 设备树中,某个I2C控制器节点下可以创建I2C设备的节点
      • 如果I2C设备节点的compatible属性跟of_match_table的某项兼容,则匹配成功
    • i2c_client.name跟某个of_match_table[i].compatible值相同,则匹配成功
  • 使用id_table来判断
    • i2c_client.name跟某个id_table[i].name值相同,则匹配成功

i2c_driver跟i2c_client匹配成功后,就调用i2c_driver.probe函数。

2.2 i2c_client

i2c_client表示一个I2C设备,创建i2c_client的方法有4种:

  • 方法1

    • 通过I2C bus number来创建

      int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);
      
    • 通过设备树来创建

      	i2c1: i2c@400a0000 {/* ... master properties skipped ... */clock-frequency = <100000>;flash@50 {compatible = "atmel,24c256";reg = <0x50>;};pca9532: gpio@60 {compatible = "nxp,pca9532";gpio-controller;#gpio-cells = <2>;reg = <0x60>;};};
      
  • 方法2
    有时候无法知道该设备挂载哪个I2C bus下,无法知道它对应的I2C bus number。
    但是可以通过其他方法知道对应的i2c_adapter结构体。
    可以使用下面两个函数来创建i2c_client:

    • i2c_new_device

        static struct i2c_board_info sfe4001_hwmon_info = {I2C_BOARD_INFO("max6647", 0x4e),};int sfe4001_init(struct efx_nic *efx){(...)efx->board_info.hwmon_client =i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info);(...)}
      
    • i2c_new_probed_device

        static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };static int usb_hcd_nxp_probe(struct platform_device *pdev){(...)struct i2c_adapter *i2c_adap;struct i2c_board_info i2c_info;(...)i2c_adap = i2c_get_adapter(2);memset(&i2c_info, 0, sizeof(struct i2c_board_info));strscpy(i2c_info.type, "isp1301_nxp", sizeof(i2c_info.type));isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,normal_i2c, NULL);i2c_put_adapter(i2c_adap);(...)}
      
    • 差别:

      • i2c_new_device:会创建i2c_client,即使该设备并不存在
      • i2c_new_probed_device:
        • 它成功的话,会创建i2c_client,并且表示这个设备肯定存在
        • I2C设备的地址可能发生变化,比如AT24C02的引脚A2A1A0电平不一样时,设备地址就不一样
        • 可以罗列出可能的地址
        • i2c_new_probed_device使用这些地址判断设备是否存在
  • 方法3(不推荐):由i2c_driver.detect函数来判断是否有对应的I2C设备并生成i2c_client

  • 方法4:通过用户空间(user-space)生成
    调试时、或者不方便通过代码明确地生成i2c_client时,可以通过用户空间来生成。

  // 创建一个i2c_client, .name = "eeprom", .addr=0x50, .adapter是i2c-3# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device// 删除一个i2c_client# echo 0x50 > /sys/bus/i2c/devices/i2c-3/delete_device

编写设备驱动之i2c_driver

参考资料:

Linux内核文档:
Documentation\i2c\instantiating-devices.rst
Documentation\i2c\writing-clients.rst
Linux内核驱动程序示例:
drivers/eeprom/at24.c

1. 套路

1.1 I2C总线-设备-驱动模型

在这里插入图片描述

1.2 示例

分配、设置、注册一个i2c_driver结构体,类似drivers/eeprom/at24.c:
在这里插入图片描述

2. 编写i2c_driver

2.1 先写一个框架

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>static const struct of_device_id of_match_ids_example[] = {{ .compatible = "com_name,chip_name",		.data = NULL },{ /* END OF LIST */ },
};static const struct i2c_device_id example_ids[] = {{ "chip_name",	(kernel_ulong_t)NULL },{ /* END OF LIST */ }
};static int i2c_driver_example_probe(struct i2c_client *client)
{return 0;
}static int i2c_driver_example_remove(struct i2c_client *client)
{return 0;
}static struct i2c_driver i2c_example_driver = {.driver = {.name = "example",.of_match_table = of_match_ids_example,},.probe_new = i2c_driver_example_probe,.remove = i2c_driver_example_remove,.id_table = example_ids,
};static int __init i2c_driver_example_init(void)
{return i2c_add_driver(&i2c_example_driver);
}
module_init(i2c_driver_example_init);static void __exit i2c_driver_example_exit(void)
{i2c_del_driver(&i2c_example_driver);
}module_exit(i2c_driver_example_exit);
MODULE_LICENSE("GPL");

2.2 在为AP3216C编写代码

百问网的开发板上有光感芯片AP3216C:
在这里插入图片描述
AP3216C是红外、光强、距离三合一的传感器,以读出光强、距离值为例,步骤如下:

复位:往寄存器0写入0x4
使能:往寄存器0写入0x3
读红外:读寄存器0xA、0xB得到2字节的红外数据
读光强:读寄存器0xC、0xD得到2字节的光强
读距离:读寄存器0xE、0xF得到2字节的距离值
AP3216C的设备地址是0x1E。

ap3216c_drv.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/fs.h>static int major = 0;
static struct class *ap3216c_class;
static struct i2c_client *ap3216c_client;static ssize_t ap3216c_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;char kernel_buf[6];int val;if (size != 6)return -EINVAL;val = i2c_smbus_read_word_data(ap3216c_client, 0xA); /* read IR */kernel_buf[0] = val & 0xff;kernel_buf[1] = (val>>8) & 0xff;val = i2c_smbus_read_word_data(ap3216c_client, 0xC); /* read 光强 */kernel_buf[2] = val & 0xff;kernel_buf[3] = (val>>8) & 0xff;val = i2c_smbus_read_word_data(ap3216c_client, 0xE); /* read 距离 */kernel_buf[4] = val & 0xff;kernel_buf[5] = (val>>8) & 0xff;err = copy_to_user(buf, kernel_buf, size);return size;
}static int ap3216c_open (struct inode *node, struct file *file)
{i2c_smbus_write_byte_data(ap3216c_client, 0, 0x4);/* delay for reset */mdelay(20);i2c_smbus_write_byte_data(ap3216c_client, 0, 0x3);mdelay(250);return 0;
}static struct file_operations ap3216c_ops = {.owner = THIS_MODULE,.open  = ap3216c_open,.read  = ap3216c_read,
};static const struct of_device_id of_match_ids_ap3216c[] = {{ .compatible = "lite-on,ap3216c",		.data = NULL },{ /* END OF LIST */ },
};static const struct i2c_device_id ap3216c_ids[] = {{ "ap3216c",	(kernel_ulong_t)NULL },{ /* END OF LIST */ }
};static int ap3216c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);ap3216c_client = client;/* register_chrdev */major = register_chrdev(0, "ap3216c", &ap3216c_ops);ap3216c_class = class_create(THIS_MODULE, "ap3216c_class");device_create(ap3216c_class, NULL, MKDEV(major, 0), NULL, "ap3216c"); /* /dev/ap3216c */return 0;
}static int ap3216c_remove(struct i2c_client *client)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);device_destroy(ap3216c_class, MKDEV(major, 0));class_destroy(ap3216c_class);/* unregister_chrdev */unregister_chrdev(major, "ap3216c");return 0;
}static struct i2c_driver i2c_ap3216c_driver = {.driver = {.name = "ap3216c",.of_match_table = of_match_ids_ap3216c,},.probe = ap3216c_probe,.remove = ap3216c_remove,.id_table = ap3216c_ids,
};static int __init i2c_driver_ap3216c_init(void)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return i2c_add_driver(&i2c_ap3216c_driver);
}
module_init(i2c_driver_ap3216c_init);static void __exit i2c_driver_ap3216c_exit(void)
{i2c_del_driver(&i2c_ap3216c_driver);
}
module_exit(i2c_driver_ap3216c_exit);
MODULE_LICENSE("GPL");

ap3216c_client.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/mod_devicetable.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
#include <linux/property.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/fs.h>#if 1
static struct i2c_client *ap3216c_client;static int __init i2c_client_ap3216c_init(void)
{struct i2c_adapter *adapter;static struct i2c_board_info board_info = {I2C_BOARD_INFO("ap3216c", 0x1e),};printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* register I2C device */adapter = i2c_get_adapter(0);ap3216c_client = i2c_new_device(adapter, &board_info);i2c_put_adapter(adapter);return 0;
}#elsestatic struct i2c_client *ap3216c_client;/* Addresses to scan */
static const unsigned short normal_i2c[] = {0x1e, I2C_CLIENT_END
};static int __init i2c_client_ap3216c_init(void)
{struct i2c_adapter *adapter;struct i2c_board_info board_info;memset(&board_info, 0, sizeof(struct i2c_board_info));strscpy(board_info.type, "ap3216c", sizeof(board_info.type));printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);/* register I2C device */adapter = i2c_get_adapter(0);ap3216c_client = i2c_new_probed_device(adapter, &board_info,normal_i2c, NULL);i2c_put_adapter(adapter);return 0;
}
#endifmodule_init(i2c_client_ap3216c_init);static void __exit i2c_client_ap3216c_exit(void)
{i2c_unregister_device(ap3216c_client);
}
module_exit(i2c_client_ap3216c_exit);
MODULE_LICENSE("GPL");

APP

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/**/
int main(int argc, char **argv)
{int fd;char buf[6];int len;/* 2. 打开文件 */fd = open("/dev/ap3216c", O_RDWR);if (fd == -1){printf("can not open file /dev/hello\n");return -1;}len = read(fd, buf, 6);		printf("APP read : ");for (len = 0; len < 6; len++)printf("%02x ", buf[len]);printf("\n");close(fd);return 0;
}

Makefile

# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88/all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderobj-m	+= ap3216c_drv.o
obj-m	+= ap3216c_client.o

I2C_Adapter驱动框架讲解与编写

分配、设置、注册一个i2c_adpater结构体:

  • i2c_adpater的核心是i2c_algorithm
  • i2c_algorithm的核心是master_xfer函数

1. 所涉及的函数

  • 分配

    struct i2c_adpater *adap = kzalloc(sizeof(struct i2c_adpater), GFP_KERNEL);
    
  • 设置

    adap->owner = THIS_MODULE;
    adap->algo = &stm32f7_i2c_algo;
    
  • 注册:i2c_add_adapter/i2c_add_numbered_adapter

    ret = i2c_add_adapter(adap);          // 不管adap->nr原来是什么,都动态设置adap->nr
    ret = i2c_add_numbered_adapter(adap); // 如果adap->nr == -1 则动态分配nr; 否则使用该nr   
    
  • 反注册

    i2c_del_adapter(adap);
    

2. i2c_algorithm示例

  • Linux-5.4中使用GPIO模拟I2C
    在这里插入图片描述
  • Linux-5.4中STM32F157的I2C驱动
    在这里插入图片描述
  • Linux-4.9.88中IMX6ULL的I2C驱动
    在这里插入图片描述

3. 编写一个框架程序

3.1 设备树

在设备树里构造I2C Bus节点:

	i2c-bus-virtual {compatible = "100ask,i2c-bus-virtual";};

3.2 platform_driver

分配、设置、注册platform_driver结构体。

核心是probe函数,它要做这几件事:

  • 根据设备树信息设置硬件(引脚、时钟等)
  • 分配、设置、注册i2c_apdater

3.3 i2c_apdater

i2c_apdater核心是master_xfer函数,它的实现取决于硬件,大概代码如下:

static int xxx_master_xfer(struct i2c_adapter *adapter,struct i2c_msg *msgs, int num)
{for (i = 0; i < num; i++) {struct i2c_msg *msg = msgs[i];{// 1. 发出S信号: 设置寄存器发出S信号CTLREG = S;// 2. 根据Flag发出设备地址和R/W位: 把这8位数据写入某个DATAREG即可发出信号//    判断是否有ACKif (!ACK)return ERROR;else {// 3. read / writeif (read) {STATUS = XXX; // 这决定读到一个数据后是否发出ACK给对方val = DATAREG; // 这会发起I2C读操作} else if(write) {DATAREG = val; // 这会发起I2C写操作val = STATUS;  // 判断是否收到ACKif (!ACK)return ERROR;}                }// 4. 发出P信号CTLREG = P;}}   return i;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/78539.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一同走进Linux的“基操”世界

一同走进Linux的“基操”世界 众所周知&#xff0c;Linux是一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发能力已经得到业界的认可&#xff0c;可以说&#xff0c;Linux现在就像是一个“当红明星”&#xff0c;其实力赢得了大多数人的赞同&#xff0c;流量…

C++红黑树

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了红黑树并且使用红黑树模拟实现set和map 文章目录 红黑…

嵌入式学习笔记(25)串口通信的基本原理

三根通信线&#xff1a;Tx Rx GND &#xff08;1&#xff09;任何通信都要有信息作为传输载体&#xff0c;或者有线的或则无线的。 &#xff08;2&#xff09;串口通信时有线通信&#xff0c;是通过串口线来通信的。 &#xff08;3&#xff09;串口通信最少需要2根&#xff…

基于人体呼出气体的电子鼻系统的设计与实现

基于人体呼出气体的电子鼻系统的设计与实现 摘要 电子鼻技术是通过模式识别技术对传感器采集的人体呼出气体进行分类训练的方法。本文研究实现的电子鼻系统包括下面几个部分:首先搭建以Arduino为控制核心的气路采集装置&#xff0c;包括MOS传感器和双阀储气袋构建的传感器阵列和…

在网站标题中使用可以让搜索引擎更容易(识别网站的主要内容)

随着互联网的飞速发展&#xff0c;越来越多的企业开始重视网站的优化。优化网站排名不仅可以增加曝光率和点击率&#xff0c;也可以提高品牌知名度和销售额。本文将从关键字优化方案入手&#xff0c;为大家详细介绍如何提升网站排名。 什么是关键字&#xff1f; 关键字是指用…

如何在Windows 10/11中重置网络,以及重置后的注意事项有哪些

本文介绍如何在Windows 10和Windows 11中重置网络设置。 如何重置Windows 10网络设置 在Windows10中使用网络重置实用程序相当简单。 一、进入“开始”菜单>“设置”,然后选择“网络和Internet”。 二、在左侧导航窗格中,选择“状态”以确保你正在查看网络状态窗口。然…

深入解析 Nginx 代理配置:从 server 块到上游服务器的全面指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

使用CFimagehost源码搭建免费的PHP图片托管私人图床,无需数据库支持

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

Kubernetes(K8S)集群部署

目录 一、创建3台虚拟机 二、为每台虚拟机安装Docker 三、安装kubelet 3.1 安装要求 3.2 为每台服务器完成前置设置 3.3 为每台服务器安装kubelet、kubeadm、kubectl 四、使用kubeadm引导集群 4.1 master服务器 4.2 node1、node2服务器 4.3 初始化主节点 4.4 work节…

学习视觉SLAM需要会些什么?

前言 SLAM是现阶段很多研究生的研究方向&#xff0c;我也是作为一个即将步入视觉SLAM的研究生&#xff0c;网上对于SLAM的介绍很多&#xff0c;但很少有人完整系统的告诉你学习视觉SLAM该有那些基础&#xff0c;那么此贴将告诉你学习SLAM你要有那些方面的基础。 文章目录 前言…

【AI】机器学习——线性模型(线性回归)

线性模型既能体现出重要的基本思想&#xff0c;又能构造出功能更加强大的非线性模型 参考&#xff1a;唐宇迪机器学习课程 文章目录 3.1 线性模型3.1.1 数据3.1.2 目标/应用 3.2 线性回归3.2.1 回归模型历史3.2.2 回归分析研究内容回归分析步骤 3.2.3 回归分析分类3.2.4 回归模…

Codeforces Round 895 (Div. 3) A ~ F

Dashboard - Codeforces Round 895 (Div. 3) - Codeforces A 问多少次能使a 和 b相等&#xff0c;就是abs(a - b) / 2除c向上取整&#xff0c;也就是abs(a - b)除2c向上取整。 #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #de…

学习网络编程No.6【将服务器日志和守护进程化】

引言&#xff1a; 北京时间&#xff1a;2023/9/1/21:15&#xff0c;下午刚更新完博客&#xff0c;同理再接再厉&#xff0c;这样整天不需要干什么&#xff0c;除了玩手机的日子不多了&#xff0c;马上就要开学&#xff0c;每天需要签到签退的日子就要来临&#xff0c;烦躁&…

浅谈STL|STL函数对象篇

一.函数对象概念 概念: 重载函数调用操作符的类&#xff0c;其对象常称为函数对象 函数对象使用重载的()时&#xff0c;行为类似函数调用&#xff0c;也叫仿函数 本质: 函数对象(仿函数)是一个类&#xff0c;不是一个函数 特点 函数对象在使用时&#xff0c;可以像普通函数那…

Linux提权

shell分本地shell 和 webshell 有些提权方式只能本地shell使用 常见内核漏洞查找脚本以及利用 环境变量提权 suid https://www.cnblogs.com/banglook/archive/2022/03/17/16019354.html linux特殊命令https://www.secrss.com/articles/28493 什么是suid SUID (Set UID)是Li…

「中秋来袭」没想到,用OpenCV竟能画出这么漂亮的月饼「附源码」

一、前言 中秋佳节即将来临&#xff0c;作为传统的中国节日之一&#xff0c;人们除了品尝美味的月饼、赏月外&#xff0c;还喜欢通过绘画来表达对这个节日的喜悦和祝福。而如今&#xff0c;随着科技的不断发展&#xff0c;竟然可以借助计算机视觉库OpenCV来绘制精美的月饼和可…

Redis的数据持久化方案

目录 前言 RDB方式 概述&#xff1a; 1.RDB手动 &#xff12;.RDB自动 RDB优缺点 AOF方式 概述 AOF写数据的三种策略 AOF相关配置 AOF重写 AOF重写方式 手动重写 bgrewriteaof 自动重写 总结 前言 Redis是一个内存型数据库&#xff0c;也就是说如果不将内存中的…

被删除并且被回收站清空的文件如何找回

文件的意外删除和回收站清空是许多用户面临的普遍问题。这种情况下&#xff0c;很多人会感到无助和焦虑&#xff0c;担心自己的重要文件永远丢失。然而&#xff0c;幸运的是&#xff0c;依然存在一些有效的方法能够帮助我们找回被删除并且被回收站清空的文件。 ▌被删除文件在…

uniapp——实现聊天室功能——技能提升

这里写目录标题 效果图聊天室功能代码——html部分代码——js部分代码——其他部分 首先声明一点&#xff1a;下面的内容是从一个uniapp的程序中摘录的&#xff0c;并非本人所写&#xff0c;先做记录&#xff0c;以免后续遇到相似需求抓耳挠腮。 效果图 聊天室功能 发送图片 …

进制转换问题

进制 二进制 &#xff08;Binary&#xff09;&#xff1a;0、1。简写为B 八进制&#xff08;Octonary&#xff09;&#xff1a;0、1、2、3、4、5、6、7。简写为O 十进制&#xff08;decimalism&#xff09;&#xff1a;0、1、2、3、4、5、6、7、8、9 简写为D 十六进制&#xff…