当前位置: 首页 > news >正文

51单片机入门:DS1302时钟

51单片机内部含有晶振,可以实现定时/计数功能。但是其缺点有:精度往往不高、不能掉电使用等。 我们可以通过DS1302时钟芯片来解决以上的缺点。


DS1302时钟芯片

功能:DS1302是一种低功耗实时时钟芯片,内部有自动的计时功能,其范围包括:年、月、日、时、分、秒、星期。(且每个月的天数和闰年的天数可以内部自动调整)。

结构以及引脚定义

常见的DS1302时钟芯片有DIP(直插式)和SO(表贴式)两种封装 。

引脚定义
引脚名称功能
X1、X2DS1302外部晶振引脚,通常接32.768K晶振
VCC1备用电源,在主电源使用时可被充电
VCC2主电源供应管脚(与单片机共用一个电源)
GND电源地
CE使能端,也是复位引脚,在进行读写时CE要保持高电平
I/O串行数据输入或输出
SCLK串行时钟

通常通过单片机直接与CE、I/O、SCLK这3个引脚相连,控制其高低电平,进而控制DS1302时钟芯片。

DS1302电路图

其中,C2和C3为旁路电容,目的是消除晶振起振时产生的电感干扰。对于此电路,没有接入备用电池,可自行将外部备用电源接入VCC1。


 DS1302内部寄存器

控制寄存器

功能:通过给控制寄存器数据,来决定:进入年月日等具体哪一个寄存器、进行读/写操作。

 上图为控制寄存器样式。

最高位一直为1;

第6位:1表示RAM,寻址内部存储器;0为CK,寻址内部寄存器。

第5位~第1位:为年月日等日历寄存器的地址。

最低位:1表示下一步操作为“读”;0表示下一步操作为“写”。

日历/时钟寄存器

上图为年月日等相关寄存器的地址(绿框内)、功能等。以下对其进行详细说明:

相关寄存器的位说明
寄存器名称取值范围D7D6D5D4D3D2D1D0
秒寄存器00~59CH秒的十位秒的个位
分寄存器00~590分的十位分的个位
小时寄存器

1~12或

00~23

12小时制/

24小时制

0AM/PMHour小时的个位
日寄存器01~3100日的十位日的个位
月寄存器01~120001或0月的个位
星期寄存器01~070000星期几
年寄存器01~9920XX年的十位年的个位
写保护寄存器WP0000000

需特别注意以下部分:

秒寄存器:CH为DS1302的运行标志,当CH=0时,DS1302内部才能工作;当CH=1时,DS1302停止工作。

写保护寄存器:当WP为1时,DS1302只读不写。所以进行写操作时要确保WP为0。


 DS1302初始时间设置

举个例子,如果想将2024.05.04—周7—23:59:49这个时间写入DS1302内部,具体操作如下:

1、对0x8E地址操作,关闭写保护;

2、对秒寄存器0x80操作,写入0x49;

3、对分寄存器0x82操作,写入0x59;

4、对时寄存器0x84操作,写入0x23;

......以此类推,最后对0x8E地址操作,打开写保护。

BCD码

BCD码:用4位二进制数来表示1位十进制数。

例如:0001 0011表示13、1000 0101表示85、0001 1010不合法。

日历/时钟寄存器内部都是以BCD码来存放数据。因此要设置DS1302的时间,要写入BCD码格式。同时读取数据时,读到的也是BCD码,使用时需转换为对应十进制。

0000050101
1000160110
2001070111
3001181000
4010091001

 转换公式:

读写时序

前面提到:单片机与DS1302相连的线有3根,分别为:CE、SCLK和I/O引脚;如何通过这3根线进行数据写入和读出呢?

CE:初始化使其为低电平,在整个读写过程中,要保持高电平;一次读写操作完毕后,再回到低电平。

//  功能:DS1302初始化
void DS1302_Init(){DS1302_CE=0;    //使能端置0DS1302_SCLK=0;  //时钟脉冲置0
}

单字节写入:(先关闭写保护)当CE为高电平时,通过单片机控制SCLK产生脉冲,每一个上升沿,I/O线的数据就进入控制寄存器;当控制寄存器配置完成后,紧接着的I/O线数据会在上升沿时进入对应地址的寄存器。

