0%

概述

SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一种同步串行接口技术,是一种高速的,全双工,同步的通信总线。

优缺点

特点

  1. 高速、同步、全双工、非差分、总线式
  2. 主从机通信模式

优点

  1. 支持全双工通信
  2. 通信简单
  3. 数据传输速率块

缺点

  1. 没有指定的流控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据
  2. 可靠性上有一定的缺陷。

协议详解

它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选)。

  1. SDO/MOSI – 主设备数据输出,从设备数据输入;
  2. SDI/MISO – 主设备数据输入,从设备数据输出;
  3. SCLK – 时钟信号,由主设备产生;
  4. CS/SS – 从设备使能信号,由主设备控制。当有多个从设备的时候,因为每个从设备上都有一个片选引脚接入到主设备机中,当我们的主设备和某个从设备通信时将需要将从设备对应的片选引脚电平拉低或者是拉高。

mark

SPI通信有4种不同的模式,不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来控制我们主设备的通信模式,具体如下:

  1. Mode0:CPOL=0,CPHA=0
  2. Mode1:CPOL=0,CPHA=1
  3. Mode2:CPOL=1,CPHA=0
  4. Mode3:CPOL=1,CPHA=1

时钟极性CPOL是用来配置SCLK的电平出于哪种状态时是空闲态或者有效态,时钟相位CPHA是用来配置数据采样是在第几个边沿:

  1. CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
  2. CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时
  3. CPHA=0,表示数据采样是在第1个边沿,数据发送在第2个边沿
  4. CPHA=1,表示数据采样是在第2个边沿,数据发送在第1个边沿

例如:

CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。

CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。

mark

mark

需要注意的是:我们的主设备能够控制时钟,因为我们的SPI通信并不像UART或者IIC通信
那样有专门的通信周期,有专门的通信起始信号,有专门的通信结束信号;所以我们的
SPI协议能够通过控制时钟信号线,当没有数据交流的时候我们的时钟线要么是
保持高电平要么是保持低电平。

协议对比

spi 与 iic

  1. iic总线不是全双工,2根线SCL SDA。spi总线实现全双工,4根线SCK CS MOSI MISO

  2. iic总线是多主机总线,通过SDA上的地址信息来锁定从设备。spi总线只有一个主设备,主设备通过CS片选来确定从设备

  3. iic总线传输速度在100kbps-4Mbps。spi总线传输速度更快,可以达到30MHZ以上。

  4. iic总线空闲状态下SDA SCL都是高电平。spi总线空闲状态MOSI MISO也都是 SCK是有CPOL决定的

  5. iic总线scl高电平时sda下降沿标志传输开始,上升沿标志传输结束。spi总线cs拉低标志传输开始,cs拉高标志传输结束

  6. iic总线是SCL高电平采样。spi总线因为是全双工,因此是沿采样,具体要根据CPHA决定。一般情况下master device是SCK的上升沿发送,下降沿采集

  7. iic总线和spi总线数据传输都是MSB在前,LSB在后(串口是LSB在前)

  8. iic总线和spi总线时钟都是由主设备产生,并且只在数据传输时发出时钟

  9. iic总线读写时序比较固定统一,设备驱动编写方便。spi总线不同从设备读写时序差别比较大,因此必须根据具体的设备datasheet来实现读写,相对复杂一些。

SPI、IIC、UART和CAN 使用场景对比

SPI 和I2C这两种通信方式都是短距离的,芯片和芯片之间或者其他元器件如传感器和芯片之间的通信。 SPI和IIC是板上通信,IIC有时也会做板间通信,不过距离甚短,不过超过一米,例如一些触摸屏,手机液晶屏那些薄膜排线很多用IIC,I2C能用于替代标准的并行总线,能连接的各种集成电路和功能模块。I2C是多主控总线,所以任何一个设备都能像主控器一样工作,并控制总线。总线上每一个设备都有一个独一无二的地址,根据设备它们自己的能力,它们可以作为发射器或接收器工作。多路微控制器能在同一个I2C总线上共存这两种线属于低速传输。

