STC15单片机-数码管显示PCB板温度(TM1620驱动芯片使用介绍)
数码管显示PCB板温度、TM1620使用介绍
数码管驱动方式
单片机直接扫描:硬件设备简单,但会耗费大量的单片机CPU时间
专用驱动芯片:内部自带显存、扫描电路,单片机只需告诉它显示什么即可,如TM1620、TM1640
TM1620
TM1620是一种LED(发光二极管显示器)驱动控制专用IC,内部集成有MCU数字接口、数据锁存器、LED驱动等电路。多用于数码管或LED显示设备。
工作温度:-0.5V ~ +7.0V
特性说明
- 采用CMOS工艺
- 显示模式(8 段×6 位~10段×4位)
- 辉度调节电路(8 级占空比可调)
- 串行接口(CLK,STB,DIN)
- 振荡方式:内置RC振荡
- 内置上电复位电路
- 内置数据锁存电路
- 内置针对LED反偏漏电导致暗亮问题优化电路
- 抗干扰能力强
- 封装形式:SOP20
管脚定义
管脚功能
符号 | 管脚名称 | 管脚号 | 说明 |
---|---|---|---|
DIN | 数据输入 | 18 | 在时钟上升沿输入串行数据,从低位开始。 |
CLK | 时钟输入 | 19 | 在上升沿读取串行数据,下降沿输出数据。 |
STB | 片选输入 | 20 | 在下降沿初始化串行接口,随后等待接收指令。STB为低后的第一个字节作为指令,当处理指令时,当前其它处理被终止。当STB为高时,CLK 被忽略。 |
SGE1 ~SGE8 | 输出(段) | 2 ~ 9 | 段输出,P管开漏输出 |
GRID1 ~ GRID4 | 输出(位) | 16 ~ 17 、13 ~ 14 | 位输出,N管开漏输出 |
SEG13/GRID6 ~ SEG14/GRID5 | 输出(段/位) | 10 ~ 11 | 段/位复用输出,只能选段或位输出 |
VDD | 逻辑电源 | 1 | 接电源正 |
GND | 逻辑地 | 12、15 | 接系统地 |
硬件设计电路
DIG1、DIG2连接到了TM1620的位选引脚,分别是GRID1和GRID2,因为数码管就两个,就靠这两个位来进行控制
SEG1 ~ SEG8是段选,就是控制 A ~ DP 8个段哪一个段亮,8个位组成一个字节
STB、CLK、DIN是TM1620接收STC15单片机控制信号的,通过厂商定义的串行协议进行通信
串行通信
在进行通行前,要先将STB拉低,开启数据传输,CLK在低电平时,可以往DIN上放数据,当CLK在高电平时,TM1620就读取DIN上的数据,数据传输是从低位开始,一位一位地传,最高位结束
/*
* @name TM1620_Write_Byte
* @brief TM1620写入一个字节
* @param dat:待写入数据
* @retval None
*/
static void TM1620_Write_Byte(uint8_t dat)
{uint8_t i = 0;STB = 0;Public.Delay_ms(1);for(i=0;i<8;i++){//CLK为低电平时往DIN上放数据CLK = 0;DIN = 0x01 & (dat>>i); //先取出最低位进行发送,然后dat右移,把最低位移出去,再取补上地低位进行发送_nop_(); //延时1us//CLK为高电平时TM1620读取DIN上的数据CLK = 1;_nop_(); //延时1us}
}
通信命令
通过上面写好的TM1620_Write_Byte()函数,就可以往TM1620写入数据了,那TM1620怎么识别STC15传输过来的数据是要干嘛的呢?
厂商对TM1620也做了设置,来识别传输过来的数据的目的
简单理解:调用TM1620_Write_Byte()函数往TM1620写入一个字节数据,共8位,而TM1620就是根据最高的两位B7、B6来区别为不同的指令,如上表所示,4种不同的指令分别表示了不同的命令,而这命令的说明也是只有高手才能一眼看出是什么作用的,新手想弄懂还得花点时间
显示模式命令
B7、B6都为0的命令就是显示模式命令,这两位是固定的了,该模式下B5 ~ B2是没用的位,所以就剩下B1、B0来控制,是用来设置TM1620要控制多少位和多少段的,有4位10段,这说明有4个数码管,一个数码管里面有10个段要控制,用函数往TM1620写入0x00就表示设置显示模式为4位10段;
本次实验用的到是6位8段,但实战板数码管只有两个,就是由上面硬件电路图中的DIG1和DIG2位控制,其他的DIG位选引脚不接,8段就是SEG1 ~ SEG8段选全用上,写入0x02就是设置为6位8段
数据命令设置
B7为0,B6为1就是数据命令模式,B5和B4没有用到,靠B3 ~ B0来设置为不同的数据命令;
主要是地址增加模式设置,数据模式设置没用到,测试模式是厂商内部测试用的,做实验也没用到
自动地址增加:后面会介绍到显示寄存器,就是往显示寄存器写入一个地址初值,然后写入数据(要显示的段),每次写入一个字节数据后,地址指针会从初值自动加一,跳到下一个地址,可以不用再设置地址,直接写入数据;就只设置一次地址,可以连续写数据;
固定地址:先写入地址,再写入数据,写下一个数据前,要先再写入一个地址,就每次写数据前都要先写地址
显示控制命令
这个命令比较简单,就是用来设置数码管显示的亮度,B7为1,B6为0,B5和B4没用,用剩余位进行选择控制
亮度调整是用了PWM,是TM1620内部自动发出的PWM波,只要写入不同的命令就能控制输出不同的占空比,这不需要额外的控制线
注意B3是控制显示开关的,要数码管亮起来,B3必须为1,也就是设置脉冲宽度的命令中,B3都是1,如设置脉冲宽度为1/16,那写入的命令就是0x88;让数码管不亮,则B3位清0,写入的命令就是0x80
显示寄存器地址
我觉得在看地址命令设置之前,要先看懂显示寄存器地址的说明,所以先把显示寄存器地址解释一下
对这个显示寄存器的简单理解就是:数码管的位选,选择哪一个数码管亮起
GRID1 ~ GRID6 共6个位选引脚,一个位选引脚控制一个数码管;那数码管有可能接到GRID1,也有可能接到GRID6,当然也可以6个数码管分别接完6个GRID引脚,那想指定某一个数码管亮起来该怎么设置?这就要通过往TM1620写入上表中的地址数据来进行选择某一位选引脚
先看表右边的位选,再水平着向左看,HL(低四位)和HU(高四位)是对段选SEG来说的,和位选GRID的地址设置没关系,先不用管。
GRID1对应的地址是01和00,也就是说可以往TM1620写入0x01或者0x00来选择是GRID1这个位选引脚,那为什么两个地址都是选择这个位选引脚呢?因为地址00对应了SEG1 ~ SEG8这8个段选,地址01对应了SEG13和SEG14这两个段选(表的上半部分),因为TM1620是可以控制9段或者10段的,所以复用了SEG13和SEG14这两个段选引脚;但本次实验中的数码管是8段的,分别接到了SEG1 ~ SEG8,而位选引脚接到了GRID1,所以位选就是GRID1,再根据段选,GRID1的地址就设置为0x00,没有用到SEG13和SEG14,所以不用管0x01;其他位选引脚同理
而图片开头的文字说明说12个字节单元也能理解了,就6个位选,每个位选对应两种不同的地址,6 * 2 = 12,所以是12个字节单元
这就相当于一步把位选和段选都确定了,因为确定位选引脚后,那也要确定段选引脚吧,段选选好后,后续再写入数据控制哪几个段亮起,就可以显示数字了
地址命令设置
经过上面的显示寄存器地址解释,就可以理解这个地址命令设置是什么东西了;上面的位选地址00和01等的地址怎么来,就是在这里进行设置的
B7、B6固定都为1,B3 ~ B0不同的组合就表示不同的地址,这些地址在程序中最好先用宏定义写好,在后面想设置位选和段选时,就直接把这些地址写入到TM1620就行了;可以说这些地址就是为了设置显示寄存器而准备的
前面介绍的都是一些命令或地址,TM1620收到了这些命令会做出相应的设置,把这些命令都通过TM1620_Write_Byte()函数发送给TM1620即可,数码管就会亮起;那具体怎么个发送法呢,厂商也给出了通信的图示,如下面介绍到的
数据传输(地址自动增加模式)
按照厂商给的这个数据传输图,首先在STB为低电平时,才开始往DIN上发送命令,每一步命令是设置什么的图上有说明,注意每次传输完一个命令后,STB要拉高,下次发送命令时要先再次拉低再发送命令;在发送段选数据的时候STB就不用再拉高了
注意:TM1620的数据手册上有这样一句话:芯片显示寄存器在上电瞬间其内部保存的值可能是随机不确定的,此时客户直接发送开屏命令,将有可能出现显示乱码。所以我司建议客户对显示寄存器进行一次上电清零操作,即上电后向12位显存地址(00H-0BH)中全部写入数据0x00
清零操作就可以设置为地址自动增加模式,然后写入位选初始地址是0x00,从GRID1开始,然后用循环不断写入段选数据0x00,进行清零操作,后续代码中有这一步
数据传输(固定地址模式)
固定地址模式就是每次写入段选数据前都要先确定位选,而且写完段选数据后STB要拉高,写下一个位选地址时STB要再次拉低
程序
文件结构
main.c ->主函数文件,包含main函数等;
Public.c ->公共函数文件,包含Delay延时函数等;
Sys_init ->系统初始化函数,包含GPIO初始化函数等;
ADC.c ->ADC初始化,采集ADC值等;
NTC.c ->NTC外设函数,包含查表,获取环境温度等;
TM1620.c ->驱动IC初始化,协议,温度显示等函数;
实验现象
每间隔 500ms 通过ADC获取一次PCB板温度,数码管显示PCB板温度,数码管亮度会自动变化。
TM1620.h
主要是定义4种不同命令的枚举类型,将所有的十六进制的命令都写成能看懂的名称,不然在c文件里发送0x00根本不知道是什么命令,还得去看手册
#ifndef __TM1620_H_
#define __TM1620_H_//显示模式枚举类型
typedef enum
{Disp_Mode_GRID4_SEG10 = 0x00, //4位10段Disp_Mode_GRID5_SEG9 = 0x01, //5位9段Disp_Mode_GRID6_SEG8 = 0x02 //6位8段
}Disp_Mode_t;//写数据地址模式枚举类型
typedef enum
{Write_Data_Addr_Auto_Add = 0x40, //自动地址增加Write_Data_Addr_Fix = 0x44 //固定地址
}Write_Data_Addr_Mode_t;//辉度等级枚举类型
typedef enum
{Brightness_level_0 = 0x80, //显示关Brightness_level_1 = 0x88, //脉冲宽度为1/16Brightness_level_2 = 0x89, //脉冲宽度为2/16Brightness_level_3 = 0x8A, //脉冲宽度为4/16Brightness_level_4 = 0x8B, //脉冲宽度为10/16Brightness_level_5 = 0x8C, //脉冲宽度为11/16Brightness_level_6 = 0x8D, //脉冲宽度为12/16Brightness_level_7 = 0x8E, //脉冲宽度为13/16Brightness_level_8 = 0x8F, //脉冲宽度为14/16
}Brightness_level_t;//显示寄存器地址枚举类型 —> 位选GRID的地址
typedef enum
{Disp_SFR_Addr_Num = (uint8_t)12,Disp_SFR_Addr_00H = 0xC0, Disp_SFR_Addr_01H = 0xC1,Disp_SFR_Addr_02H = 0xC2,Disp_SFR_Addr_03H = 0xC3,Disp_SFR_Addr_04H = 0xC4,Disp_SFR_Addr_05H = 0xC5,Disp_SFR_Addr_06H = 0xC6,Disp_SFR_Addr_07H = 0xC7,Disp_SFR_Addr_08H = 0xC8,Disp_SFR_Addr_09H = 0xC9,Disp_SFR_Addr_0AH = 0xCA,Disp_SFR_Addr_0BH = 0xCB,
}Disp_SFR_Addr_t;//定义结构体类型
typedef struct
{Brightness_level_t Brightness; //辉度变量void (*TM1620_Init)(); //TM1620初始化void (*Disp_Tempareture)(); //数码管显示温度
}TM1620_t;/* extern variables-----------------------------------------------------------*/
extern TM1620_t idata TM1620;
/* extern function prototypes-------------------------------------------------*/ #endif
/********************************************************End Of File
********************************************************/
TM1620.c
实现三个函数,第一个是TM162通过串行通行发送一个字节的函数,要注意STB拉低后要适当延时,不然数据通信会出错;
第二个函数是TM1620的初始化,先设置为地址自动增加,然后循环写入0x00清零显示寄存器,然后再设置为固定地址模式,给左右两个数码管初始化为全亮;
第三个函数是读取温度值并显示,把浮点型的温度值先转为整型,再分别取出十位和个位,分别显示在左边和右边的数码管上
注意:TM1620_Write_Byte()函数只是在TM1620.c文件里使用,并不提供给外部使用,所以不用声明函数指针指向该函数
/* Includes ------------------------------------------------------------------*/
#include <main.h>/* Private define-------------------------------------------------------------*/
#define DIN P24
#define CLK P25
#define STB P26//左右两个数码管显示寄存器地址宏定义
#define Disp_Position_Left Disp_SFR_Addr_00H
#define Disp_Position_Right Disp_SFR_Addr_02H
/* Private variables----------------------------------------------------------*/
uint8_t Disp_SEG[10] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //数码管显示0 ~ 9static void TM1620_Write_Byte(uint8_t );
static void TM1620_Init();
static void Disp_Tempareture();
/* Public variables-----------------------------------------------------------*/
TM1620_t idata TM1620 =
{Brightness_level_3,TM1620_Init,Disp_Tempareture
};
/* Private function prototypes------------------------------------------------*//*
* @name TM1620_Write_Byte
* @brief TM1620写入一个字节
* @param dat:待写入数据
* @retval None
*/
static void TM1620_Write_Byte(uint8_t dat)
{uint8_t i = 0;STB = 0;Public.Delay_ms(1); //需要加延时等待,不然数码管显示会出异常for(i=0;i<8;i++){//CLK为低电平时往DIN上放数据CLK = 0;DIN = 0x01 & (dat>>i); //先取出最低位进行发送,然后dat右移,把最低位移出去,再取补上地低位进行发送_nop_(); //延时1us//CLK为高电平时TM1620读取DIN上的数据CLK = 1;_nop_(); //延时1us}
}/*
* @name TM1620_Init
* @brief TM1620初始化
* @param None
* @retval None
*/
static void TM1620_Init()
{uint8_t i = 0;//设置显示模式:6位8段TM1620_Write_Byte(Disp_Mode_GRID6_SEG8);STB = 1;//设置地址模式:自动地址增加TM1620_Write_Byte(Write_Data_Addr_Auto_Add);STB = 1;//清除显示寄存器,厂商要求TM1620_Write_Byte(Disp_SFR_Addr_00H);for(i=0;i<Disp_SFR_Addr_Num;i++){TM1620_Write_Byte(0x00);}STB = 1;//显示默认辉度:level3TM1620_Write_Byte(TM1620.Brightness);STB = 1;//设置显示模式:6位8段TM1620_Write_Byte(Disp_Mode_GRID6_SEG8);STB = 1;//设置地址模式:固定地址TM1620_Write_Byte(Write_Data_Addr_Fix);STB = 1;//写显示寄存器//先设置位选,设置为左边的数码管,再写入段选的数据0xFF,数码管8个段全亮TM1620_Write_Byte(Disp_Position_Left);TM1620_Write_Byte(0xFF);STB = 1;//然后设置位选为右边的数码管,同样写入段选数据0xFF,8个段全亮TM1620_Write_Byte(Disp_Position_Right);TM1620_Write_Byte(0xFF);STB = 1;//显示辉度TM1620_Write_Byte(TM1620.Brightness);STB = 1;
}/*
* @name Disp_Tempareture
* @brief 数码管显示温度
* @param None
* @retval None
*/
static void Disp_Tempareture()
{uint8_t temp = 0;//因为获取到的温度是浮点型,而数码管只有两位,不够显示,所以要转为无符号整型数据temp = (uint8_t)NTC.fTemperature;TM1620_Write_Byte(Disp_Position_Left); //选择左边的数码管TM1620_Write_Byte(Disp_SEG[temp/10]); //取出温度值的十位作为下标去找段码表对应的段选数据STB = 1;TM1620_Write_Byte(Disp_Position_Right); //选择右边的数码管TM1620_Write_Byte(Disp_SEG[temp%10]); //取出温度值的个位作为下标去找段码表对应的段选数据STB = 1;//显示辉度TM1620_Write_Byte(TM1620.Brightness);STB = 1;
}
/********************************************************End Of File
********************************************************/
main.c
主函数中先预编译串口打印初始化信息,然后while循环内不断获取温度值,再调用TM1620的Disp_Tempareture()函数来在数码管上显示两位温度值;
用switch语句来切换数码管的辉度,数码管的亮度就会一节一节地从暗到亮
/*
* @name main
* @brief 主函数
* @param void
* @retval int
*/
int main(void)
{//系统初始化Hradware.Sys_Init();//串口1发送初始化信息#ifdef Monitor_Run_Codeprintf("Initialization completed,system startup!\r\n\r\n");#endif//系统主循环while(1){NTC.Get_Temperature_Value();Public.Delay_ms(500);//数码管显示温度TM1620.Disp_Tempareture();//调整亮度switch (TM1620.Brightness){case Brightness_level_1:TM1620.Brightness = Brightness_level_2;break;case Brightness_level_2:TM1620.Brightness = Brightness_level_3;break;case Brightness_level_3:TM1620.Brightness = Brightness_level_4;break;case Brightness_level_4:TM1620.Brightness = Brightness_level_5;break;case Brightness_level_5:TM1620.Brightness = Brightness_level_6;break;case Brightness_level_6:TM1620.Brightness = Brightness_level_7;break;case Brightness_level_7:TM1620.Brightness = Brightness_level_8;break;case Brightness_level_8:TM1620.Brightness = Brightness_level_1;break;default:TM1620.Brightness = Brightness_level_1;break;}Public.Delay_ms(500);}
}
/********************************************************End Of File
********************************************************/
出现问题
如果定义函数指针指向TM1620_Write_Byte()函数,那在TM1620初始化和显示温度的函数中全都用TM1620.TM1620_Write_Byte()的形式来调用该函数往TM1620写数据的话,烧录后数码管是没有亮的;
但只要把任意一个TM1620.TM1620_Write_Byte()改为TM1620_Write_Byte(),即本来通过函数指针调用的,改为直接用函数名调用,烧录后数码管居然是可以亮的;或者全部改为直接用函数名也是可以亮
找了几个小时也没发现问题出在哪,这种现象也是第一次遇见,按理说通过函数指针调用和直接用函数名调用是没有区别的,但为什么在这个实验中就出现问题,而且还只要改其中任意一个就行,改了之后数码管就显示了,说明两种调用方式都可以用,混着用也行,说明代码逻辑是没有问题的
另外我把教程的代码也全改为了用函数指针调用,也是不亮的,网上也没查到这个问题,只能留着以后再看看有什么解决办法了
TM1620.h
//定义结构体类型
typedef struct
{Brightness_level_t Brightness;void (*TM1620_Write_Byte)(uint8_t); //指向TM1620初始化函数的函数指针void (*TM1620_Init)();void (*Disp_Tempareture)();
}TM1620_t;
TM1620.c
TM1620_t idata TM1620 =
{Brightness_level_3,TM1620_Write_Byte, TM1620_Init,Disp_Tempareture
};//函数指针调用方式,全部使用这种调用方式,则数码管不亮
TM1620.TM1620_Write_Byte();//函数名调用方式,只要有一个函数名调用方式,则数码管能亮
TM1620_Write_Byte();
看教程时注意的点
驱动数码管也可以用三极管,但这样就需要单片机不断的进行扫描才能显示,使用专用的IC,如TM1620,就能实现自动扫描并显示
项目的TM1620显示模式命令设置是6位8段
根据TM1620的手册将寄存器的值进行定义封装,32的库就类似这样,不用每次使用时都要去看手册配寄存器
TM1620也相当于一个小MCU,也有自己的寄存器,STC15MCU通过串行协议与TM1620进行通信,对TM1620内部寄存器进行配置,让TM1620自动工作
当写很多地址时,选用地址增加模式,当写一两个地址时,选用固定地址模式
TM1620写入字节函数是内部函数,不需要被其他函数调用,所以不用写在结构体里
单片机引脚P24、P25、P26设置为开漏输出,因为这是给一个信号,不是进行驱动,如果要驱动的话,就要设置为推挽输出,输出信号控制的话,开漏和准双向口都可以
显示寄存器地址:GRID是位选,SEG是段选,根据硬件电路,第一个数码管接到了GRID1上,并且用到了SEG1 ~ SEG8,并没有用到SEG13和SEG14,所以GRID1的地址就是00H,GRID2同理
GRID位选最多是6个,每一个位选可以选择SEG1 ~SEG8 或者SEG13 ~SEG14两种段选,该两种段选所对应的GRID位选寄存器的地址又是不同的,两种段选不能一起使用,所以便有6 x 2 = 12个位选的地址
TM1620会根据写入数据的首两位判断为不同的命令
STC15单片机-数码管显示PCB板温度(TM1620驱动芯片使用介绍)相关推荐
- 单片机数码管显示热敏电阻实测温度,
51单片机开发板,功能模块独立性高,能够实现各种各样的功能.本文中,主要使用热敏电阻和数码管完成了对环境实时温度的显示. (实验所用的51单片机开发板) 在实现功能时,我们需要了解热敏电阻测温度的原理 ...
- 51单片机数码管显示60秒倒计时(C语言)
51单片机数码管显示60秒倒计时(C语言) 基于普中51单片机开发板,运用定时器/计数器0和1,实现60秒的倒计时和LED灯0.5s间隔闪烁 文章目录 51单片机数码管显示60秒倒计时(C语言) 前言 ...
- 基于51单片机数码管显示
基于51单片机数码管显示 ## 数码管显示原理 数码管(LED Segment Displays)由多个发光二极管封装在一起组成"8"字型的器件,引线已在内部连接完成,只需引出它们 ...
- STC51单片机数码管显示程序和仿真
STC51单片机数码管显示程序和仿真 仿真使用的数码管时共阴极 1.共阳: char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92
- 单片机c语言数码管显示5,51单片机数码管显示实验报告(5页)-原创力文档
51单片机数码管显示实验 实验内容: 编写程序让8只数码管初始显示0,每隔大约1s加1显示(可以用延时函数实现),到数码管显示9后,再从0开始显示,如此循环反复. C语言程序 #include #de ...
- 【Proteus仿真】STC15单片机 + DS1302 + LCD1602显示时间
[Proteus仿真]STC15单片机 + DS1302 + LCD1602显示时间 Proteus仿真 本来想通过轮询方式读取DS1302秒时间的变化来刷新LCD1602显示的,但是这种方式在STC ...
- 【Proteus仿真】STC15单片机+LCD1602驱动显示时间(DEMO)示例
[Proteus仿真]STC15单片机+LCD1602驱动显示时间(DEMO)示例 Proteus仿真 Proteus加载 STC15单片机说明 在Proteus里面唯一能找到的 STC15一款支持仿 ...
- #普中51开发板# 52单片机数码管显示5201314
74HC138真值表(H高,L 低,倒着数) #include<reg52.h> #include<intrins.h> #define LED P0 typedef unsi ...
- 51单片机数码管显示
一.数码管静态显示 1.原理:数码管无非就是八块发光二极管集成在 了一起,如右图所示,数码管有共阴极 和共阳极数码管之分. 共阴极数码管:将八只发光二极管的负极通过一 根总线连接在了一起 , 然后每只 ...
- 蓝桥杯单片机 数码管显示
第二章 数码管显示 文章目录 第二章 数码管显示 前言 一.数码管原理图 二.数码管静态显示与动态显示 1.数码管知识点 2.数码管段码 3.数码管静态显示 4.数码管动态显示 三.代码实现 总结 ...
最新文章
- 商淘多b2b2c商城系统怎么在个人电脑上安装_B2B2c商城系统怎么选?开源和定制哪个好?...
- linux 脚本continue,shell中的break和continue
- android封装aidl接口,Android远端接口AIDL及服务回调用法
- 中国水银矿石行业市场供需与战略研究报告
- 核PCA与PCA的精髓和核函数的映射实质
- Python学习笔记020——数据库基本操作
- Android下最简单的AudioTrack播放PCM的例子
- 提升 10 倍!阿里云对象存储 OSS 可用性 SLA 技术揭秘
- ArcGIS之定义投影
- 计算机工作原理--时钟概念
- matlab误码率理论,PSK理论误码率与实际误码率MATLAB仿真程序
- 笔记整理之 寒门难出贵子1 正传
- Docker一键部署MySQL
- TADF的发展史前景概念,热活化延迟荧光(TADF)材料的未来发展
- drf路由组件Routers
- mongodb误删数据该如何恢复
- python与r语言处理excel数据_R语言 | 读写txt、csv、excel文件
- 《上海市工业互联网创新发展专项支持实施细则》政策解读
- 查看Python的版本_查看当前安装Python的版本
- 推荐五款免费且优质的自学网站,你值得拥有