恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Arduino驱动16×2 LCD屏:从硬件连接到代码实现的完整指南

  • 首页
  • 资讯中心
  • /
  • Arduino驱动16×2 LCD屏:从硬件连接到代码实现的完整指南

相关资讯

ComfyUI-Manager 保姆级上手:插件装崩、节点报错、环境失控?这一篇救回你的工作流 2026/8/19 9:30:45
多智能体系统故障定位:从黑盒调试到可观测性实践 2026/8/19 9:30:45
鸿蒙 升级targetSDKVersion的兼容性处理 2026/8/19 9:30:45

最新资讯

CRC职业进阶:从流程执行到临床研究项目管理的核心能力构建
基于分层LLM与提示词优化的多机器人任务规划框架设计与实践
一个项目经理能不能扛事,先看他会不会这“三板斧”
Beyond Compare 5 评估期不再愁:BCompare_Keygen 快速生成注册密钥的完整指南
思源宋体CN免费商用字体入门:7个TTF字重下载安装与网页落地一次讲透
基于SwinTransformer的YOLOv8药品检测算法研究

今日推荐

Windows 安卓应用安装终极方案:5分钟上手免费APK安装器,三步告别模拟器
WarcraftHelper 魔兽争霸3优化实战指南
抖音批量下载实战手册:用douyin-downloader把6小时手工劳动压缩到15分钟

本周热门

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码
【双层规划,节点出清价,绿证交易,CVaR方法】两级电力市场环境下计及风险的省间交易商最优购电模型附Matlab代码
隐式mpc+自适应mpc+时变mpc,线性时变模型预测控制附Simulink仿真

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

Arduino驱动16×2 LCD屏:从硬件连接到代码实现的完整指南