UART是应用于两个设备之间的通信,如用单片机做好的设备和计算机的通信。这样的通信可以做长距离的。UART速度比上面两者者快,最高达100K左右,用与计算机与设备或者计算机和计算之间通信,但有效范围不会很长,约10米左右,UART优点是支持面广,程序设计结构很简单,随着USB的发展,UART也逐渐走向下坡。

CAN使用场景完全不一样:

  1. CAN 通讯距离最大是10 公里(设速率为5Kbps),或最大通信速率为1Mbps(设通信距离为40 米)。
  2. CAN 总线上的节点数可达110 个。通信介质可在双绞线,同轴电缆,光纤中选择。
  3. CAN 采用非破坏性的总线仲裁技术,当多个节点同时发送数据时,优先级低的节点会主动退出发送,高优先级的节点可继续发送,节省总线仲裁时间。
  4. CAN 是多主方式工作,网上的任一节点均可在任意时刻主动地向网络上其他节点发送信息。
  5. CAN 采用报文识别符识别网络上的节点,从而把节点分成不同的优先级,高优先级的节点享有传送报文的优先权。报文是短帧结构,短的传送时间使其受干扰概率低,CAN 有很好的效验机制,这些都保证了CAN 通信的可靠性。

主类 次类 用途
折线图 折线图 用于反应和时间相关的数据变化(趋势)。
面积图 用于反应主次之间基于时间的对比。
柱状图 柱状图 分类项目的数量比较。也能反应趋势。
条形图 分类项目的数量比较。
环状条形图 分类项目的数量比较。更能反应项目之间的数量关系。
南丁格尔玫瑰图 以夸张的形式来表示分类项目的数量对比
饼状图 饼状图 反映分类数据反占比例
旭日图 表示比例对比的同时,也表示层次关系
对状图 表示比例,可以多层线。
散点图 散点图 反应相关性和分布关系,两个变量
气泡图 反应相关性和分布关系,三个变量
带线散点 趋势线
地图 地图 反应空间信息
其它图 股价图/箱线图 反映数据分散情况
直方图 反映数据分布
瀑布图 数量变化的过程

设置窗口标题

1
setWindowTitle("Touch Screen"); 

设置窗口固定大小

1
setFixedSize(QT_WINDOW_WIDTH_FOR_TOUCH, QT_WINDOW_HEIGHT_FOR_TOUCH);

设置窗口显示在另外一个显示器上

1
2
3
4
5
QDesktopWidget* desktop = QApplication::desktop();
if (desktop->screenCount() > 1)
{
setGeometry(desktop->screenGeometry(1));
}

在非主线程更新显示

1
QMetaObject::invokeMethod(this, "asyncUpdateGui", Qt::QueuedConnection);

其中 asyncUpdateGui 的定义:

1
2
private slots:
Q_INVOKABLE void asyncUpdateGui();

实现:

1
2
3
4
void xApplicationWindow::asyncUpdateGui()
{
update();
}

解决 package ‘fontconfig’ not found

Whenever you get messages about missing packages (or suggestions to modify your PKG_CONFIG_PATH) during a build, it usually indicates that you are missing the corresponding development package - which is typically separate from the runtime package that is normally installed on the system.

In this case you have the most recent version of fontconfig but are probably missing the corresponding libfontconfig1-dev package.

正确的解决方法是安装:libfontconfig1-dev

WOL through Telnet/SSH

Note: This is the preferred method to send WOL magic packets remotely.

If you have local or remote Telnet/SSH access to your router, you can wake up a machine on the LAN by using the following command:

1
/usr/sbin/wol -i 192.168.1.255 -p PP AA:BB:CC:DD:EE:FF

Note that the full path to “/usr/sbin/wol” is important. Simply “wol” will not work.