/***@breaf DS1302单字节写入函数*@param command:写入命令字,包含要写入寄存器的地址;*@param Data:将要写入的数据内容;*@retval 无*/
void  DS1302_WriteBety(unsigned char command,Data)
{unsigned char i;DS1302_CE=1;//使能位置高电平;//设置控制寄存器for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入{DS1302_IO=command&(0x01<<i);DS1302_SCLK=1;  //给一个上升沿DS1302_SCLK=0;}//设置相关年月日寄存器for(i=0;i<8;i++)//数据写入{DS1302_IO=Data&(0x01<<i);DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0;	
}

单字节读出:当CE为高电平时,通过单片机控制SCLK产生脉冲,每一个上升沿,I/O线的数据就进入控制寄存器;当控制寄存器配置完成后,紧接着对应地址的寄存器数据会在下降沿时进入I/O线。

/***@breaf  DS1302单字节读出函数*@param command:写入控制指令的指令,包含要读出寄存器的地址;*@retval Data:读出的数据;*/
unsigned char   DS1302_ReadBety(unsigned char command)
{unsigned i,Data=0X00;command|=0X01;//写入指令与读出指令只在最后一位相差1,故在此利用或运算消除;DS1302_CE=1;//使能位置高电平;for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入{DS1302_IO=command&(0x01<<i);DS1302_SCLK=0;	DS1302_SCLK=1;}DS1302_IO=0;for(i=0;i<8;i++)//数据读出{DS1302_SCLK=1;DS1302_SCLK=0;			if(DS1302_IO)  {Data |=(0X01<<i);}}DS1302_CE=0;return Data;
}

注意数据输入从低位开始。


代码设计

main.c

#include <REGX52.H>
#include "lcd1602.h"//包含LCD1602头文件
#include "DS1302.h"//包含DS1302头文件
void main ()//定义主函数
{LCD_Init();	//LCD1602初始化DS1302_Init();//DS1302初始化LCD_ShowString(1,1,"  -  -  ");//设置年月日格式LCD_ShowString(2,1,"  :  :  ");//设置时分秒格式DS1302_SetTime();//设置时间,通过数组进行设置while(1){DS1302_ReadTime();//读取内部时间LCD_ShowNum(1,1,DS1302_Time[0],2);//显示年LCD_ShowNum(1,4,DS1302_Time[1],2);//显示月LCD_ShowNum(1,7,DS1302_Time[2],2);//显示日LCD_ShowNum(2,1,DS1302_Time[3],2);//显示时LCD_ShowNum(2,4,DS1302_Time[4],2);//显示分LCD_ShowNum(2,7,DS1302_Time[5],2);//显示秒LCD_ShowNum(2,13,DS1302_Time[6], 1);//显示星期}
}

DS1302.c