发布时间:2026/8/19 9:35:45
Arduino驱动16×2 LCD屏:从硬件连接到代码实现的完整指南 1. 项目概述从“Hello World”开始的硬件交互之旅在软件编程的世界里“Hello World”是每个新手迈出的第一步它标志着一段学习旅程的开启。而在硬件与嵌入式开发领域当我们将这个经典的问候语从冰冷的命令行窗口转移到一块小小的、发光的液晶显示屏上时那种亲手点亮物理世界的感觉是完全不同的。今天我们就来聊聊如何用一块最常见的Arduino Uno开发板和一块经典的16×2字符型LCD显示屏完成这个硬件世界的“Hello World”仪式。这个项目看似简单却是连接数字逻辑与物理世界的绝佳桥梁。它不只是一个简单的显示任务更是一个涵盖了硬件接口、通信协议、库函数调用和基础编程逻辑的微型系统工程。对于刚接触Arduino或嵌入式开发的朋友来说成功驱动一块LCD屏意味着你掌握了如何让微控制器与外部设备“对话”的基本能力。这块小小的屏幕未来可以成为你智能家居项目的状态显示器、数据采集系统的实时监控面板或是机器人项目的交互界面。市面上最常见的16×2 LCD屏其核心驱动芯片通常是HD44780或其兼容芯片。理解这一点至关重要因为它决定了我们后续编程时使用的库和通信方式。整个项目的核心逻辑就是Arduino作为大脑通过特定的引脚数据线和控制线向LCD屏的HD44780驱动芯片发送指令和数据驱动芯片再控制屏幕上的像素点最终显示出我们想要的字符。接下来我将带你从硬件连接到软件编程一步步拆解这个过程并分享那些教程里通常不会写的、容易踩坑的细节。2. 硬件清单与连接原理不仅仅是插线那么简单动手之前我们先来清点一下需要的“食材”。核心部件有两样一块Arduino开发板以最普及的Arduino Uno R3为例和一块16×2字符LCD显示屏。此外你还需要一些杜邦线公对公用于连接以及一个电位器通常为10kΩ来调节屏幕对比度。LCD屏的型号可能略有不同但只要是基于HD44780或兼容控制器的16×2屏操作方法都是通用的。现在让我们深入看看连接背后的逻辑而不仅仅是记住线序。LCD屏通常有16个引脚有些是14个或更少但功能对应其核心功能可以分为三大部分电源、数据和指令。电源部分VCC, GND, VEEVCC接5VGND接地这很好理解。关键是VEE引脚它负责调节显示对比度。你可以把它理解成屏幕的“亮度”严格说是深浅调节旋钮。直接接地会导致对比度过高屏幕全黑只能看到背光直接接5V则对比度过低字符几乎看不见。所以我们需要通过一个10kΩ的可调电位器将VEE连接到一个可变的电压上电位器两端接5V和GND中间滑动端接VEE通过旋转来找到字符最清晰的那个“甜点”。数据部分D0-D7这是Arduino与LCD通信的“高速公路”。HD44780控制器支持两种数据模式8位模式和4位模式。8位模式使用D0-D7全部8根数据线速度快4位模式只使用高4位D4-D7可以节省4个宝贵的I/O引脚。对于Arduino Uno这种I/O资源不算特别宽裕的板子我们几乎总是选择4位模式用效率换引脚这是非常实际的选择。控制部分RS, RW, E这是通信的“交通指挥灯”。RS (Register Select)寄存器选择引脚。它告诉LCD接下来发送的是指令如清屏、移动光标还是数据要显示的字符。RS低电平为指令模式RS高电平为数据模式。这个概念必须清晰它是编程逻辑的基础。RW (Read/Write)读写选择引脚。大部分时候我们只向LCD写数据所以通常将此引脚直接接地低电平设置为写模式。如果接地不牢靠可能会导致通信混乱。E (Enable)使能引脚。这是最重要的时序控制引脚。你可以把它想象成一个“确认接收”的按钮。数据或指令在数据线上准备好后我们需要给E引脚一个从高电平到低电平的跳变即一个下降沿这个跳变就像对LCD说“喂数据放好了快来拿”LCD会在下降沿的时刻锁存数据线上的值。理解了这些连接就变得有逻辑了。下面是一个典型的4位模式连接表格我强烈建议你对照表格和原理来连接而不是死记硬背Arduino Uno 引脚LCD 16×2 引脚功能说明5VVCC (Pin 2)电源正极GNDGND (Pin 1)电源地GNDVEE (Pin 3)通过10kΩ电位器中间端接入用于调节对比度D12D4 (Pin 11)数据位4D11D5 (Pin 12)数据位5D10D6 (Pin 13)数据位6D9D7 (Pin 14)数据位7D8RS (Pin 4)寄存器选择GNDRW (Pin 5)直接接地始终为写模式D7E (Pin 6)使能信号注意上表中的Arduino引脚D12, D11, D10, D9, D8, D7并非固定不可变它们可以在代码中自定义。但必须保证代码中声明的引脚与实际连接一致。这是一个常见的错误来源连接了一套引脚代码里初始化了另一套。连接时还有一个硬件上的小坑LCD屏的背光。有些屏的背光LED是独立的引脚标为A和K需要单独接限流电阻到5V和GND。有些屏则已将背光集成只要接上VCC就会亮。如果你的屏幕连接后电源正常但完全不亮先检查背光是否已经供电。3. 软件环境搭建与LiquidCrystal库深度解析硬件连接妥当后我们进入软件部分。首先确保你已安装Arduino IDE。这里我不再赘述下载安装过程但想强调一个版本选择的问题。对于这类基础项目经典的Arduino IDE 1.8.x版本和新的2.x版本都可以完美胜任。新手如果遇到2.x版本一些界面上的不习惯换回1.8.19等稳定版也完全没有问题。关键是要知道库的安装位置在1.8.x中库通常安装在文档/Arduino/libraries下在2.x中位置可能略有不同可以通过“文件”-“首选项”查看项目文件夹位置。本项目最核心的软件依赖是Arduino内置的LiquidCrystal库。这个库由Arduino官方团队维护封装了与HD44780兼容控制器通信的所有底层细节。我们不需要去研究如何手动产生E信号的下降沿如何按4位模式分两次发送一个字节库都帮我们做好了。但作为一名有追求的开发者理解库在背后做了什么能让你在出问题时快速定位。LiquidCrystal库支持多种引脚连接方式。我们最常用的是它的构造函数LiquidCrystal lcd(rs, enable, d4, d5, d6, d7)。这个构造函数对应我们刚才采用的4位数据线模式。参数依次是RS引脚、E引脚、以及D4到D7四个数据引脚。库在初始化时会通过一系列复杂的指令序列对LCD进行“唤醒”和设置包括设置数据位宽4位、显示行数、字体大小5x8点阵等。这个过程如果由我们手动实现需要编写几十行严格按照时序要求的代码而现在一行构造函数调用就完成了。除了最常用的4位模式构造函数该库还支持8位模式需要更多引脚和使用I2C/SPI转接板的模式。对于后者你通常需要安装额外的库如LiquidCrystal_I2C它通过一个叫PCF8574的芯片将I2C信号转换为并行信号驱动LCD可以只用两根线SDA, SCL就完成控制极大地节省了引脚适合复杂项目。但作为入门我们先从最“原始”的并行连接学起这有助于建立根本性的理解。在编写代码前我建议在Arduino IDE中打开一个示例看看。点击“文件”-“示例”-“LiquidCrystal”-“HelloWorld”。你会看到官方示例代码。我们可以借鉴其结构但不要完全照抄因为它的引脚定义可能和我们的不同。下面我将基于我们的连接方式从头构建一个更清晰、注释更完整的“Hello World”程序并解释每一部分的作用。4. 代码逐行详解与你的第一个显示程序让我们打开Arduino IDE创建一个新项目。我将把代码分成几个逻辑块并详细解释每一行。// 1. 引入必要的库 #include LiquidCrystal.h // 2. 初始化LCD对象定义引脚连接 // 格式LiquidCrystal lcd(RS, E, D4, D5, D6, D7); // 请务必确保这里的引脚编号与你的实际硬件连接完全一致 LiquidCrystal lcd(8, 7, 12, 11, 10, 9); void setup() { // 3. 初始化LCD设置屏幕尺寸16列2行 lcd.begin(16, 2); // 4. 在屏幕第一行、第一列的位置打印“Hello World!” lcd.print(Hello World!); } void loop() { // 5. loop函数在本例中为空因为只需要显示一次。 // 后续可以在这里添加动态变化的内容。 }现在我们来拆解每一部分第1部分引入库#include LiquidCrystal.h这行代码告诉编译器我们要使用LiquidCrystal库中定义好的类和函数。没有这行下面的LiquidCrystal lcd(...)就会报错。第2部分对象初始化LiquidCrystal lcd(8, 7, 12, 11, 10, 9);这行代码在全局区域创建了一个名为lcd的对象。括号里的数字对应我们之前连接表格中的Arduino引脚RS8, E7, D412, D511, D610, D79。这是整个代码中与硬件关联最紧密的一行也是最容易出错的地方。我见过太多人因为这里写错一个数字而对着一块空白的屏幕调试半天。第3部分Setup()中的初始化lcd.begin(16, 2);在setup()函数中我们调用lcd对象的begin()方法。这个方法有两个参数列数和行数。对于我们的16×2屏幕就是16和2。这个函数执行了关键的硬件初始化序列将LCD设置为正确的工作模式。务必在setup()中调用且只调用一次。第4部分打印文字lcd.print(Hello World!);这是最直观的一行作用就是在当前光标位置默认是第0行第0列即左上角打印出引号内的字符串。print()方法是这个库最常用的函数它可以打印字符串、整数、浮点数等各种类型的数据。第5部分Loop()函数目前它是空的。对于只显示静态文本的项目loop()确实可以空着。但它的存在意味着可能性——你可以在这里让文字滚动、显示传感器读数、或者制作一个简单的动画。将这段代码上传到你的Arduino Uno。如果一切顺利你应该能看到屏幕上清晰地显示出“Hello World!”。但根据我的经验第一次尝试就完美显示的概率大概只有50%。更多时候你会遇到屏幕全亮、只显示白块、字符显示不全等问题。别担心这正是学习的一部分。5. 常见问题排查与深度调试指南当你满怀期待地上传代码却发现LCD屏没有按预期显示时请不要气馁。硬件项目的乐趣和挑战就在于此。下面我根据多年踩坑经验总结了一套从易到难的排查流程。第一步电源与背光检查这是最基础也最容易被忽略的。首先确认你的Arduino通过USB线或外部电源正常供电板载电源指示灯ON亮起。然后观察LCD屏屏幕完全无光检查VCC和GND是否接反或接触不良。检查背光引脚如果有是否连接。用万用表测量LCD的VCC和GND之间是否有5V电压。屏幕有均匀的背光全亮但无任何黑色字符这是最典型的现象。问题几乎肯定出在对比度VEE上。你连接的电位器可能没有调节到合适的电压。请缓慢旋转电位器在整个旋转范围内来回调节。正确的对比度下第一行的字符位置会隐约出现黑色小方块即使没有字符。如果无论如何调节都只有背光检查VEE引脚是否确实接到了电位器的中间滑动端电位器两端是否分别接在了5V和GND上。第二步软件与连接复查如果背光和对比度都正常但仍无显示或显示乱码进入软件和连接检查。核对代码引脚再次、仔细地核对代码LiquidCrystal lcd(8, 7, 12, 11, 10, 9);这一行中的每一个数字是否与你实际用杜邦线连接的Arduino引脚一一对应。一个数字错误就足以导致失败。检查杜邦线连接杜邦线接触不良是“玄学”问题的首要元凶。用手轻轻按压每个接口或者重新插拔一次。有条件的话使用万用表的通断档在断电状态下逐一检查每根线从Arduino引脚到LCD引脚的连通性。确认RW引脚接地确保LCD的RW引脚第5脚已经可靠地连接到GND。如果它悬空未连接LCD可能处于不稳定的读/写状态。第三步高级调试与逻辑分析如果以上步骤都无效你可能遇到了更隐蔽的问题。这时我们需要一些简单的调试代码。简化测试修改你的代码在setup()里只做初始化然后在loop()里反复执行清屏和打印并加入短暂延时。这可以排除初始化时序上的偶发问题。void loop() { lcd.clear(); lcd.setCursor(0,0); lcd.print(Test); delay(1000); }检查库与板卡类型确保在Arduino IDE的“工具”-“开发板”菜单中正确选择了“Arduino Uno”。如果你用的不是Uno比如Nano、Leonardo务必选择对应的型号。引脚冲突排查Arduino Uno的D0和D1引脚也用于串口通信USB。虽然我们的示例没有使用它们但如果你的项目后续使用了串口打印调试信息Serial.begin()要避免与LCD引脚冲突。不过更常见的是与内置LEDD13的冲突但我们的引脚列表避开了它。一个我亲身经历的坑有一次我使用的LCD屏型号比较老其初始化所需的延时比标准库预设的要长。在lcd.begin()之后立即打印字符会错位。解决方案是在begin()后加一个delay(100)给屏幕足够的准备时间。虽然这种情况不常见但它说明了一个道理库函数是通用封装而硬件个体可能有微小差异。当所有标准排查都无效时尝试增加延时有时会有奇效。6. 超越“Hello World”基础显示功能的探索成功显示“Hello World”只是一个开始。LiquidCrystal库提供了丰富的函数让你能真正控制这块屏幕。我们来探索几个最常用的功能让你的显示项目立刻生动起来。6.1 控制光标位置setCursor()默认情况下print()会从当前位置开始打印而初始位置是(0,0)。setCursor(col, row)函数可以让你将光标移动到任意位置。注意行列的索引都是从0开始。lcd.setCursor(0, 0); // 移动到第一行第一列 lcd.print(Line 1); lcd.setCursor(0, 1); // 移动到第二行第一列 lcd.print(Line 2); lcd.setCursor(5, 1); // 移动到第二行第六列 lcd.print(^);6.2 清屏与归位clear()和home()lcd.clear()清除屏幕上所有字符并将光标移回(0,0)。这个操作需要一定时间约2ms如果后续立即执行打印可以考虑加一个短暂的delay(2)。lcd.home()仅将光标移回(0,0)不清除屏幕内容。6.3 显示与关闭光标cursor()和noCursor()调用lcd.cursor()会在当前光标位置显示一个下划线“_”。调用lcd.noCursor()则关闭它。这常用于提示用户输入位置。lcd.cursor(); // 显示闪烁光标 delay(2000); lcd.noCursor(); // 关闭光标6.4 制作滚动效果库提供了两种滚动方式scrollDisplayLeft()和scrollDisplayRight()它们会将整个屏幕的内容向左或向右移动一格。你可以利用这个功能在loop()中结合delay()制作简单的跑马灯效果。void setup() { lcd.begin(16, 2); lcd.print(Hello Long Text!); } void loop() { delay(500); // 等待半秒 lcd.scrollDisplayLeft(); // 向左滚动一格 }更灵活的方式是你可以通过setCursor()和print()的组合自己实现字符串的截取和重绘来实现更复杂的滚动逻辑。6.5 显示自定义字符16×2 LCD内置了HD44780控制器它本身存储了一套标准的字符集类似于ASCII码。但更酷的是它允许你定义最多8个自定义的5x8点阵字符。你可以用它来显示简单的图标、标志或特殊符号。 步骤大致如下使用一个字节数组byte array来定义字符的点阵图。数组有8个元素每个元素对应一行从上到下每个元素的8个比特位中低5位对应这一行的5个像素点从左到右1表示点亮。使用lcd.createChar(num, data)函数将定义好的点阵数据注册到LCD的CGRAM自定义字符存储器中num是0-7的编号。使用lcd.write(num)来显示这个自定义字符。例如定义一个笑脸byte smiley[8] { B00000, B10001, B00000, B00000, B10001, B01110, B00000, }; void setup() { lcd.begin(16, 2); lcd.createChar(0, smiley); // 注册为0号自定义字符 lcd.setCursor(0,0); lcd.write(0); // 显示0号自定义字符即笑脸 }这个功能极大地扩展了LCD的表现力非常适合用于显示简单的状态图标。7. 项目进阶将LCD融入实际应用场景掌握了基础显示后我们可以尝试把LCD从一个演示设备变成一个真正有用的信息输出终端。这里我分享两个简单但实用的进阶思路它们能立刻让你感受到硬件编程的实用性。7.1 实时时钟与温度显示器这个项目需要额外添加一个DS3231高精度时钟模块和一个DHT11温湿度传感器。DS3231通过I2C接口与Arduino连接A4-SDA, A5-SCLDHT11使用一根数据线连接。LCD负责显示时间和温度。 核心逻辑在于loop()函数中定期比如每秒从传感器读取数据然后刷新LCD的特定位置。为了避免屏幕频繁闪烁我们只在数据发生变化时才更新显示。void loop() { DateTime now rtc.now(); // 从DS3231读取时间 float temp dht.readTemperature(); // 从DHT11读取温度 // 只在秒数变化或温度变化时更新显示 if (now.second() ! lastSecond) { lcd.setCursor(0,0); lcd.print(now.format(“%Y-%m-%d”)); lcd.setCursor(0,1); lcd.print(now.format(“%H:%M:%S”)); lastSecond now.second(); } if (abs(temp - lastTemp) 0.1) { // 温度变化超过0.1度才更新 lcd.setCursor(11,1); lcd.print(temp, 1); // 显示一位小数 lcd.print(“C”); lastTemp temp; } delay(200); // 短暂延时降低CPU占用 }这个项目的难点在于多库协同Wire库用于I2CRTClib用于时钟DHT sensor library用于温湿度和避免阻塞。delay()用得太长会影响响应太短又会无谓消耗资源。采用状态机或非阻塞定时如millis()是更优的方案。7.2 交互式菜单系统利用一个旋转编码器或几个按键配合LCD可以制作一个简单的菜单系统用于设置参数或选择功能。 例如用一个旋转编码器控制光标在菜单项间移动按一下编码器确认选择。LCD第一行显示菜单标题第二行显示当前选项。// 简化逻辑示例 int menuIndex 0; String menuItems[] {“Start”, “Settings”, “Info”, “Exit”}; void loop() { int encoderChange readEncoder(); // 读取编码器变化值 menuIndex constrain(menuIndex encoderChange, 0, 3); lcd.clear(); lcd.setCursor(0,0); lcd.print(“Main Menu”); lcd.setCursor(0,1); lcd.print(“ “); lcd.print(menuItems[menuIndex]); if (isButtonPressed()) { // 检测确认键 executeMenuItem(menuIndex); } delay(150); // 防抖延时 }这个项目的核心是状态管理。你需要清晰地定义每个菜单页面对应的状态以及状态之间如何切换。代码结构会变得比简单显示复杂但这是构建更复杂人机交互界面的基础。8. 性能优化与资源管理思考当你的项目变得越来越复杂可能会遇到屏幕响应慢、闪烁或者与其他任务冲突的问题。这时一些优化技巧就显得尤为重要。8.1 减少不必要的清屏操作lcd.clear()是一个比较耗时的操作而且会导致屏幕短暂闪烁。如果只是更新部分内容尽量使用setCursor()定位到特定位置然后用空格覆盖旧内容再打印新内容。例如更新一个数字// 不推荐清屏重绘 lcd.clear(); lcd.setCursor(0,0); lcd.print(“Value: “); lcd.print(newValue); // 推荐局部更新 lcd.setCursor(7,0); // “Value: “占了7个字符 lcd.print(” “); // 用空格覆盖旧值假设旧值最多4位 lcd.setCursor(7,0); lcd.print(newValue);8.2 使用非阻塞延时处理动态内容在loop()中使用delay()来控制滚动或刷新频率会阻塞整个程序导致无法响应其他输入如按钮。使用millis()函数进行非阻塞定时是标准做法。unsigned long previousMillis 0; const long interval 500; // 滚动间隔500ms void loop() { unsigned long currentMillis millis(); if (currentMillis - previousMillis interval) { previousMillis currentMillis; lcd.scrollDisplayLeft(); // 执行滚动 } // 这里可以同时执行其他任务如读取按钮状态 checkButton(); }8.3 考虑使用I2C LCD模块以节省引脚如前所述并行连接需要占用6-10个I/O引脚。对于需要连接多个传感器和执行器的项目引脚资源会非常紧张。一个完美的解决方案是使用带有I2C接口的LCD模块。这种模块在LCD背面集成了一个I2C转接板常用芯片如PCF8574你只需要连接4根线VCC, GND, SDA, SCL到Arduino就能通过I2C协议控制LCD。I2C总线可以挂载多个设备极大地节省了引脚。你需要安装额外的库如LiquidCrystal_I2C其编程接口与标准库非常相似初始化方式变为LiquidCrystal_I2C lcd(0x27, 16, 2);其中0x27是I2C地址可能需要扫描确认。8.4 处理长字符串与自动换行标准LiquidCrystal库的print()函数不会自动换行。如果你打印的字符串超过16个字符超出的部分会显示在第二行吗不会。它会从第一行第17列开始显示但屏幕上没有第17列所以实际上会从第二行第0列开始显示也不是。实际情况是HD44780控制器内部有一个40字节的显示缓冲区每行对应40个字符位置。对于16×2的屏我们只看到前16列。当你打印第17个字符时它进入了第一行缓冲区的第17位但物理屏幕不显示。只有当你打印到第41个字符时才会出现在第二行物理屏幕的第0列。这种行为非常反直觉。因此处理长字符串的最佳实践是手动管理使用String类的substring()方法截取或者用字符数组手动控制确保每行打印的内容不超过屏幕宽度并使用setCursor()明确指定换行位置。从点亮第一个“Hello World”到构建一个稳定的信息显示系统这中间每一步都充满了实践性的知识。硬件项目最大的特点就是“所见即所得”但也正是“所得非所见”时的调试过程最能锻炼解决问题的能力。希望这篇超详细的指南不仅能帮你点亮屏幕更能点亮你探索嵌入式世界的好奇心。记住每一个复杂的项目都是由无数个这样的“Hello World”叠加而成的。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号