版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/Angelia620/article/details/85123642
            </div><!--一个博主专栏付费入口--><!--一个博主专栏付费入口结束--><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><div class="htmledit_views" id="content_views"><p>最近2个月,有了写博客的习惯,有时候在查找文章资料的时候,看到对自己很有用的文章时,就会想转载一下,一开始找不到方法,就真的是一点一点的粘贴复制的,后来通过查找资料,再加上自己的思考。总结了一下步骤:</p>
  • 首先,在你感兴趣的文章上面,点击键盘上的F12。或者右键属性,点击“检查”(谷歌浏览器)
  • 然后在代码中找到“article_content”这一行代码。由于它藏的很深,我也是找了很久才找到,所以大家找的时候,直接就找最外面的<div class=container ·······>这一行代码,然后再去里面找目标代码。

  • 接下来点击这一行,鼠标右键,点击Copy Element

  • 接下来再打来你的CSDN的MarkDown编译器,再空白页面上鼠标右键,点击粘贴,文本就会被粘贴上面了

 

  • 最后,点击右上角的发不文章,填写信息之后,点击确定,即可发表成功

注意:文章类型一定要标注为“转载”,尊重作者的知识成果。

@[TOC](这

         <!--一个博主专栏付费入口结束--><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css"><div class="htmledit_views" id="content_views">

URL: http://jyqcxl122621.blog.163.com/blog/static/61323392201172392519647/

通过上一章的学习,我想你已经掌握了如何在程序中释放CPU了。希望能够继续坚持下去。一个良好的开始是成功的一半。我们今天所做的一切都是为了在单片机编程上做的更好。

在谈论今天的主题之前,先说下我以前的一些经历。在刚开始接触到C语言程序的时候,由于学习内容所限,写的程序都不是很大,一般也就几百行而矣。所以所有的程序都完成在一个源文件里面。记得那时候大一参加学校里的一个电子设计大赛,调试了一个多星期,所有程序加起来大概将近1000行,长长的一个文件,从上浏览下来都要好半天。出了错误简单的语法错误还好定位,其它一些错误,往往找半天才找的到。那个时候开始知道了模块化编程这个东西,也尝试着开始把程序分模块编写。最开始是把相同功能的一些函数(譬如1602液晶的驱动)全部写在一个头文件(.h)文件里面,然后需要调用的地方包含进去,但是很快发现这种方法有其局限性,很容易犯重复包含的错误。

而且调用起来也很不方便。很快暑假的电子设计大赛来临了,学校对我们的单片机软件编程进行了一些培训。由于学校历年来参加国赛和省赛,因此积累了一定数量的驱动模块,那些日子,老师每天都会布置一定量的任务,让我们用这些模块组合起来,完成一定功能。而正是那些日子模块化编程的培训,使我对于模块化编程有了更进一步的认识。并且程序规范也开始慢慢注意起来。此后的日子,无论程序的大小,均采用模块化编程的方式去编写。很长一段时间以来,一直有单片机爱好者在QQ上和我一起交流。有时候,他们会发过来一些有问题的程序源文件,让我帮忙修改一下。同样是长长的一个文件,而且命名极不规范,从头看下来,着实是痛苦,说实话,还真不如我重新给他们写一个更快一些,此话到不假,因为手头积累了一定量的模块,在完成一个新的系统时候,只需要根据上层功能需求,在底层模块的支持下,可以很快方便的完成。而不需要从头到尾再一砖一瓦的重新编写。藉此,也可以看出模块化编程的一个好处,就是可重复利用率高。下面让我们揭开模块化神秘面纱,一窥其真面目。

C语言源文件 *.c

提到C语言源文件,大家都不会陌生。因为我们平常写的程序代码几乎都在这个XX.C文件里面。编译器也是以此文件来进行编译并生成相应的目标文件。作为模块化编程的组成基础,我们所要实现的所有功能的源代码均在这个文件里。理想的模块化应该可以看成是一个黑盒子。即我们只关心模块提供的功能,而不管模块内部的实现细节。好比我们买了一部手机,我们只需要会用手机提供的功能即可,不需要知晓它是如何把短信发出去的,如何响应我们按键的输入,这些过程对我们用户而言,就是是一个黑盒子。

在大规模程序开发中,一个程序由很多个模块组成,很可能,这些模块的编写任务被分配到不同的人。而你在编写这个模块的时候很可能就需要利用到别人写好的模块的借口,这个时候我们关心的是,它的模块实现了什么样的接口,我该如何去调用,至于模块内部是如何组织的,对于我而言,无需过多关注。而追求接口的单一性,把不需要的细节尽可能对外部屏蔽起来,正是我们所需要注意的地方。

C语言头文件 *.h

谈及到模块化编程,必然会涉及到多文件编译,也就是工程编译。在这样的一个系统中,往往会有多个C文件,而且每个C文件的作用不尽相同。在我们的C文件中,由于需要对外提供接口,因此必须有一些函数或者是变量提供给外部其它文件进行调用。

假设我们有一个LCD.C文件,其提供最基本的LCD的驱动函数

LcdPutChar(char cNewValue) ;  //在当前位置输出一个字符

而在我们的另外一个文件中需要调用此函数,那么我们该如何做呢?

头文件的作用正是在此。可以称其为一份接口描述文件。其文件内部不应该包含任何实质性的函数代码。我们可以把这个头文件理解成为一份说明书,说明的内容就是我们的模块对外提供的接口函数或者是接口变量。同时该文件也包含了一些很重要的宏定义以及一些结构体的信息,离开了这些信息,很可能就无法正常使用接口函数或者是接口变量。但是总的原则是:不该让外界知道的信息就不应该出现在头文件里,而外界调用模块内接口函数或者是接口变量所必须的信息就一定要出现在头文件里,否则,外界就无法正确的调用我们提供的接口功能。因而为了让外部函数或者文件调用我们提供的接口功能,就必须包含我们提供的这个接口描述文件----即头文件。同时,我们自身模块也需要包含这份模块头文件(因为其包含了模块源文件中所需要的宏定义或者是结构体),好比我们平常所用的文件都是一式三份一样,模块本身也需要包含这个头文件。

下面我们来定义这个头文件,一般来说,头文件的名字应该与源文件的名字保持一致,这样我们便可以清晰的知道哪个头文件是哪个源文件的描述。

于是便得到了LCD.C的头文件LCD.h 其内容如下。

#ifndef    _LCD_H_

#define     _LCD_H_

extern   LcdPutChar(char cNewValue) ;

#endif

这与我们在源文件中定义函数时有点类似。不同的是,在其前面添加了extern 修饰符表明其是一个外部函数,可以被外部其它模块进行调用。

#ifndef     _LCD_H_

#define     _LCD_H_

#endif

这个几条条件编译和宏定义是为了防止重复包含。假如有两个不同源文件需要调用LcdPutChar(char cNewValue)这个函数,他们分别都通过#include “Lcd.h”把这个头文件包含了进去。在第一个源文件进行编译时候,由于没有定义过 _LCD_H_ 因此 #ifndef _LCD_H_ 条件成立,于是定义_LCD_H_ 并将下面的声明包含进去。在第二个文件编译时候,由于第一个文件包含时候,已经将_LCD_H_定义过了。因此#ifndef _LCD_H_ 不成立,整个头文件内容就没有被包含。假设没有这样的条件编译语句,那么两个文件都包含了extern  LcdPutChar(char cNewValue) ; 就会引起重复包含的错误。

不得不说的typedef

很多朋友似乎了习惯程序中利用如下语句来对数据类型进行定义

#define uint  unsigned int

#define uchar  unsigned char

然后在定义变量的时候 直接这样使用

uint  g_nTimeCounter = 0 ;

不可否认,这样确实很方便,而且对于移植起来也有一定的方便性。但是考虑下面这种情况你还会 这么认为吗?

#define PINT unsigned int *  //定义unsigned int 指针类型

PINT  g_npTimeCounter, g_npTimeState ;

那么你到底是定义了两个unsigned int 型的指针变量,还是一个指针变量,一个整形变量呢?而你的初衷又是什么呢,想定义两个unsigned int 型的指针变量吗?如果是这样,那么估计过不久就会到处抓狂找错误了。

庆幸的是C语言已经为我们考虑到了这一点。typedef 正是为此而生。为了给变量起一个别名我们可以用如下的语句

typedef  unsigned  int    uint16 ;    //给指向无符号整形变量起一个别名 uint16

typedef  unsigned  int  * puint16 ;  //给指向无符号整形变量指针起一个别名 puint16

在我们定义变量时候便可以这样定义了:

uint16    g_nTimeCounter  =  0 ;  //定义一个无符号的整形变量

puint16  g_npTimeCounter  ;    //定义一个无符号的整形变量的指针

在我们使用51单片机的C语言编程的时候,整形变量的范围是16位,而在基于32的微处理下的整形变量是32位。倘若我们在8位单片机下编写的一些代码想要移植到32位的处理器上,那么很可能我们就需要在源文件中到处修改变量的类型定义。这是一件庞大的工作,为了考虑程序的可移植性,在一开始,我们就应该养成良好的习惯,用变量的别名进行定义。

如在8位单片机的平台下,有如下一个变量定义

uint16    g_nTimeCounter  =  0 ;

如果移植32单片机的平台下,想要其的范围依旧为16位。

可以直接修改uint16 的定义,即

typedef  unsigned  short  int    uint16 ;

这样就可以了,而不需要到源文件处处寻找并修改。

将常用的数据类型全部采用此种方法定义,形成一个头文件,便于我们以后编程直接调用。

文件名 MacroAndConst.h

其内容如下:

#ifndef   _MACRO_AND_CONST_H_

#define   _MACRO_AND_CONST_H_

typedef    unsigned int    uint16;

typedef    unsigned int   UINT;

typedef    unsigned int   uint;

typedef    unsigned int   UINT16;

typedef    unsigned int   WORD;

typedef    unsigned int   word;

typedef      int        int16;

typedef      int        INT16;

typedef    unsigned long  uint32;

typedef    unsigned long     UINT32;

typedef    unsigned long    DWORD;

typedef    unsigned long    dword;

typedef    long            int32;

typedef    long            INT32;

typedef    signed  char     int8;

typedef    signed  char     INT8;

typedef    unsigned char      byte;

typedef    unsigned char     BYTE;

typedef    unsigned char     uchar;

typedef    unsigned char     UINT8;

typedef    unsigned char    uint8;

typedef    unsigned char    BOOL;

#endif

至此,似乎我们对于源文件和头文件的分工以及模块化编程有那么一点概念了。那么让我们趁热打铁,将上一章的我们编写的LED闪烁函数进行模块划分并重新组织进行编译。

在上一章中我们主要完成的功能是P0口所驱动的LED以1Hz的频率闪烁。其中用到了定时器,以及LED驱动模块。因而我们可以简单的将整个工程分成三个模块,定时器模块,LED模块,以及主函数

对应的文件关系如下

main.c

Timer.c  --?Timer.h

Led.c      --?Led.h

在开始重新编写我们的程序之前,先给大家讲一下如何在KEIL中建立工程模板吧,这个模板是我一直沿用至今。希望能够给大家一点启发。

下面的内容就主要以图片为主了。同时辅以少量文字说明。

我们以芯片AT89S52为例。

OK ,到此一个简单的工程模板就建立起来了,以后我们再新建源文件和头文件的时候,就可以直接保存到src文件目录下面了。

下面我们开始编写各个模块文件。

首先编写Timer.c 这个文件主要内容就是定时器初始化,以及定时器中断服务函数。其内容如下。

#include <reg52.h>

bit g_bSystemTime1Ms = 0 ;              // 1MS系统时标

void Timer0Init(void)

{

TMOD &= 0xf0 ;

TMOD |= 0x01 ;      //定时器0工作方式1

TH0  =    0xfc ;      //定时器初始值

TL0  =  0x66 ;

TR0  = 1 ;

ET0  = 1 ;

}

void Time0Isr(void) interrupt 1

{

TH0  =    0xfc ;            //定时器重新赋初值

TL0  =  0x66 ;

g_bSystemTime1Ms = 1 ;    //1MS时标标志位置位

}

由于在Led.c文件中需要调用我们的g_bSystemTime1Ms变量。同时主函数需要调用Timer0Init()初始化函数,所以应该对这个变量和函数在头文件里作外部声明。以方便其它函数调用。

Timer.h 内容如下。

#ifndef _TIMER_H_

#define _TIMER_H_

extern void Timer0Init(void) ;

extern bit g_bSystemTime1Ms ;

#endif

完成了定时器模块后,我们开始编写LED驱动模块。

Led.c 内容如下:

#include <reg52.h>

#include "MacroAndConst.h"

#include "Led.h"

#include "Timer.h"

static uint16  g_u16LedTimeCount = 0 ; //LED计数器

static uint8  g_u8LedState = 0 ;      //LED状态标志, 0表示亮,1表示熄灭

#define LED P0            //定义LED接口

#define LED_ON()      LED = 0x00 ;  //所有LED亮

#define LED_OFF()    LED = 0xff ;  //所有LED熄灭

void LedProcess(void)

{

if(0 == g_u8LedState)  //如果LED的状态为亮,则点亮LED

{

LED_ON() ;

}

else                //否则熄灭LED

{

LED_OFF() ;

}

}

void LedStateChange(void)

{

if(g_bSystemTime1Ms)            //系统1MS时标到

{

g_bSystemTime1Ms = 0 ;

g_u16LedTimeCount++ ;      //LED计数器加一

if(g_u16LedTimeCount >= 500) //计数达到500,即500MS到了,改变LED的状态。

{

g_u16LedTimeCount = 0 ;

g_u8LedState  = ! g_u8LedState    ;

}

}

}

这个模块对外的借口只有两个函数,因此在相应的Led.h 中需要作相应的声明。

Led.h 内容:

#ifndef _LED_H_

#define _LED_H_

extern void LedProcess(void) ;

extern void LedStateChange(void) ;

#endif

这两个模块完成后,我们将其C文件添加到工程中。然后开始编写主函数里的代码。

如下所示:

#include <reg52.h>

#include "MacroAndConst.h"

#include "Timer.h"

#include "Led.h"

sbit LED_SEG  = P1^4;  //数码管段选

sbit LED_DIG  = P1^5;  //数码管位选

sbit LED_CS11 = P1^6;  //led控制位

void main(void)

{

LED_CS11 = 1 ; //74HC595输出允许

LED_SEG = 0 ;  //数码管段选和位选禁止(因为它们和LED共用P0口)

LED_DIG = 0 ;

Timer0Init() ;

EA = 1 ;

while(1)

{

LedProcess() ;

LedStateChange() ;

}

}

整个工程截图如下

里写自定义目录标题)