#include <REGX52.H>//引脚定义;
sbit  DS1302_SCLK=P3^6;
sbit  DS1302_IO=P3^4;
sbit  DS1302_CE=P3^5;//对应寄存器位置定义
#define  DS1302_SECOND		0X80
#define  DS1302_MINUTE  	0X82
#define  DS1302_HOUR		0X84
#define  DS1302_DATE        0X86
#define  DS1302_MONTH		0X88
#define  DS1302_DAY         0X8A
#define  DS1302_YEAR        0X8C
#define  DS1302_WP          0X8E //定义数组,用于存放设定的时间,年月日时分秒星期
unsigned char DS1302_Time[]={23,10, 28,19,00,59,6};//顺序:年月日时分秒星期
/***@breaf DS1302初始化*@param无*@retval无*/
void  DS1302_Init()
{DS1302_CE=0;//将使能位置0,低电平;DS1302_SCLK=0;//将时钟位置0,低电平;
}/***@breaf DS1302单字节写入函数*@param command:写入控制指令的指令,包含要写入寄存器的地址;*@param Data:将要写入的数据内容;*@retval 无*/
void  DS1302_WriteBety(unsigned char command,Data)
{unsigned char i;DS1302_CE=1;//使能位置高电平;for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入{DS1302_IO=command&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;DS1302_SCLK=1;DS1302_SCLK=0;}for(i=0;i<8;i++)//数据写入{DS1302_IO=Data&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;DS1302_SCLK=1;DS1302_SCLK=0;}DS1302_CE=0;	
}/***@breaf  DS1302单字节读出函数*@param command:写入控制指令的指令,包含要读出寄存器的地址;*@retval Data:读出的数据;*/
unsigned char   DS1302_ReadBety(unsigned char command)
{unsigned i,Data=0X00;command|=0X01;//写入指令与读出指令只在最后一位相差1,故在此利用或运算消除;DS1302_CE=1;//使能位置高电平;for(i=0;i<8;i++)//控制寄存器数据需要通过IO线一个一个写入控制寄存器;低位先写入{DS1302_IO=command&(0x01<<i);//相当于把第1--7位置0,只留第0位,如果第0位是0,则为0;反之则为1;DS1302_SCLK=0;	DS1302_SCLK=1;}DS1302_IO=0;for(i=0;i<8;i++)//数据读出{DS1302_SCLK=1;DS1302_SCLK=0;			if(DS1302_IO)  {Data |=(0X01<<i);}}DS1302_CE=0;return Data;
}/***@breaf 向DS1302内设定时间*@param无*@retval无*/
void DS1302_SetTime()
{DS1302_WriteBety(DS1302_WP,0x00);//操作 DS1302 之前,关闭写保护,不然指令无法进入控制寄存器;DS1302_WriteBety(DS1302_YEAR, DS1302_Time[0]/10*16+DS1302_Time[0]%10);//写入年,并将10进制转化BCD码;DS1302_WriteBety(DS1302_MONTH, DS1302_Time[1]/10*16+DS1302_Time[1]%10);//写入月,并将10进制转化BCD码;DS1302_WriteBety(DS1302_DATE, DS1302_Time[2]/10*16+DS1302_Time[2]%10);//写入日,并将10进制转化BCD码;DS1302_WriteBety(DS1302_HOUR, DS1302_Time[3]/10*16+DS1302_Time[3]%10);//写入时,并将10进制转化BCD码;DS1302_WriteBety(DS1302_MINUTE, DS1302_Time[4]/10*16+DS1302_Time[4]%10);//写入分,并将10进制转化BCD码;DS1302_WriteBety(DS1302_SECOND, DS1302_Time[5]/10*16+DS1302_Time[5]%10);//写入秒,并将10进制转化BCD码;DS1302_WriteBety(DS1302_DAY, DS1302_Time[6]/10*16+DS1302_Time[6]%10);//写入星期,并将10进制转化BCD码;DS1302_WriteBety( DS1302_WP,0x80);//写入结束,开启写保护;
}/**
*@breaf 读取DS1302内时间
*@param无
*@retval无
*/
void DS1302_ReadTime()	
{unsigned char Temp;//定义变量,用于暂时存储BCD码Temp=DS1302_ReadBety(DS1302_YEAR);//读取年BCD码;DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_MONTH);//读取月BCD码;DS1302_Time[1]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_DATE);//读取日BCD码;DS1302_Time[2]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_HOUR);//读取小时BCD码;DS1302_Time[3]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_MINUTE);//读取分钟BCD码;DS1302_Time[4]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_SECOND);//读取秒BCD码;DS1302_Time[5]=Temp/16*10+Temp%16;//BCD码转十进制;Temp=DS1302_ReadBety(DS1302_DAY);//读取星期BCD码;DS1302_Time[6]=Temp/16*10+Temp%16;//BCD码转十进制;
}

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__extern unsigned char DS1302_Time[];//声明设置时间的数组
void  DS1302_Init();//声明初始化函数
void  DS1302_WriteBety(unsigned char command,Data);//声明时间写入函数
unsigned char   DS1302_ReadBety(unsigned char command);//声明时间读出函数
void DS1302_SetTime();//声明设置内部时间函数
void DS1302_ReadTime();//声明读取内部时间函数#endif

相关文章:

51单片机入门:DS1302时钟

