-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
300 lines (145 loc) · 153 KB
/
atom.xml
File metadata and controls
300 lines (145 loc) · 153 KB
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Varocol's Blog</title>
<link href="https://www.varocol.top/atom.xml" rel="self"/>
<link href="https://www.varocol.top/"/>
<updated>2021-10-19T11:45:47.447Z</updated>
<id>https://www.varocol.top/</id>
<author>
<name>Varocol</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>【EASYX配置教程】在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)</title>
<link href="https://www.varocol.top/2021/10/20/%E5%9C%A8VScode%E4%B8%AD%E4%BD%BF%E7%94%A8EASYX%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B(VScode+MSVC+EasyX)/"/>
<id>https://www.varocol.top/2021/10/20/%E5%9C%A8VScode%E4%B8%AD%E4%BD%BF%E7%94%A8EASYX%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B(VScode+MSVC+EasyX)/</id>
<published>2021-10-19T19:13:07.000Z</published>
<updated>2021-10-19T11:45:47.447Z</updated>
<content type="html"><![CDATA[<p>众所周知,vscode是一款强大的IDE,深受广大码友喜爱,博主曾尝试过用它实现各种脱离特定平台的写码,这里给大家介绍vscode配置EASYX的详细教程。</p><hr><h2 id="1-配置MSVC编译环境"><a href="#1-配置MSVC编译环境" class="headerlink" title="1.配置MSVC编译环境"></a>1.配置MSVC编译环境</h2><p>首先要知道的是EASYX官方库只支持vs的编译器,不支持MinGW,除非是自己从github上下的代码重新编译过的并且封装的库。<br>可以借鉴一下其他优秀博主的教程,这里不详细介绍。<br><a href="https://blog.csdn.net/heilone6688/article/details/91050508">参考教程1</a><br><a href="https://blog.csdn.net/qq_38981614/article/details/99629597">参考教程2</a></p><blockquote><p>教程2没有包含vs的库,所以每次编译都要从vs的develop模式进入,有些麻烦,但是教程2的配置文件写的很详细,大家可以结合着看。如果配置文件有问题的话,博主下面会贴配置文件的代码</p></blockquote><hr><h2 id="2-安装EASYX"><a href="#2-安装EASYX" class="headerlink" title="2.安装EASYX"></a>2.安装EASYX</h2><p><a href="https://easyx.cn/">EASYX链接</a><br>官网界面如下:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)/images/20201206191846751.png" style="zoom:200%;" /><br>下载完直接安装(前提是你电脑要有vs系列,其实在安装MSVC环境的时候就已经应该有了)</p><hr><h2 id="3-EASYX文件路径的调整"><a href="#3-EASYX文件路径的调整" class="headerlink" title="3.EASYX文件路径的调整"></a>3.EASYX文件路径的调整</h2><p>如果你用easyx的软件安装的话,头文件和库文件会放在如下文件夹:<br>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\VS\lib\x64<br>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\VS\include<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E5%9C%A8VScode%E4%B8%AD%E4%BD%BF%E7%94%A8EASYX%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B(VScode+MSVC+EasyX)/images/20201209170208553.png"><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E5%9C%A8VScode%E4%B8%AD%E4%BD%BF%E7%94%A8EASYX%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B(VScode+MSVC+EasyX)/images/20201209170345319.png"><br>但实际上我们环境变量包含的库文件路径和头文件路径是在tools文件夹下的:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E5%9C%A8VScode%E4%B8%AD%E4%BD%BF%E7%94%A8EASYX%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B(VScode+MSVC+EasyX)/images/20201209170700525.png"><br>而easyx的头文件和库文件并不在tools文件夹下,所以我需要做个迁移工作;<br>把C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\VS\lib\x64下的EasyXa.lib和EasyXw.lib复制到C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\lib\x64下,相应的,把C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\VS\include文件夹下的easyx.h和graphics.h复制到C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\include,这样以后系统就能找到easyx的文件了。</p><hr><h2 id="4-划重点!!VScode各种json的配置"><a href="#4-划重点!!VScode各种json的配置" class="headerlink" title="4.划重点!!VScode各种json的配置"></a>4.划重点!!VScode各种json的配置</h2><p>如果之前你的MSVC环境配置好的话,并且能正常编译C++/C的代码的话,4个json文件的样子大概如下(已经安装MSVC环境还没安装EASYX的代码),大家如果配置文件不会配的话直接复制下面的代码也行,有些目录需要根据实际情况写入。</p><h3 id="这里提醒一个常识:launch-json中的preLaunchTask参数和task-json中的label参数必须要对应,因为task是任务,launch想要调取任务两个名字就要相对应。"><a href="#这里提醒一个常识:launch-json中的preLaunchTask参数和task-json中的label参数必须要对应,因为task是任务,launch想要调取任务两个名字就要相对应。" class="headerlink" title="这里提醒一个常识:launch.json中的preLaunchTask参数和task.json中的label参数必须要对应,因为task是任务,launch想要调取任务两个名字就要相对应。"></a>这里提醒一个常识:launch.json中的preLaunchTask参数和task.json中的label参数必须要对应,因为task是任务,launch想要调取任务两个名字就要相对应。</h3><p><em><strong>launch.json</strong></em></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs json">{<br> <span class="hljs-comment">// 使用 IntelliSense 了解相关属性。 </span><br> <span class="hljs-comment">// 悬停以查看现有属性的描述。</span><br> <span class="hljs-comment">// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387</span><br> <span class="hljs-attr">"version"</span>: <span class="hljs-string">"0.2.0"</span>,<br> <span class="hljs-attr">"configurations"</span>: [<br> {<br> <span class="hljs-attr">"name"</span>: <span class="hljs-string">"cl.exe - 生成和调试活动文件"</span>,<br> <span class="hljs-attr">"type"</span>: <span class="hljs-string">"cppvsdbg"</span>,<br> <span class="hljs-attr">"request"</span>: <span class="hljs-string">"launch"</span>,<br> <span class="hljs-attr">"program"</span>: <span class="hljs-string">"${fileDirname}\\${fileBasenameNoExtension}.exe"</span>,<br> <span class="hljs-attr">"args"</span>: [],<br> <span class="hljs-attr">"stopAtEntry"</span>: <span class="hljs-literal">false</span>,<br> <span class="hljs-attr">"cwd"</span>: <span class="hljs-string">"${workspaceFolder}"</span>,<br> <span class="hljs-attr">"environment"</span>: [],<br> <span class="hljs-attr">"externalConsole"</span>: <span class="hljs-literal">true</span>,<br> <span class="hljs-attr">"preLaunchTask"</span>: <span class="hljs-string">"C/C++: cl.exe build active file"</span><br> }<br> ]<br>}<br></code></pre></td></tr></table></figure><p><em><strong>c_cpp_properties.json</strong></em></p><figure class="highlight clojure"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs clojure">{<br> <span class="hljs-string">"configurations"</span>: [<br> {<br> <span class="hljs-string">"name"</span>: <span class="hljs-string">"Win32"</span>,<br> <span class="hljs-string">"includePath"</span>: [<br> <span class="hljs-string">"${workspaceFolder}/**"</span><br> ],<br> <span class="hljs-string">"defines"</span>: [<br> <span class="hljs-string">"_DEBUG"</span>,<br> <span class="hljs-string">"UNICODE"</span>,<br> <span class="hljs-string">"_UNICODE"</span><br> ],<br> <span class="hljs-string">"windowsSdkVersion"</span>: <span class="hljs-string">"10.0.18362.0"</span>,<br> <span class="hljs-string">"compilerPath"</span>: <span class="hljs-string">"C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29333/bin/Hostx64/x64/cl.exe"</span>,<br> //cl.exe文件的目录要自己找,我这个是装的vs2019community版本,具体目录要根据你的情况,可以参考上面教程<span class="hljs-number">2</span>的配置方式<br> <span class="hljs-string">"cStandard"</span>: <span class="hljs-string">"c17"</span>,,<br> <span class="hljs-string">"cppStandard"</span>: <span class="hljs-string">"c++17"</span>,<br> <span class="hljs-string">"intelliSenseMode"</span>: <span class="hljs-string">"msvc-x64"</span><br> }<br> ],<br> <span class="hljs-string">"version"</span>: <span class="hljs-number">4</span><br>}<br></code></pre></td></tr></table></figure><p><em><strong>settings.json</strong></em></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs json">{<br> <span class="hljs-attr">"files.associations"</span>: {<br> <span class="hljs-attr">"iostream"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"algorithm"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"chrono"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"codecvt"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"forward_list"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"functional"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"istream"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"limits"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"list"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"memory_resource"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"random"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"regex"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"utility"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"vector"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xhash"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xlocale"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xmemory"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xstring"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xtree"</span>: <span class="hljs-string">"cpp"</span>,<br> <span class="hljs-attr">"xutility"</span>: <span class="hljs-string">"cpp"</span><br> },<br> <span class="hljs-attr">"C_Cpp.dimInactiveRegions"</span>: <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><p><em><strong>最重要的task.json</strong></em></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><code class="hljs json">{<br><span class="hljs-attr">"version"</span>: <span class="hljs-string">"2.0.0"</span>,<br><span class="hljs-attr">"tasks"</span>: [<br>{<br><span class="hljs-attr">"type"</span>: <span class="hljs-string">"cppbuild"</span>,<br><span class="hljs-attr">"label"</span>: <span class="hljs-string">"C/C++: cl.exe build active file"</span>,<br><span class="hljs-attr">"command"</span>: <span class="hljs-string">"cl.exe"</span>,<br><span class="hljs-attr">"args"</span>: [<br><span class="hljs-string">"/Zi"</span>,<br><span class="hljs-string">"/EHsc"</span>,<br><span class="hljs-string">"/Fe:"</span>,<br><span class="hljs-string">"${fileDirname}\\${fileBasenameNoExtension}.exe"</span>,<br><span class="hljs-string">"${file}"</span><br>],<br><span class="hljs-attr">"options"</span>: {<br><span class="hljs-attr">"cwd"</span>: <span class="hljs-string">"${workspaceFolder}"</span><br>},<br><span class="hljs-attr">"problemMatcher"</span>: [<br><span class="hljs-string">"$msCompile"</span><br>],<br><span class="hljs-attr">"group"</span>: <span class="hljs-string">"build"</span>,<br><span class="hljs-attr">"detail"</span>: <span class="hljs-string">"compiler: cl.exe"</span><br>}<br>]<br>}<br></code></pre></td></tr></table></figure><p>如果安装EASYX成功后你的vs应该可以索引到graphics.h这个文件:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)/images/20201206193823672.png" style="zoom:200%;" /><br>如果你就这样直接调试用EASYX的代码就会出现如下情况:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)/images/20201206194223713.png" style="zoom:200%;" />经典的VS link2019问题<br>这是因为你少了把lib链接起来的命令<br>所以我们只要修改task.json就可以了</p><h2 id="这里强调一下在type里的那个参数默认生成的是”cppbuild”-要给它改成”shell”!!-这个是关键)"><a href="#这里强调一下在type里的那个参数默认生成的是”cppbuild”-要给它改成”shell”!!-这个是关键)" class="headerlink" title="这里强调一下在type里的那个参数默认生成的是”cppbuild”,要给它改成”shell”!!!(这个是关键)"></a>这里强调一下在type里的那个参数默认生成的是”cppbuild”,要给它改成”shell”!!!(这个是关键)</h2><p><em><strong>task.json</strong></em></p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><code class="hljs json">{<br> <span class="hljs-attr">"version"</span>: <span class="hljs-string">"2.0.0"</span>,<br> <span class="hljs-attr">"tasks"</span>: [<br> {<br><span class="hljs-attr">"type"</span>:<span class="hljs-string">"shell"</span>,<span class="hljs-comment">//不要用"cppbuild"!!!</span><br> <span class="hljs-attr">"label"</span>: <span class="hljs-string">"C/C++: cl.exe build active file"</span>,<br> <span class="hljs-attr">"command"</span>: <span class="hljs-string">"cl.exe"</span>,<br> <span class="hljs-attr">"args"</span>: [<br> <span class="hljs-string">"/EHsc"</span>,<br><span class="hljs-string">"/Zi"</span>,<br><span class="hljs-string">"kernel32.lib"</span>,<br><span class="hljs-string">"gdi32.lib"</span>,<br><span class="hljs-string">"winspool.lib"</span>,<br><span class="hljs-string">"comdlg32.lib"</span>,<br><span class="hljs-string">"advapi32.lib"</span>,<br><span class="hljs-string">"shell32.lib"</span>,<br><span class="hljs-string">"ole32.lib"</span>,<br><span class="hljs-string">"oleaut32.lib"</span>,<br><span class="hljs-string">"uuid.lib"</span>,<br><span class="hljs-string">"odbc32.lib"</span>,<br><span class="hljs-string">"odbccp32.lib"</span>,<br><span class="hljs-string">"User32.lib"</span>,<br><span class="hljs-string">"EasyXa.lib"</span>,<br><span class="hljs-string">"EasyXw.lib"</span>,<br><span class="hljs-string">"/Fd.\\"</span>,<br><span class="hljs-string">"/Fo.\\"</span>,<br><span class="hljs-string">"/Fe:"</span>,<br><span class="hljs-string">"${fileDirname}\\${fileBasenameNoExtension}.exe"</span>,<br><span class="hljs-string">"${file}"</span><br> ],<br> <span class="hljs-attr">"options"</span>: {<br> <span class="hljs-attr">"cwd"</span>: <span class="hljs-string">"${workspaceFolder}"</span><br> },<br> <span class="hljs-attr">"problemMatcher"</span>: [<br> <span class="hljs-string">"$msCompile"</span><br> ],<br> <span class="hljs-attr">"group"</span>: <span class="hljs-string">"build"</span>,<br> <span class="hljs-attr">"detail"</span>: <span class="hljs-string">"compiler: cl.exe"</span><br> },<br> ]<br>}<br></code></pre></td></tr></table></figure><p>这里强调一下,中间那些增加的lib是vs调用编译时所必须的,其中包括easyx的库,其次,为啥有人添加了那些lib结果发现还是报错,是因为你调错了模式,原task.json的type是cppbuild,应该给他改成shell命令行模式,这样才能执行下面arg里面的命令。还有就是”${fileDirname}\${fileBasenameNoExtension}.exe”和”${file}”分别代表生成的exe(名字中不带拓展名,如你写的源文件是1.cpp,对应的是1.exe而不是1.cpp.exe)。<br>最后就是”/Fd.\\“和”/Fo.\\“,其中/Fd和/Fo是命令,后面跟的是vc140.pdb和XX.obj文件的目录,如果用.\就表示工作区目录。如果你的vc140.pdb和XX.obj放在工作区下的一个build文件目录下的话那就可以改成”/Fdbuild\\“ 和 “/Fobuild\\“,但没必要,因为一般默认都生成在工作区内<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)/images/20201206195856601.png" style="zoom:200%;" /><br>这是我写的代码,相应的文件位置关系如上图;<br>若环境配置正确那么结果如下图:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/在VScode中使用EASYX详细教程(VScode+MSVC+EasyX)/images/20201206200028902.png" style="zoom:200%;" /></p><hr><blockquote><p>整个过程下来个人认为这个task.json是最伤人脑筋的,尤其是shell模式,我也是看我的终端上没有出调式命令才知道要调成shell模式,官方给的是cppbuild我也没办法。</p></blockquote><hr>]]></content>
<summary type="html"><p>众所周知,vscode是一款强大的IDE,深受广大码友喜爱,博主曾尝试过用它实现各种脱离特定平台的写码,这里给大家介绍vscode配置EASYX的详细教程。</p>
<hr>
<h2 id="1-配置MSVC编译环境"><a href="#1-配置MSVC编译环境" cla</summary>
<category term="教程" scheme="https://www.varocol.top/categories/%E6%95%99%E7%A8%8B/"/>
<category term="EasyX" scheme="https://www.varocol.top/tags/EasyX/"/>
<category term="教程" scheme="https://www.varocol.top/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>【HDU题解】杭电 Oj 1006 Tick and Tick 个人题解</title>
<link href="https://www.varocol.top/2021/10/20/%E6%9D%AD%E7%94%B5%20oj%201006%20Tick%20and%20Tick%20%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/"/>
<id>https://www.varocol.top/2021/10/20/%E6%9D%AD%E7%94%B5%20oj%201006%20Tick%20and%20Tick%20%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/</id>
<published>2021-10-19T19:13:07.000Z</published>
<updated>2021-10-19T12:04:03.978Z</updated>
<content type="html"><![CDATA[<h2 id="杭电-oj-1006-Tick-and-Tick-个人题解"><a href="#杭电-oj-1006-Tick-and-Tick-个人题解" class="headerlink" title="杭电 oj 1006 Tick and Tick 个人题解"></a>杭电 oj 1006 Tick and Tick 个人题解</h2><p> <em><strong>首先贴上官网原题</strong></em><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022221959964.png"><br> 刚开始看到这道题觉得又是一道水题,后面仔细看了一下题目后才知道这道题更加考数学,确实让我纠结了很久。以下是我的一些思路:</p><hr><h2 id="思路一:暴力模拟法"><a href="#思路一:暴力模拟法" class="headerlink" title="思路一:暴力模拟法"></a>思路一:暴力模拟法</h2><p>可能一般人都会用秒数来模拟时钟,然后根据秒数来确定时针和分针的位置,然后累加时间,这里可以用1s,0.1s,0.01s,甚至是0.001s来作为单位时间模拟,但其实有两大缺点:<br> 1. 单位时间小,要模拟的次数多。<br> 2. 精度不够,要保留小数点后3位。<br> 我用的不是秒数模拟,而是用秒针所走过的度数来模拟,这样可以省去时间与度数的转换。<br> 需要知道的是:秒针的速度=60×分针的速度=720×时针的速度<br>这里先贴上我写的代码(作为第一种思路提交的,oj上失败了): </p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string"><bits/stdc++.h></span><span class="hljs-comment">//这个头文件也称万能头,包括c和c++的很多头文件</span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">int</span> n;<br> <span class="hljs-keyword">double</span> a=<span class="hljs-number">0</span>,t=<span class="hljs-number">0</span>,miao,fen,shi;<br> cin>>n;<br> <span class="hljs-keyword">while</span>(n<=<span class="hljs-number">120</span>&&n>=<span class="hljs-number">0</span>)<br> {<br> <span class="hljs-comment">//模拟时钟</span><br> <span class="hljs-keyword">while</span>(shi<<span class="hljs-number">360</span>)<br> {<br> t+=<span class="hljs-number">0.45</span>;<span class="hljs-comment">//t是计算总时间,以0.45°为单位累加</span><br> miao=t-(<span class="hljs-keyword">int</span>)t/<span class="hljs-number">360</span>*<span class="hljs-number">360</span>;<span class="hljs-comment">//这里因为t为double型,用不了%,所以自己写了一个类似与%的东西。</span><br> fen=t/<span class="hljs-number">60</span>-(<span class="hljs-keyword">int</span>)t/<span class="hljs-number">60</span>/<span class="hljs-number">360</span>*<span class="hljs-number">360</span>;<br> shi=t/<span class="hljs-number">720</span>;<br> <span class="hljs-keyword">if</span>(<span class="hljs-built_in">abs</span>(miao-fen)>=n&&miao-fen+<span class="hljs-number">360</span>>=n&&fen+<span class="hljs-number">360</span>-miao>=n)<span class="hljs-comment">//这里的判断略显繁琐,其实可以用define宏来简化代码。</span><br> <span class="hljs-keyword">if</span>(<span class="hljs-built_in">abs</span>(miao-shi)>=n&&miao-shi+<span class="hljs-number">360</span>>=n&&shi+<span class="hljs-number">360</span>-miao>=n)<br> <span class="hljs-keyword">if</span>(<span class="hljs-built_in">abs</span>(fen-shi)>=n&&fen-shi+<span class="hljs-number">360</span>>=n&&shi+<span class="hljs-number">360</span>-fen>=n)<br> a+=<span class="hljs-number">0.45</span>;<span class="hljs-comment">//a用来统计开心时间</span><br> }<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%.3lf\n"</span>,a/t*<span class="hljs-number">100</span>);<span class="hljs-comment">//c++的小数点控制不大会用,方便起见用了c的printf函数</span><br> cin>>n;<br> a=t=shi=<span class="hljs-number">0</span>;<span class="hljs-comment">//这里需要重置数据</span><br> }<br> cin.<span class="hljs-built_in">get</span>();<br> cin.<span class="hljs-built_in">get</span>();<span class="hljs-comment">//这里用两个cin.get();来暂停界面,保留窗口,不影响oj的判断</span><br>}<br></code></pre></td></tr></table></figure><p>这里其实有很多细节处理过程,<br>如:3个if的写法,举其中一例,abs(miao-fen)>=n,是判断miao和fen的度数之差,这里用abs是因为fen的度数有可能超过miao(相对与起始位置)。还有就是后面的(miao-fen+360)>=n和fen-miao+360是用来算另一个夹角的。</p><p>然后这个0.45也是调试过好几遍,刚开始用的是0.01,运行后发现运行时间太长了,就把它改大了一些,变成1,虽然测试样例对了,但是提交上去的时候就错了(精度不够)。<br>贴上提交的图:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022230023515.png"><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022225850487.png"><br>这里可以看到答案错误,而且运行时间还不小。<br>所以我尝试着用时间来换精度。<br>结果如图所示:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022230243559.png"><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022230320790.png"><br>然后尝试着调大一些,调成0.5:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022230625847.png"><br>在调小一些(心累),0.45:<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022230740955.png"><br>事实证明:没有好的算法oj不认!<br>所以我就开始百度,发现很多其他博主用的是解方程的形式, 但也都是代码一贴,看不懂,或者太长了不想看,本来想着要放弃,但是后来想想不会的题目不去做永远不会,还不如再试试。<br>今天费了整天,终于死磕出来,也就是思路2。</p><hr><h2 id="思路2-解方程-算符合条件的两两之间的区间-最后取交集-合并区间。"><a href="#思路2-解方程-算符合条件的两两之间的区间-最后取交集-合并区间。" class="headerlink" title="思路2:解方程,算符合条件的两两之间的区间,最后取交集,合并区间。"></a>思路2:解方程,算符合条件的两两之间的区间,最后取交集,合并区间。</h2><h2 id="闲谈"><a href="#闲谈" class="headerlink" title="闲谈:"></a>闲谈:</h2><p>先说说我的整个挣扎的过程(不想看的可以直接跳过,博主个人的废话):<br>开始,我想的是用做数学题的想法,就是先让分针和时针先产生一个n的夹角,算出此时的时间,然后再在此基础之上去确定秒针的位置,这里贴一下我半途而废的代码:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string"><bits/stdc++.h></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">int</span> n,q=<span class="hljs-number">0</span>;<br> <span class="hljs-keyword">double</span> miao=<span class="hljs-number">0</span>,fen,shi,t1,t2,t3,t4,ans=<span class="hljs-number">0</span>;<br> cin>>n;<br> <span class="hljs-keyword">while</span>(n<=<span class="hljs-number">120</span>&&n>=<span class="hljs-number">0</span>)<br> {<br> <span class="hljs-comment">//解多次方程</span><br> <span class="hljs-keyword">while</span>(<span class="hljs-number">720</span>/<span class="hljs-number">11</span>*(n+q*<span class="hljs-number">360</span>)<<span class="hljs-number">259200</span>)<span class="hljs-comment">//用度数来解方程</span><br> {<br> t1=<span class="hljs-number">720</span>/<span class="hljs-number">11</span>*(n+q*<span class="hljs-number">360</span>);q++;<span class="hljs-comment">//解出分针与时针满足条件时的时间</span><br> t2=<span class="hljs-number">720</span>/<span class="hljs-number">11</span>*(q*<span class="hljs-number">360</span>-n);<span class="hljs-comment">//t1,t2用来确定分针和时针开心的边界,t3,t4用来确定秒针分别与时针和分针的开心边界</span><br> <span class="hljs-comment">//用for循环寻找在t1-t2该区间的miao的范围</span><br> t3=t4=<span class="hljs-number">0</span>;<br> <br> <br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;t3<<span class="hljs-number">259200</span>;i++)<br> {<br> t3=(n+(i*<span class="hljs-number">360</span>))*<span class="hljs-number">720</span>/<span class="hljs-number">719</span>;<br> <span class="hljs-keyword">if</span>(t1<t3&&t3<t2)<span class="hljs-keyword">break</span>;<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;t4<<span class="hljs-number">259200</span>;i++)<br> {<br> t4=(<span class="hljs-number">360</span>*(i+<span class="hljs-number">1</span>)-n)*<span class="hljs-number">720</span>/<span class="hljs-number">719</span>;<br> } <br> }<br> <br> }<br> cin.<span class="hljs-built_in">get</span>();<br> cin.<span class="hljs-built_in">get</span>();<br>}<br></code></pre></td></tr></table></figure><p>但后来才发现不对,t3和t4那个在前面,那个后面呢?t3和t4还要去公共部分,可能会与上一个t3或者上一个t4 时间有重叠等等…….<br>所以,我决定用计算机特性:能够存储大量数据,来解决所有头疼的问题</p><hr><h2 id="正题"><a href="#正题" class="headerlink" title="正题:"></a>正题:</h2><p>其实回过头来看这道题会发现,无非他让我们做的不就是算出所有满足条件的时间区间,然后相加,最后计算占总时间的比例.<br>因为一天24小时前12个小时和后12个小时情况相同,所以就用12个小时为总时间.<br>首先,对于这道题总的框架应该是先计算两两直接满足条件的区间(你也不可能一次性把三个条件全满足的区间算出来)<br>所以应当是算时针和秒针的区间,时针和分针的区间,以及分针和时针的区间,最后取交集.<br>先贴上代码再说明:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-meta-keyword">include</span><span class="hljs-meta-string"><bits/stdc++.h></span></span><br><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<br><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-keyword">int</span> n,s1=<span class="hljs-number">0</span>,s2=<span class="hljs-number">0</span>,s3=<span class="hljs-number">0</span>,s4=<span class="hljs-number">0</span>;<br> <span class="hljs-keyword">double</span> ms[<span class="hljs-number">2000</span>],fs[<span class="hljs-number">30</span>],fm[<span class="hljs-number">2000</span>],h1[<span class="hljs-number">2000</span>],ans=<span class="hljs-number">0</span>;<br> cin>>n;<br> <span class="hljs-keyword">while</span>(n<=<span class="hljs-number">120</span>&&n>=<span class="hljs-number">0</span>)<br> {<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">720.0</span>/<span class="hljs-number">719</span><<span class="hljs-number">259200</span>;i++)<br> {<br> ms[s1++]=(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">720.0</span>/<span class="hljs-number">719</span>;<br> ms[s1++]=((i+<span class="hljs-number">1</span>)*<span class="hljs-number">360</span>-n)*<span class="hljs-number">720.0</span>/<span class="hljs-number">719</span>;<br> }<br><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">720.0</span>/<span class="hljs-number">11</span><<span class="hljs-number">259200</span>;i++)<br> {<br> fs[s2++]=(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">720.0</span>/<span class="hljs-number">11</span>;<br> fs[s2++]=((i+<span class="hljs-number">1</span>)*<span class="hljs-number">360</span>-n)*<span class="hljs-number">720.0</span>/<span class="hljs-number">11</span>;<br> }<br><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">60.0</span>/<span class="hljs-number">59</span><<span class="hljs-number">259200</span>;i++)<br> {<br> fm[s3++]=(n+<span class="hljs-number">360</span>*i)*<span class="hljs-number">60.0</span>/<span class="hljs-number">59</span>;<br> fm[s3++]=((i+<span class="hljs-number">1</span>)*<span class="hljs-number">360</span>-n)*<span class="hljs-number">60.0</span>/<span class="hljs-number">59</span>;<br> }<br> <span class="hljs-comment">//合并fs和fm,并入h1之中</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;i<s2;i+=<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=<span class="hljs-number">0</span>;j<s3&&fm[j]<fs[i+<span class="hljs-number">1</span>];j+=<span class="hljs-number">2</span>)<br> {<br> <span class="hljs-keyword">if</span>(fm[j+<span class="hljs-number">1</span>]>fs[i])<br> {<br> h1[s4++]=<span class="hljs-built_in">max</span>(fm[j],fs[i]);<br> h1[s4++]=<span class="hljs-built_in">min</span>(fm[j+<span class="hljs-number">1</span>],fs[i+<span class="hljs-number">1</span>]);<br> }<br> }<br> <span class="hljs-comment">//合并h1和ms,并入fm</span><br> s3=<span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;i<s4;i+=<span class="hljs-number">2</span>)<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=<span class="hljs-number">0</span>;j<s1&&ms[j]<h1[i+<span class="hljs-number">1</span>];j+=<span class="hljs-number">2</span>)<br> {<br> <span class="hljs-keyword">if</span>(ms[j+<span class="hljs-number">1</span>]>h1[i])<br> {<br> fm[s3++]=<span class="hljs-built_in">max</span>(ms[j],h1[i]);<br> fm[s3++]=<span class="hljs-built_in">min</span>(ms[j+<span class="hljs-number">1</span>],h1[i+<span class="hljs-number">1</span>]);<br> }<br> }<br> <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>;i<s3;i+=<span class="hljs-number">2</span>)ans+=fm[i+<span class="hljs-number">1</span>]-fm[i];<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"%.3f\n"</span>,ans/<span class="hljs-number">259200</span>*<span class="hljs-number">100</span>);<br> s1=s2=s3=s4=ans=<span class="hljs-number">0</span>;<br> cin>>n;<br> }<br> cin.<span class="hljs-built_in">get</span>();<br> cin.<span class="hljs-built_in">get</span>();<br>}<br></code></pre></td></tr></table></figure><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201022235727706.png" alt="46ms还可以"><br>1.<br> int型:<br>n 用来存储输入数据<br>s1 用来存储ms数组的元素个数(预计有1440,保险起见用2000个)<br>s2 存储fs数组的元素个数(预计24个,用30)<br>s3 存储fm数组的元素个数(预计1440个,用2000)<br>s4 存储h1数组的元素个数(预计1440个,用2000)<br>2.<br>double数组:<br>ms数组存的是秒针和时针满足条件的区间(ms是秒时的缩写)<br>以此类推<br>h1数组用来存第一次合并的区间(两两合并要2次,本来要有2个数组来存合并区间,但是我是先把fs和fm合并的,所以第二次合并的时候fm数组没用,可以空出来当最终的区间数组,另外主要是fs数组的值很少,先合并fs数组可以少循环几次)<br>double ans用来存储开心时间.<br>3.(最核心的部分)</p><h1 id="如何算即如何解方程"><a href="#如何算即如何解方程" class="headerlink" title="如何算即如何解方程?"></a>如何算即如何解方程?</h1><p>其实很简单,我们先以n=90°,秒针和时针为例,我这里用的是度数列的方程,即设秒针走过的度数为x,则第一次满足条件时:<br>x-x/720=90<br>那秒针再超过时针一圈呢?<br>x-x/720=90+360<br>再来一圈呢?<br>x-x/720=90+360×2<br>…<br>x-x/720=90+360×i</p><h1 id="那么解得x-90-360×i-×720-719"><a href="#那么解得x-90-360×i-×720-719" class="headerlink" title="那么解得x=(90+360×i)×720/719."></a>那么解得x=(90+360×i)×720/719.</h1><p>其实还有一种情况:<br>还是时针和秒针<br>当秒针超过时针并去追时针时,第一次满足条件时有:<br>x/720+360-x=90<br>同理i圈后:<br>x/720+360×i-x=90</p><h1 id="解得x-360×i-90-×720-719"><a href="#解得x-360×i-90-×720-719" class="headerlink" title="解得x=(360×i-90)×720/719."></a>解得x=(360×i-90)×720/719.</h1><p>那么可以以此类推秒针和分针,分针和时针的情况.<br>最后再两两合并,累加时间ans.然后输出比例后记得重置数据,以便下一次的运算.<br>==<br>(PS:评论支持一下博主,深夜12:30了,有点困了~ )</p><p>附上我的草稿(乱的一)<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/%E6%9D%AD%E7%94%B5oj1006TickandTick%E4%B8%AA%E4%BA%BA%E9%A2%98%E8%A7%A3/images/20201023003346436.jpg"></p><p> </p>]]></content>
<summary type="html"><h2 id="杭电-oj-1006-Tick-and-Tick-个人题解"><a href="#杭电-oj-1006-Tick-and-Tick-个人题解" class="headerlink" title="杭电 oj 1006 Tick and Tick 个人题解"></a</summary>
<category term="ACM" scheme="https://www.varocol.top/categories/ACM/"/>
<category term="ACM" scheme="https://www.varocol.top/tags/ACM/"/>
<category term="算法" scheme="https://www.varocol.top/tags/%E7%AE%97%E6%B3%95/"/>
</entry>
<entry>
<title>【STM32学习笔记】STM32 I2C读写EEPROM(AT24C02)理论知识</title>
<link href="https://www.varocol.top/2021/10/20/STM32%20I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/"/>
<id>https://www.varocol.top/2021/10/20/STM32%20I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/</id>
<published>2021-10-19T19:03:07.000Z</published>
<updated>2021-10-19T11:09:10.590Z</updated>
<content type="html"><![CDATA[<h1 id="STM32-I2C读写EEPROM-AT24C02-个人调试Bug经验"><a href="#STM32-I2C读写EEPROM-AT24C02-个人调试Bug经验" class="headerlink" title="STM32 I2C读写EEPROM(AT24C02)个人调试Bug经验"></a><a href="https://www.varocol.top/2021/10/19/STM32%20I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%9E%E9%99%85%E9%97%AE%E9%A2%98%E5%92%8CBug/">STM32 I2C读写EEPROM(AT24C02)个人调试Bug经验</a></h1><h4 id="本篇文章是本人学习野火STM32读写EEPROM的视频总结而来的笔记-上面的链接有解答关于《火哥视频中EEPROM-WaitForWriteEnd-函数检测EV6事件为什么不能用CheckEvent-函数来检测》问题的解答。"><a href="#本篇文章是本人学习野火STM32读写EEPROM的视频总结而来的笔记-上面的链接有解答关于《火哥视频中EEPROM-WaitForWriteEnd-函数检测EV6事件为什么不能用CheckEvent-函数来检测》问题的解答。" class="headerlink" title="本篇文章是本人学习野火STM32读写EEPROM的视频总结而来的笔记,上面的链接有解答关于《火哥视频中EEPROM_WaitForWriteEnd()函数检测EV6事件为什么不能用CheckEvent()函数来检测》问题的解答。"></a>本篇文章是本人学习<a href="https://www.bilibili.com/video/BV1ps411M7Dr?p=22">野火STM32读写EEPROM</a>的视频总结而来的笔记,上面的链接有解答关于《火哥视频中EEPROM_WaitForWriteEnd()函数检测EV6事件为什么不能用CheckEvent()函数来检测》问题的解答。</h4><h3 id="上述问题火哥视频的链接-24-I2C—读写EEPROM(第7节中)—代码详解-读写EEPROM-进度条58-50自己去看"><a href="#上述问题火哥视频的链接-24-I2C—读写EEPROM(第7节中)—代码详解-读写EEPROM-进度条58-50自己去看" class="headerlink" title="上述问题火哥视频的链接[24-I2C—读写EEPROM(第7节中)—代码详解-读写EEPROM] 进度条58:50自己去看"></a>上述问题火哥视频的链接[<a href="https://www.bilibili.com/video/BV1ps411M7Dr?p=30">24-I2C—读写EEPROM(第7节中)—代码详解-读写EEPROM</a>] 进度条58:50自己去看</h3><hr><h1 id="I2C协议介绍"><a href="#I2C协议介绍" class="headerlink" title="I2C协议介绍"></a>I2C协议介绍</h1><h1 id="物理层"><a href="#物理层" class="headerlink" title="物理层"></a>物理层</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/58bf08d2a99f4d48832f15001f33f5b6.png"><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/211966f5a4384c6e8b080a413f2b8e00.png"></p><h3 id="1-SCL-串行时钟线"><a href="#1-SCL-串行时钟线" class="headerlink" title="1.SCL 串行时钟线"></a>1.SCL 串行时钟线</h3><h3 id="2-SDA-双向串行数据线"><a href="#2-SDA-双向串行数据线" class="headerlink" title="2.SDA 双向串行数据线"></a>2.SDA 双向串行数据线</h3><h3 id="3-每个设备有独立的地址"><a href="#3-每个设备有独立的地址" class="headerlink" title="3.每个设备有独立的地址"></a>3.每个设备有独立的地址</h3><h3 id="4-每个设备在空闲状态时都会输出高阻态,所有都为空闲状态时,则总线被上拉为高电平"><a href="#4-每个设备在空闲状态时都会输出高阻态,所有都为空闲状态时,则总线被上拉为高电平" class="headerlink" title="4.每个设备在空闲状态时都会输出高阻态,所有都为空闲状态时,则总线被上拉为高电平"></a>4.每个设备在空闲状态时都会输出高阻态,所有都为空闲状态时,则总线被上拉为高电平</h3><h3 id="5-SDA-设备用高阻态表示高电平-1-,接地表示低电平-0"><a href="#5-SDA-设备用高阻态表示高电平-1-,接地表示低电平-0" class="headerlink" title="5.SDA 设备用高阻态表示高电平(1),接地表示低电平(0)"></a>5.SDA 设备用高阻态表示高电平(1),接地表示低电平(0)</h3><h3 id="6-三种传输模式:标准传输速率为100kbit-s,快速模式为400kbits-s,高速模式为3-4Mbit-s-大多数设备不支持"><a href="#6-三种传输模式:标准传输速率为100kbit-s,快速模式为400kbits-s,高速模式为3-4Mbit-s-大多数设备不支持" class="headerlink" title="6.三种传输模式:标准传输速率为100kbit/s,快速模式为400kbits/s,高速模式为3.4Mbit/s(大多数设备不支持)"></a>6.三种传输模式:标准传输速率为100kbit/s,快速模式为400kbits/s,高速模式为3.4Mbit/s(大多数设备不支持)</h3><br/><hr><h1 id="协议层"><a href="#协议层" class="headerlink" title="协议层"></a>协议层</h1><h1 id="1-I2C基本读写过程"><a href="#1-I2C基本读写过程" class="headerlink" title="1.I2C基本读写过程"></a>1.I2C基本读写过程</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/605b347efddd4f059c7f07419ef923a8.png"><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/a6d42d3b5fe04790a1f8ad7ee042e383.png"></p><h3 id="1-数据和时钟线都为高时总线处于空闲状态。"><a href="#1-数据和时钟线都为高时总线处于空闲状态。" class="headerlink" title="1. 数据和时钟线都为高时总线处于空闲状态。"></a>1. 数据和时钟线都为高时总线处于<u>空闲状态</u>。</h3><h3 id="2-当SCL为高电平时SDA的下降沿为起始条件-S-。"><a href="#2-当SCL为高电平时SDA的下降沿为起始条件-S-。" class="headerlink" title="2. 当SCL为高电平时SDA的下降沿为起始条件( S )。"></a>2. 当SCL为高电平时SDA的下降沿为<u>起始条件</u>( S )。</h3><h3 id="3-当SCL为高电平时SDA的上升沿为停止条件-P-。"><a href="#3-当SCL为高电平时SDA的上升沿为停止条件-P-。" class="headerlink" title="3. 当SCL为高电平时SDA的上升沿为停止条件( P )。"></a>3. 当SCL为高电平时SDA的上升沿为<u>停止条件</u>( P )。</h3><h3 id="4-当SCL为高电平时,SDA的数据有效,否则无效。"><a href="#4-当SCL为高电平时,SDA的数据有效,否则无效。" class="headerlink" title="4. 当SCL为高电平时,SDA的数据有效,否则无效。"></a>4. 当SCL为高电平时,SDA的<u>数据有效</u>,否则<u>无效</u>。</h3><br/><h1 id="2-地址及数据方向"><a href="#2-地址及数据方向" class="headerlink" title="2.地址及数据方向"></a>2.地址及数据方向</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/b2e117d16f914160aebedd83263d52ee.png"></p><h3 id="前七位为从机地址,最后一位为读写方向位"><a href="#前七位为从机地址,最后一位为读写方向位" class="headerlink" title="前七位为从机地址,最后一位为读写方向位"></a>前七位为从机地址,最后一位为读写方向位</h3><h3 id="从高位开始传输"><a href="#从高位开始传输" class="headerlink" title="从高位开始传输"></a>从高位开始传输</h3><br/><h1 id="3-响应"><a href="#3-响应" class="headerlink" title="3.响应"></a>3.响应</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/046d448f1f414cc68d699eb59f829c99.png"></p><h3 id="当数据端释放SDA控制权后,若接收端控制SDA为低电平时-在第9个时钟-,则产生了应答信号-ACK-,若为高电平,即无动作,则产生非应答信号-NACK-。"><a href="#当数据端释放SDA控制权后,若接收端控制SDA为低电平时-在第9个时钟-,则产生了应答信号-ACK-,若为高电平,即无动作,则产生非应答信号-NACK-。" class="headerlink" title="当数据端释放SDA控制权后,若接收端控制SDA为低电平时(在第9个时钟),则产生了应答信号(ACK),若为高电平,即无动作,则产生非应答信号(NACK)。"></a>当数据端释放SDA控制权后,若接收端控制SDA为低电平时(在第9个时钟),则产生了<u>应答信号(ACK)</u>,若为高电平,即无动作,则产生<u>非应答信号(NACK)</u>。</h3><br/><hr><h1 id="STM32的I2C架构"><a href="#STM32的I2C架构" class="headerlink" title="STM32的I2C架构"></a>STM32的I2C架构</h1><br/><h2 id="1-通讯引脚"><a href="#1-通讯引脚" class="headerlink" title="1.通讯引脚"></a>1.通讯引脚</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/5e747754a818448ab1bb687014ac6cb2.png"></p><h3 id="I2C1"><a href="#I2C1" class="headerlink" title="I2C1"></a>I2C1</h3><h4 id="默认复用"><a href="#默认复用" class="headerlink" title="默认复用"></a>默认复用</h4><h5 id="SCL-PB5-SDA-PB6"><a href="#SCL-PB5-SDA-PB6" class="headerlink" title="SCL:PB5 SDA:PB6"></a>SCL:PB5 SDA:PB6</h5><br/><h5 id="重定义"><a href="#重定义" class="headerlink" title="重定义"></a>重定义</h5><h5 id="SCL-PB8-SDA-PB9"><a href="#SCL-PB8-SDA-PB9" class="headerlink" title="SCL:PB8 SDA:PB9"></a>SCL:PB8 SDA:PB9</h5><h3 id="I2C2"><a href="#I2C2" class="headerlink" title="I2C2"></a>I2C2</h3><h4 id="默认复用-1"><a href="#默认复用-1" class="headerlink" title="默认复用"></a>默认复用</h4><h5 id="SCL-PB10-SDA-PB11"><a href="#SCL-PB10-SDA-PB11" class="headerlink" title="SCL:PB10 SDA:PB11"></a>SCL:PB10 SDA:PB11</h5><br/><h2 id="2-时钟控制逻辑"><a href="#2-时钟控制逻辑" class="headerlink" title="2.时钟控制逻辑"></a>2.时钟控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/d903ef71ddda44e7ae4c784cb25e90c4.png"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/b93e18ec2b2546cabe88cb26fba88e2a.png"><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/0e3e9bbbdba1475bb26b499ffa1e5f72.png"></p><h3 id="1-I2C模块的时钟频率必须是10MHz整数倍"><a href="#1-I2C模块的时钟频率必须是10MHz整数倍" class="headerlink" title="1.I2C模块的时钟频率必须是10MHz整数倍"></a>1.I2C模块的时钟频率必须是10MHz整数倍</h3><h3 id="2-PE为0时才能配置CCR寄存器"><a href="#2-PE为0时才能配置CCR寄存器" class="headerlink" title="2.PE为0时才能配置CCR寄存器"></a>2.PE为0时才能配置CCR寄存器</h3><h3 id="3-标准模式下-100kbit-s-Thigh-Tlow-注:T-Thigh-Tlow,这里的100kHz的周期应当是二者相加"><a href="#3-标准模式下-100kbit-s-Thigh-Tlow-注:T-Thigh-Tlow,这里的100kHz的周期应当是二者相加" class="headerlink" title="3.标准模式下(100kbit/s) Thigh = Tlow(注:T = Thigh + Tlow,这里的100kHz的周期应当是二者相加)"></a>3.标准模式下(100kbit/s) Thigh = Tlow(注:T = Thigh + Tlow,这里的100kHz的周期应当是二者相加)</h3><h3 id="4-DUTY-位标准模式没关系,是用来设置快速模式的占空比-2-1-16-9"><a href="#4-DUTY-位标准模式没关系,是用来设置快速模式的占空比-2-1-16-9" class="headerlink" title="4.DUTY 位标准模式没关系,是用来设置快速模式的占空比(2:1 16:9)"></a>4.DUTY 位标准模式没关系,是用来设置快速模式的占空比(2:1 16:9)</h3><h3 id="5-CCR根据自己配置的I2C模式自行计算,"><a href="#5-CCR根据自己配置的I2C模式自行计算," class="headerlink" title="5.CCR根据自己配置的I2C模式自行计算,"></a>5.CCR根据自己配置的I2C模式自行计算,</h3><h3 id="若PCLK-8MHz-FREQ寄存器控制"><a href="#若PCLK-8MHz-FREQ寄存器控制" class="headerlink" title="若PCLK = 8MHz (FREQ寄存器控制)"></a>若PCLK = 8MHz (FREQ寄存器控制)</h3><h3 id="100kbit-s-对应的-CCR-0x28-40"><a href="#100kbit-s-对应的-CCR-0x28-40" class="headerlink" title="100kbit/s 对应的 CCR = 0x28 = 40"></a>100kbit/s 对应的 CCR = 0x28 = 40</h3><h3 id="400kbit-s-对应的-CCR-0x0A-10"><a href="#400kbit-s-对应的-CCR-0x0A-10" class="headerlink" title="400kbit/s 对应的 CCR = 0x0A = 10"></a>400kbit/s 对应的 CCR = 0x0A = 10</h3><br/><h2 id="3-数据控制逻辑"><a href="#3-数据控制逻辑" class="headerlink" title="3.数据控制逻辑"></a>3.数据控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/3639a075012f44898dce0f54b34c378e.png"><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/4eed5acd5bac48b29db5db930956b66d.png"></p><br/><h2 id="4-整体控制逻辑"><a href="#4-整体控制逻辑" class="headerlink" title="4.整体控制逻辑"></a>4.整体控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/8f849285deff4e21a8e7f636dc3e38eb.png"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/b23f45a0fe584e6b9625452f1a7502a4.png"><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/3e3b8c0356a54b0e9ea86516379a6605.png"><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/84370d0750f141499dc845d24bd3deb3.png"></p><h4 id="I2C配置由CR1-和-CR2-寄存器配置"><a href="#I2C配置由CR1-和-CR2-寄存器配置" class="headerlink" title="I2C配置由CR1 和 CR2 寄存器配置"></a>I2C配置由CR1 和 CR2 寄存器配置</h4><h4 id="工作时的状态由SR1-和-SR2-寄存器显示"><a href="#工作时的状态由SR1-和-SR2-寄存器显示" class="headerlink" title="工作时的状态由SR1 和 SR2 寄存器显示"></a>工作时的状态由SR1 和 SR2 寄存器显示</h4><br/><hr><h1 id="STM32-I2C-通讯过程"><a href="#STM32-I2C-通讯过程" class="headerlink" title="STM32 I2C 通讯过程"></a>STM32 I2C 通讯过程</h1><h2 id="1-主发送器模式"><a href="#1-主发送器模式" class="headerlink" title="1.主发送器模式"></a>1.主发送器模式</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/7fd4b855a80f4036aaf04d598f0533d6.png"></p><h3 id="7位主发送模式过程:"><a href="#7位主发送模式过程:" class="headerlink" title="7位主发送模式过程:"></a>7位主发送模式过程:</h3><h4 id="1-Start-信号产生。"><a href="#1-Start-信号产生。" class="headerlink" title="1. Start 信号产生。"></a>1. Start 信号产生。</h4><h4 id="2-EV5事件产生,SB-1-,即开始条件发送完成位置1,读SR1-寄存器,并写入DR寄存器能清除该事件。"><a href="#2-EV5事件产生,SB-1-,即开始条件发送完成位置1,读SR1-寄存器,并写入DR寄存器能清除该事件。" class="headerlink" title="2. EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。"></a>2. EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。</h4><h4 id="3-把地址写入DR寄存器。"><a href="#3-把地址写入DR寄存器。" class="headerlink" title="3. 把地址写入DR寄存器。"></a>3. 把地址写入DR寄存器。</h4><h4 id="4-接收到ACK信号。"><a href="#4-接收到ACK信号。" class="headerlink" title="4. 接收到ACK信号。"></a>4. 接收到ACK信号。</h4><h4 id="5-产生EV6事件,ADDR-地址已被发送位-1-,当收到地址的ACK后该位被置1,读SR1-和-SR2-会清除该位。"><a href="#5-产生EV6事件,ADDR-地址已被发送位-1-,当收到地址的ACK后该位被置1,读SR1-和-SR2-会清除该位。" class="headerlink" title="5. 产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。"></a>5. 产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。</h4><h4 id="6-产生EV8-1事件,-TXE-数据寄存器为空位-1-,移位寄存器和数据寄存器都为空,写入DR寄存器可以清除该标志位。"><a href="#6-产生EV8-1事件,-TXE-数据寄存器为空位-1-,移位寄存器和数据寄存器都为空,写入DR寄存器可以清除该标志位。" class="headerlink" title="6. 产生EV8_1事件, TXE(数据寄存器为空位) = 1 ,移位寄存器和数据寄存器都为空,写入DR寄存器可以清除该标志位。"></a>6. 产生EV8_1事件, TXE(数据寄存器为空位) = 1 ,移位寄存器和数据寄存器都为空,写入DR寄存器可以清除该标志位。</h4><h4 id="7-写入DR寄存器。"><a href="#7-写入DR寄存器。" class="headerlink" title="7. 写入DR寄存器。"></a>7. 写入DR寄存器。</h4><h4 id="8-产生EV8事件,TXE-数据寄存器为空位-1-,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。"><a href="#8-产生EV8事件,TXE-数据寄存器为空位-1-,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。" class="headerlink" title="8. 产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。"></a>8. 产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。</h4><h4 id="9-接收到ACK应答信号。"><a href="#9-接收到ACK应答信号。" class="headerlink" title="9. 接收到ACK应答信号。"></a>9. 接收到ACK应答信号。</h4><h4 id="10-写入DR寄存器-第二次发送数据-。"><a href="#10-写入DR寄存器-第二次发送数据-。" class="headerlink" title="10. 写入DR寄存器(第二次发送数据)。"></a>10. 写入DR寄存器(第二次发送数据)。</h4><h4 id="11-产生EV8事件,TXE-数据寄存器为空位-1-,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。"><a href="#11-产生EV8事件,TXE-数据寄存器为空位-1-,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。" class="headerlink" title="11. 产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。"></a>11. 产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。</h4><h4 id="12-所有数据发送完成后产生EV8-2事件,此时BTF-和-TXE-1-。"><a href="#12-所有数据发送完成后产生EV8-2事件,此时BTF-和-TXE-1-。" class="headerlink" title="12. 所有数据发送完成后产生EV8_2事件,此时BTF 和 TXE = 1 。"></a>12. 所有数据发送完成后产生EV8_2事件,此时BTF 和 TXE = 1 。</h4><h4 id="13-发送停止信号"><a href="#13-发送停止信号" class="headerlink" title="13. 发送停止信号"></a>13. 发送停止信号</h4><h3 id="10位主发送模式过程同理"><a href="#10位主发送模式过程同理" class="headerlink" title="10位主发送模式过程同理"></a>10位主发送模式过程同理</h3><h2 id="2-主接收器模式"><a href="#2-主接收器模式" class="headerlink" title="2.主接收器模式"></a>2.主接收器模式</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/41e5fbc1f0084619878c80ff84814f57.png"></p><h3 id="7位主接收模式过程:"><a href="#7位主接收模式过程:" class="headerlink" title="7位主接收模式过程:"></a>7位主接收模式过程:</h3><h4 id="1-Start-信号产生。-1"><a href="#1-Start-信号产生。-1" class="headerlink" title="1. Start 信号产生。"></a>1. Start 信号产生。</h4><h4 id="2-EV5事件产生,SB-1-,即开始条件发送完成位置1,读SR1-寄存器,并写入DR寄存器能清除该事件。-1"><a href="#2-EV5事件产生,SB-1-,即开始条件发送完成位置1,读SR1-寄存器,并写入DR寄存器能清除该事件。-1" class="headerlink" title="2. EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。"></a>2. EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。</h4><h4 id="3-把地址写入DR寄存器。-1"><a href="#3-把地址写入DR寄存器。-1" class="headerlink" title="3. 把地址写入DR寄存器。"></a>3. 把地址写入DR寄存器。</h4><h4 id="4-接收到ACK信号。-1"><a href="#4-接收到ACK信号。-1" class="headerlink" title="4. 接收到ACK信号。"></a>4. 接收到ACK信号。</h4><h4 id="5-产生EV6事件,ADDR-地址已被发送位-1-,当收到地址的ACK后该位被置1,读SR1-和-SR2-会清除该位。-1"><a href="#5-产生EV6事件,ADDR-地址已被发送位-1-,当收到地址的ACK后该位被置1,读SR1-和-SR2-会清除该位。-1" class="headerlink" title="5. 产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。"></a>5. 产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。</h4><h4 id="6-产生EV6-1事件,用于接收1个字节,需要清除响应-ACK-和停止条件-STOP-的产生位。"><a href="#6-产生EV6-1事件,用于接收1个字节,需要清除响应-ACK-和停止条件-STOP-的产生位。" class="headerlink" title="6. 产生EV6_1事件,用于接收1个字节,需要清除响应(ACK)和停止条件(STOP)的产生位。"></a>6. 产生EV6_1事件,用于接收1个字节,需要清除响应(ACK)和停止条件(STOP)的产生位。</h4><h4 id="7-主机产生ACK应答信号。"><a href="#7-主机产生ACK应答信号。" class="headerlink" title="7. 主机产生ACK应答信号。"></a>7. 主机产生ACK应答信号。</h4><h4 id="8-产生EV7事件,RXNE-1-,此时DR寄存器不为空,需要读DR寄存器来清除该事件。"><a href="#8-产生EV7事件,RXNE-1-,此时DR寄存器不为空,需要读DR寄存器来清除该事件。" class="headerlink" title="8. 产生EV7事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。"></a>8. 产生EV7事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。</h4><h4 id="9-主机产生ACK应答信号。"><a href="#9-主机产生ACK应答信号。" class="headerlink" title="9. 主机产生ACK应答信号。"></a>9. 主机产生ACK应答信号。</h4><h4 id="10-产生EV7-1事件,RXNE-1-,此时DR寄存器不为空,需要读DR寄存器来清除该事件。并且需要设置ACK-0-,STOP-1。"><a href="#10-产生EV7-1事件,RXNE-1-,此时DR寄存器不为空,需要读DR寄存器来清除该事件。并且需要设置ACK-0-,STOP-1。" class="headerlink" title="10. 产生EV7_1事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。并且需要设置ACK = 0 ,STOP = 1。"></a>10. 产生EV7_1事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。并且需要设置ACK = 0 ,STOP = 1。</h4><h4 id="11-主机产生NACK非应答信号。"><a href="#11-主机产生NACK非应答信号。" class="headerlink" title="11. 主机产生NACK非应答信号。"></a>11. 主机产生NACK非应答信号。</h4><h4 id="12-主机产生STOP信号。"><a href="#12-主机产生STOP信号。" class="headerlink" title="12. 主机产生STOP信号。"></a>12. 主机产生STOP信号。</h4><h4 id="13-产生EV7事件。"><a href="#13-产生EV7事件。" class="headerlink" title="13. 产生EV7事件。"></a>13. 产生EV7事件。</h4><h3 id="10位主接收模式过程同理"><a href="#10位主接收模式过程同理" class="headerlink" title="10位主接收模式过程同理"></a>10位主接收模式过程同理</h3><br/><hr><h1 id="STM32-IIC-库函数"><a href="#STM32-IIC-库函数" class="headerlink" title="STM32 IIC 库函数"></a>STM32 IIC 库函数</h1><h2 id="1-I2C-初始化结构体"><a href="#1-I2C-初始化结构体" class="headerlink" title="1.I2C 初始化结构体"></a>1.I2C 初始化结构体</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/299a94df358a45faaa7c259675d3d748.png"></p><h3 id="1-I2C-ClockSpeed"><a href="#1-I2C-ClockSpeed" class="headerlink" title="1.I2C_ClockSpeed"></a>1.I2C_ClockSpeed</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/b22a375d6ac9486f87e04fba69810ffb.png"></p><p><strong>注:I2C的标准和快速模式已经在这里配置完成,根据输入的时钟值来确定,小于等于100k为标准,否则为快速</strong></p><br/><h3 id="2-I2C-Mode"><a href="#2-I2C-Mode" class="headerlink" title="2.I2C_Mode"></a>2.I2C_Mode</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/167761144d1c4da98952f5a8b9a7a573.png"></p><h3 id="3-I2C-DutyCycle"><a href="#3-I2C-DutyCycle" class="headerlink" title="3.I2C_DutyCycle"></a>3.I2C_DutyCycle</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/f7345ec5247e466bb5c6180d7ff39ece.png"></p><h3 id="4-I2C-OwnAddress1"><a href="#4-I2C-OwnAddress1" class="headerlink" title="4.I2C_OwnAddress1"></a>4.I2C_OwnAddress1</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/7d93b9b5359440e7875a960e3c082f4b.png"></p><h3 id="5-I2C-Ack"><a href="#5-I2C-Ack" class="headerlink" title="5.I2C_Ack"></a>5.I2C_Ack</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/3cecb490735e47ba881c757f83345d41.png"></p><h3 id="6-I2C-AcknowledgedAddress"><a href="#6-I2C-AcknowledgedAddress" class="headerlink" title="6.I2C_AcknowledgedAddress"></a>6.I2C_AcknowledgedAddress</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%90%86%E8%AE%BA%E7%9F%A5%E8%AF%86/images/abbe6829601a43daa4c0aa17420c9982.png"></p>]]></content>
<summary type="html"><h1 id="STM32-I2C读写EEPROM-AT24C02-个人调试Bug经验"><a href="#STM32-I2C读写EEPROM-AT24C02-个人调试Bug经验" class="headerlink" title="STM32 I2C读写EEPROM(AT24</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】STM32 I2C读写EEPROM(AT24C02)的一些实际问题和Bug</title>
<link href="https://www.varocol.top/2021/10/19/STM32%20I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%9E%E9%99%85%E9%97%AE%E9%A2%98%E5%92%8CBug/"/>
<id>https://www.varocol.top/2021/10/19/STM32%20I2C%E8%AF%BB%E5%86%99EEPROM(AT24C02)%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%9E%E9%99%85%E9%97%AE%E9%A2%98%E5%92%8CBug/</id>
<published>2021-10-18T20:17:07.000Z</published>
<updated>2021-10-19T10:47:06.516Z</updated>
<content type="html"><![CDATA[<hr><p><strong>本文中的IDE是VScode,用的EIDE插件调用Keil的底层,所以跟Keil是一样的,只不过外观不一样。做实验用的是野火的霸道板子。下面的问题和细节在我的bilibili视频上会有说明。</strong></p><p><a href="https://www.bilibili.com/video/BV1v3411i7DZ/"><strong>我的bilibili视频链接</strong></a></p><hr><h1 id="1-STM32-I2C-通讯失败后Busy位一直为1的问题"><a href="#1-STM32-I2C-通讯失败后Busy位一直为1的问题" class="headerlink" title="1.STM32 I2C 通讯失败后Busy位一直为1的问题"></a>1.STM32 I2C 通讯失败后Busy位一直为1的问题</h1><p><strong>相信只要玩过STM32 I2C外设的都有碰到过这个问题,调试的时候经常能看到刚刚初始化完成或者程序一运行Busy位就为1的情况,网上查询了一下,这个问题已经存在很多年了,我也是准大二,刚刚调试完I2C,在学习的很多阶段都遇到过这个问题,我总结出来我碰到过的</strong><u>三种情况</u><strong>。</strong></p><hr><h2 id="a-程序错误导致的通讯失败,从而进入死循环"><a href="#a-程序错误导致的通讯失败,从而进入死循环" class="headerlink" title="a.程序错误导致的通讯失败,从而进入死循环"></a>a.程序错误导致的通讯失败,从而进入死循环</h2><hr><h3 id="原因分析:"><a href="#原因分析:" class="headerlink" title="原因分析:"></a>原因分析:</h3><p><strong>对于刚开始写驱动的小白而言,对STM I2C时序图没有深入了解,所以代码容易写错,如果以错误的时序驱动STM32 I2C,那么当把程序烧入到STM32时,程序一瞬间运行卡死,然后导致Busy锁死,锁死之后调试发现还未初始化I2C 的SR2寄存器Busy位就有值,然后尝试复位,但只是按钮复位是不能清除锁死的Busy位,重新上电复位才能清除。上电后又运行错误的程序,然后就进入了无限制的循环。</strong></p><p><strong>(PS:有些人可能会说其实不用管这个Busy位继续调试就行,但是作为初学者来说应该要知道Busy位为1这个问题侧面反映了你自己写程序是有问题的,如果程序正确了,Busy也就不为1(除非有其他的情况)。)</strong><br><br/></p><hr><h3 id="解决方案:"><a href="#解决方案:" class="headerlink" title="解决方案:"></a>解决方案:</h3><p><strong>把程序调正确。可以看火哥或者正点原子的视频,或者直接看正确的源代码(下面有野火亲测可用代码),如果能够正确运行别人的代码,而自己的代码不好使,那么就是代码的问题;如果都不好使,那么可能是其他两种情况。</strong></p><p><a href="https://download.csdn.net/download/qq_35598074/21763497">野火示例代码</a></p><hr><h3 id="案例:"><a href="#案例:" class="headerlink" title="案例:"></a>案例:</h3><p><strong>计划是写WriteByte()函数和WritePage()函数,最后写一个ReadByte()函数验证,用串口输出测试信息。</strong><br><strong>(PS:这里的WriteByte()是用来写一个字节的,WritePage()是页写,ReadByte()是读多个字节)。</strong></p><p><strong>写WriteByte函数没有任何问题,贴图如下。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/095470f1b72c4076a6bd35335f63ee92.png" style="zoom:200%;" /><br><strong>然后后面也是一口气把WritePage()和ReadByte()函数全部写完,当然程序是有问题的,因为是自己照着时序图写的,没有在意一些细节,调试结果如下。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/ef8699dfdd4d4afb8f7dd36177ca2759.png" style="zoom:200%;" /><br><strong>调试信息提示函数是卡在WritePage();然后进入调试环节,这里可以看到我已进入调试就出现了刚初始化I2C后SR2寄存器为2(Busy位为1)的情况,复位后也是如此,然后我将后来写的两个函数注释掉,就没有发生过这种情况,所以由此推断是程序编写错误所导致的初始化后Busy=1的问题。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/89de2b766cb847e7843214e9c47e2535.png" style="zoom:200%;" /><br><strong>把程序调试好后就没有问题了结果如下。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/a647055ef552492babbcd7e5e8317b3a.png" style="zoom:200%;" /></p><hr><h2 id="b-硬件错误导致的通讯失败,从而进入死循环"><a href="#b-硬件错误导致的通讯失败,从而进入死循环" class="headerlink" title="b.硬件错误导致的通讯失败,从而进入死循环"></a>b.硬件错误导致的通讯失败,从而进入死循环</h2><hr><h3 id="原因分析"><a href="#原因分析" class="headerlink" title="原因分析:"></a>原因分析:</h3><p><strong>没有分析自己的硬件情况,盲目调试代码。比如:根据Busy位的介绍可以看到,SDA和SCL为低电平时,硬件将置1,这个置1是实时的,也就是这个位会根据你硬件的实际情况实时变化(即使I2C没有使能也会变化)。就比如你的SCL和SDA线突然短路了,那么就会导致这种情况。</strong></p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/b6d6d794b0d242afb88aa593bca15ed7.png" style="zoom:200%;" /><hr><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案:"></a>解决方案:</h3><p><strong>可以尝试拿万用表测试一下引脚的电压值,看看是否达到所需要求,当然这个电压范围也要在EEPROM工作范围内,如果元件好使的话就是电路的问题,仔细排查肯定没问题。</strong><br><br/></p><hr><h3 id="案例:-1"><a href="#案例:-1" class="headerlink" title="案例:"></a>案例:</h3><p><strong>刚把程序调试完,打算把程序升级一下,在追加一个WriteBuffer()函数,但是写完之后烧入第一遍是没问题的,然后用手摸了一下板子,结果发现程序又不行了,我就估计着这个板子可能是有些地方被摸短路了,重新上电程序正常运行,这是第一个地方。后面把这个程序用在I2C2上(板子上的I2C线路默认是接I2C1的),测试了一下发现Busy=1,这次是因为I2C2的引脚没有接入线路,所以无法正常通讯。</strong><br><br/></p><hr><h2 id="c-工作到一半因为各种原因通讯失败,调试的时候出现Busy-1"><a href="#c-工作到一半因为各种原因通讯失败,调试的时候出现Busy-1" class="headerlink" title="c.工作到一半因为各种原因通讯失败,调试的时候出现Busy=1"></a>c.工作到一半因为各种原因通讯失败,调试的时候出现Busy=1</h2><hr><p><strong>因为在实际开发生产过程很可能因为人为原因导致这个问题,但是又不可能断电复位,那么Busy位被锁死就非常棘手,所以这里可以借鉴一位优秀博主的解决方案。</strong></p><p><strong><a href="https://blog.csdn.net/dldw8816/article/details/51579781">解决方案</a></strong></p><p><strong>具体操作流程可以看我视频,方案概括起来就是在初始化I2C之前先利用GPIO IPU模式上拉使其引脚高电平,然后再利用CR1寄存器的第15位SWRST软件复位,这样一来就能在SCL和SDA总线高电平的基础之上复位Busy,最后再重新配置GPIO为开漏继续初始化I2C。<br>这里可以看到这个软件复位说明中有提到可以复位Busy位。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/8cda2e4ca7af4358944464c65ac3ae34.png" style="zoom:200%;" /></p><hr><h1 id="2-STM32-I2C-在调试的时候明明已经GenerateSTART结果SB还是为0"><a href="#2-STM32-I2C-在调试的时候明明已经GenerateSTART结果SB还是为0" class="headerlink" title="2.STM32 I2C 在调试的时候明明已经GenerateSTART结果SB还是为0"></a>2.STM32 I2C 在调试的时候明明已经GenerateSTART结果SB还是为0</h1><h3 id="原因分析:-1"><a href="#原因分析:-1" class="headerlink" title="原因分析:"></a>原因分析:</h3><p><strong>STM32的这个位自带检测功能,也就是说这个位只有在==正确发送完==后才会置位,即使发送完成但是没有发送正确也是不置位的。就例如我给SCL线拉低了,这个时候就不满足起始条件的要求。</strong></p><hr><h3 id="解决方案:-1"><a href="#解决方案:-1" class="headerlink" title="解决方案:"></a>解决方案:</h3><p><strong>如果是硬件问题,可以拿万用表测一下引脚,看看是否满足电位需求,一般来说硬件没有问题了这个位是没问题的。</strong></p><hr><h3 id="案例:-2"><a href="#案例:-2" class="headerlink" title="案例:"></a>案例:</h3><p><strong>将开发板上的PB6(I2C1 SCL引脚)接入3.3V或者5V,程序就会出错,调试结果如下:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/9a59f7b18b154e63818128c527a60af2.png" style="zoom:200%;" /><br><strong>通过Debug我们也可以看到此时SR1寄存器的值为0,也就说明了SCL的电压低于所需的高电平标准,此时无法正确产生起始信号。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/c97e98e12a994849a273d1f153c84ea1.png" style="zoom:200%;" /></p><hr><h1 id="3-火哥视频中所提到的问题-不能用CheckEvent-可以用getFlagStatus"><a href="#3-火哥视频中所提到的问题-不能用CheckEvent-可以用getFlagStatus" class="headerlink" title="3.火哥视频中所提到的问题(不能用CheckEvent(),可以用getFlagStatus())"></a>3.火哥视频中所提到的问题(不能用CheckEvent(),可以用getFlagStatus())</h1><h3 id="原因分析:-2"><a href="#原因分析:-2" class="headerlink" title="原因分析:"></a>原因分析:</h3><p> <strong>首先说明一点:<br> 下面的结论大部分讨论的是发送的情况(主机当发送端的情况),EV6事件是这个问题的关键,EV6事件检测5个位,分别为Busy,TRA,MSL,TXE,ADDR。所以下面的结论都会围绕这5个位进行说明。还有下面的图片不是直接用的固件库函数,是经过自己封装过的函数,效果与固件库一致。</strong></p><p><strong>这里先提出四条结论:</strong><br> <strong>==1.由于STM32 I2C发送速率(Max = 400K)远小于单片机本身运行的速率(72M),所以从发送(接收)完成到检测到EV6,EV8事件这段时间可以运行很多行代码,在主频为72M下I2C传输速率为400K情况下测出,要经过刚好8条CheckEvent()才会出现一次发送成功。==</strong><br> <strong>==2.TXE和TRA以及ADDR位在地址发送成功并成功响应条件下是同时置位的。并且TXE和TRA状态时刻相同(至少我测出来是这样的)。==</strong><br> <strong>==3.TXE和TRA会在起始条件或者停止条件后由硬件自动清除。==</strong><br> <strong>==4.TXE和TRA的置位会受到从机应答的影响,过程为:主机先发送数据,发送结束后先等待从机的应答,如果从机应答,那么将TXE,TRA,ADDR置1,否则置0。==</strong></p><hr><p> <strong>以下是关于结论说明</strong></p><hr><h4 id="结论1:"><a href="#结论1:" class="headerlink" title="结论1:"></a>结论1:</h4><p><strong>不难看出这一条结论说明当写入DR寄存器后仅仅只是写入了DR寄存器,数据也可能到达了移位寄存器,但是数据还没有完全发送出去,这需要好几次CheckEvent()执行完毕后才可能检测出EV6,或者EV8事件。所以从这条可以得出在使用SendData()后或者使用Send7bitAddress()后一定要跟一个检测事件循环。</strong></p><hr><h4 id="结论2:"><a href="#结论2:" class="headerlink" title="结论2:"></a>结论2:</h4><p><strong>经过测试可以得出在使用Send7bitAddress()后这些位同时置位的。视频中有相应说明,下面也有相关配图。<br>在使用Send7bitAddress()前:<br>可以看到SR1=1,SR2=3,这里的TRA和TXE还有ADDR都为0,SR1=1是刚发送了起始条件,SB=1。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/722b3f9779b242c2ac03775dff81752a.png" style="zoom:200%;" /><br><strong>在使用Send7bitAddress()后:<br>这里的SR1 = 130,SR2 = 7,说明了TRA和TXE还有ADDR都为1。当然这是在调试断点的时候的,已经过了很长时间,两个断点之间的时间足以让EEPROM响应,所以这两组数据说服力不强。</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/ec2614b85e1846c0a39059c874e52677.png" style="zoom:200%;" /><br><strong>所以我又重新做了一个实验,通过改写固件库中的CheckEvent()函数,往里面加了几行代码,使得每次寄存器的值都能够被记录到两个数组中。<br>贴图如下:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/e0715d69ff9c473aa1ccdccac7daee57.png" style="zoom:200%;" /><br><strong>由于前面有一个EV5事件的检测,所以会有几组数据是EV5的数据,而我们所需要的是EV6事件的数据,所以可以先在检测EV6前断个点,最好是在Send7bitAddress()之前断点,得到如下结果。</strong></p><p><strong>SR1寄存器:</strong></p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/78ea2ac7f170470fb3208dcf17b837b5.png" style="zoom:200%;" />**SR2寄存器:**<img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/c1b290d30079489ea9db70947b691bb7.png" style="zoom:200%;" />**可以看到都是4组数据,然后我们只需从第5组数据开始分析数据即可(EV5事件结束后就是EV6)。继续往下运行得:SR1寄存器:**<img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/e56c7b84531944a3a7781eb1337d28ac.png" style="zoom:200%;" />**SR2寄存器:**<img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/dccfef8b0ebe4128a19fd8043aa8012b.png" style="zoom:200%;" />**刚好SR1寄存器的8个0对应SR2寄存器8个3,SR1寄存器最后一个130对应最后一个7。本次的测试没有将发送地址和检测EV6事件断开,是直接运行到底的。这也就很好的说明了结论1,并且最后一组数据说明了ADDR和TXE和TRA是同时置位的。这个也间接说明了结论4的正确性,不难猜出这三个位是有关联的。**<hr><h4 id="结论3:"><a href="#结论3:" class="headerlink" title="结论3:"></a>结论3:</h4><p><strong>这一条是对于结论2的理论说明,先来看一下各个位的说明</strong><br><strong>TXE位:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/b5cb400123a94095bb28e7c60420509a.png" style="zoom:200%;" /><br><strong>TRA位:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/54eb6564767f407b81efde0e30db7cc5.png" style="zoom:200%;" /><br><strong>图上也说明了起始条件或停止条件都会清除这两个位,而且也可以看到TRA的值是根据RW来的,所以如果是发送情况的话这两个位是相同的。</strong></p><hr><h4 id="结论4-重点!!!-:"><a href="#结论4-重点!!!-:" class="headerlink" title="结论4(重点!!!):"></a>结论4(重点!!!):</h4><p><strong>这里可以沿用结论2的实验,操作如下:<br>在Send7bitAddress()的前面先断一个点,然后给SCL接一个5V(或者3.3V)导致SCL为低电平,在开始往下运行,然后按暂停键,查看寄存器的值。<br>结果如下:</strong></p><p><strong>SR1寄存器:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/cb34fcb4c45f44b3b34623fa49ef0c3a.png" style="zoom:200%;" /></p><p><strong>SR2寄存器:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/4ef29936337042489a3ecf5a4f2f39eb.png" style="zoom:200%;" /><br><strong>还是从第5个数据开始分析,不难看出现处于总线出错状态,所以BERR位置1,也就是SR1=256。从这里也可以看出TXE和ADDR以及TRA位都为0。对于TXE和TRA的一般认识都是I2C模块发送完毕后就会置位,但是这里并没有置位,因为总线出错的缘故,所以导致应答失败,进而没有置位TXE和TRA。<br>(有些杠精如果要说我这个AF应答失败位为啥没有置位,那么你去视频里看细节或者下面对于火哥问题的具体分析过程,这里就不细说,因为实际调Bug的时候没有这么顺利,也不是做这些实验调出来的,这些实验只能一部分说明,不能完全说明)。</strong></p><hr><h3 id="回归问题"><a href="#回归问题" class="headerlink" title="回归问题"></a>回归问题</h3><p>首先先将还未经过修改的代码贴出来<br>(PS:强调一下,这个代码经过个人封装,跟野火的不一样,抄了也没用,自己看懂了再去改)<br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/c2413bf6a885414891cd84439d6507d6.png" style="zoom:200%;" /></p><p><strong>大概说明一下程序,首先,程序运行一次WriteByte(),然后再运行这个CheckAT24C02Busy函数(火哥的那个是WaitForWriteEnd(),一样的)。这个时候EEPROM正在忙碌,所以程序会整体卡在这部分代码里。</strong></p><h4 id="1-第一点"><a href="#1-第一点" class="headerlink" title="1.第一点"></a>1.第一点</h4><p><strong>根据上述结论1和结论3程序运行完Send7bitAddress()后,只是经过一次CheckEvent()判断EV6事件,而新一轮循环又开始产生START信号,所以一次CheckEvent()的时间完全不足以置位TXE和TRA,其次有START信号就会清除TXE和TRA位,所以EV6永远不可能检测的出来。</strong></p><h4 id="2-第二点"><a href="#2-第二点" class="headerlink" title="2.第二点"></a>2.第二点</h4><p><strong>即使可能发送出去了,因为EV5事件检测时需要读SR1和SR2寄存器,并且Send7bitAddress()函数会写入DR寄存器,这样就会清除ADDR位。这样的话5个位有3个位丢失了。</strong></p><hr><h4 id="针对前两点的临时解决方案"><a href="#针对前两点的临时解决方案" class="headerlink" title="针对前两点的临时解决方案"></a>针对前两点的临时解决方案</h4><p><strong>1. 先把EV5事件的CheckEvent()改为getFlag(),用于检测SB位,这样的话只读取了SR1寄存器,不是两个寄存器都读,也就不会清除ADDR位。</strong></p><p><strong>2. 在Send7bitAddress()后面,CheckEvent()前面加一个While,用于检测TXE位,理论上可以保证有时间发送完成地址。(后面会说明这个地方是错误的)。</strong></p><p><strong>得到如下结果:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/623279d7e21f47e98fa5de36b226f61a.png" style="zoom:200%;" /></p><hr><p><strong>按下F5调试,你会发现程序会卡死在检测TXE位上,为什么???</strong></p><h4 id="细节解释"><a href="#细节解释" class="headerlink" title="细节解释"></a>细节解释</h4><p><strong>根据最重要的结论4可知:由于EEPROM处于忙碌状态,在Send7bitAddress()后会处于应答失败的情况,也就是AF=1,这样一来TXE和TRA就不能置位,所以这样检验是徒劳的,只会让程序卡死。</strong></p><h4 id="处理方案"><a href="#处理方案" class="headerlink" title="处理方案"></a>处理方案</h4><p><strong>不能光检测TXE位,应当AF和TXE同时检测,从上面的结论可以推导出来,如果应答成功,则AF=0,TXE=1,应答失败,则AF=1,TXE=0。所以可以同时检测两个位,结果如下:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/269988f7955a408e8e63654054061924.png" style="zoom:200%;" /><br><strong>说明一下细节:<br>如果应答成功,那么这个检测AF和TXE的While()肯定能够满足地址有足够的发送时间。<br>如果应答失败,那么这个也可以有足够的时间,因为AF的置位是要等发送完成并且花一定的时间去等待应答,肯定够了。<br>所以就是要么AF=1,要么TXE=1,毕竟这两个位是有关系的。</strong></p><p><strong>最后要注意的是,应答失败的循环肯定有好几次,那么对于用于检测<br>AF和TXE循环肯定是有影响的,毕竟AF位又不会自动清除,所以在每遍循环都要软件清除AF位。</strong></p><p><strong>修改后代码的最终成品:</strong><br><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32I2C读写EEPROM(AT24C02)的一些实际问题和Bug/images/b69321e126794c47ac2cc04aa69117d7.png" style="zoom:200%;" /></p><hr><h1 id="4-后记"><a href="#4-后记" class="headerlink" title="4.后记"></a>4.后记</h1><p><strong>对于修改成功的代码可以往里面加入超时处理和用于输出调试信息的代码。整个过程来讲并没有这篇博客写的这么简单,前前后后也是经过反复测试和猜想的,这段过程给我最大的感受就是有些可能不是硬件上Bug,只能说是缺陷,只不过不知道而已,就比如这个SB位和TXE位都设计的过于智能,能够检测过程是否成功,成功再置位。这些东西在文档中没有说明,都得靠自己去摸索。再怎么Bug也是可以避过的,大不了用软件I2C(实际开发项目的时候是不建议这么做的,少了很多功能)。加油吧,打工人。</strong></p><br/><br/><br/><br/><h3 id="如果文章写的有问题的话,还请各位大佬指点"><a href="#如果文章写的有问题的话,还请各位大佬指点" class="headerlink" title="==如果文章写的有问题的话,还请各位大佬指点=="></a>==如果文章写的有问题的话,还请各位大佬指点==</h3><br/><br/><br/><br/><h1 id="原创的文章,写作不易,引用的时候记得给个链接!!!!!!!!!!!!!"><a href="#原创的文章,写作不易,引用的时候记得给个链接!!!!!!!!!!!!!" class="headerlink" title="原创的文章,写作不易,引用的时候记得给个链接!!!!!!!!!!!!!"></a>原创的文章,写作不易,引用的时候记得给个链接!!!!!!!!!!!!!</h1>]]></content>
<summary type="html"><hr>
<p><strong>本文中的IDE是VScode,用的EIDE插件调用Keil的底层,所以跟Keil是一样的,只不过外观不一样。做实验用的是野火的霸道板子。下面的问题和细节在我的bilibili视频上会有说明。</strong></p>
<p><a href="htt</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】USART串口</title>
<link href="https://www.varocol.top/2021/10/11/USART%E4%B8%B2%E5%8F%A3/"/>
<id>https://www.varocol.top/2021/10/11/USART%E4%B8%B2%E5%8F%A3/</id>
<published>2021-10-10T20:38:07.000Z</published>
<updated>2021-10-13T02:28:58.366Z</updated>
<content type="html"><![CDATA[<h1 id="1-串口通信协议简介"><a href="#1-串口通信协议简介" class="headerlink" title="1.串口通信协议简介"></a>1.串口通信协议简介</h1><p><strong>物理层</strong>:</p><p>规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在屋里媒体的传输。</p><p>(硬件部分)</p><p><strong>协议层</strong>:</p><p>协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。<br>(软件部分)</p><h1 id="2-STM32串口功能框图讲解"><a href="#2-STM32串口功能框图讲解" class="headerlink" title="2.STM32串口功能框图讲解"></a>2.STM32串口功能框图讲解</h1><p>1-RS232</p><p>2-USB转串口(TTL)</p><p>3-原生的串口到串口(TTL->TTL)</p><p>TTL(3.3V或5V表示高电平,0表示低电平)</p><p>RS-232(15V表示低电平,-15表示高电平)</p><h3 id="1-RS232"><a href="#1-RS232" class="headerlink" title="1-RS232"></a>1-RS232</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/f4b9bb39a0815d15d23df9d0b10d999d.png" style="zoom:200%;" /><p><strong>1、RS232标准串口主要用于工业设备直接通信</strong></p><p><strong>1、电平转换芯片主要有MAX3232 ,SP3232</strong></p><h3 id="2-USB转串口(TTL"><a href="#2-USB转串口(TTL" class="headerlink" title="2-USB转串口(TTL)"></a>2-USB转串口(TTL)</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/ee5821e5b6ca433908b31ee7f8ae0b4e.png" style="zoom:200%;" /><p><strong>1、USB转串口主要用于设备跟电脑通信</strong></p><p><strong>2、电平转换芯片一般有CH340、PL2303、CP2102、FT232</strong></p><p><strong>3、使用的时候电脑端需要装电平转换芯片的驱动</strong></p><h3 id="3-原生的串口到串口-TTL-gt-TTL"><a href="#3-原生的串口到串口-TTL-gt-TTL" class="headerlink" title="3-原生的串口到串口(TTL->TTL)"></a>3-原生的串口到串口(TTL->TTL)</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/4331b902ebfc28d95460c753afe1fe0a.png" style="zoom:200%;" /><h3 id="4-串口数据包的基本组成"><a href="#4-串口数据包的基本组成" class="headerlink" title="4-串口数据包的基本组成"></a>4-串口数据包的基本组成</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/8152637bcea86de7f8f900f8344dc82b.png" style="zoom:200%;" /><p><strong>起始位:由1个逻辑0的数据位表示</strong></p><p><strong>结束位:由0.5、1、1.5或2个逻辑1的数据位表示</strong></p><p><strong>有效数据:在起始位后紧接着的就是有效数据,有效长度常被约定为5、6、7或8位长</strong></p><p><strong>校验位:可选,为的是数据的抗干扰性</strong></p><p><strong>校验方法分为:</strong></p><p><strong>1-奇校验(odd)</strong></p><p><strong>2-偶校验(even)</strong></p><p><strong>3-0 校验(space)</strong></p><p><strong>4-校验(mark)</strong></p><p><strong>5-无校验(noparity)</strong></p><h1 id="3-代码讲解"><a href="#3-代码讲解" class="headerlink" title="3.代码讲解"></a>3.代码讲解</h1><h3 id="1-引脚"><a href="#1-引脚" class="headerlink" title="1-引脚"></a><strong>1-引脚</strong></h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/867e579a8081853e20ca6fb20b202807.png" style="zoom:200%;" /><hr><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/8135867c3fd5bfca517822e9a8f99c88.png" style="zoom:200%;" /><hr><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/0413118f8c1b0ac19f5f774e6fc52215.png" style="zoom:200%;" /><p>有些引脚有重映射,例如USART2的TX引脚PA2和RX引脚PA3,这两个可以经过重映射到PD5和PD6</p><p>可以通过配置AFIO寄存器的USART2_REMAP来实现重映射</p><h3 id="2-数据寄存器"><a href="#2-数据寄存器" class="headerlink" title="2-数据寄存器"></a><strong>2-数据寄存器</strong></h3><p><strong>数据寄存器-USART_DR:9位有效,包含一个发送数据寄存器TDR和一个接受数据寄存器RDR。一个地址对应了两个物理内存。</strong></p><p><strong>1.USART_CR1:M , 0 :8bit , 1 : 9bit(由M位控制,如果是0数据为8位,否则为9位)</strong></p><p><strong>2.USART_CR2:STOP</strong></p><p>00: 1个停止位</p><p>01: 0.5个停止位</p><p>10: 2个停止位</p><p>11: 1.5个停止位</p><p>(注:USART4和USART5不能用0.5停止位和1.5停止位)</p><p><strong>3.USART_CR1:PCE、PS、PEIE</strong></p><p><strong>PCE:检验控制使能(Parity control enable)</strong></p><p>0:禁止校验控制;</p><p>1:使能校验控制;</p><p><strong>PS:校验选择(Parity selection)</strong></p><p>0:偶校验</p><p>1:奇校验</p><p><strong>PEIE:PE中断使能(PE interrupt enable)(数据出错时产生的中断)</strong></p><p>0:禁止产生中断</p><p>1:当USART_SR中的PE为’1‘时,产生USART中断</p><p><strong>4.USART_SR:PE</strong></p><p><strong>PE:校验错误</strong></p><p>0:没有奇偶校验错误</p><p>1:奇偶校验错误</p><h3 id="发送数据和接收数据"><a href="#发送数据和接收数据" class="headerlink" title="发送数据和接收数据"></a>发送数据和接收数据</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/USART串口/images/f8eaf04a1032fa2a054d2ec0fa2bfbda.png" alt="截图" style="zoom:200%;" /><p><u><strong>USART_CR1: UE(串口使能)、TE(发送使能)、RE(接收使能)</strong></u></p><p><strong>发送过程:</strong></p><p><strong>UE=1 TE=1</strong></p><p><strong>数据先经过TDR发送寄存器,然后再发送给发送移位寄存器</strong></p><p><strong>TXE:发送数据寄存器空</strong></p><p><strong>TC:发送完成</strong></p><p><strong>在SR寄存器内可查询标志位</strong></p><p><strong>TXEIE:转移完成中断</strong></p><p><strong>TCIE:发送完成中断</strong></p><p><strong>接收过程:</strong></p><p><strong>UE=1 RE=1</strong></p><p><strong>RXNE:读数据寄存器非空</strong></p><p><strong>RXNEIE:读数据非空中断</strong></p><h3 id="3-控制器"><a href="#3-控制器" class="headerlink" title="3-控制器"></a>3-控制器</h3><p><strong>详见数据手册</strong></p><h3 id="4-波特率"><a href="#4-波特率" class="headerlink" title="4-波特率"></a>4-波特率</h3><p><strong>USART_BRR:波特率寄存器</strong></p><p><strong>DIV_Mantissa:USARTDIV的整数部分</strong></p><p><strong>DIV_Mantissa:USARTDIV的小数部分</strong></p><p><strong>TX/RX波特率=fck/(16×USARTDIV)</strong></p><p><strong>USARTDIV:无符号的定点数</strong></p><p><strong>FCK:串口的时钟(注意区分APB2和APB1两条总线)</strong></p><p><strong>例如计算波特率为115200</strong></p><p><strong>72000000/(16×USARTDIV)</strong></p><p>解得USARTDIV=39.0625,可算得DIV_Fraction=0.0625*16=1;DIV_Mantissa=39=27</p><p><strong>设置USART_BRR的值为0x271</strong></p>]]></content>
<summary type="html"><h1 id="1-串口通信协议简介"><a href="#1-串口通信协议简介" class="headerlink" title="1.串口通信协议简介"></a>1.串口通信协议简介</h1><p><strong>物理层</strong>:</p>
<p>规定通讯系统中具有</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】TIM定时器</title>
<link href="https://www.varocol.top/2021/10/11/TIM%E5%AE%9A%E6%97%B6%E5%99%A8/"/>
<id>https://www.varocol.top/2021/10/11/TIM%E5%AE%9A%E6%97%B6%E5%99%A8/</id>
<published>2021-10-10T20:18:07.000Z</published>
<updated>2021-10-18T12:34:42.072Z</updated>
<content type="html"><![CDATA[<h1 id="1-定时器简介"><a href="#1-定时器简介" class="headerlink" title="1.定时器简介"></a>1.定时器简介</h1><h4 id="定时器功能:定时、输入比较、输入捕获、互补输出"><a href="#定时器功能:定时、输入比较、输入捕获、互补输出" class="headerlink" title="定时器功能:定时、输入比较、输入捕获、互补输出"></a>定时器功能:定时、输入比较、输入捕获、互补输出</h4><h4 id="定时器分类:基本定时器、通用定时器、高级定时器"><a href="#定时器分类:基本定时器、通用定时器、高级定时器" class="headerlink" title="定时器分类:基本定时器、通用定时器、高级定时器"></a>定时器分类:基本定时器、通用定时器、高级定时器</h4><h4 id="定时器资源:"><a href="#定时器资源:" class="headerlink" title="定时器资源:"></a>定时器资源:</h4><h4 id="F103系列:两个高级定时器TIM1-TIM8、4个通用定时器TIM2-5、2个基本定时器TIM6-TIM7"><a href="#F103系列:两个高级定时器TIM1-TIM8、4个通用定时器TIM2-5、2个基本定时器TIM6-TIM7" class="headerlink" title="F103系列:两个高级定时器TIM1,TIM8、4个通用定时器TIM2~5、2个基本定时器TIM6,TIM7"></a>F103系列:两个高级定时器TIM1,TIM8、4个通用定时器TIM2~5、2个基本定时器TIM6,TIM7</h4><h1 id="2-基本定时器功能框图"><a href="#2-基本定时器功能框图" class="headerlink" title="2.基本定时器功能框图"></a>2.基本定时器功能框图</h1><h3 id="1-基本定时器功能简介"><a href="#1-基本定时器功能简介" class="headerlink" title="1.基本定时器功能简介"></a>1.基本定时器功能简介</h3><p>1-计数器16bit,只能向上计数,只有TIM6,TIM7</p><p>2-没有外部的GPIO,是内部资源,只能用来定时</p><p>3.-时钟来自PCLK1,为72M,可实现1~65536分频</p><h3 id="2-基本定时器功能框图讲解"><a href="#2-基本定时器功能框图讲解" class="headerlink" title="2.基本定时器功能框图讲解"></a>2.基本定时器功能框图讲解</h3><h3 id="1-时钟源"><a href="#1-时钟源" class="headerlink" title="1-时钟源"></a><strong>1-时钟源</strong></h3><p>时钟源来自RCC的TIMx_CLK(属于内部的CK_INT)</p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/TIM%E5%AE%9A%E6%97%B6%E5%99%A8/images/b7ab590ffba4bd83d52be8e1872f5b84.png"></p><h3 id="2-控制器"><a href="#2-控制器" class="headerlink" title="2-控制器"></a><strong>2-控制器</strong></h3><p>1-控制器用于控制定时器的:复位、使能、计数、触发DAC</p><p>2-涉及到的寄存器为:CR1/2(控制寄存器1/2)、DIER(中断使能寄存器)、EGR(事件产生寄存器)、SR(状态寄存器)</p><h3 id="3-时基"><a href="#3-时基" class="headerlink" title="3-时基"></a><strong>3-时基</strong></h3><p> 包括<strong>预分频器(PSC)、计数器(CNT)、自动重装载寄存器(ARR)。</strong></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/TIM%E5%AE%9A%E6%97%B6%E5%99%A8/images/a408342d404aac5db774ff6cc61cf726.png"></p><p>原始时钟: <strong>CK_INT</strong></p><p>PSC时钟: <strong>CK_PSC</strong></p><p>计数时钟: <strong>CK_CNT</strong></p><p>预分频系数:<strong>PSC+1</strong></p><h3 id="4-预分频器"><a href="#4-预分频器" class="headerlink" title="4-预分频器"></a>4-预分频器</h3><p>1-<strong>16位的预分频器PSC对内部时钟CK_PSC进行分频之后,得到的计数器时钟CK_CNT=CK_PSC/(PSC+1)</strong></p><p>2-<strong>计数器CNT在计数器时钟的驱动下开始计数,计数一次的时间为1/CK_CNT</strong></p><p><strong>计数器时间为(ARR+1)/CK_CNT</strong></p><h3 id="5-计数器、自动重装载寄存器"><a href="#5-计数器、自动重装载寄存器" class="headerlink" title="5-计数器、自动重装载寄存器"></a>5-计数器、自动重装载寄存器</h3><p>定时器使能(CEN置1)后,计数器CNT在CK_CNT驱动下计数,当TCNT值与ARR的设定值相等时就自动生成事件并CNT自动清零,然后自动重新开始计数。</p><h3 id="6-影子寄存器"><a href="#6-影子寄存器" class="headerlink" title="6-影子寄存器"></a>6-影子寄存器</h3><p>1-PSC和ARR都有影子寄存器,功能框图上有个影子</p><p>2-影子寄存器的存在起到一个缓冲的作用, 用户值->寄存器->影子寄存器->起作用,如果不使用影子寄存器则用户只在写道寄存器之后则立即起作用</p><p>ARR影子,TIMx_CR1 APRE位控制( 缓冲位)</p><h3 id="7-定时时间的计算"><a href="#7-定时时间的计算" class="headerlink" title="7-定时时间的计算"></a>7-定时时间的计算</h3><p>1、PSC=72-1,定时器频率=72M/(PSC+1)=1MHZ</p><p>2、ARR = 1000-1,从0计数到999,则计了1000次</p><p>3、中断周期T=1000*1/1000000 = 1ms</p><h3 id="8-时基初始化结构体"><a href="#8-时基初始化结构体" class="headerlink" title="8-时基初始化结构体"></a>8-时基初始化结构体</h3><p>TIM_TimeBaseInitTypeDef</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs c_cpp">typedef struct<br>{<br> uint16_t TIM_Prescaler; //分频因子<br> uint16_t TIM_CounterMode; //计数模式,基本定时器只能向上计数<br> uint32_t TIM_Poriod; //自动重装载值<br> uint16_t TIM_ClockDivision; //外部输入时钟分频因子,基本定时器没有<br> uint8_t TIM_RepetitionCounter;//重复计数器,基本定时器没有,<br>}TIM_TimeBaseInitTypeDef;<br></code></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="1-定时器简介"><a href="#1-定时器简介" class="headerlink" title="1.定时器简介"></a>1.定时器简介</h1><h4 id="定时器功能:定时、输入比较、输入捕获、互补输出"><a href="#定时器功能:定时、输</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】STM32中断</title>
<link href="https://www.varocol.top/2021/10/11/STM32%E4%B8%AD%E6%96%AD/"/>
<id>https://www.varocol.top/2021/10/11/STM32%E4%B8%AD%E6%96%AD/</id>
<published>2021-10-10T19:56:20.000Z</published>
<updated>2021-10-10T12:42:53.746Z</updated>
<content type="html"><![CDATA[<h1 id="1-异常类型-中断类型)"><a href="#1-异常类型-中断类型)" class="headerlink" title="1.异常类型(中断类型)"></a>1.异常类型(中断类型)</h1><p>F103在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。</p><p><strong>系统异常8个(不算Reset和HardFault),外部中断有60个。</strong></p><p>除<strong>个别异常的优先级被定死</strong>外,其他异常的优先级都可编程。</p><p>异常和外部中断可在标准库文件<u><strong>stm32f10x.h</strong></u>这个头文件找到,在IRQn_Type这个结构体里面包含</p><p>了F103系列全部的异常声明。</p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/b81b6491adc68c59625aad2635f58eeb.png" style="zoom:150%;" /><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/092f1c9277dbbc389e5734426beeb8a6.png" style="zoom:150%;" /><h1 id="2-NVIC简介"><a href="#2-NVIC简介" class="headerlink" title="2.NVIC简介"></a>2.NVIC简介</h1><p><strong><u>NVIC </u></strong> 嵌套向量中断控制器,控制着整个芯片中断相关功能,它跟内核紧密耦合,是内核里面的一个外设。</p><h2 id="1-NVIC寄存器简介"><a href="#1-NVIC寄存器简介" class="headerlink" title="1.NVIC寄存器简介"></a>1.NVIC寄存器简介</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs c_cpp">typedef struct {<br>__IO uint32_t ISER[8]; // 中断使能寄存器<br>uint32_t RESERVED0[24];<br>__IO uint32_t ICER[8]; // 中断清除寄存器<br>uint32_t RSERVED1[24];<br>__IO uint32_t ISPR[8]; // 中断使能悬起寄存器<br>uint32_t RESERVED2[24];<br>__IO uint32_t ICPR[8]; // 中断清除悬起寄存器<br>uint32_t RESERVED3[24];<br>__IO uint32_t IABR[8]; // 中断有效位寄存器<br>uint32_t RESERVED4[56];<br>__IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide)<br>uint32_t RESERVED5[644];<br>__O uint32_t STIR; // 软件触发中断寄存器<br>} NVIC_Type;<br></code></pre></td></tr></table></figure><p>在配置中断的时候我们一般只用ISER、ICER和IP这三个寄存器,ISER用来使能中断,ICER用来失能中断,IP用来设置中断优先级。</p><h2 id="2-NVIC中断配置固件库"><a href="#2-NVIC中断配置固件库" class="headerlink" title="2.NVIC中断配置固件库"></a>2.NVIC中断配置固件库</h2><p>在固件库文件core_cm3.h的最后,还提供了NVIC的一些函数,这些函数遵循CMSIS规则,只要是Cortex-M3的处理器都可以使用。</p><h3 id="core-cm3-h"><a href="#core-cm3-h" class="headerlink" title="core_cm3.h"></a><strong><u>core_cm3.h</u></strong></h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/f2bb4751068672398db78d63f2ce6083.png" style="zoom:200%;" /><br/><h3 id="misc-h"><a href="#misc-h" class="headerlink" title="misc.h"></a><strong><u>misc.h</u></strong></h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/8e64a7dd80f1f7d671c68b959e06c9e1.png" style="zoom:200%;" /><h1 id="3-优先级的定义"><a href="#3-优先级的定义" class="headerlink" title="3.优先级的定义"></a>3.优先级的定义</h1><h2 id="1-优先级的定义"><a href="#1-优先级的定义" class="headerlink" title="1.优先级的定义"></a>1.优先级的定义</h2><p>在NVIC中有一个专门的寄存器:中断优先级寄存器NVIC_IPRx,用来配置外部中断的优先级,IPR宽度为8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高,但绝大多数CM3芯片都会精简设计,在F103中,只使用了高4bit.</p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/50ebe70c49da8c903cf276c3c0166e36.png" style="zoom:200%;" /><p>用于表达优先级的这 4bit,又被分组成<u><strong>抢占优先级</strong></u>和<u><strong>子优先级</strong></u>。如果有多个中断同时响应,<u><strong>抢占优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。</strong></u></p><h2 id="2-优先级分组"><a href="#2-优先级分组" class="headerlink" title="2.优先级分组"></a>2.优先级分组</h2><p>优先级的分组由内核外设 SCB 的应用程序中断及复位控制寄存器 AIRCR 的PRIGROUP[10:8]位决定, F103 分为了 5 组,具体如下:主优先级=抢占优先级.</p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/24570eefe1089b1eaa1ee141c7dc677d.png" style="zoom:200%;" /><p>设置优先级分组可调用库函数 NVIC_PriorityGroupConfig()实现,有关 NVIC 中断相关的库函数都在库文件 misc.c 和 misc.h 中。</p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/6c3e34b5dde26a1ab58a374729c46dd0.png" style="zoom:200%;" /><h2 id="3-中断编程"><a href="#3-中断编程" class="headerlink" title="3.中断编程"></a>3.中断编程</h2><h3 id="1-使能中断请求"><a href="#1-使能中断请求" class="headerlink" title="1-使能中断请求"></a>1-使能中断请求</h3><p><em>这个具体由每个外设的相关中断使能位控制。比如串口有发送完成中断,接收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。</em></p><h3 id="2-配置中断优先级分组"><a href="#2-配置中断优先级分组" class="headerlink" title="2-配置中断优先级分组"></a>2-配置中断优先级分组</h3><p>调用NVIC_PriorityGroupConfig()这个函数,配置分组。</p><h3 id="3-配置NVIC寄存器,初始化NVIC-InitTypeDef"><a href="#3-配置NVIC寄存器,初始化NVIC-InitTypeDef" class="headerlink" title="3-配置NVIC寄存器,初始化NVIC_InitTypeDef"></a>3-配置NVIC寄存器,初始化NVIC_InitTypeDef</h3><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/STM32中断/images/7ec3b5f2758f18393cc0f9113d4a9be3.png" style="zoom:200%;" /><h4 id="NVIC-IRQChannel-中断源"><a href="#NVIC-IRQChannel-中断源" class="headerlink" title="NVIC_IRQChannel:中断源"></a><strong>NVIC_IRQChannel:中断源</strong></h4><h4 id="NVIC-IRQChannelPreemptionPriority-抢占优先级"><a href="#NVIC-IRQChannelPreemptionPriority-抢占优先级" class="headerlink" title="NVIC_IRQChannelPreemptionPriority:抢占优先级"></a>NVIC_IRQChannelPreemptionPriority:抢占优先级</h4><h4 id="NVIC-IRQChannelSubPriority-子优先级"><a href="#NVIC-IRQChannelSubPriority-子优先级" class="headerlink" title="NVIC_IRQChannelSubPriority:子优先级"></a>NVIC_IRQChannelSubPriority:子优先级</h4><h4 id="NVIC-IRQChannelCmd-使能或者失能"><a href="#NVIC-IRQChannelCmd-使能或者失能" class="headerlink" title="NVIC_IRQChannelCmd:使能或者失能"></a>NVIC_IRQChannelCmd:使能或者失能</h4><h3 id="4-编写中断服务函数"><a href="#4-编写中断服务函数" class="headerlink" title="4-编写中断服务函数"></a>4-编写中断服务函数</h3>]]></content>
<summary type="html"><h1 id="1-异常类型-中断类型)"><a href="#1-异常类型-中断类型)" class="headerlink" title="1.异常类型(中断类型)"></a>1.异常类型(中断类型)</h1><p>F103在内核水平上搭载了一个异常响应系统,支持为数众多的系</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】SPI协议</title>
<link href="https://www.varocol.top/2021/10/11/SPI/"/>
<id>https://www.varocol.top/2021/10/11/SPI/</id>
<published>2021-10-10T19:45:20.000Z</published>
<updated>2021-10-11T11:29:58.170Z</updated>
<content type="html"><![CDATA[<h1 id="1-SPI-协议简介"><a href="#1-SPI-协议简介" class="headerlink" title="1.SPI 协议简介"></a>1.SPI 协议简介</h1><h2 id="1-SPI硬件层"><a href="#1-SPI硬件层" class="headerlink" title="1.SPI硬件层"></a>1.SPI硬件层</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/499c7a57ac6abb3830243cdead54b413.png" alt="SPI协议简介"></p><hr><h3 id="引脚-SS-MOSI-MISO-SCK"><a href="#引脚-SS-MOSI-MISO-SCK" class="headerlink" title="引脚(SS,MOSI,MISO,SCK)"></a>引脚(SS,MOSI,MISO,SCK)</h3><hr><h3 id="SS"><a href="#SS" class="headerlink" title="SS"></a>SS</h3><p><strong>从设备选择信号线,常称为片选信号线,也称CS,NSS</strong></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/a9d728fb85d3ccbe6a6f67eab71c455b.png"></p><hr><h3 id="SCK"><a href="#SCK" class="headerlink" title="SCK"></a>SCK</h3><p><strong>时钟信号线,用于通讯数据同步</strong></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/03d1b4356b79b9d8999a55f0b0e060f1.png"></p><hr><h3 id="MOSI-MISO"><a href="#MOSI-MISO" class="headerlink" title="MOSI MISO"></a>MOSI MISO</h3><h4 id="MOSI"><a href="#MOSI" class="headerlink" title="MOSI"></a>MOSI</h4><p><strong>主设备输出/从设备输入</strong></p><h4 id="MISO"><a href="#MISO" class="headerlink" title="MISO"></a>MISO</h4><p><strong>主设备输入/从设备输出</strong></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/bd641ca007d05633b5b0172a7bc18681.png"></p><hr><h2 id="1-SPI协议层"><a href="#1-SPI协议层" class="headerlink" title="1.SPI协议层"></a>1.SPI协议层</h2><h2 id="1-SPI基本通讯过程"><a href="#1-SPI基本通讯过程" class="headerlink" title="1.SPI基本通讯过程"></a>1.SPI基本通讯过程</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/f13cfa441606fdcffc5d099e175e1079.png"></p><h2 id="2-通讯的起始和停止信号"><a href="#2-通讯的起始和停止信号" class="headerlink" title="2.通讯的起始和停止信号"></a>2.通讯的起始和停止信号</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/2fa061cf10ba70046d06e01b51241e96.png"></p><h2 id="3-数据的有效性"><a href="#3-数据的有效性" class="headerlink" title="3.数据的有效性"></a>3.数据的有效性</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/2cd4b18def34ce80ff58dc11f5f86933.png"></p><h2 id="4-CPOL-CPHA及通讯模式"><a href="#4-CPOL-CPHA及通讯模式" class="headerlink" title="4.CPOL/CPHA及通讯模式"></a>4.CPOL/CPHA及通讯模式</h2><h3 id="CPHA-0-CPOL-0-1"><a href="#CPHA-0-CPOL-0-1" class="headerlink" title="CPHA = 0 CPOL = 0/1"></a>CPHA = 0 CPOL = 0/1</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/26eacb0ae9e6aac7d8703f106aa061da.png"></p><h3 id="CPHA-1-CPOL-0-1"><a href="#CPHA-1-CPOL-0-1" class="headerlink" title="CPHA = 1 CPOL = 0/1"></a>CPHA = 1 CPOL = 0/1</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/6c249fd4b9c0b2dc1b5e79f34f5f812d.png"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/1880707b7761a39abe953c698a820562.png"></p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><h4 id="1-CPOL控制高电平还是低电平为空闲状态"><a href="#1-CPOL控制高电平还是低电平为空闲状态" class="headerlink" title="1.CPOL控制高电平还是低电平为空闲状态"></a>1.CPOL控制高电平还是低电平为空闲状态</h4><h4 id="2-CPLA控制奇数边沿还是偶数边沿为采样"><a href="#2-CPLA控制奇数边沿还是偶数边沿为采样" class="headerlink" title="2.CPLA控制奇数边沿还是偶数边沿为采样"></a>2.CPLA控制奇数边沿还是偶数边沿为采样</h4><h4 id="3-总共有4种模式"><a href="#3-总共有4种模式" class="headerlink" title="3.总共有4种模式"></a>3.总共有4种模式</h4><h1 id="2-STM32-SPI特性及架构"><a href="#2-STM32-SPI特性及架构" class="headerlink" title="2.STM32 SPI特性及架构"></a>2.STM32 SPI特性及架构</h1><h2 id="STM32-SPI架构"><a href="#STM32-SPI架构" class="headerlink" title="STM32 SPI架构"></a>STM32 SPI架构</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/59ce4ee548a17797e424147b2a76a419.png"></p><hr><h2 id="STM32-SPI简介"><a href="#STM32-SPI简介" class="headerlink" title="STM32 SPI简介"></a>STM32 SPI简介</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/d1aeb7e7cb081c5ac50697851b2384de.png"></p><p><strong>SPI1挂载在APB2总线上,最高36MHz。(F3)</strong></p><p><strong>SPI2/SPI3挂载在APB1总线上,最高18MHz。(F3)</strong></p><p><strong>数据帧可设置为8或16位。可设置低位或高位先行。</strong></p><hr><h2 id="通讯引脚"><a href="#通讯引脚" class="headerlink" title="通讯引脚"></a>通讯引脚</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/768a633183db90807ef2d9c4c39ecf38.png"></p><h3 id="SPI1"><a href="#SPI1" class="headerlink" title="SPI1"></a>SPI1</h3><p><strong>NSS PA4</strong></p><p><strong>CLK PA5</strong></p><p><strong>MISO PA6</strong></p><p><strong>MOSI PA7</strong></p><h3 id="SPI2"><a href="#SPI2" class="headerlink" title="SPI2"></a>SPI2</h3><p><strong>NSS PB12</strong></p><p><strong>CLK PB13</strong></p><p><strong>MISO PB14</strong></p><p><strong>MOSI PB15</strong></p><h3 id="SPI3"><a href="#SPI3" class="headerlink" title="SPI3"></a>SPI3</h3><p><strong>NSS PA15</strong></p><p><strong>CLK PB3</strong></p><p><strong>MISO PB4</strong></p><p><strong>MOSI PB5</strong></p><hr><h2 id="时钟控制逻辑"><a href="#时钟控制逻辑" class="headerlink" title="时钟控制逻辑"></a>时钟控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/7816273643794122b84d31ab1c7944df.png"></p><h3 id="控制部分"><a href="#控制部分" class="headerlink" title="控制部分"></a>控制部分</h3><p><strong>CR1 的 BR[0:2]</strong></p><p><strong>APB1的fpclk = 36MHz APB2的fpclk = 72MHz</strong></p><p><strong>作为主机的时候用来分频</strong></p><hr><h2 id="数据控制逻辑"><a href="#数据控制逻辑" class="headerlink" title="数据控制逻辑"></a>数据控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/48047b2d39a4a290685bc09adc594594.png"></p><p><strong>移位寄存器是有两个,一个用来发送,一个用来接收。</strong></p><p><strong>当写入数据寄存器DR,数据会被填充到发送缓冲区。</strong></p><p><strong>当读数据寄存器DR,可以获取接受缓冲区的内容。</strong></p><hr><h2 id="整体控制逻辑"><a href="#整体控制逻辑" class="headerlink" title="整体控制逻辑"></a>整体控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/03ae355edd6bb55154eb34dfdce13b1b.png"></p><h3 id="控制寄存器"><a href="#控制寄存器" class="headerlink" title="控制寄存器"></a>控制寄存器</h3><p><strong>CR1/CR2</strong></p><p><strong>可以控制SPI模式、波特率、LSB先行、主从模式、单双向模式,中断请求等。</strong></p><h3 id="状态寄存器"><a href="#状态寄存器" class="headerlink" title="状态寄存器"></a>状态寄存器</h3><p><strong>SR</strong></p><p><strong>记录当前SPI的工作状态。</strong></p><h3 id="NSS引脚"><a href="#NSS引脚" class="headerlink" title="NSS引脚"></a>NSS引脚</h3><p><strong>这个可以由软件选择特定的GPIO引脚初始化为推挽输出替代SPI固定的NSS引脚</strong></p><hr><h2 id="通讯过程"><a href="#通讯过程" class="headerlink" title="通讯过程"></a>通讯过程</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/c1ff21aeeb26f161f8670950213dc3f2.png"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/390914df9dc4076964a58dfff279fd7a.png"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/4276c3f2fee5bd36d445cf512672f399.png"></p><hr><h1 id="3-STM32-SPI初始化结构体"><a href="#3-STM32-SPI初始化结构体" class="headerlink" title="3.STM32 SPI初始化结构体"></a>3.STM32 SPI初始化结构体</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/b38acfc43693b659c3b3a2c76a9ff863.png"></p><h2 id="1-SPI-Direction"><a href="#1-SPI-Direction" class="headerlink" title="1.SPI_Direction"></a>1.SPI_Direction</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/b63ab00223ed12310dd7ebfc2814def7.png"></p><h2 id="2-SPI-Mode"><a href="#2-SPI-Mode" class="headerlink" title="2.SPI_Mode"></a>2.SPI_Mode</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/911344666f13f0857858882077354882.png"></p><h2 id="3-SPI-DataSize"><a href="#3-SPI-DataSize" class="headerlink" title="3.SPI_DataSize"></a>3.SPI_DataSize</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/094c13f337772ad84188cf2aff226e43.png"></p><h2 id="4-SPI-CPOL-amp-SPI-CPHA"><a href="#4-SPI-CPOL-amp-SPI-CPHA" class="headerlink" title="4.SPI_CPOL & SPI_CPHA"></a>4.SPI_CPOL & SPI_CPHA</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/b5c2e4abb31dfd9b1644ff936b5e95d7.png"></p><h2 id="5-SPI-NSS"><a href="#5-SPI-NSS" class="headerlink" title="5.SPI_NSS"></a>5.SPI_NSS</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/327eb47a2f1903d8ed494b46278cb0ba.png"></p><h2 id="6-SPI-BaudRatePrescaler"><a href="#6-SPI-BaudRatePrescaler" class="headerlink" title="6.SPI_BaudRatePrescaler"></a>6.SPI_BaudRatePrescaler</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/37e672e70df2919efc92a5af50b23427.png"></p><h2 id="7-SPI-FirstBit"><a href="#7-SPI-FirstBit" class="headerlink" title="7.SPI_FirstBit"></a>7.SPI_FirstBit</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/b868fad6a4ed31c3f11c81916e249bfe.png"></p><h2 id="8-SPI-CRCPolynomial"><a href="#8-SPI-CRCPolynomial" class="headerlink" title="8.SPI_CRCPolynomial"></a>8.SPI_CRCPolynomial</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/SPI/images/aa3b1c667598b400c96b25b80bdedb72.png"></p>]]></content>
<summary type="html"><h1 id="1-SPI-协议简介"><a href="#1-SPI-协议简介" class="headerlink" title="1.SPI 协议简介"></a>1.SPI 协议简介</h1><h2 id="1-SPI硬件层"><a href="#1-SPI硬件层" cla</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】I2C协议</title>
<link href="https://www.varocol.top/2021/10/10/I2C/"/>
<id>https://www.varocol.top/2021/10/10/I2C/</id>
<published>2021-10-10T15:35:20.000Z</published>
<updated>2021-10-11T10:32:39.126Z</updated>
<content type="html"><![CDATA[<h1 id="1-物理层"><a href="#1-物理层" class="headerlink" title="1.物理层"></a>1.物理层</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/b6747c60b42b8ec1f4ad8176e7aaa340.png" alt="I2C物理层"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/fc83b55798ea12c72d97b448196edf7c.png"></p><p><strong>1.SCL 串行时钟线</strong></p><p><strong>2.SDA 双向串行数据线</strong></p><p><strong>3.每个设备有独立的地址</strong></p><p><strong>4.每个设备在空闲状态时都会输出高阻态,所有都为空闲状态时,则总线被上拉为高电平</strong></p><p><strong>5.SDA 设备用高阻态表示高电平(1),接地表示低电平(0)</strong></p><p><strong>6.三种传输模式:标准传输速率为100kbit/s,快速模式为400kbits/s,高速模式为3.4Mbit/s(大多数设备不支持)</strong></p><h1 id="2-协议层"><a href="#2-协议层" class="headerlink" title="2.协议层"></a>2.协议层</h1><h2 id="1-I2C基本读写过程"><a href="#1-I2C基本读写过程" class="headerlink" title="1.I2C基本读写过程"></a>1.I2C基本读写过程</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/706cbc41f98c28dcc277fc789d384d65.png" alt="I2C的协议层"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/997d8baff82185bd1a7b05190612d63f.png"></p><p><strong>1. 数据和时钟线都为高时总线处于<u>空闲状态</u>。</strong></p><p><strong>2. 当SCL为高电平时SDA的下降沿为<u>起始条件(S)</u>。</strong></p><p><strong>3. 当SCL为高电平时SDA的上升沿为<u>停止条件(P)</u>。</strong></p><p><strong>4. 当SCL为高电平时,SDA的<u>数据有效</u>,否则<u>无效</u>。</strong></p><h2 id="2-地址及数据方向"><a href="#2-地址及数据方向" class="headerlink" title="2.地址及数据方向"></a>2.地址及数据方向</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/a58550372243af2a48b5d97efe9cef85.png" alt="数据方向"></p><p><strong>前七位为从机地址,最后一位为读写方向位</strong></p><p><strong>从高位开始传输</strong></p><h2 id="3-响应"><a href="#3-响应" class="headerlink" title="3.响应"></a>3.响应</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/4ce7fd1576e0c80ec8d2c98232c20d9d.png" alt="I2C通信规则"></p><p><strong>当数据端释放SDA控制权后,若接收端控制SDA为低电平时(在第9个时钟),则产生了<u>应答信号(ACK)</u>,若为高电平,即无动作,则产生<u>非应答信号(NACK)</u>。</strong></p><h1 id="3-STM32的I2C架构"><a href="#3-STM32的I2C架构" class="headerlink" title="3.STM32的I2C架构"></a>3.STM32的I2C架构</h1><h2 id="1-通讯引脚"><a href="#1-通讯引脚" class="headerlink" title="1.通讯引脚"></a>1.通讯引脚</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/e0a8cf127f8e7a510d3c44d97ba1780b.png" alt="STM32 I2Cx(x=1,2)引脚"></p><br/><h3 id="I2C1"><a href="#I2C1" class="headerlink" title="I2C1"></a>I2C1</h3><p><strong>默认复用</strong></p><h5 id="SCL-PB5-SDA-PB6"><a href="#SCL-PB5-SDA-PB6" class="headerlink" title="SCL:PB5 SDA:PB6"></a>SCL:PB5 SDA:PB6</h5><h5 id="重定义"><a href="#重定义" class="headerlink" title="重定义"></a>重定义</h5><h5 id="SCL-PB8-SDA-PB9"><a href="#SCL-PB8-SDA-PB9" class="headerlink" title="SCL:PB8 SDA:PB9"></a>SCL:PB8 SDA:PB9</h5><h3 id="I2C2"><a href="#I2C2" class="headerlink" title="I2C2"></a>I2C2</h3><p><strong>默认复用</strong></p><h5 id="SCL-PB10-SDA-PB11"><a href="#SCL-PB10-SDA-PB11" class="headerlink" title="SCL:PB10 SDA:PB11"></a>SCL:PB10 SDA:PB11</h5><h2 id="2-时钟控制逻辑"><a href="#2-时钟控制逻辑" class="headerlink" title="2.时钟控制逻辑"></a>2.时钟控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/32634e3bf7adbf33b4b66d7ae204d129.png" alt="时钟控制逻辑"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/a6dbd60e4faa39e76cad733061a76fd1.png" alt="时钟控制寄存器 I2C_CCR"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/61c4f3e6a7ecfb8b77430f5736ba06d0.png" alt="CCR寄存器位"></p><p><strong>1.I2C模块的时钟频率必须是10MHz整数倍</strong><br><strong>2.PE为0时才能配置CCR寄存器</strong><br><strong>3.标准模式下(100kbit/s) Thigh = Tlow(注:T = Thigh + Tlow,这里的100kHz的周期应当是二者相加)</strong><br><strong>4.DUTY 位标准模式没关系,是用来设置快速模式的占空比(2:1 16:9)</strong><br><strong>5.CCR根据自己配置的I2C模式自行计算</strong><br><strong>若PCLK = 8MHz (FREQ寄存器控制)</strong><br><strong>100kbit/s 对应的 CCR = 0x28 = 40</strong><br><strong>400kbit/s 对应的 CCR = 0x0A = 10</strong></p><h2 id="3-数据控制逻辑"><a href="#3-数据控制逻辑" class="headerlink" title="3.数据控制逻辑"></a>3.数据控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/7442cd57c7ae2816a8549d8bbf069156.png" alt="I2C_DR"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/020971b38e2025cf9e6f99a22f8cbcc1.png" alt="数据控制逻辑"></p><br/><h2 id="4-整体控制逻辑"><a href="#4-整体控制逻辑" class="headerlink" title="4.整体控制逻辑"></a>4.整体控制逻辑</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/411cfa8735617bd474b3d04c41f9941f.png" alt="I2C_CR1"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/da5b1a120482719d6ccd74966aaf750b.png" alt="I2C_CR2"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/116c42a85422663cbdb676bef3440959.png" alt="I2C_SR1"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/26bd9ca1b346ee305c6c8c5aaa4f6ead.png" alt="I2C_SR2"></p><h4 id="I2C配置由CR1-和-CR2-寄存器配置"><a href="#I2C配置由CR1-和-CR2-寄存器配置" class="headerlink" title="I2C配置由CR1 和 CR2 寄存器配置"></a>I2C配置由CR1 和 CR2 寄存器配置</h4><h4 id="工作时的状态由SR1-和-SR2-寄存器显示"><a href="#工作时的状态由SR1-和-SR2-寄存器显示" class="headerlink" title="工作时的状态由SR1 和 SR2 寄存器显示"></a>工作时的状态由SR1 和 SR2 寄存器显示</h4><h1 id="4-STM32-I2C-通讯过程"><a href="#4-STM32-I2C-通讯过程" class="headerlink" title="4.STM32 I2C 通讯过程"></a>4.STM32 I2C 通讯过程</h1><h2 id="1-主发送器模式"><a href="#1-主发送器模式" class="headerlink" title="1.主发送器模式"></a>1.主发送器模式</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/8cceef41261925c0edaeafce531441e7.png" alt="7位发送模式"></p><h3 id="7位主发送模式过程:"><a href="#7位主发送模式过程:" class="headerlink" title="7位主发送模式过程:"></a>7位主发送模式过程:</h3><ol><li><p>Start 信号产生。</p></li><li><p>EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。</p></li><li><p>把地址写入DR寄存器。</p></li><li><p>接收到ACK信号。</p></li><li><p>产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。</p></li><li><p>产生EV8_1事件, TXE(数据寄存器为空位) = 1 ,移位寄存器和数据寄存器都为空,写入DR寄存器可以清除该标志位。</p></li><li><p>写入DR寄存器。</p></li><li><p>产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。</p></li><li><p>接收到ACK应答信号。</p></li><li><p>写入DR寄存器(第二次发送数据)。</p></li><li><p>产生EV8事件,TXE(数据寄存器为空位) = 1 ,数据寄存器为空,移位寄存器不为空,写入DR寄存器可以清除该位。</p></li><li><p>所有数据发送完成后产生EV8_2事件,此时BTF 和 TXE = 1 。</p></li><li><p>发送停止信号</p></li></ol><h3 id="10位主发送模式过程同理"><a href="#10位主发送模式过程同理" class="headerlink" title="10位主发送模式过程同理"></a>10位主发送模式过程同理</h3><h2 id="2-主接收器模式"><a href="#2-主接收器模式" class="headerlink" title="2.主接收器模式"></a>2.主接收器模式</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/d9de0863835f923e78a5ee440833df67.png" alt="7位主接受"></p><h3 id="7位主接收模式过程:"><a href="#7位主接收模式过程:" class="headerlink" title="7位主接收模式过程:"></a>7位主接收模式过程:</h3><p><strong>1. Start 信号产生。</strong><br><strong>2. EV5事件产生,SB = 1 ,即开始条件发送完成位置1,读SR1 寄存器,并写入DR寄存器能清除该事件。</strong><br><strong>3. 把地址写入DR寄存器。</strong><br><strong>4. 接收到ACK信号。</strong><br><strong>5. 产生EV6事件,ADDR(地址已被发送位) = 1 ,当收到地址的ACK后该位被置1,读SR1 和 SR2 会清除该位。</strong><br><strong>6. 产生EV6_1事件,用于接收1个字节,需要清除响应(ACK)和停止条件(STOP)的产生位。</strong><br><strong>7. 主机产生ACK应答信号。</strong><br><strong>8. 产生EV7事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。</strong><br><strong>9. 主机产生ACK应答信号。</strong><br><strong>10. 产生EV7_1事件,RXNE = 1 ,此时DR寄存器不为空,需要读DR寄存器来清除该事件。并且需要设置ACK = 0 ,STOP = 1。</strong><br><strong>11. 主机产生NACK非应答信号。</strong><br><strong>12. 主机产生STOP信号。</strong><br><strong>13. 产生EV7事件。</strong></p><h3 id="10位主接收模式过程同理"><a href="#10位主接收模式过程同理" class="headerlink" title="10位主接收模式过程同理"></a>10位主接收模式过程同理</h3><h1 id="5-STM32-IIC-库函数"><a href="#5-STM32-IIC-库函数" class="headerlink" title="5. STM32 IIC 库函数"></a>5. STM32 IIC 库函数</h1><h2 id="1-I2C-初始化结构体"><a href="#1-I2C-初始化结构体" class="headerlink" title="1.I2C 初始化结构体"></a>1.I2C 初始化结构体</h2><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/9454448cbdd82f0ea15a44d508962410.png" alt="I2C 初始化结构体"></p><h3 id="1-I2C-ClockSpeed"><a href="#1-I2C-ClockSpeed" class="headerlink" title="1.I2C_ClockSpeed"></a>1.I2C_ClockSpeed</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/04763a06d3262b5b5f58d66a5c2438ed.png" alt="I2C ClockSpeed"></p><p><strong>注:I2C的标准和快速模式已经在这里配置完成,根据输入的时钟值来确定,小于等于100k为标准,否则为快速</strong></p><h3 id="2-I2C-Mode"><a href="#2-I2C-Mode" class="headerlink" title="2.I2C_Mode"></a>2.I2C_Mode</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/344fdeacab0d76005c333b605cd2338c.png" alt="I2C Mode"></p><h3 id="3-I2C-DutyCycle"><a href="#3-I2C-DutyCycle" class="headerlink" title="3.I2C_DutyCycle"></a>3.I2C_DutyCycle</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/58d909b8a74961ade68125badcf4c397.png" alt="I2C_DutyCycle"></p><h3 id="4-I2C-OwnAddress1"><a href="#4-I2C-OwnAddress1" class="headerlink" title="4.I2C_OwnAddress1"></a>4.I2C_OwnAddress1</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/5c79c0793201714c83435dad0e8f0e25.png" alt="I2C_OwnAddress1"></p><h3 id="5-I2C-Ack"><a href="#5-I2C-Ack" class="headerlink" title="5.I2C_Ack"></a>5.I2C_Ack</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/6033a1fda1e571c96880e842f2fcda70.png" alt="I2C_Ack"></p><h3 id="6-I2C-AcknowledgedAddress"><a href="#6-I2C-AcknowledgedAddress" class="headerlink" title="6.I2C_AcknowledgedAddress"></a>6.I2C_AcknowledgedAddress</h3><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/I2C/images/dc3253a491d8e2982ab742fec8a77f23.png" alt="I2C_AcknowledgedAddress"></p>]]></content>
<summary type="html"><h1 id="1-物理层"><a href="#1-物理层" class="headerlink" title="1.物理层"></a>1.物理层</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/V</summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>【STM32学习笔记】EXTI中断</title>
<link href="https://www.varocol.top/2021/10/10/EXTI%E4%B8%AD%E6%96%AD/"/>
<id>https://www.varocol.top/2021/10/10/EXTI%E4%B8%AD%E6%96%AD/</id>
<published>2021-10-09T17:02:20.000Z</published>
<updated>2021-10-10T01:29:10.052Z</updated>
<content type="html"><![CDATA[<h1 id="1-EXTI简介"><a href="#1-EXTI简介" class="headerlink" title="1.EXTI简介"></a>1.EXTI简介</h1><p><strong>EXTI(外部中断/事件控制器),管理20个中断。</strong><br><strong>每个中断/事件线都对应一个边沿检测器,可以实现输入信号的上升沿检测和下降沿检测。</strong><br><strong>EXTI可以实现对每个中断进行单独配置,可以单独配置中断或者事件。</strong></p><h1 id="2-EXTI-功能框图"><a href="#2-EXTI-功能框图" class="headerlink" title="2.EXTI 功能框图"></a>2.EXTI 功能框图</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI%E4%B8%AD%E6%96%AD/images/bfee6138d7ec18f42aaff95258f05f61.png" alt="EXTI功能框图"></p><p>EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件。</p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI%E4%B8%AD%E6%96%AD/images/884c0cffc0b7395b034ea10ccffe10ba.png" alt="EXTI框图解释"></p><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI%E4%B8%AD%E6%96%AD/images/e4409ae054b51d8ca0db6d8b947be3dd.png"></p><h1 id="3-中断-事件线"><a href="#3-中断-事件线" class="headerlink" title="3.中断/事件线"></a>3.中断/事件线</h1><p>EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至 EXTI15,</p><p>还有另外四根用于特定的外设事件。</p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI中断/images/88f70120dd0b2c99ac05f27d131e2319.png" alt="EXTI信号线" style="zoom:200%;" /><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI%E4%B8%AD%E6%96%AD/images/eb96c500c8529d2f175a200905337f7c.png" alt="EXTI输入示意图"></p><h1 id="4-EXTI初始化结构体详解"><a href="#4-EXTI初始化结构体详解" class="headerlink" title="4.EXTI初始化结构体详解"></a>4.EXTI初始化结构体详解</h1><p><img src="https://cdn.jsdelivr.net/gh/Varocol/ImgHosting/Varocol_Blog/EXTI%E4%B8%AD%E6%96%AD/images/878597d6ed4a2207994c237ada8b6e7c.png" alt="EXTI初始化结构体"></p>]]></content>
<summary type="html"><h1 id="1-EXTI简介"><a href="#1-EXTI简介" class="headerlink" title="1.EXTI简介"></a>1.EXTI简介</h1><p><strong>EXTI(外部中断/事件控制器),管理20个中断。</strong><br></summary>
<category term="STM32" scheme="https://www.varocol.top/categories/STM32/"/>
<category term="STM32" scheme="https://www.varocol.top/tags/STM32/"/>
<category term="单片机" scheme="https://www.varocol.top/tags/%E5%8D%95%E7%89%87%E6%9C%BA/"/>
<category term="学习笔记" scheme="https://www.varocol.top/tags/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
</feed>