Substitute AA:BB:CC:DD:EE:FF with the actual MAC address of the computer which you wish to boot remotely. Likewise, replace 192.168.1.255 with the actual broadcast address of the network (192.168.1.255 is the broadcast address when the machine has an IP of 192.168.1.x and subnet mask of 255.255.255.0). Replace “PP” with the port number your machine listens on (usually 7 or 9).

1
/usr/sbin/wol -i 192.168.1.255 -p 9 24:5E:BE:32:C8:EB

页眉与页脚

iText5中并没有之前版本HeaderFooter对象设置页眉和页脚,可以利用PdfPageEventHelper来完成页眉页脚的设置工作。PdfPageEventHelper中包含以下事件处理器。

1
2
3
4
5
onOpenDocument() — 当打开一个文档时触发,可以用于初始化文档的全局变量。
onStartPage() — 当一个页面初始化时触发,可用于初始化页面的设置参数,但是注意这个函数触发时,该页面并没有创建好,不用利用这个函数添加内容,最好利用onEndPage()处理页面的初始化。
onEndPage() — 在创建一个新页面完成但写入内容之前触发,是添加页眉、页脚、水印等最佳时机。
onCloseDocument() — 在文档关闭之前触发,可以用于释放一些资源。
onCloseDocument() — 在文档关闭之前触发,可以用于释放一些资源。

要想出发事件需要在程序中添加事件

如下

1
2
PdfReportM1HeaderFooter footer=new PdfReportM1HeaderFooter();
writer.setPageEvent(footer);

该类PdfReportM1HeaderFooter继承自PdfPageEventHelper所以可以直接添加、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

package demo;

/**
* Project Name:report
* File Name:PdfReportM1HeaderFooter.java
* Package Name:com.riambsoft.report.pdf
* Date:2013-9-16上午08:59:00
* Copyright (c) 2013, riambsoft All Rights Reserved.
*
*/

import java.io.IOException;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;

/**
* ClassName:PdfReportM1HeaderFooter <br/>
* Function: TODO ADD FUNCTION. <br/>
* Reason: TODO ADD REASON. <br/>
* Date: 2013-9-13 上午08:59:00 <br/>
*
* @author 落雨
* @version 394263788(QQ)
* @since JDK 1.5
* @see http://hi.baidu.com/ae6623
*/
public class PdfReportM1HeaderFooter extends PdfPageEventHelper {

/**
* 页眉
*/
public String header = "";

/**
* 文档字体大小,页脚页眉最好和文本大小一致
*/
public int presentFontSize = 12;

/**
* 文档页面大小,最好前面传入,否则默认为A4纸张
*/
public Rectangle pageSize = PageSize.A4;

// 模板
public PdfTemplate total;

// 基础字体对象
public BaseFont bf = null;

// 利用基础字体生成的字体对象,一般用于生成中文文字
public Font fontDetail = null;

/**
*
* Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.
*
*/
public PdfReportM1HeaderFooter() {

}

/**
*
* Creates a new instance of PdfReportM1HeaderFooter 构造方法.
*
* @param yeMei 页眉字符串
* @param presentFontSize 数据体字体大小
* @param pageSize 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
*/
public PdfReportM1HeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) {
this.header = yeMei;
this.presentFontSize = presentFontSize;
this.pageSize = pageSize;
}

public void setHeader(String header) {
this.header = header;
}

public void setPresentFontSize(int presentFontSize) {
this.presentFontSize = presentFontSize;
}

/**
*
* TODO 文档打开时创建模板
*
* @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter,
* com.itextpdf.text.Document)
*/
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
}