欢迎使用Markdown编辑器

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片:

带尺寸的图片:

居中的图片:

居中并且带尺寸的图片:

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目

    • 项目

      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目 Value
电脑 $1600
手机 $12
导管 $1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列 第二列 第三列
第一列文本居中 第二列文本居右 第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPE ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to-HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ(n)=(n−1)!∀n∈N\Gamma(n) = (n-1)!\quad\forall n\in\mathbb NΓ(n)=(n−1)!∀n∈N 是通过欧拉积分

Γ(z)=∫0∞tz−1e−tdt.\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞​tz−1e−tdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06Mon 13Mon 20已完成 进行中 计划一 计划二 现有任务Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三李四王五你好!李四, 最近怎么样?你最近怎么样,王五?我很好,谢谢!我很好,谢谢!李四想了很长时间,文字太长了不适合放在一行.打量着王五...很好... 王五, 你怎么样?张三李四王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0开始我的操作确认?结束yesno
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

如何快速的转发别人的CSDN博客(转载)相关推荐

  1. 如何快速转载别人的CSDN博客文章并附带格式与图片

    1.问题背景 最近在学习Git过程中想了解git reflog命令的高级用法与命令详解,于是找到了这几篇特别优秀的文章: [1]使用git reflog 命令来查看历史提交记录并使用提交记录恢复已经被 ...

  2. 【工具】复制别人的CSDN博客文章到本地

    复制别人的CSDN博客文章到本地 操作流程 1.打开自己喜欢的博客的文章,然后同时按shift+ctrl+I三个键,打开开发者工具. 2.选择elements选项,按下面图片选择(chorme浏览器) ...

  3. 如何转载别人的csdn博客

    起意 看到一篇不错的博客,想转载但是不会(没有转载键),网搜发现没有Chrome浏览器的详细转载办法,受博主Bily猪启发,弄了这个教程,给小白的,大神勿嗤.时间紧急的直接看总结. 实践 检查.在喜欢 ...

  4. CSDN博客转载攻略

    1.在需要转载的CSDN博客页面右键,点击[检查] 谷歌浏览器F12 2.点击检查后,页面右侧出现html代码,如下图 3. 如果需要转载全文,则在html代码下侧点击选中article_conten ...

  5. 新版CSDN中如何快速转载别人的CSDN博客,详细方法与步骤!!!

    前言 作为DSCN博客用户小萌新,有可能自己写的博客还不够好,或者当看到别人写的特别好的博客时,就想转载(有些人可能会问:不是可以收藏吗?当然可以收藏,但是有些人也会想转载下载,不可能一个一个字再敲吧 ...

  6. 怎样取消关注别人的csdn博客

    今天不小心点错 关注了一个人的博客 可是怎么取消关注呢 找了半天 终于找到解决办法 0x01:     来到个人主页 (地址就是https://blog.csdn.net/用户名)      接着将鼠 ...

  7. 2018年CSDN博客排名第一名,花落谁家?

    截止2018年10月9日 https://blog.csdn.net/stpeace/ [小虎问题]: 通过搜索引擎例如:百度.搜狗.Bing等 如何快速搜索,定位谁是CSDN博客的第几名? 想知道谁 ...

  8. 如何快速转载CSDN博客(详细)

    转载CSDN博客步骤: 1.CSDN博客页面右键,点击[检查] 2.点击检查后,页面右侧出现html代码,如下图 3.点击写博客.点击左侧栏[博客设置] 4.选择MarkDown编辑器,保存 5.重新 ...

  9. 从CSDN博客到独立博客的蜕变

    近日受到CSDN博客运营密斯大白的邀请,他希望我能以CSDN博客专家的身份写一篇探讨CSDN博客和独立博客各自优劣的文章,因此就有了今天这篇文章,本文从我作为一名CSDN博客专家的角度阐述博客作者们在 ...

最新文章

  1. 关于整合spring+mybatis 第三种方式-使用注解
  2. 反Secure Boot垄断:兼谈如何在Windows 8电脑上安装Linux
  3. python glob.glob使用
  4. 7-181 最长连续递增子序列 (20 分)
  5. 6、宏定义与预处理、函数与函数库
  6. 0/0型极限等于多少_高数求极限的一些总结
  7. 如何通过蓝牙将PC与Windows Mobile 6的手持机连接,方便调试。
  8. 魔王语言解释器C语言,[数据结构]魔王语言解释c语言实现
  9. shiro中的过滤器
  10. 大咖面对面 | LOWB 志愿者视频首秀:普通不是我们放弃“折腾”的理由
  11. html5 lang属性都有哪些语言,HTML5中的lang属性,zh
  12. 【小迪安全】Day04基础入门-30 余种加密编码进制Web数据库系统代码参数值
  13. 盘点Scratch少儿编程的实用性
  14. 通用爬取文章及图片导出到Word主程序代码
  15. asynchronous aof fsync is taking too long (disk is busy?)
  16. Redis RU101课程 Introduction to Redis Data Structures 第5周学习笔记
  17. PHOTOSHOP超强磨皮大法 将斑点选出来
  18. Visual Studio 2017十五项新功能体验
  19. OSChina 周三乱弹 ——大变魔术啦,汪星人秒变熊孩子
  20. [原创发现]使用第三方crunch工具做java混淆字典,

热门文章

  1. 网易七鱼客服 发起客服-触发两条会话
  2. 免费素材:气球样式的图标集(PSD, SVG, PNG)
  3. 阿里云对象存储OSS(Object Storage Service)
  4. centos 安装yapi 详细教程
  5. 初学者都能学会的ElasticSearch入门实战《玩转ElasticSearch 2》
  6. 你们现在都用什么软件画原型?
  7. increment java_Java LongAdder increment()用法及代码示例
  8. 距离模糊与多普勒模糊
  9. App启动就闪退引发的深思
  10. SQL SERVER 服务器登录名、数据库用户名、服务器角色、数据库角色、DENY、sp_addlogin ETC.