51单片机内部含有晶振&#xff0c;可以实现定时/计数功能。但是其缺点有&#xff1a;精度往往不高、不能掉电使用等。 我们可以通过DS1302时钟芯片来解决以上的缺点。 DS1302时钟芯片 功能&#xff1a;DS1302是一种低功耗实时时钟芯片&#xff0c;内部有自动的计时功能&#x…...

Redis-5 分布式锁

一.为什么要使用分布式锁&#xff1f; 传统的互斥锁synchronized只能作用于同一台虚拟机上的线程&#xff0c;在使用服务器集群部署的情况下&#xff0c;互斥锁就会失效&#xff0c;因此要采用分布式锁来处理不同服务器上的线程访问同一资源的情况。 二.redis的分布式锁是如何…...

音转文工具,9.8k star! 【送源码】

我们经常会遇到将音频转为文字的情况&#xff0c;比如在开会时录音的会议纪要、上课时录下的老师讲课内容。虽然网上也有一些在线的工具可以将音频转为文字&#xff0c;但是考虑到数据安全和费用问题&#xff0c;使用起来也不是很方便。 今天了不起给大家介绍一款开源工具——…...

【首次发布】华为 OD 机试 C卷抽中题库清单(真题库),目前华为OD机考以C卷为主,特殊情况会发送D卷

本篇博客为大家整理华为 OD 考友反馈 C 卷抽中题&#xff0c;经过 1 个的考友复盘&#xff0c;目前已经收录 100 题目&#xff0c;预计在有 2 周可以收集完整。 所有题目&#xff0c;都有考友截图反馈&#xff0c;同时欢迎大家机考过后&#xff0c;提供橡皮擦真题&#xff0c;获…...

【进程等待】waitpid的参数pid | status的位图位操作WIFEXITEDWEXITSTATUS宏

目录 waitpid pid status status位图 status按位操作 输入型参数和输入型参数 宏WIFEXITED&WEXITSTATUS options&非阻塞等待 上篇进程等待我们介绍到怎样去进程等待。我们介绍了wait函数&阻塞等待。本篇我们将介绍waitpid函数的参数pid和status。 waitp…...

unity---常用API

1. Vector3&#xff1a;结构体由x、y、z这3个数值组成&#xff0c;表示一个向量 magnitude变量返回该向量的长度normalized变量返回 magnitude 为 1 时的该向量zero静态变量Vector3(0, 0, 0)one静态变量Vector3(1, 1, 1)forward静态变量Vector3(0, 0, 1)back静态变量Vector3(0…...

设计模式: 模板模式

目录 一&#xff0c;模板模式 二&#xff0c;特点 三&#xff0c;组成部分 四&#xff0c;实现步骤 五&#xff0c;案例 一&#xff0c;模板模式 模板模式&#xff08;Template Pattern&#xff09;是一种行为型设计模式&#xff0c;它在超类中定义了一个算法的骨架&#…...

[虚拟机+单机]梦幻契约H5修复版_附GM工具

本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff01; 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行的&#xff0c;踩过的坑都给你们填上了 视频演示 [虚拟机单…...

头文件相互包含 前向声明

当两个类需要相互访问对方的成员或方法时&#xff0c;通常意味着它们之间存在某种依赖关系。这种依赖关系可能源于类的设计或功能需求。以下是一个简单的例子&#xff0c;展示了当两个类需要相互访问对方成员或方法时&#xff0c;如何使用包含对方头文件的方式来解决循环包含的…...

七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统

七款好用的上网行为管理软件推荐 |有没有好用的上网行为管理系统 员工上班刷视频&#xff01; 员工上班炒股&#xff01; 员工上班干副业&#xff01; 碰见这种情况怎么办&#xff1f;当然是用电脑监控软件来监视员工的一举一动了&#xff0c;那么这样的软件有哪些呢&#…...

centos7-bcc 安装

检查 内核信息 确保安装的kernel-dev 和内核版本一致!!! rpm -qa|grep kernel kernel-tools-3.10.0-1160.92.1.el7.x86_64 kernel-devel-3.10.0-1160.92.1.el7.x86_64 kernel-headers-3.10.0-1160.92.1.el7.x86_64 kernel-3.10.0-1160.92.1.el7.x86_64 kernel-tools-libs-3.1…...

5.06号模拟前端面试8问