/**
*
* TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
*
* @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter,
* com.itextpdf.text.Document)
*/
public void onEndPage(PdfWriter writer, Document document) {

try {
if (bf == null) {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
}
if (fontDetail == null) {
fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

// 1.写入页眉
ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail),
document.left(), document.top() + 20, 0);

// 2.写入前半部分的 第 X页/共
int pageS = writer.getPageNumber();
String foot1 = "第 " + pageS + " 页 /共";
Phrase footer = new Phrase(foot1, fontDetail);

// 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
float len = bf.getWidthPoint(foot1, presentFontSize);

// 4.拿到当前的PdfContentByte
PdfContentByte cb = writer.getDirectContent();

// 自己增加的
if (pageS == 1) {
Phrase footerLeft = new Phrase("978-1-4799-0530-031.00 ©2013 IEEE", fontDetail);
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, footerLeft, document.left(), document.bottom() - 20, 0);
}

// 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
// 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了
// ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer,
(document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F
+ 20F,
document.bottom() - 20, 0);

// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F + len , y
// 轴和之前的保持一致,底边界-20
cb.addTemplate(total,
(document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F,
document.bottom() - 20); // 调节模版显示的位置

}

/**
*
* TODO 关闭文档时,替换模板,完成整个页眉页脚组件
*
* @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter,
* com.itextpdf.text.Document)
*/
public void onCloseDocument(PdfWriter writer, Document document) {
// 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
total.beginText();
total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
String foot2 = " " + (writer.getPageNumber() - 1) + " 页";
total.showText(foot2);// 模版显示的内容
total.endText();
total.closePath();
}
}

页边距

Isn’t it possible for you to use HtmlConverter#convertToElements method. It returns List as a result and then you can add its elements to a document with set margins:

1
2
3
4
5
6
7
Document document = new Document(pdfDocument);
List list = HtmlConverter.convertToElements(new FileInputStream(htmlSource));
for (IElement element : list) {
if (element instanceof IBlockElement) {
document.add((IBlockElement) element);
}
}

Another approach: in your html just introduce the @page rule which sets the margins you need, for example:

1
@page {margin: 0;}

Yet another solution: implement your own custom tag worker for  tag and set margins on its level. For example, to set zero margins one could create tag the next worker:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CustomTagWorkerFactory extends DefaultTagWorkerFactory {
public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) {
if (TagConstants.HTML.equals(tag.name())) {
return new ZeroMarginHtmlTagWorker(tag, context);
}
return null;
}
}
public class ZeroMarginHtmlTagWorker extends HtmlTagWorker {
public ZeroMarginHtmlTagWorker(IElementNode element, ProcessorContext context) {
super(element, context);
Document doc = (Document) getElementResult();
doc.setMargins(0, 0, 0, 0);
}
}

and pass it as a ConverterProperties parameter to Htmlconverter:

converterProperties.setTagWorkerFactory(new CustomTagWorkerFactory());
HtmlConverter.convertToPdf(new File(htmlPath), new File(pdfPath), converterProperties);

表格跨页问题

代码的处理方式

pdfHtml的一种处理方式

I had a similar issue of trying to keep together content within a div. I applied the following css property and this kept everything together. This worked with itext7 pdfhtml.

1
page-break-inside: avoid;

PdfPage转换成图片

生成image对象

https://stackoverflow.com/questions/37809019/itext7-pdf-to-image

Please read the official documentation for iText 7, more specifically Chapter 6: Reusing existing PDF documents
In PDF, there’s the concept of _Form XObject_s. A Form XObject is a piece of PDF content that is stored outside the content stream of a page, hence XObject which stands for eXternal Object. The use of the word Form in Form XObject could be confusing, because people might be thinking of a form as in a fillable form with fields. To avoid that confusing, we introduced the term PdfTemplate in iText 5.
The class PdfImportedPage you refer to was a subclass of PdfTemplate: it was a piece of PDF syntax that could be reused in another page. Over the years, we noticed that people also got confused by the word PdfTemplate.
In iText 7, we returned to the basics. When talking about a Form XObject, we use the class PdfFormXObject. When talking about a page in a PDF file, we use the class PdfPage.
This is how we get a PdfPage from an existing document:

1
2
PdfDocument origPdf = new PdfDocument(new PdfReader(src));
PdfPage origPage = origPdf.getPage(1);

This is how we use that page in a new document:

1
2
PdfDocument pdf = new PdfDocument(new PdfWriter(dest));
PdfFormXObject pageCopy = origPage.copyAsFormXObject(pdf);

If you want to use that pageCopy as an Image, just create it like this:

1
Image image = new Image(pageCopy);

存成图片(验证了这种方法不可行)

https://stackoverflow.com/questions/24940813/saving-com-itextpdf-text-image-as-a-image-file
Just convert the Barcode39 itext image into an AWT image using createAwtImage:

1
java.awt.Image awtImage = code39.createAwtImage(Color.BLACK, Color.WHITE);

Then convert it to a BufferedImage and store it:

1
2
3
4
5
6
BufferedImage bImage= new BufferedImage(awtImage.getWidth(), awtImage.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g = bImage.createGraphics();
g.drawImage(awtImage, 0, 0, null);
g.dispose();
File outputfile = new File("saved.png");
ImageIO.write(bImage, "jpg", new File("code39.jpg"));

回顾

之前在阿里云上花钱买了一个网页空间,用了好几年,刚开始还挺好的,但最近半年,完全不能用。频繁刷新都能被关黑屋。还遇到有人恶意访问。

今天终于花时间弄清楚了 github + hexo + next + travis-ci 的blog组合。

搞清楚了hexo 的 tags 和 categories 的启用方法。

从目前的情况来说,与之前的 wordpress 对比,显示完美,当然写作没有之前的方便。

还支持 https,并且 github 技术加持,不担心被人恶意黑掉。自己的域名也能完美支持。

总之,blog 重新复活。

如何快速创建一个github个人网站?

克隆一个已经存在的网站:),比如我这个网站。然后把source目录中的内容删除掉。在调整一下自己的配置就可以了。

hexo blog 如何创建404页面

有两种方法:

  1. 可以自己创建一个 404.html 页面直接放到 source 目录下面。

  2. 也可以在 source 目录下面创建一个 404 的文件夹, 然后面在里面创建一个 index.md 的文件。 可以使用这个命令创建 hexo new page "404"

图床如何用?

  1. 七牛的不错,可以绑定自己的域名。做好备份,如果那天免费不能用了,换地方应该也不需要在文章里面改链接。

  2. 还有一个自动上传的工作可用。 MPic官方网址:http://mpic.lzhaofu.cn

问题

在Windows 10下面,按住中键,拔动小红点,页面滚动的同时,光标也会一起跑。控制面板中也找不到设置的地方。

解决方案

需要修改注册表:
在HKEY_CURRENT_USER\Software\Synaptics\SynTPEnh\UltraNavPS2中,把TrackPointModeFunction的值修改一下即可。
原为:”TrackPointModeFunction”=dword:00000011
改为:”TrackPointModeFunction”=dword:00000010
这样就跟以前使用完全相同了,中键点击是小手或指针,滚动是鼠标中键滚动的图标,一切完美。

docker create \ –name=transmission \ -e PUID=1000 \ -e PGID=1000 \ -e TZ=Europe/London \ -e TRANSMISSION_WEB_HOME=/combustion-release/ #optional \ -p 9091:9091 \ -p 51413:51413 \ -p 51413:51413/udp \ -v /share/homes/docker/trans/data:/config \ -v /share/homes/docker/trans/downloads:/downloads \ -v /share/homes/docker/trans/watch:/watch \ –restart unless-stopped \ linuxserver/transmission

1
keep-together.within-page
  1. auto是默认形为, 写不写都是一样的。

  2. always是强制在一页中。如果当前限制的内容超过一页时,会从页面下方溢出。

  3. 指定一个数字。测试 1 的形为是这样的:会换页将当前内容保持在一页中。但如果当前内容超过一页时,也会将多余的内容显示到下一页中,保证不会将内容溢出到纸的外面。

https://www.w3.org/TR/xsl11/#keep-together