5.06号模拟前端面试8问 1.promise如何实现then处理 在JavaScript中&#xff0c;Promise 是一个代表异步操作最终完成或失败的对象。它有三种状态&#xff1a;pending&#xff08;等待&#xff09;&#xff0c;fulfilled&#xff08;完成&#xff09;&#xff0c;rejected&…...

解读Inscode AI:开启代码智能化的新时代

导语&#xff1a; 近年来&#xff0c;人工智能技术的迅猛发展已经深刻地影响着各个行业&#xff0c;而在软件开发领域&#xff0c;Inscode AI的出现无疑将给代码智能化带来一场革命。本文将为大家解读Inscode AI的特点和应用&#xff0c;探索其如何改变我们的软件开发方式。 一…...

快速了解Vuex

Vuex Vuex使用Vuex Vuex &#x1f4cc;vuex 是一个专为 Vue.js 应用程序开发的状态管理库 &#x1f4cc;vuex 可以在多个组件之间共享数据&#xff0c;并且共享的数据是响应式的&#xff0c;即数据的变更能及时渲染到模板 &#x1f4cc;vuex 采用集中式存储管理所有组件的状态…...

vue管理系统导航中添加新的iconfont的图标

1.在官网上将需要的图标&#xff0c;加入项目中&#xff0c;下载 2.下载的压缩包中&#xff0c;可以选择这两个&#xff0c;复制到项目目录中 3.如果和之前的iconfont有重复&#xff0c;那么就重新命名 4.将这里的.ttf文件&#xff0c;也重命名为自己的 5.在main文件中导入 6.在…...

Docker的介绍及与传统虚拟化技术的区别

Docker是一个开源的应用容器引擎&#xff0c;它使得开发者可以将应用及其依赖包打包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上。Docker基于Go语言开发&#xff0c;它的出现极大地简化了应用程序的部署、管理和扩展。 以下是Docker…...

06.Git远程仓库

Git远程仓库 #仓库种类&#xff0c;举例说明 github gitlab gitee #以这个仓库为例子操作登录码云 https://gitee.com/projects/new 创建仓库 选择ssh方式 需要配置ssh公钥 在系统上获取公钥输入命令&#xff1a;ssh-keygen 查看文件&#xff0c;复制公钥信息内…...

Anaconda安装和深度学习环境的安装(TensorFlow、Pytorch)

换了新电脑&#xff0c;重新装一下anaconda这些编程环境。好久没装过了&#xff0c;自己也需要查查资料&#xff0c;然后记录一下&#xff0c;分享给别人。 目标&#xff0c;三个环境&#xff1a;1.anaconda基础环境&#xff08;包含xgboost和lightgbm&#xff09;&#xff0c…...

元素设置 flex:1,但是会被内部长单词宽度超出拉伸

初始布局如上图&#xff0c;left中是代码编辑器&#xff0c;实际上是个文本域&#xff0c;当输入长文本过长时&#xff0c;left宽度会被拉伸。 右侧容器被挤压。 解决方案&#xff1a;width&#xff1a;0&#xff1b; .left{flex:1; width:0} 当输入长文本过长时&#xff0c…...

win11 安装oracle11g详细流程及问题总结

1.安装包下载地址 本案例操作系统&#xff0c; Oracle 11g下载-Oracle 11g 64位/32位下载官方版(附详细的安装图解教程) - 多多软件站多多为大家免费提供Oracle 11g下载&#xff0c;包含64位/32位官方版本&#xff0c;并附详细的Oracle 11g安装图解教程&#xff0c;同时希望能…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

对象回调初步研究

_OBJECT_TYPE结构分析 在介绍什么是对象回调前&#xff0c;首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例&#xff0c;用_OBJECT_TYPE这个结构来解析它&#xff0c;0x80处就是今天要介绍的回调链表&#xff0c;但是先不着急&#xff0c;先把目光…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)

之前都是使用react-pdf来渲染pdf文件&#xff0c;这次有个需求是要兼容xp环境&#xff0c;xp上chrome最高支持到49&#xff0c;虽然说iframe或者embed都可以实现预览pdf&#xff0c;但为了后续的定制化需求&#xff0c;还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...