-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
2096 lines (1905 loc) · 409 KB
/
search.xml
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
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>使用AI对话将内容部署到微信上</title>
<url>/2020/36.AItalk-WeChat/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近闲来无事,在玩ESP32的时候看到了HTTP请求,从<a href="https://id.qweather.com/" target="_blank" rel="noopener">和风天气</a>爬到了一些信息,当看到返回的Json的数据时还是非常兴奋的。就顺便想了下,觉得如果有AI对话,那肯定很有意思,那如果能够发到微信上面,那不是我女神每天早上的早安和晚安语录那不是也有了嘛?哈哈哈,说干就干,下面是每天早上七点半的早安语录示例,还要说明一下,这个小项目的话个人开源,<a href="https://github.com/Homepea7/OneWordEveryday" target="_blank" rel="noopener">代码在这里</a>。<img src="/images/Python/1.0.png" alt="内容">。</p>
<h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><p>话不多说,直接上代码,首先是利用的库。如果没有的话请自行pip安装,linux用户记得使用pip3:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># -*- coding: utf-8 -*-</span></span><br><span class="line">import os</span><br><span class="line">import re</span><br><span class="line">import json</span><br><span class="line">import time</span><br><span class="line">import string</span><br><span class="line">import random</span><br><span class="line">import urllib</span><br><span class="line">import hashlib</span><br><span class="line">import requests</span><br><span class="line">import schedule</span><br><span class="line">import datetime</span><br><span class="line">from urllib.parse import quote</span><br><span class="line">from pyserverchan import pyserver</span><br></pre></td></tr></table></figure>
<p>然后就是我用到的AI机器人,刚刚开始的时候我都想试试,最后确定了两个我觉得挺好用的,这里都分享出来,分别是<a href="https://api.qingyunke.com/" target="_blank" rel="noopener">青云客</a>的AI对话和<a href="https://ai.qq.com/product/nlpchat.shtml" target="_blank" rel="noopener">腾讯闲聊</a>的AI对话。下面我都会对这两个进行简单的分析。</p>
<p>下面呢我还是对这两个AI对话做一个简单的介绍吧,首先是青云客,我选择的理由非常简单,不用注册,不用申请key,直接拿来立马就可以用,而且实现超级简单,功能如下:完全免费,支持功能:天气、翻译、藏头诗、笑话、歌词、计算、域名信息/备案/收录查询、IP查询、手机号码归属、人工智能聊天;</p>
<p>其次是腾讯闲聊AI对话:腾讯闲聊服务基于AI Lab领先的NLP引擎能力、数据运算能力和千亿级互联网语料数据的支持,同时集成了广泛的知识问答能力,可实现上百种自定义属性配置,以及男、女不同的语言风格及说话方式,从而让聊天变得更睿智、简单和有趣。而且有一个非常好用的点事可以接入微信公众号,实现简单的AI对话,如果有需求的话实现会很简单。</p>
<p>做一个简单的对比吧,青云客的机器人使用简单,但是速度相对较慢,一般发言一次可能需要5-6秒才能恢复;腾讯的AI对话使用较为麻烦,还需要注册和申请key,但是作为国内的巨头之一,速度真的是非常快,感觉1-2秒就能返回想要的数据。好了,下面是具体的代码解析。</p>
<h2 id="青云客的实现"><a href="#青云客的实现" class="headerlink" title="青云客的实现"></a>青云客的实现</h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:青云客机器人的简单对话</span></span><br><span class="line"><span class="comment"># 函数输入:想要的对话(utf-8编码的)</span></span><br><span class="line"><span class="comment"># 函数输出:AI对话的结果</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line">def qingyunkeAI(msg):</span><br><span class="line"> url = <span class="string">'http://api.qingyunke.com/api.php?key=free&appid=0&msg={}'</span>.format(urllib.parse.quote(msg))</span><br><span class="line"> html = requests.get(url)</span><br><span class="line"> <span class="built_in">return</span> html.json()[<span class="string">"content"</span>]</span><br><span class="line"><span class="comment"># msg = '武汉的天气怎么样'</span></span><br><span class="line"><span class="comment"># print("原话>>", msg)</span></span><br><span class="line"><span class="comment"># res = qingyunkeAI(msg)</span></span><br><span class="line"><span class="comment"># print("青云客>>", res)</span></span><br></pre></td></tr></table></figure>
<h2 id="腾讯闲聊的实现"><a href="#腾讯闲聊的实现" class="headerlink" title="腾讯闲聊的实现"></a>腾讯闲聊的实现</h2><p>首先去腾讯闲聊登录,第一选择肯定是QQ登录,他默认也是会使用QQ登录的,然后直接<img src="/images/Python/1.1.png" alt="创建应用">),然后就可以拿到APPID和APPKEY。<img src="/images/Python/1.3.png" alt="如下"><br>然后就可以愉快的调用下面的代码啦(在仓库里面还有一个单独的TencentAI.py文件,也是用来解析的,那个使用控制台进行的对话):</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:腾讯AI的简单对话</span></span><br><span class="line"><span class="comment"># 函数输入:想要的对话(utf-8编码的)</span></span><br><span class="line"><span class="comment"># 函数输出:AI对话的结果</span></span><br><span class="line"><span class="comment"># 备注: 腾讯闲聊机器人的凭证如下:</span></span><br><span class="line"><span class="comment"># App_ID: 123456</span></span><br><span class="line"><span class="comment"># App_Key: 123456</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line">def tencentAI(msg):</span><br><span class="line"> APPID = <span class="string">"123456"</span> <span class="comment">#替换成自己申请的ID</span></span><br><span class="line"> APPKEY = <span class="string">"123456"</span> <span class="comment">#替换成自己申请的KEY</span></span><br><span class="line"> url = <span class="string">"https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat"</span></span><br><span class="line"> params = {</span><br><span class="line"> <span class="string">"app_id"</span>: APPID,</span><br><span class="line"> <span class="string">"time_stamp"</span>: str(int(time.time())),</span><br><span class="line"> <span class="string">"nonce_str"</span>: <span class="string">""</span>.join(random.choice(string.ascii_letters + string.digits) <span class="keyword">for</span> x <span class="keyword">in</span> range(16)),</span><br><span class="line"> <span class="string">"session"</span>: <span class="string">"10000"</span>.encode(<span class="string">"utf-8"</span>),</span><br><span class="line"> <span class="string">"question"</span>: msg.encode(<span class="string">"utf-8"</span>)</span><br><span class="line"> }</span><br><span class="line"> sign_before = <span class="string">""</span></span><br><span class="line"> <span class="keyword">for</span> key <span class="keyword">in</span> sorted(params):</span><br><span class="line"> <span class="comment"># 键值拼接过程value部分需要URL编码,URL编码算法用大写字母,例如%E8。quote默认大写。</span></span><br><span class="line"> sign_before += <span class="string">"{}={}&"</span>.format(key, urllib.parse.quote(params[key], safe=<span class="string">""</span>))</span><br><span class="line"> <span class="comment"># 将应用密钥以app_key为键名,拼接到字符串sign_before末尾</span></span><br><span class="line"> sign_before += <span class="string">"app_key={}"</span>.format(APPKEY)</span><br><span class="line"> <span class="comment"># 对字符串sign_before进行MD5运算,得到接口请求签名</span></span><br><span class="line"> sign = hashlib.md5(sign_before.encode(<span class="string">"UTF-8"</span>)).hexdigest().upper()</span><br><span class="line"> params[<span class="string">"sign"</span>] = sign</span><br><span class="line"> <span class="comment"># print(params)</span></span><br><span class="line"> html = requests.post(url, data=params).json()</span><br><span class="line"> <span class="built_in">return</span> html[<span class="string">"data"</span>][<span class="string">"answer"</span>]</span><br><span class="line"><span class="comment"># msg= "讲一个笑话"</span></span><br><span class="line"><span class="comment"># print("原话>>", msg)</span></span><br><span class="line"><span class="comment"># res = tencentAI(msg)</span></span><br><span class="line"><span class="comment"># print("腾讯>>", res)</span></span><br></pre></td></tr></table></figure>
<h2 id="关于一言的获取"><a href="#关于一言的获取" class="headerlink" title="关于一言的获取"></a>关于一言的获取</h2><p>一言(Hitokoto)网创立于2016 年,隶属于萌创团队,目前网站主要提供一句话服务。不论在哪里,总有那么几个句子能穿透你的心。把这些句子汇聚起来,传递更多的心情。它也是可以免费和无KEY调用的,接口也是十分简单,代码如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:获取一言接口的数据,并存储到全局的字符串OneWord中</span></span><br><span class="line"><span class="comment"># 函数输入:无</span></span><br><span class="line"><span class="comment"># 函数输出:True/False</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line">def getOneWord():</span><br><span class="line"> <span class="comment"># 1. 请求一言的接口</span></span><br><span class="line"> url = <span class="string">"https://v1.hitokoto.cn/"</span></span><br><span class="line"> response = requests.get(url)</span><br><span class="line"> <span class="comment"># 2. 获取响应数据,并解析JSON,转化为python字典</span></span><br><span class="line"> result = response.json()</span><br><span class="line"> <span class="comment"># 3. 打印结果中的"hitokoto"(想要的句子)</span></span><br><span class="line"> <span class="built_in">print</span>(result[<span class="string">"hitokoto"</span>]) <span class="comment"># Json解析</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> response.status_code == 200 :</span><br><span class="line"> <span class="built_in">return</span> result[<span class="string">"hitokoto"</span>]</span><br><span class="line"> <span class="keyword">else</span> :</span><br><span class="line"> <span class="built_in">return</span> <span class="string">""</span></span><br><span class="line"><span class="comment"># getOneWord() # 测试获取一言数据</span></span><br></pre></td></tr></table></figure>
<h1 id="推送到微信端"><a href="#推送到微信端" class="headerlink" title="推送到微信端"></a>推送到微信端</h1><p>微信端额推送服务我选择了<a href="http://sc.ftqq.com/3.version" target="_blank" rel="noopener">Server酱</a>。没有别的原因,就是主页的那句话我很喜欢,<code>是的是的,有很多的客户端都可以做到这个功能,比如Slack。那为什么我还要写一个呢?因为它们总是给得太多,我只是要一个简简单单的消息接收器而已。这也成为了「Server酱」的设计目标:功能越少越好。</code>,就凭这句话,我觉得不需要多少话来介绍了,使用起来只需要授权GitHub账号,并且绑定微信,就能得到一个Key,就能很快的实现消息的推送。下面我还是简单介绍自己用法,首先是我最开始用的将一言的数据发送到微信:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:将一言数据发送到Server酱,即微信的提醒</span></span><br><span class="line"><span class="comment"># 函数输入:无</span></span><br><span class="line"><span class="comment"># 函数输出:无</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line">def sendOneWord():</span><br><span class="line"> <span class="comment"># 1. 获取sckey,具体请见:http://sc.ftqq.com/3.version</span></span><br><span class="line"> sckeyDC = <span class="string">"XXX"</span></span><br><span class="line"> sckeyLL = <span class="string">"XXX"</span></span><br><span class="line"> <span class="comment"># 2. 拼接url并且发送请求,text为推送的title,desp为推送的描述</span></span><br><span class="line"> OneWord = getOneWord()</span><br><span class="line"> <span class="comment"># print(OneWord)</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(OneWord == <span class="string">""</span>):</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">" 不好啦,服务器疯了: 未能正确获取一言的数据"</span>)</span><br><span class="line"> requests.get(<span class="string">"https://sc.ftqq.com/%s.send?text=不好啦,服务器崩了!&desp=未能正确获取一言的数据"</span>%sckeyLL)</span><br><span class="line"> requests.get(<span class="string">"https://sc.ftqq.com/%s.send?text=不好啦,服务器崩了!&desp=未能正确获取一言的数据"</span>%sckeyDC)</span><br><span class="line"> <span class="keyword">else</span>:</span><br><span class="line"> url = <span class="string">"https://sc.ftqq.com/%s.send?text=程序的测试&desp=%s"</span> % (sckeyLL, OneWord)</span><br><span class="line"> requests.get(url)</span><br><span class="line"> url = <span class="string">"https://sc.ftqq.com/%s.send?text=程序的测试&desp=%s"</span> % (sckeyDC, OneWord)</span><br><span class="line"> requests.get(url)</span><br><span class="line"><span class="comment"># sendOneWord() # 测试发送到Server酱</span></span><br></pre></td></tr></table></figure>
<p>然后我发现这个消息好像不方便设置格式,而且既然是给女神发送的,格式不好看怎么能行。我看到了Server酱是支持Markdown格式的,而且我的这么多博客都是Markdown格式,如果能够简单排版的话效果肯定会好很多,于是我又开始寻找怎么发送Markdown格式。官网上面说,两个空格就是换行,但是我发送字符串,怎么都不行,最后我就google查了一下,还真的查到了一些,我新建一个<code>.md</code>文件,然后使用Python对文件进行读写,将爬到的数据写入这个文本,然后使用函数就能直接发送Markdown格式的文件了,真的是太有才了!具体代码如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:把获取的结果保存到md文件中,方便发送</span></span><br><span class="line"><span class="comment"># 函数输入:无</span></span><br><span class="line"><span class="comment"># 函数输出:全部内容都在README.md文件中</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line">def all2md():</span><br><span class="line"> with open(<span class="string">"README.md"</span>, mode=<span class="string">'w'</span>, encoding=<span class="string">'utf-8'</span>) as f: <span class="comment"># 'w'是写模式,会清空内容</span></span><br><span class="line"> f.write(<span class="string">"# 知心一言\n"</span>)</span><br><span class="line"> f.write(<span class="string">" "</span> + getOneWord() + <span class="string">"\n\n"</span>)</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line"> msg = <span class="string">"武汉的天气怎么样"</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"原话>>"</span>, msg)</span><br><span class="line"> res = qingyunkeAI(msg)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"青云客>>"</span>, res)</span><br><span class="line"> with open(<span class="string">"README.md"</span>, mode=<span class="string">'a'</span>, encoding=<span class="string">'utf-8'</span>) as f: <span class="comment"># 'a'是追加模式</span></span><br><span class="line"> f.write(<span class="string">"# 最近天气\n"</span>)</span><br><span class="line"> f.write(<span class="string">" "</span> + re.sub(<span class="string">'{br}'</span>, <span class="string">'\n '</span>, res) + <span class="string">"\n\n"</span>)</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> msg = <span class="string">"讲一个笑话"</span></span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"原话>>"</span>, msg)</span><br><span class="line"> res = tencentAI(msg)</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">"腾讯>>"</span>, res)</span><br><span class="line"></span><br><span class="line"> with open(<span class="string">"README.md"</span>, mode=<span class="string">'a'</span>, encoding=<span class="string">'utf-8'</span>) as f: <span class="comment"># 'a'是追加模式</span></span><br><span class="line"> f.write(<span class="string">"# 每日笑话\n"</span>)</span><br><span class="line"> f.write(<span class="string">" "</span> + res + <span class="string">"\n\n"</span>)</span><br><span class="line"> f.close()</span><br><span class="line"></span><br><span class="line"> sckeyDC = <span class="string">"XXX"</span></span><br><span class="line"> sckeyLL = <span class="string">"XXX"</span></span><br><span class="line"></span><br><span class="line"> user_URL = <span class="string">'https://sc.ftqq.com/'</span> + sckeyLL + <span class="string">'.send'</span></span><br><span class="line"> svc = pyserver.ServerChan(user_URL)</span><br><span class="line"> svc.output_to_weixin_markdown(<span class="string">"README.md"</span>, title=<span class="string">'****早安呀╰(*°▽°*)╯'</span>)</span><br><span class="line"></span><br><span class="line"> user_URL = <span class="string">'https://sc.ftqq.com/'</span> + sckeyDC + <span class="string">'.send'</span></span><br><span class="line"> svc = pyserver.ServerChan(user_URL)</span><br><span class="line"> <span class="comment"># svc.output_to_weixin("ATestMessage.")</span></span><br><span class="line"> <span class="comment"># svc.output_to_weixin_picture("http://sc.ftqq.com/static/image/bottom_logo.png")</span></span><br><span class="line"> svc.output_to_weixin_markdown(<span class="string">"README.md"</span>, title=<span class="string">'***早安呀╰(*°▽°*)╯'</span>)</span><br></pre></td></tr></table></figure>
<h1 id="定时任务"><a href="#定时任务" class="headerlink" title="定时任务"></a>定时任务</h1><p>定时任务我是用的是轻量级的schedule模块,他的特点是就是非常方便,但是只能用于轻量的任务调度,务必保持执行的时间小于任务调度时间,否则会调用越来越多的资源直至崩溃。具体代码如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="comment"># 函数说明:定时执行任务(schedule模块)</span></span><br><span class="line"><span class="comment"># 函数输入:无</span></span><br><span class="line"><span class="comment"># 函数输出:无</span></span><br><span class="line"><span class="comment"># 函数说明:schedule模块只能用于轻量的任务调度,务必保持执行的</span></span><br><span class="line"><span class="comment"># 时间小于任务调度时间</span></span><br><span class="line"><span class="comment"># *********************************************************</span></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">"__main__"</span>:</span><br><span class="line"> <span class="built_in">print</span>(<span class="string">" main "</span>)</span><br><span class="line"> <span class="comment"># schedule.every(1).minutes.do(all2md)</span></span><br><span class="line"> <span class="comment"># schedule.every().hour.do(all2md)</span></span><br><span class="line"> <span class="comment"># schedule.every().day.at("07:30").do(all2md)</span></span><br><span class="line"> <span class="comment"># schedule.every(5).to(10).days.do(all2md)</span></span><br><span class="line"> <span class="comment"># schedule.every().monday.do(all2md)</span></span><br><span class="line"> <span class="comment"># schedule.every().wednesday.at("13:15").do(all2md)</span></span><br><span class="line"> </span><br><span class="line"> schedule.every().day.at(<span class="string">"07:30"</span>).<span class="keyword">do</span>(all2md)</span><br><span class="line"> <span class="keyword">while</span> True:</span><br><span class="line"> schedule.run_pending()</span><br><span class="line"> time.sleep(1)</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>好啦,程序总体就是这样,我个人觉得从功能上肯定还是有很多可以开发的内容,但是目前我就是仅仅是想发送一个早安语,目前的功能也差不多足够了。程序放到我的小猫盘上面跑,24小时待机还是美滋滋。对了,如果群辉上面运行有问题,请看我上一篇文章呀。</p>
<p>话说有一个自己的小服务器真的是很爽的啊<del>~</del></p>
]]></content>
<categories>
<category>Python</category>
</categories>
<tags>
<tag>AI</tag>
<tag>Python</tag>
<tag>WeChat</tag>
</tags>
</entry>
<entry>
<title>在群辉上面安装pip</title>
<url>/2020/35.DSM-Synology-pip/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>关于NAS,群辉肯定是不得不提的,本人之前也是疫情在家的时候买了一个小猫盘,也算是尝鲜了一波NAS吧,毕竟猫盘的性能还是有点捉急的,而且是ARM的(以后肯定还是要装一台x86的)。然后最近稍微学习了一下Python的<code>requests</code>,正缺一个24小时不关机的设备跑Python的,如实就想到了群辉,而且也装好了Python,但是奈何没有pip,于是查询了一些资料(国内的几个方法好像都不行),终于给解决了。</p>
<h1 id="群辉安装Python"><a href="#群辉安装Python" class="headerlink" title="群辉安装Python"></a>群辉安装Python</h1><p>这一点应该不用说了吧,直接去群辉的套件中心,一键安装即可,然后再用SSH登录,输入<code>python -v</code>或者<code>python3 -v</code>即可查看Python版本,并且进入对应的Python环境。</p>
<h1 id="安装request库"><a href="#安装request库" class="headerlink" title="安装request库"></a>安装request库</h1><p>看了一些资料,比如<a href="https://www.bilibili.com/read/cv1428431/" target="_blank" rel="noopener">学海无涯的B站专栏</a>,这个应该是讲的最详细的一个了,但是很无奈,我这边尝试了没用,不知道是不是我平台的问题。然后就有继续找,找到了<a href="https://stackoverrun.com/cn/q/13048281" target="_blank" rel="noopener">stackoverrun</a>上面的问题讨论,也是在讨论这个问题,下面给出了相应的答案,而且回答的十分详细,步骤真的超级简单,如实就尝试了一下,果然成功了!</p>
<ul>
<li><p>首先登陆SSH并输入密码</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ssh user@synology</span><br></pre></td></tr></table></figure>
</li>
<li><p>获取管理员权限</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo su</span><br></pre></td></tr></table></figure>
</li>
<li><p>下载脚本文件到本地</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">wget https://bootstrap.pypa.io/get-pip.py</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>*最后运行文件即可</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">python get-pip.py</span><br></pre></td></tr></table></figure>
<p>下面是我运行的结果(包括了最后输入pip的测试):</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># wget https://bootstrap.pypa.io/get-pip.py</span></span><br><span class="line">--2020-10-23 08:43:55-- https://bootstrap.pypa.io/get-pip.py</span><br><span class="line">Resolving bootstrap.pypa.io... 151.101.228.175, 2a04:4e42:36::175</span><br><span class="line">Connecting to bootstrap.pypa.io|151.101.228.175|:443... connected.</span><br><span class="line">HTTP request sent, awaiting response... 200 OK</span><br><span class="line">Length: 1886796 (1.8M) [text/x-python]</span><br><span class="line">Saving to: <span class="string">'get-pip.py'</span></span><br><span class="line"></span><br><span class="line">get-pip.py 100%[===========================================>] 1.80M 1.26MB/s <span class="keyword">in</span> 1.4s </span><br><span class="line"></span><br><span class="line">2020-10-23 08:43:58 (1.26 MB/s) - <span class="string">'get-pip.py'</span> saved [1886796/1886796]</span><br><span class="line"></span><br><span class="line">ash-4.3<span class="comment"># python get-pip.py</span></span><br><span class="line">DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support <span class="keyword">for</span> Python 2.7 <span class="keyword">in</span> January 2021. More details about Python 2 support <span class="keyword">in</span> pip can be found at https://pip.pypa.io/en/latest/development/release-process/<span class="comment">#python-2-support pip 21.0 will remove support for this functionality.</span></span><br><span class="line">Collecting pip</span><br><span class="line"> Downloading pip-20.2.4-py2.py3-none-any.whl (1.5 MB)</span><br><span class="line"> |████████████████████████████████| 1.5 MB 272 kB/s </span><br><span class="line">Collecting setuptools</span><br><span class="line"> Downloading setuptools-44.1.1-py2.py3-none-any.whl (583 kB)</span><br><span class="line"> |████████████████████████████████| 583 kB 6.6 MB/s </span><br><span class="line">Collecting wheel</span><br><span class="line"> Downloading wheel-0.35.1-py2.py3-none-any.whl (33 kB)</span><br><span class="line">Installing collected packages: pip, setuptools, wheel</span><br><span class="line">Successfully installed pip-20.2.4 setuptools-44.1.1 wheel-0.35.1</span><br><span class="line">ash-4.3<span class="comment"># pip</span></span><br><span class="line"></span><br><span class="line">Usage: </span><br><span class="line"> pip <<span class="built_in">command</span>> [options]</span><br><span class="line"></span><br><span class="line">Commands:</span><br><span class="line"> install Install packages.</span><br><span class="line"> download Download packages.</span><br><span class="line"> uninstall Uninstall packages.</span><br><span class="line"> freeze Output installed packages <span class="keyword">in</span> requirements format.</span><br><span class="line"> list List installed packages.</span><br><span class="line"> show Show information about installed packages.</span><br><span class="line"> check Verify installed packages have compatible dependencies.</span><br><span class="line"> config Manage <span class="built_in">local</span> and global configuration.</span><br><span class="line"> search Search PyPI <span class="keyword">for</span> packages.</span><br><span class="line"> cache Inspect and manage pip<span class="string">'s wheel cache.</span></span><br><span class="line"><span class="string"> wheel Build wheels from your requirements.</span></span><br><span class="line"><span class="string"> hash Compute hashes of package archives.</span></span><br><span class="line"><span class="string"> completion A helper command used for command completion.</span></span><br><span class="line"><span class="string"> debug Show information useful for debugging.</span></span><br><span class="line"><span class="string"> help Show help for commands.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">General Options:</span></span><br><span class="line"><span class="string"> -h, --help Show help.</span></span><br><span class="line"><span class="string"> --isolated Run pip in an isolated mode, ignoring environment variables and user</span></span><br><span class="line"><span class="string"> configuration.</span></span><br><span class="line"><span class="string"> -v, --verbose Give more output. Option is additive, and can be used up to 3 times.</span></span><br><span class="line"><span class="string"> -V, --version Show version and exit.</span></span><br><span class="line"><span class="string"> -q, --quiet Give less output. Option is additive, and can be used up to 3 times</span></span><br><span class="line"><span class="string"> (corresponding to WARNING, ERROR, and CRITICAL logging levels).</span></span><br><span class="line"><span class="string"> --log <path> Path to a verbose appending log.</span></span><br><span class="line"><span class="string"> --no-input Disable prompting for input.</span></span><br><span class="line"><span class="string"> --proxy <proxy> Specify a proxy in the form [user:passwd@]proxy.server:port.</span></span><br><span class="line"><span class="string"> --retries <retries> Maximum number of retries each connection should attempt (default 5 times).</span></span><br><span class="line"><span class="string"> --timeout <sec> Set the socket timeout (default 15 seconds).</span></span><br><span class="line"><span class="string"> --exists-action <action> Default action when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup,</span></span><br><span class="line"><span class="string"> (a)bort.</span></span><br><span class="line"><span class="string"> --trusted-host <hostname> Mark this host or host:port pair as trusted, even though it does not have valid</span></span><br><span class="line"><span class="string"> or any HTTPS.</span></span><br><span class="line"><span class="string"> --cert <path> Path to alternate CA bundle.</span></span><br><span class="line"><span class="string"> --client-cert <path> Path to SSL client certificate, a single file containing the private key and the</span></span><br><span class="line"><span class="string"> certificate in PEM format.</span></span><br><span class="line"><span class="string"> --cache-dir <dir> Store the cache data in <dir>.</span></span><br><span class="line"><span class="string"> --no-cache-dir Disable the cache.</span></span><br><span class="line"><span class="string"> --disable-pip-version-check</span></span><br><span class="line"><span class="string"> Don'</span>t periodically check PyPI to determine whether a new version of pip is</span><br><span class="line"> available <span class="keyword">for</span> download. Implied with --no-index.</span><br><span class="line"> --no-color Suppress colored output</span><br><span class="line"> --no-python-version-warning</span><br><span class="line"> Silence deprecation warnings <span class="keyword">for</span> upcoming unsupported Pythons.</span><br><span class="line"> --use-feature <feature> Enable new functionality, that may be backward incompatible.</span><br><span class="line"> --use-deprecated <feature> Enable deprecated functionality, that will be removed <span class="keyword">in</span> the future.</span><br></pre></td></tr></table></figure>
<h1 id="下一步问题"><a href="#下一步问题" class="headerlink" title="下一步问题"></a>下一步问题</h1><p>到这里貌似已经完美解决了问题,但是我发现一个问题,我实用下列指令安装了一下<code>requests</code>:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">pip install requests</span><br></pre></td></tr></table></figure>
<p>但是在实际的实用过程中,我是用的是Python3,具体版本是3.8.2,我import requests发现直接报错,经过一番查找,发现这里的pip居然是python2的,跟我在PC上面使用的体验全完不用,可能是他默认的版本是Python2,这个的话Linux一般都是默认的2而不是3,然后我又继续小找了一番,找到了<a href="https://www.codenong.com/38141115/" target="_blank" rel="noopener">码农家园</a>的一个帖子,回复的超级乱,但是我还是找到了一些有用的信息,然后根据系统给出的提示,终于给弄好了,下面说说具体的步骤:</p>
<p>首先我直接删除之前下载的get-pip.py文件,然后重新下载了一个:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># ls</span></span><br><span class="line">get-pip.py</span><br><span class="line">ash-4.3<span class="comment"># rm get-pip.py </span></span><br><span class="line">ash-4.3<span class="comment"># curl -O https://bootstrap.pypa.io/get-pip.py</span></span><br><span class="line"> % Total % Received % Xferd Average Speed Time Time Time Current</span><br><span class="line"> Dload Upload Total Spent Left Speed</span><br><span class="line">100 1842k 100 1842k 0 0 359k 0 0:00:05 0:00:05 --:--:-- 445k</span><br><span class="line">ash-4.3<span class="comment"># sudo python3 get-pip.py</span></span><br><span class="line">Collecting pip</span><br><span class="line"> Using cached pip-20.2.4-py2.py3-none-any.whl (1.5 MB)</span><br><span class="line">Collecting setuptools</span><br><span class="line"> Downloading setuptools-50.3.2-py3-none-any.whl (785 kB)</span><br><span class="line"> |████████████████████████████████| 785 kB 71 kB/s </span><br><span class="line">Collecting wheel</span><br><span class="line"> Using cached wheel-0.35.1-py2.py3-none-any.whl (33 kB)</span><br><span class="line">Installing collected packages: pip, setuptools, wheel</span><br><span class="line"> WARNING: The scripts pip, pip3 and pip3.8 are installed <span class="keyword">in</span> <span class="string">'/var/packages/py3k/target/usr/local/bin'</span> <span class="built_in">which</span> is not on PATH.</span><br><span class="line"> Consider adding this directory to PATH or, <span class="keyword">if</span> you prefer to suppress this warning, use --no-warn-script-location.</span><br><span class="line"> WARNING: The scripts easy_install and easy_install-3.8 are installed <span class="keyword">in</span> <span class="string">'/var/packages/py3k/target/usr/local/bin'</span> <span class="built_in">which</span> is not on PATH.</span><br><span class="line"> Consider adding this directory to PATH or, <span class="keyword">if</span> you prefer to suppress this warning, use --no-warn-script-location.</span><br><span class="line"> WARNING: The script wheel is installed <span class="keyword">in</span> <span class="string">'/var/packages/py3k/target/usr/local/bin'</span> <span class="built_in">which</span> is not on PATH.</span><br><span class="line"> Consider adding this directory to PATH or, <span class="keyword">if</span> you prefer to suppress this warning, use --no-warn-script-location.</span><br><span class="line">Successfully installed pip-20.2.4 setuptools-50.3.2 wheel-0.35.1</span><br></pre></td></tr></table></figure>
<p>大家可以仔细看看这个里面的说明,目录是在 /var/packages/py3k/target/usr/local/bin 下面,这个时候pip3是不能用的:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># pip3</span></span><br><span class="line">ash: pip3: <span class="built_in">command</span> not found</span><br></pre></td></tr></table></figure>
<p>然后我又进入到他给的文件夹里面,看看有什么东西,发现有pip3这个文件,真的超级开心有木有,然后尝试用了一下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># cd /var/packages/py3k/target/usr/local/bin</span></span><br><span class="line">ash-4.3<span class="comment"># ls</span></span><br><span class="line">easy_install easy_install-3.8 pip pip3 pip3.8 python3 python3.8 wheel</span><br><span class="line">ash-4.3<span class="comment"># pip3 install requests</span></span><br><span class="line">ash: pip3: <span class="built_in">command</span> not found</span><br><span class="line">ash-4.3<span class="comment"># pip3 -v</span></span><br><span class="line">ash: pip3: <span class="built_in">command</span> not found</span><br></pre></td></tr></table></figure>
<p>哎,还是不能用,你别说,我又试了一下<code>pip -v</code>,默认的pip2还是能行,你说气不气?<br>然后我想了一下,既然不能直接运行,我用<code>./command</code>这种运行的方式还不行吗?得到一下结果:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># ./pip3</span></span><br><span class="line"></span><br><span class="line">Usage: </span><br><span class="line"> pip3 <<span class="built_in">command</span>> [options]</span><br><span class="line"></span><br><span class="line">Commands:</span><br><span class="line"> install Install packages.</span><br><span class="line"> download Download packages.</span><br><span class="line"> uninstall Uninstall packages.</span><br><span class="line"> freeze Output installed packages <span class="keyword">in</span> requirements format.</span><br><span class="line"> list List installed packages.</span><br><span class="line"> show Show information about installed packages.</span><br><span class="line"> check Verify installed packages have compatible dependencies.</span><br><span class="line"> config Manage <span class="built_in">local</span> and global configuration.</span><br><span class="line"> search Search PyPI <span class="keyword">for</span> packages.</span><br><span class="line"> cache Inspect and manage pip<span class="string">'s wheel cache.</span></span><br><span class="line"><span class="string"> wheel Build wheels from your requirements.</span></span><br><span class="line"><span class="string"> hash Compute hashes of package archives.</span></span><br><span class="line"><span class="string"> completion A helper command used for command completion.</span></span><br><span class="line"><span class="string"> debug Show information useful for debugging.</span></span><br><span class="line"><span class="string"> help Show help for commands.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">General Options:</span></span><br><span class="line"><span class="string"> -h, --help Show help.</span></span><br><span class="line"><span class="string"> --isolated Run pip in an isolated mode, ignoring environment variables and user configuration.</span></span><br><span class="line"><span class="string"> -v, --verbose Give more output. Option is additive, and can be used up to 3 times.</span></span><br><span class="line"><span class="string"> -V, --version Show version and exit.</span></span><br><span class="line"><span class="string"> -q, --quiet Give less output. Option is additive, and can be used up to 3 times (corresponding to WARNING, ERROR, and CRITICAL logging levels).</span></span><br><span class="line"><span class="string"> --log <path> Path to a verbose appending log.</span></span><br><span class="line"><span class="string"> --no-input Disable prompting for input.</span></span><br><span class="line"><span class="string"> --proxy <proxy> Specify a proxy in the form [user:passwd@]proxy.server:port.</span></span><br><span class="line"><span class="string"> --retries <retries> Maximum number of retries each connection should attempt (default 5 times).</span></span><br><span class="line"><span class="string"> --timeout <sec> Set the socket timeout (default 15 seconds).</span></span><br><span class="line"><span class="string"> --exists-action <action> Default action when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.</span></span><br><span class="line"><span class="string"> --trusted-host <hostname> Mark this host or host:port pair as trusted, even though it does not have valid or any HTTPS.</span></span><br><span class="line"><span class="string"> --cert <path> Path to alternate CA bundle.</span></span><br><span class="line"><span class="string"> --client-cert <path> Path to SSL client certificate, a single file containing the private key and the certificate in PEM format.</span></span><br><span class="line"><span class="string"> --cache-dir <dir> Store the cache data in <dir>.</span></span><br><span class="line"><span class="string"> --no-cache-dir Disable the cache.</span></span><br><span class="line"><span class="string"> --disable-pip-version-check</span></span><br><span class="line"><span class="string"> Don'</span>t periodically check PyPI to determine whether a new version of pip is available <span class="keyword">for</span> download. Implied with --no-index.</span><br><span class="line"> --no-color Suppress colored output</span><br><span class="line"> --no-python-version-warning</span><br><span class="line"> Silence deprecation warnings <span class="keyword">for</span> upcoming unsupported Pythons.</span><br><span class="line"> --use-feature <feature> Enable new functionality, that may be backward incompatible.</span><br><span class="line"> --use-deprecated <feature> Enable deprecated functionality, that will be removed <span class="keyword">in</span> the future.</span><br></pre></td></tr></table></figure>
<p>喜出望外,然后果断使用<code>./pip install xxx</code>安装了 requests 并且 import 了一下,发现可以用,真的是喜出望外,具体如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># ./pip3 install requests</span></span><br><span class="line">Collecting requests</span><br><span class="line"> Using cached requests-2.24.0-py2.py3-none-any.whl (61 kB)</span><br><span class="line">Collecting certifi>=2017.4.17</span><br><span class="line"> Using cached certifi-2020.6.20-py2.py3-none-any.whl (156 kB)</span><br><span class="line">Collecting chardet<4,>=3.0.2</span><br><span class="line"> Using cached chardet-3.0.4-py2.py3-none-any.whl (133 kB)</span><br><span class="line">Collecting idna<3,>=2.5</span><br><span class="line"> Using cached idna-2.10-py2.py3-none-any.whl (58 kB)</span><br><span class="line">Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1</span><br><span class="line"> Using cached urllib3-1.25.11-py2.py3-none-any.whl (127 kB)</span><br><span class="line">Installing collected packages: certifi, chardet, idna, urllib3, requests</span><br><span class="line"> WARNING: The script chardetect is installed <span class="keyword">in</span> <span class="string">'/var/packages/py3k/target/usr/local/bin'</span> <span class="built_in">which</span> is not on PATH.</span><br><span class="line"> Consider adding this directory to PATH or, <span class="keyword">if</span> you prefer to suppress this warning, use --no-warn-script-location.</span><br><span class="line">Successfully installed certifi-2020.6.20 chardet-3.0.4 idna-2.10 requests-2.24.0 urllib3-1.25.11</span><br><span class="line">ash-4.3<span class="comment"># python3</span></span><br><span class="line">Python 3.8.2 (tags/Contacts-1.0.0-0232-200617:57e5f51, Jun 29 2020, 09:38:52) </span><br><span class="line">[GCC 4.9.4 20150629 (prerelease)] on linux</span><br><span class="line">Type <span class="string">"help"</span>, <span class="string">"copyright"</span>, <span class="string">"credits"</span> or <span class="string">"license"</span> <span class="keyword">for</span> more information.</span><br><span class="line">>>> import requests</span><br><span class="line">>>></span><br></pre></td></tr></table></figure>
<p>可以看到,import的时候没有报错,现在已经是可以正常使用了。但是距离完美使用肯定是差一点点的,可以看到我们不可能每次都进入到<code>/var/packages/py3k/target/usr/local/bin</code>这个目录来使用pip3指令的,因此最后一步当然是将该目录加入到PATH中啦,指令如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ash-4.3<span class="comment"># export PATH="/var/packages/py3k/target/usr/local/bin:$PATH"</span></span><br><span class="line">ash-4.3<span class="comment"># pip3</span></span><br><span class="line"></span><br><span class="line">Usage: </span><br><span class="line"> pip3 <<span class="built_in">command</span>> [options]</span><br><span class="line"></span><br><span class="line">Commands:</span><br><span class="line"> install Install packages.</span><br><span class="line"> download Download packages.</span><br><span class="line"> uninstall Uninstall packages.</span><br><span class="line"> freeze Output installed packages <span class="keyword">in</span> requirements format.</span><br><span class="line"> list List installed packages.</span><br><span class="line"> show Show information about installed packages.</span><br><span class="line"> check Verify installed packages have compatible dependencies.</span><br><span class="line"> config Manage <span class="built_in">local</span> and global configuration.</span><br><span class="line"> search Search PyPI <span class="keyword">for</span> packages.</span><br><span class="line"> cache Inspect and manage pip<span class="string">'s wheel cache.</span></span><br><span class="line"><span class="string"> wheel Build wheels from your requirements.</span></span><br><span class="line"><span class="string"> hash Compute hashes of package archives.</span></span><br><span class="line"><span class="string"> completion A helper command used for command completion.</span></span><br><span class="line"><span class="string"> debug Show information useful for debugging.</span></span><br><span class="line"><span class="string"> help Show help for commands.</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">General Options:</span></span><br><span class="line"><span class="string"> -h, --help Show help.</span></span><br><span class="line"><span class="string"> --isolated Run pip in an isolated mode, ignoring environment variables and user configuration.</span></span><br><span class="line"><span class="string"> -v, --verbose Give more output. Option is additive, and can be used up to 3 times.</span></span><br><span class="line"><span class="string"> -V, --version Show version and exit.</span></span><br><span class="line"><span class="string"> -q, --quiet Give less output. Option is additive, and can be used up to 3 times (corresponding to WARNING, ERROR, and CRITICAL logging levels).</span></span><br><span class="line"><span class="string"> --log <path> Path to a verbose appending log.</span></span><br><span class="line"><span class="string"> --no-input Disable prompting for input.</span></span><br><span class="line"><span class="string"> --proxy <proxy> Specify a proxy in the form [user:passwd@]proxy.server:port.</span></span><br><span class="line"><span class="string"> --retries <retries> Maximum number of retries each connection should attempt (default 5 times).</span></span><br><span class="line"><span class="string"> --timeout <sec> Set the socket timeout (default 15 seconds).</span></span><br><span class="line"><span class="string"> --exists-action <action> Default action when a path already exists: (s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.</span></span><br><span class="line"><span class="string"> --trusted-host <hostname> Mark this host or host:port pair as trusted, even though it does not have valid or any HTTPS.</span></span><br><span class="line"><span class="string"> --cert <path> Path to alternate CA bundle.</span></span><br><span class="line"><span class="string"> --client-cert <path> Path to SSL client certificate, a single file containing the private key and the certificate in PEM format.</span></span><br><span class="line"><span class="string"> --cache-dir <dir> Store the cache data in <dir>.</span></span><br><span class="line"><span class="string"> --no-cache-dir Disable the cache.</span></span><br><span class="line"><span class="string"> --disable-pip-version-check</span></span><br><span class="line"><span class="string"> Don'</span>t periodically check PyPI to determine whether a new version of pip is available <span class="keyword">for</span> download. Implied with --no-index.</span><br><span class="line"> --no-color Suppress colored output</span><br><span class="line"> --no-python-version-warning</span><br><span class="line"> Silence deprecation warnings <span class="keyword">for</span> upcoming unsupported Pythons.</span><br><span class="line"> --use-feature <feature> Enable new functionality, that may be backward incompatible.</span><br><span class="line"> --use-deprecated <feature> Enable deprecated functionality, that will be removed <span class="keyword">in</span> the future.</span><br></pre></td></tr></table></figure>
<p>上面添加了以后我还测试了一下,任何位置都可以使用pip3来安装相应的库,好用多了!</p>
<h1 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h1><p>完美解决,皆大欢喜<del>~</del></p>
]]></content>
<categories>
<category>Python</category>
</categories>
<tags>
<tag>Python</tag>
<tag>DSM/Synology</tag>
<tag>pip</tag>
</tags>
</entry>
<entry>
<title>输入数字判断CPU是大端还是小端模式</title>
<url>/2020/30.Endian/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>前几天做了一个笔试题目,是输入一个数字,16进制的,类似 <code>0x12345678</code> 这种的,当时就想应该还是很好判断的,直接取数字的地址,然后取相应的位计算大小即可,但是通过率一直是0。一直在分析原因,由于他需要输入数据,当时也没多想,反正一直就没有做出来。知道前两天想到了一个点,存储数据最方便的肯定是字符串呀,如实今天上午花了点时间,重新写了一些,也不知道有没有通过率,反正当做是复习知识点了。</p>
<h1 id="概念与详解"><a href="#概念与详解" class="headerlink" title="概念与详解"></a>概念与详解</h1><p>在各种体系的计算机中通常采用的字节存储机制主要有两种: Big-Endian和Little-Endian,即大端模式和小端模式。<br>Big-Endian和Little-Endian的定义如下:</p>
<p>1) Little-Endian:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,如Intel的8086系列。<br>2) Big-Endian:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,如PowerPC处理器。</p>
<p>举个例子,比如16进制数字 <code>0x12345678</code> 在内存中的表示形式为:</p>
<p>大端模式:</p>
<table>
<thead>
<tr>
<th>adress</th>
<th align="center">…</th>
<th align="center">0x2000</th>
<th align="right">0x2001</th>
<th align="right">0x2002</th>
<th align="right">0x2003</th>
<th align="right">…</th>
</tr>
</thead>
<tbody><tr>
<td>data</td>
<td align="center">…</td>
<td align="center"><strong>0x12</strong></td>
<td align="right"><strong>0x34</strong></td>
<td align="right"><strong>0x56</strong></td>
<td align="right"><strong>0x78</strong></td>
<td align="right">…</td>
</tr>
</tbody></table>
<p>小端模式:</p>
<table>
<thead>
<tr>
<th>adress</th>
<th>…</th>
<th align="center">0x2000</th>
<th align="right">0x2001</th>
<th align="right">0x2002</th>
<th align="right">0x2003</th>
<th align="right">…</th>
</tr>
</thead>
<tbody><tr>
<td>data</td>
<td>…</td>
<td align="center"><strong>0x78</strong></td>
<td align="right"><strong>0x56</strong></td>
<td align="right"><strong>0x34</strong></td>
<td align="right"><strong>0x12</strong></td>
<td align="right">…</td>
</tr>
</tbody></table>
<p>小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。<br>大端模式 :符号位的判定固定为第一个字节,容易判断正负。</p>
<p>为什么会有大小端模式之分呢?<br>这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。</p>
<p>例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的x86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。</p>
<h1 id="如何判断大小端"><a href="#如何判断大小端" class="headerlink" title="如何判断大小端"></a>如何判断大小端</h1><p>直接取整数的地址,用short两位的性质才判断即可:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int i=1; </span><br><span class="line">char *p=(char *)&i; </span><br><span class="line"><span class="keyword">if</span>(*p == 1) </span><br><span class="line"> cout << <span class="string">"Little-Endian"</span> << endl;</span><br><span class="line"><span class="keyword">else</span> // (*p == 0)</span><br><span class="line"> cout << <span class="string">"Big-Endian"</span> << endl;</span><br></pre></td></tr></table></figure>
<p>或者使用联合体</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">//<span class="built_in">return</span> 1 : little-endian</span><br><span class="line">// 0 : big-endian</span><br><span class="line">int checkCPUendian()</span><br><span class="line">{</span><br><span class="line"> union {</span><br><span class="line"> unsigned int a;</span><br><span class="line"> unsigned char b; </span><br><span class="line"> } c;</span><br><span class="line"> </span><br><span class="line"> c.a = 1;</span><br><span class="line"> <span class="built_in">return</span> (c.b == 1); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结做题"><a href="#总结做题" class="headerlink" title="总结做题"></a>总结做题</h1><p>一个输入一个输出,而且大小端肯定是会变的,用一个字符串就能完美替代,具体代码如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line"><span class="comment">#include <string></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">// ** 功能:判断当前操作系统大小端的函数</span><br><span class="line">// ** 输入:一个字符串,要求是十进制的格式,Eg:0x1A2B3C4D</span><br><span class="line">// ** 输出:-1: 无法判断/ 0:小端模式/ 1:大端模式</span><br><span class="line">int judgeEndian(string str)</span><br><span class="line">{</span><br><span class="line"> // 首先字符串去头(<span class="string">"0x"</span>的头部)</span><br><span class="line"> str = str.substr(2, str.size()-1); </span><br><span class="line"> </span><br><span class="line"> // 然后去掉不能判断的(长度是奇数的可以)</span><br><span class="line"> int size = str.size(), flag = 0;</span><br><span class="line"> <span class="keyword">if</span>( !(size%2) ) {</span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < size/2; i+= 2) {</span><br><span class="line"> // cout << str.substr(i, 2) << <span class="string">" | "</span> << str.substr(size-2-i, 2) << endl; </span><br><span class="line"> <span class="keyword">if</span>(str.substr(i, 2) != str.substr(size-2-i, 2)){</span><br><span class="line"> flag = 1;</span><br><span class="line"> <span class="built_in">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(flag == 0) {</span><br><span class="line"> cout << <span class="string">" can not jundge! "</span>;</span><br><span class="line"> <span class="built_in">return</span> -1;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> // 下面开始计算</span><br><span class="line"> // 直接转换成16进制</span><br><span class="line"> int num = stoi(str, nullptr, 16);</span><br><span class="line"> // <span class="built_in">printf</span>(<span class="string">"%X \r\n"</span>, num);</span><br><span class="line"> // <span class="built_in">printf</span>(<span class="string">"%X \r\n"</span>, ((char*)&num)[0]);</span><br><span class="line"></span><br><span class="line"> // 下面是两个尾部值</span><br><span class="line"> short int orgEnd = stoi(str.substr(size-2, 2),nullptr, 16); //原本值由字符串转化而来</span><br><span class="line"> short int trsEnd = ((char*)&num)[0]; //转化值由整数经过存储,然后取地址得到</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span>(orgEnd == trsEnd) {</span><br><span class="line"> cout << <span class="string">"Little-Endian! "</span>;</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> cout << <span class="string">"Big-Endian! "</span>;</span><br><span class="line"> <span class="built_in">return</span> 1;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> string str;</span><br><span class="line"> cin >> str;</span><br><span class="line"> judgeEndian(str);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>没有什么值得特别总结的吧,感觉还是多加练习多多刷题就行!</p>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
</entry>
<entry>
<title>ESP32的定时器</title>
<url>/2020/34.ESP32-Timer/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>说起单片机或者嵌入式系统,定时器应该可以说是不可不提的内容,下面以具体的代码来介绍ESP32的定时器如何使用,一般而言在实现中断处理代码时,最好让ISR仅对中断进行响应,然后把实际的处理(可能包含时间较长的操作)交给主循环来做。按照惯例,先介绍一下环境吧:<br>硬件:TTGO T-Display ESP32带1.14LCD的小开发板 + 编码器<br>软件:VSCode + PlatformIO IDE(其实就是Arduino环境)</p>
<h1 id="程序详解"><a href="#程序详解" class="headerlink" title="程序详解"></a>程序详解</h1><p>关于定时器的初始化大概只有四五个函数,下面直接每一段单独放出来,有详细的注释。</p>
<h2 id="timerBegin"><a href="#timerBegin" class="headerlink" title=" timerBegin() "></a><coder> timerBegin() </coder></h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// 函数名称:timerBegin()</span><br><span class="line">// 函数功能:Timer初始化,分别有三个参数</span><br><span class="line">// 函数输入:1. 定时器编号(0到3,对应全部4个硬件定时器)</span><br><span class="line">// 2. 预分频器数值(ESP32计数器基频为80M,80分频单位是微秒)</span><br><span class="line">// 3. 计数器向上(<span class="literal">true</span>)或向下(<span class="literal">false</span>)计数的标志</span><br><span class="line">// 函数返回:一个指向 hw_timer_t 结构类型的指针</span><br><span class="line">timer = timerBegin(0, 80, <span class="literal">true</span>);</span><br></pre></td></tr></table></figure>
<h2 id="timerAttachInterrupt"><a href="#timerAttachInterrupt" class="headerlink" title=" timerAttachInterrupt() "></a><coder> timerAttachInterrupt() </coder></h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// 函数名称:timerAttachInterrupt()</span><br><span class="line">// 函数功能:绑定定时器的中断处理函数,分别有三个参数</span><br><span class="line">// 函数输入:1. 指向已初始化定时器的指针(本例子:timer)</span><br><span class="line">// 2. 中断处理函数的地址</span><br><span class="line">// 3. 表示中断触发类型是边沿(<span class="literal">true</span>)还是电平(<span class="literal">false</span>)的标志</span><br><span class="line">// 函数返回:无</span><br><span class="line">timerAttachInterrupt(timer, &onTimer, <span class="literal">true</span>);</span><br></pre></td></tr></table></figure>
<h2 id="timerAlarmWrite"><a href="#timerAlarmWrite" class="headerlink" title=" timerAlarmWrite() "></a><coder> timerAlarmWrite() </coder></h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// 函数名称:timerAlarmWrite()</span><br><span class="line">// 函数功能:指定触发定时器中断的计数器值,分别有三个参数</span><br><span class="line">// 函数输入:1. 指向已初始化定时器的指针(本例子:timer)</span><br><span class="line">// 2. 第二个参数是触发中断的计数器值(1000000 us -> 1s)</span><br><span class="line">// 3. 定时器在产生中断时是否重新加载的标志</span><br><span class="line">// 函数返回:无</span><br><span class="line">timerAlarmWrite(timer, 1000000, <span class="literal">true</span>);</span><br></pre></td></tr></table></figure>
<h2 id="timerAlarmEnable"><a href="#timerAlarmEnable" class="headerlink" title=" timerAlarmEnable() "></a><coder> timerAlarmEnable() </coder></h2><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">timerAlarmEnable(timer); // 使能定时器</span><br></pre></td></tr></table></figure>
<p>然后是中断服务函数ISR:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// 函数名称:onTimer()</span><br><span class="line">// 函数功能:中断服务的功能,它必须是一个返回void(空)且没有输入参数的函数,</span><br><span class="line">// 为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性</span><br><span class="line">void IRAM_ATTR <span class="function"><span class="title">onTimer</span></span>() {</span><br><span class="line"> Serial.println(interruptCounter++);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>最后是主函数,啥都不做:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>函数的结果:每秒输出一个自加的 interruptCounter,具体如下图所示:<br><img src="/images/RaspberryPi/4.5.png" alt="4.5"></p>
<h1 id="结构优化"><a href="#结构优化" class="headerlink" title="结构优化"></a>结构优化</h1><p>如前文所述,在ISR对中断做出响应之后,真正的定时器中断处理操作其实是在主循环中,更有效的处理方式是,使用一个信号量将主循环锁定,然后在ISR中将其解锁。具体操作如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <Arduino.h></span></span><br><span class="line"></span><br><span class="line">volatile int interruptCounter;</span><br><span class="line">int totalInterruptCounter;</span><br><span class="line">hw_timer_t * timer = NULL;</span><br><span class="line">portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;</span><br><span class="line"></span><br><span class="line">// 函数名称:onTimer()</span><br><span class="line">// 函数功能:中断服务的功能,它必须是一个返回void(空)且没有输入参数的函数,</span><br><span class="line">// 为使编译器将代码分配到IRAM内,中断处理程序应该具有 IRAM_ATTR 属性</span><br><span class="line">void IRAM_ATTR <span class="function"><span class="title">onTimer</span></span>() {</span><br><span class="line"> // Serial.println(interruptCounter++);</span><br><span class="line"> portENTER_CRITICAL_ISR(&timerMux);</span><br><span class="line"> interruptCounter++;</span><br><span class="line"> portEXIT_CRITICAL_ISR(&timerMux);</span><br><span class="line">}</span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(115200);</span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> // 函数名称:timerBegin()</span><br><span class="line"> // 函数功能:Timer初始化,分别有三个参数</span><br><span class="line"> // 函数输入:1. 定时器编号(0到3,对应全部4个硬件定时器)</span><br><span class="line"> // 2. 预分频器数值(ESP32计数器基频为80M,80分频单位是微秒)</span><br><span class="line"> // 3. 计数器向上(<span class="literal">true</span>)或向下(<span class="literal">false</span>)计数的标志</span><br><span class="line"> // 函数返回:一个指向 hw_timer_t 结构类型的指针</span><br><span class="line"> timer = timerBegin(0, 80, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> // 函数名称:timerAttachInterrupt()</span><br><span class="line"> // 函数功能:绑定定时器的中断处理函数,分别有三个参数</span><br><span class="line"> // 函数输入:1. 指向已初始化定时器的指针(本例子:timer)</span><br><span class="line"> // 2. 中断处理函数的地址</span><br><span class="line"> // 3. 表示中断触发类型是边沿(<span class="literal">true</span>)还是电平(<span class="literal">false</span>)的标志</span><br><span class="line"> // 函数返回:无</span><br><span class="line"> timerAttachInterrupt(timer, &onTimer, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"> // 函数名称:timerAlarmWrite()</span><br><span class="line"> // 函数功能:指定触发定时器中断的计数器值,分别有三个参数</span><br><span class="line"> // 函数输入:1. 指向已初始化定时器的指针(本例子:timer)</span><br><span class="line"> // 2. 第二个参数是触发中断的计数器值(1000000 us -> 1s)</span><br><span class="line"> // 3. 定时器在产生中断时是否重新加载的标志</span><br><span class="line"> // 函数返回:无</span><br><span class="line"> timerAlarmWrite(timer, 1000000, <span class="literal">true</span>);</span><br><span class="line"> timerAlarmEnable(timer); // 使能定时器</span><br><span class="line">}</span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> (interruptCounter > 0) {</span><br><span class="line"> portENTER_CRITICAL(&timerMux);</span><br><span class="line"> interruptCounter--;</span><br><span class="line"> portEXIT_CRITICAL(&timerMux);</span><br><span class="line"> totalInterruptCounter++;</span><br><span class="line"> Serial.print(<span class="string">"An interrupt as occurred. Total number: "</span>);</span><br><span class="line"> Serial.println(totalInterruptCounter);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>关于定时器,我个人觉得使用环境真的是非常多,也希望大家能够多看看,下面贴<a href="https://electronics.stackexchange.com/questions/21886/what-does-edge-triggered-and-level-triggered-mean" target="_blank" rel="noopener">大佬的链接</a>,可以多多参考。</p>
]]></content>
<categories>
<category>ESP32</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>ESP32</tag>
<tag>Timer</tag>
</tags>
</entry>
<entry>
<title>ESP32的外部中断和编码器的示例</title>
<url>/2020/33.ESP32-Interrupt/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>这次主要是记录ESP32的外部中断的相关内容,并且刚刚调试好了编码器,也做一个小小的分享!<br>按照惯例,先介绍一下环境吧:<br>硬件:TTGO T-Display ESP32带1.14LCD的小开发板 + 编码器<br>软件:VSCode + PlatformIO IDE(其实就是Arduino环境)</p>
<h1 id="程序详解"><a href="#程序详解" class="headerlink" title="程序详解"></a>程序详解</h1><p>下面就一具体的功能实现来讲解使用外部中断调试编码器。首先还是简单介绍一下<a href="https://baike.baidu.com/item/%E7%BC%96%E7%A0%81%E5%99%A8" target="_blank" rel="noopener">编码器</a>吧,编码器(encoder)是将信号(如比特流)或数据进行编制、转换为可用以通讯、传输和存储的信号形式的设备。编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺。按照读出方式编码器可以分为接触式和非接触式两种;按照工作原理编码器可分为增量式和绝对式两类。增量式编码器是将位移转换成周期性的电信号,再把这个电信号转变成计数脉冲,用脉冲的个数表示位移的大小。绝对式编码器的每一个位置对应一个确定的数字码,因此它的示值只与测量的起始和终止位置有关,而与测量的中间过程无关。</p>
<p>我们直接上淘宝搜索,看具体的实物我觉得会看的更加清楚。然后开始看具体的程序了,首先定义引脚和一些需要用到的变量:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">//定义引脚连接</span><br><span class="line">int CLK = 12; //CLK->D2</span><br><span class="line">int DT = 13; //DT->D3</span><br><span class="line">int SW = 15; //SW->D4</span><br><span class="line"></span><br><span class="line">const int Int_Pin = digitalPinToInterrupt(CLK);// Interrupt 0 在 pin 2 上</span><br><span class="line">int count = 0;//计数值</span><br><span class="line">int lastCLK = 0;//CLK历史值</span><br></pre></td></tr></table></figure>
<p>其次是中断处理函数,就是我们在出发外部中断时需要用到的操作:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">//中断处理函数</span><br><span class="line">void ClockChanged()</span><br><span class="line">{</span><br><span class="line"> // Serial.println("a");</span><br><span class="line"> int clkValue = digitalRead(CLK); //读取CLK引脚的电平</span><br><span class="line"> int dtValue = digitalRead(DT); //读取DT引脚的电平</span><br><span class="line"> if (lastCLK != clkValue) {</span><br><span class="line"> lastCLK = clkValue;</span><br><span class="line"> count += (clkValue != dtValue ? 1 : -1);//CLK和DT不一致时+1,否则-1</span><br><span class="line"> Serial.print("count:");</span><br><span class="line"> Serial.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其次是初始化的函数,其中外部中断的初始化函数<code>attachInterrupt()</code>也在里面。接下来,由于将使用外部引脚中断,需要将先前声明的引脚编号配置为输入引脚。为此,调用pinMode函数,将引脚编号和操作模式作为参数传递。<code>pinMode(interruptPin, INPUT_PULLUP);</code></p>
<p>接下来,通过调用attachInterrupt函数将中断附加到引脚。作为首个参数,将调用结果传递给digitalPinToInterrupt函数,该函数将使用的引脚编号转换为相应的内部中断编号。接下来,我们传递中断处理函数,换而言之,当指定引脚上出现中断时,该函数将予以执行。我们将其称为handleInterruptand,稍后再指定其代码。最后我们传递中断模式,它基本指定了在引脚输入信号中哪种类型变化触发了中断。直接F12查看模式,会发现一共有七种模式,具体如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">//Interrupt Modes</span><br><span class="line"><span class="comment">#define RISING 0x01</span></span><br><span class="line"><span class="comment">#define FALLING 0x02</span></span><br><span class="line"><span class="comment">#define CHANGE 0x03</span></span><br><span class="line"><span class="comment">#define ONLOW 0x04</span></span><br><span class="line"><span class="comment">#define ONHIGH 0x05</span></span><br><span class="line"><span class="comment">#define ONLOW_WE 0x0C</span></span><br><span class="line"><span class="comment">#define ONHIGH_WE 0x0D</span></span><br></pre></td></tr></table></figure>
<p>然后下面是具体的初始化函数,如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void setup()</span><br><span class="line">{</span><br><span class="line">// pinMode(SW, INPUT);</span><br><span class="line">// digitalWrite(SW, HIGH);</span><br><span class="line"> pinMode(CLK, INPUT);</span><br><span class="line"> pinMode(DT, INPUT);</span><br><span class="line"> attachInterrupt(digitalPinToInterrupt(CLK), ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发</span><br><span class="line"> Serial.begin(115200);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>最后的主循环里面就很简单了,一秒打印一次<code>count</code>就可以了,具体如下所示:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void loop()</span><br><span class="line">{</span><br><span class="line">// <span class="keyword">if</span> (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零</span><br><span class="line">// {</span><br><span class="line">// count = 0;</span><br><span class="line"> Serial.print(<span class="string">"count:"</span>);</span><br><span class="line"> Serial.println(count);</span><br><span class="line"> delay(1000);</span><br><span class="line">// }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>最后把代码整合一下吧:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <Arduino.h></span></span><br><span class="line"></span><br><span class="line">//定义引脚连接</span><br><span class="line">int CLK = 12;//CLK->D2</span><br><span class="line">int DT = 13;//DT->D3</span><br><span class="line">int SW = 15;//SW->D4</span><br><span class="line"></span><br><span class="line">const int Int_Pin = digitalPinToInterrupt(CLK);// Interrupt 0 在 pin 2 上</span><br><span class="line">int count = 0;//计数值</span><br><span class="line">int lastCLK = 0;//CLK历史值</span><br><span class="line"></span><br><span class="line">//中断处理函数</span><br><span class="line">void ClockChanged()</span><br><span class="line">{</span><br><span class="line"> // Serial.println(<span class="string">"a"</span>);</span><br><span class="line"> int clkValue = digitalRead(CLK);//读取CLK引脚的电平</span><br><span class="line"> int dtValue = digitalRead(DT);//读取DT引脚的电平</span><br><span class="line"> <span class="keyword">if</span> (lastCLK != clkValue)</span><br><span class="line"> {</span><br><span class="line"> lastCLK = clkValue;</span><br><span class="line"> count += (clkValue != dtValue ? 1 : -1);//CLK和DT不一致时+1,否则-1</span><br><span class="line"> Serial.print(<span class="string">"count:"</span>);</span><br><span class="line"> Serial.println(count);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void setup()</span><br><span class="line">{</span><br><span class="line">// pinMode(SW, INPUT);</span><br><span class="line">// digitalWrite(SW, HIGH);</span><br><span class="line"> pinMode(CLK, INPUT);</span><br><span class="line"> pinMode(DT, INPUT);</span><br><span class="line"> attachInterrupt(digitalPinToInterrupt(CLK), ClockChanged, CHANGE);//设置中断0的处理函数,电平变化触发</span><br><span class="line"> Serial.begin(115200);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void loop()</span><br><span class="line">{</span><br><span class="line">// <span class="keyword">if</span> (!digitalRead(SW) && count != 0) //读取到按钮按下并且计数值不为0时把计数器清零</span><br><span class="line">// {</span><br><span class="line">// count = 0;</span><br><span class="line"> Serial.print(<span class="string">"count:"</span>);</span><br><span class="line"> Serial.println(count);</span><br><span class="line"> delay(1000);</span><br><span class="line">// }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>ESP32使用外部中断的话还是挺方便的,初始化的设计也是很容易,我写的东西可能如果是有用过相应的硬件来找一下方向应该还是比较容易看懂的,希望以后可能慢慢分享一些内容。</p>
]]></content>
<categories>
<category>ESP32</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>ESP32</tag>
<tag>外部中断</tag>
<tag>编码器</tag>
</tags>
</entry>
<entry>
<title>ESP32使用串口发送和接收数据</title>
<url>/2020/32.ESP32-UART/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>承接上文,准备玩单片机肯定是以IO和其他的外设来玩的,这次准备试试串口。资料来自Arduino的<a href="https://www.arduino.cc/reference/en/language/functions/communication/serial/print/" target="_blank" rel="noopener">官网</a>。有一说一,ESP32是真的好用!<br>按照惯例,先介绍一下环境吧:<br>硬件:TTGO T-Display ESP32带1.14LCD的小开发板<br>软件:VSCode + PlatformIO IDE(其实就是Arduino环境)</p>
<h1 id="几个常用的函数"><a href="#几个常用的函数" class="headerlink" title="几个常用的函数"></a>几个常用的函数</h1><h2 id="Serial-print"><a href="#Serial-print" class="headerlink" title="Serial.print()"></a><code>Serial.print()</code></h2><p>将数据作为人类可读的 ASCII 文本打印到串行端口。此命令可以有多种形式。每个数字都使用 ASCII 字符打印数字。浮数类似地打印为 ASCII 数字,默认为小数点两位。字节作为单个字符发送。字符和字符串按现在样发送。例如,</p>
<ul>
<li><code> Serial.print(78); </code> 输出: <code>"78"</code></li>
<li><code> Serial.print(1.23456); </code> 输出: <code>"1.23"</code></li>
<li><code> Serial.print('N'); </code> 输出: <code>"N"</code></li>
<li><code> Serial.print("Hello world."); </code> 输出: <code>"Hello world."</code></li>
</ul>
<p>可选的第二个参数指定要使用的基础(格式);允许的值为、、、对于浮点数字,此参数指定要使用的小数位数。例如,<code>BIN(binary, or base 2)OCT(octal, or base 8)DEC(decimal, or base 10)HEX(hexadecimal, or base 16) <code></p>
<ul>
<li><code> Serial.print(78, BIN); </code> 输出: <code>"1001110"</code></li>
<li><code> Serial.print(78, OCT); </code> 输出: <code>"116"</code></li>
<li><code> Serial.print(78, DEC); </code> 输出: <code>"78"</code></li>
<li><code> Serial.print(78, HEX); </code> 输出: <code>"4e"</code></li>
<li><code> Serial.print(1.23456, 0); </code> 输出: <code>"1"</code></li>
<li><code> Serial.print(1.23456, 2); </code> 输出: <code>"1.23"</code></li>
<li><code> Serial.print(1.23456, 4); </code> 输出: <code>"1.2345"</code></li>
</ul>
<p>您可以通过用<code>F()</code>包装它们来传递基于闪存的字符串。例如:Serial.print()</p>
<p><code> Serial.print(F("Hello World")); </code><br>若要在不转换为字符表示形式的情况下发送数据,请使用Serial.write()。</p>
<p><strong>语法</strong></p>
<ul>
<li><code> Serial.print(val);</code></li>
<li><code> Serial.print(val, format);</code></li>
</ul>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅串行主页上每个主板的可用串行端口列表。要打印的值。允许的数据类型:任何数据类型。</p>
<p><strong>返回值</strong><br><code>print()</code>返回写入的字节数,但读取该数字是可选的。数据类型: <code>.size_t</code></p>
<p><strong>示例代码</strong></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">/*</span><br><span class="line"> Uses a <span class="keyword">for</span> loop to <span class="built_in">print</span> numbers <span class="keyword">in</span> various formats.</span><br><span class="line">*/</span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600); // open the serial port at 9600 bps:</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // <span class="built_in">print</span> labels</span><br><span class="line"> Serial.print(<span class="string">"NO FORMAT"</span>); // prints a label</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>); // prints a tab</span><br><span class="line"></span><br><span class="line"> Serial.print(<span class="string">"DEC"</span>);</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>);</span><br><span class="line"></span><br><span class="line"> Serial.print(<span class="string">"HEX"</span>);</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>);</span><br><span class="line"></span><br><span class="line"> Serial.print(<span class="string">"OCT"</span>);</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>);</span><br><span class="line"></span><br><span class="line"> Serial.print(<span class="string">"BIN"</span>);</span><br><span class="line"> Serial.println(); // carriage <span class="built_in">return</span> after the last label</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (int x = 0; x < 64; x++) { // only part of the ASCII chart, change to suit</span><br><span class="line"> // <span class="built_in">print</span> it out <span class="keyword">in</span> many formats:</span><br><span class="line"> Serial.print(x); // <span class="built_in">print</span> as an ASCII-encoded decimal - same as <span class="string">"DEC"</span></span><br><span class="line"> Serial.print(<span class="string">"\t\t"</span>); // prints two tabs to accomodate the label lenght</span><br><span class="line"></span><br><span class="line"> Serial.print(x, DEC); // <span class="built_in">print</span> as an ASCII-encoded decimal</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>); // prints a tab</span><br><span class="line"></span><br><span class="line"> Serial.print(x, HEX); // <span class="built_in">print</span> as an ASCII-encoded hexadecimal</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>); // prints a tab</span><br><span class="line"></span><br><span class="line"> Serial.print(x, OCT); // <span class="built_in">print</span> as an ASCII-encoded octal</span><br><span class="line"> Serial.print(<span class="string">"\t"</span>); // prints a tab</span><br><span class="line"></span><br><span class="line"> Serial.println(x, BIN); // <span class="built_in">print</span> as an ASCII-encoded binary</span><br><span class="line"> // <span class="keyword">then</span> adds the carriage <span class="built_in">return</span> with <span class="string">"println"</span></span><br><span class="line"> delay(200); // delay 200 milliseconds</span><br><span class="line"> }</span><br><span class="line"> Serial.println(); // prints another carriage <span class="built_in">return</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Serial-println"><a href="#Serial-println" class="headerlink" title="Serial.println()"></a><code>Serial.println()</code></h2><p><strong>描述</strong><br>将数据打印为可人工可读的 ASCII 文本,后跟回车字符(ASCII 13 或”\r”)和一个新行字符(ASCII 10 或’\n’)。此命令采用与串行打印() 相同的形式。</p>
<p><strong>语法</strong><br><code> Serial.println(val); </code><br><code> Serial.println(val, format); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅<a href="https://www.arduino.cc/reference/en/language/functions/communication/serial/" target="_blank" rel="noopener">参考主页</a>上每个主板的可用串行端口列表。<br>:要打印的值。允许的数据类型:任何数据类型。<br>:指定数字基数(用于积分数据类型)或小数位数(对于浮点类型)。<code>valformat</code></p>
<p><strong>返回值</strong><br><code> println(); </code>返回写入的字节数,但读取该数字是可选的。数据类型: .size_t</p>
<p><strong>示例代码</strong></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">/*</span><br><span class="line"> Analog input reads an analog input on analog <span class="keyword">in</span> 0, prints the value out.</span><br><span class="line"> created 24 March 2006</span><br><span class="line"> by Tom Igoe</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">int analogValue = 0; // variable to hold the analog value</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> // open the serial port at 9600 bps:</span><br><span class="line"> Serial.begin(9600);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // <span class="built_in">read</span> the analog input on pin 0:</span><br><span class="line"> analogValue = analogRead(0);</span><br><span class="line"></span><br><span class="line"> // <span class="built_in">print</span> it out <span class="keyword">in</span> many formats:</span><br><span class="line"> Serial.println(analogValue); // <span class="built_in">print</span> as an ASCII-encoded decimal</span><br><span class="line"> Serial.println(analogValue, DEC); // <span class="built_in">print</span> as an ASCII-encoded decimal</span><br><span class="line"> Serial.println(analogValue, HEX); // <span class="built_in">print</span> as an ASCII-encoded hexadecimal</span><br><span class="line"> Serial.println(analogValue, OCT); // <span class="built_in">print</span> as an ASCII-encoded octal</span><br><span class="line"> Serial.println(analogValue, BIN); // <span class="built_in">print</span> as an ASCII-encoded binary</span><br><span class="line"></span><br><span class="line"> // delay 10 milliseconds before the next reading:</span><br><span class="line"> delay(10);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Serial-begin"><a href="#Serial-begin" class="headerlink" title="Serial.begin()"></a><code>Serial.begin()</code></h2><p><strong>描述</strong><br>为串行数据传输设置以比特/秒(波特)为单位的数据速率。要与串行监视器通信,请确保使用屏幕右下角菜单中列出的波特率之一。但是,您可以指定其他速率 - 例如,通过引脚 0 和 1 与需要特定波特速率的组件进行通信。</p>
<p>可选的第二个参数配置数据、奇偶校验和停止位。默认值为 8 个数据位,无奇偶校验,一个停止位。</p>
<p><strong>语法</strong><br><code> Serial.begin(speed); </code><br><code> Serial.begin(speed, config); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅串行主页上每个主板的可用串行端口列表。<br>:以比特/秒(波特为单位)。允许的数据类型: 。<br>:设置数据、奇偶校验和停止位。有效值为:<br>(默认值): 偶数奇偶<br> 校验:奇偶校验<br>speedlongconfigSERIAL_5N1SERIAL_6N1SERIAL_7N1SERIAL_8N1SERIAL_5N2SERIAL_6N2SERIAL_7N2SERIAL_8N2SERIAL_5E1SERIAL_6E1SERIAL_7E1SERIAL_8E1SERIAL_5E2SERIAL_6E2SERIAL_7E2SERIAL_8E2SERIAL_5O1<br>SERIAL_6O1<br>SERIAL_7O1<br>SERIAL_8O1<br>SERIAL_5O2<br>SERIAL_6O2<br>SERIAL_7O2<br>SERIAL_8O2</p>
<p><strong>返回值</strong><br>无</p>
<p>示例代码</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600); // opens serial port, sets data rate to 9600 bps</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {}</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// Arduino Mega using all four of its Serial ports</span><br><span class="line">// (Serial, Serial1, Serial2, Serial3),</span><br><span class="line">// with different baud rates:</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600);</span><br><span class="line"> Serial1.begin(38400);</span><br><span class="line"> Serial2.begin(19200);</span><br><span class="line"> Serial3.begin(4800);</span><br><span class="line"></span><br><span class="line"> Serial.println(<span class="string">"Hello Computer"</span>);</span><br><span class="line"> Serial1.println(<span class="string">"Hello Serial 1"</span>);</span><br><span class="line"> Serial2.println(<span class="string">"Hello Serial 2"</span>);</span><br><span class="line"> Serial3.println(<span class="string">"Hello Serial 3"</span>);</span><br><span class="line">}</span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {}</span><br></pre></td></tr></table></figure>
<h2 id="Serial-End"><a href="#Serial-End" class="headerlink" title="Serial.End()"></a><code>Serial.End()</code></h2><p><strong>描述</strong><br>禁用串行通信,允许将 RX 和 TX 引脚用于常规输入和输出。要重新启用串行通信,请调用<code>Serial.begin()</code>。</p>
<p><strong>语法</strong><br><code> Serial.end(); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅串行主页上每个主板的可用串行端口列表。</p>
<p><strong>返回值</strong><br>无</p>
<h2 id="Serial-available"><a href="#Serial-available" class="headerlink" title="Serial.available()"></a><code>Serial.available()</code></h2><p><strong>描述</strong><br>获取可用于从串行端口读取的字节数(字符)。这是已到达并存储在串行接收缓冲区(包含 64 个字节)中的数据。<br><code>Serial.available()</code>从 Stream 实用程序类继承。</p>
<p><strong>语法</strong><br><code> Serial.available(); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅<a href="https://www.arduino.cc/reference/en/language/functions/communication/serial/" target="_blank" rel="noopener">参考主页</a>上每个主板的可用串行端口列表。</p>
<p><strong>返回值</strong><br>可供读取的字节数。</p>
<p>示例代码<br>以下代码返回通过串行端口接收的字符。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int incomingByte = 0; // <span class="keyword">for</span> incoming serial data</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600); // opens serial port, sets data rate to 9600 bps</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // reply only when you receive data:</span><br><span class="line"> <span class="keyword">if</span> (Serial.available() > 0) {</span><br><span class="line"> // <span class="built_in">read</span> the incoming byte:</span><br><span class="line"> incomingByte = Serial.read();</span><br><span class="line"></span><br><span class="line"> // say what you got:</span><br><span class="line"> Serial.print(<span class="string">"I received: "</span>);</span><br><span class="line"> Serial.println(incomingByte, DEC);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>示例2:此代码将板子的一个串行端口中接收的数据发送到另一个。例如,这可用于通过 Arduino 板将串行设备连接到计算机。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600);</span><br><span class="line"> Serial1.begin(9600);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // <span class="built_in">read</span> from port 0, send to port 1:</span><br><span class="line"> <span class="keyword">if</span> (Serial.available()) {</span><br><span class="line"> int inByte = Serial.read();</span><br><span class="line"> Serial1.print(inByte, DEC);</span><br><span class="line"> }</span><br><span class="line"> // <span class="built_in">read</span> from port 1, send to port 0:</span><br><span class="line"> <span class="keyword">if</span> (Serial1.available()) {</span><br><span class="line"> int inByte = Serial1.read();</span><br><span class="line"> Serial.print(inByte, DEC);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Serial-read"><a href="#Serial-read" class="headerlink" title="Serial.read()"></a><code>Serial.read()</code></h2><p><strong>描述</strong><br>读取传入串行数据。<br><code>Serial.read()</code>从 Stream 实用程序类继承。</p>
<p><strong>语法</strong><br><code> Serial.read(); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅串行主页上每个主板的可用串行端口列表。</p>
<p><strong>返回值</strong><br>传入串行数据的第一个字节可用(如果没有数据可用,或 -1)。数据类型: .int</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int incomingByte = 0; // <span class="keyword">for</span> incoming serial data</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600); // opens serial port, sets data rate to 9600 bps</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // send data only when you receive data:</span><br><span class="line"> <span class="keyword">if</span> (Serial.available() > 0) {</span><br><span class="line"> // <span class="built_in">read</span> the incoming byte:</span><br><span class="line"> incomingByte = Serial.read();</span><br><span class="line"></span><br><span class="line"> // say what you got:</span><br><span class="line"> Serial.print(<span class="string">"I received: "</span>);</span><br><span class="line"> Serial.println(incomingByte, DEC);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="Serial-peek"><a href="#Serial-peek" class="headerlink" title="Serial.peek()"></a><code>Serial.peek()</code></h2><p><strong>描述</strong><br>返回传入串行数据的下一个字节(字符),而不将其从内部串行缓冲区中删除。</p>
<p><code>Serial.peek()</code>从 Stream 实用程序类继承。</p>
<p><strong>语法</strong><br><code> Serial.peek(); </code></p>
<p><strong>参数</strong><br>Serial:串行端口对象。请参阅串行主页上每个主板的可用串行端口列表。</p>
<p><strong>返回值</strong><br>传入串行数据的第一个字节可用(如果没有数据可用,或 -1)。数据类型:<code>.int</code></p>
<p>示例代码:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">char incomingByte; // <span class="keyword">for</span> incoming serial data</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> Serial.begin(9600); // opens serial port, sets data rate to 9600 bps</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // send data only when you receive data:</span><br><span class="line"> <span class="keyword">if</span> (Serial.available() > 0) {</span><br><span class="line"> // <span class="built_in">read</span> the incoming byte:</span><br><span class="line"> incomingByte = Serial.peek();</span><br><span class="line"></span><br><span class="line"> // say what you got:</span><br><span class="line"> <span class="comment"># Serial.print("I received: ");</span></span><br><span class="line"> Serial.printf(<span class="string">"%c"</span>, incomingByte);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="一些注意点"><a href="#一些注意点" class="headerlink" title="一些注意点"></a>一些注意点</h1><p>最大的一个貌似是<code>serialEvent()</code>这个串口的时间,他本来是串口在接收数据之后会自动调用的,但是我尝试了好几次,但是都没有成功,因此在我的库函数里面我是会将其屏蔽的,即默认是不能用的,因为这个Arduino的库放到ESP32中也不一定的完全移植好了。下面给了一个线程来接收数据的方法,示例代码如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include "uart.h"</span></span><br><span class="line"></span><br><span class="line">String inputString = <span class="string">""</span>; // a string to hold incoming data</span><br><span class="line">boolean stringComplete = <span class="literal">false</span>; // whether the string is complete</span><br><span class="line"></span><br><span class="line">// 监听串口收到数据的事件</span><br><span class="line">void <span class="function"><span class="title">serialEvent</span></span>() {</span><br><span class="line"> <span class="keyword">while</span> (Serial.available()) {</span><br><span class="line"> char inChar = (char)Serial.read();</span><br><span class="line"> inputString += inChar;</span><br><span class="line"> <span class="keyword">if</span> (inChar == <span class="string">'\n'</span>) { //注意是以换行符为标志位的</span><br><span class="line"> stringComplete = <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 准备串口接收数据的线程函数</span><br><span class="line">// 示例:</span><br><span class="line">// xTaskCreate(</span><br><span class="line">// serialGetdata, /* Task <span class="keyword">function</span>. */</span><br><span class="line">// <span class="string">"Task_SerialGetdata"</span>, /* String with name of task. */</span><br><span class="line">// 10000, /* Stack size <span class="keyword">in</span> bytes. */</span><br><span class="line">// NULL, /* Parameter passed as input of the task */</span><br><span class="line">// 1, /* Priority of the task. */</span><br><span class="line">// NULL); /* Task handle. */</span><br><span class="line">void serialGetdata(void *uartPtr) {</span><br><span class="line"> <span class="keyword">while</span>(1){</span><br><span class="line"> serialEvent();</span><br><span class="line"> <span class="keyword">if</span> (stringComplete) {</span><br><span class="line"> Serial.println(inputString);</span><br><span class="line"> // clear the string:</span><br><span class="line"> inputString = <span class="string">""</span>;</span><br><span class="line"> stringComplete = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> // vTaskDelay(500 / portTICK_PERIOD_MS);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>我们都只是库函数的使用者,但是库函数的完善一直是任重而道远,因此发现问题也是一个很有意义的一件事儿。能够分享也是非常开心的。</p>
]]></content>
<categories>
<category>ESP32</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>ESP32</tag>
<tag>串口发送</tag>
<tag>串口接收</tag>
</tags>
</entry>
<entry>
<title>ESP32使用与环境配置介绍</title>
<url>/2020/31.ESP32-Introduce/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近总体来说自由的时间还比较多吧,开始准备弄一些之前没有弄得东西了,准备上手好好玩玩ESP32,并且打算将其作为以后长期使用的主力单片机,如实开始准备写一个关于ESP32的相关内容,这一次就是简单的介绍并且简介开发环境(其实是我找了很多资料发现很多就写了一个VSCode+PaltrformIO配置初始化的环境,而且感觉都是抄的同一个人的),没有玩过Arduino的同志可能会觉得还有点麻烦,因此决定自己开始搞一搞,主要的资料还是来自<a href="https://www.arduino.cc/en/Main/Products" target="_blank" rel="noopener">官方社区</a>。</p>
<h1 id="配置环境"><a href="#配置环境" class="headerlink" title="配置环境"></a>配置环境</h1><h2 id="安装-VSCode-PlatFormIO-IDE"><a href="#安装-VSCode-PlatFormIO-IDE" class="headerlink" title="安装 VSCode + PlatFormIO IDE"></a>安装 VSCode + PlatFormIO IDE</h2><p>首先是VScode的安装,比较简单,直接去<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">官网</a>下载安装即可。完成以后启动VScode,在拓展页面直接搜索Platformio IDE,并且安装即可。具体操作如图:<br><img src="/images/RaspberryPi/4.1.png" alt="Platformio1"></p>
<p>安装完成并且重新启动VSCode以后,拓展那一栏有一个外星人样子的图标,活着看左下角error和waring的右边出现一个小房子的小图标,这个就是PlatformIO IDE的主页,这样就表示安装好了。<br><img src="/images/RaspberryPi/4.2.png" alt="Platformio2"></p>
<h2 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h2><ul>
<li><p>选择New Project创建工程,选择相应的Board,我这里使用DOIT ESP32 DEVKIT V1,输入ESP32找到对应的Board</p>
</li>
<li><p>选择Framework是Arduino,选择保存路径,等待工程完成需要一点时间.</p>
</li>
<li><p>完成,打开工程文件夹,找到目录src下的main.cpp并修改如下:<br><img src="/images/RaspberryPi/4.3.png" alt="Platformio3"><br><img src="/images/RaspberryPi/4.4.png" alt="Platformio4"></p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <Arduino.h></span></span><br><span class="line"> </span><br><span class="line">void <span class="function"><span class="title">setup</span></span>() {</span><br><span class="line"> // put your setup code here, to run once:</span><br><span class="line"> pinMode(32, OUTPUT);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">void <span class="function"><span class="title">loop</span></span>() {</span><br><span class="line"> // put your main code here, to run repeatedly:</span><br><span class="line"> digitalWrite(32, HIGH); // turn the LED on (HIGH is the voltage level)</span><br><span class="line"> delay(1000); // <span class="built_in">wait</span> <span class="keyword">for</span> a second</span><br><span class="line"> digitalWrite(32, LOW); // turn the LED off by making the voltage LOW</span><br><span class="line"> delay(1000);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
<li><p>编译与下载同样左下角有一堆按钮,如上图可以看到相应的按钮</p>
</li>
<li><p>选择upload即可完成下载,GPIO32引脚电平翻转,可以看到我们连端口都没有选择就完成了下载的工作,PlatformIO IDE自动扫描串口设备,非常方便。</p>
</li>
<li><p>Arduino IDE有库管理功能,可以下载到需要的库,就不具体讲了。</p>
</li>
</ul>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>具体而言,ESP32的性价比是真的非常高的,而且我觉得有一个最大的好处就是可以使用C++,C++里面的库函数比C语言真的是封装了好多好多;其次是多线程。多线程在对比单片机的中断而言,其实是非常方便的。尤其是在设计比较大的系统而言。</p>
]]></content>
<categories>
<category>ESP32</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>ESP32</tag>
<tag>VSCode</tag>
</tags>
</entry>
<entry>
<title>C/C++常见输入输出的小总结</title>
<url>/2020/29.IO-Stream/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>怎么说呢,首先说说地址,还是<a href="https://ac.nowcoder.com/acm/contest/5650?from=hr_test#question" target="_blank" rel="noopener">牛客网</a>。总地来说吧,最近也是做了不少的题目,对于输入和输出数据的类型东西也是有了一些了解。我最开始利用输入字符串的形式,加上 vector 解析的<a href="http://localhost:4000/2020/23.GetData-C/" target="_blank" rel="noopener">例子</a>也是一个不错的想法,但是最近仔细的做了一系列的输入输出题目以后,发现有了新的思路。</p>
<h1 id="例题分析"><a href="#例题分析" class="headerlink" title="例题分析"></a>例题分析</h1><p>废话不多说,直接上题,题型全是计算A+B的类型,具体如下:</p>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/A" target="_blank" rel="noopener">1. 题目描述</a></strong><br>计算a+b</p>
<p><strong>输入描述:</strong><br>输入包括两个正整数a,b(1 <= a, b <= 10^9),输入数据包括多组。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">1 5</span><br><span class="line">10 20</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">6</span><br><span class="line">30</span><br></pre></td></tr></table></figure>
<p>一个简单的EOF,判断是否结束,比较简单直接贴答案:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int a, b;</span><br><span class="line"> <span class="keyword">while</span>(scanf(<span class="string">"%d %d"</span>, &a, &b) != EOF)</span><br><span class="line"> cout << a + b << endl;</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/B" target="_blank" rel="noopener">2. 题目描述</a></strong><br>计算a+b</p>
<p><strong>输入描述:</strong><br>输入第一行包括一个数据组数t(1 <= t <= 100)<br>接下来每行包括两个正整数a,b(1 <= a, b <= 10^9)<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">2</span><br><span class="line">1 5</span><br><span class="line">10 20</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">6</span><br><span class="line">30</span><br></pre></td></tr></table></figure>
<p>这个应该是最简单的一类了,直接上:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n, a, b;</span><br><span class="line"> cin >> n;</span><br><span class="line"> <span class="keyword">if</span>(n <= 0) <span class="built_in">return</span> 0;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < n ; i++)</span><br><span class="line"> {</span><br><span class="line"> cin >> a >> b;</span><br><span class="line"> cout << a+b << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/C" target="_blank" rel="noopener">3. 题目描述</a></strong><br>计算a+b</p>
<p><strong>输入描述:</strong><br>输入包括两个正整数a,b(1 <= a, b <= 10^9),输入数据有多组, 如果输入为0 0则结束输入<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">1 5</span><br><span class="line">10 20</span><br><span class="line">0 0</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">6</span><br><span class="line">30</span><br></pre></td></tr></table></figure>
<p>这个直接判断输入的数据,直接上:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int a, b;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(1)</span><br><span class="line"> {</span><br><span class="line"> cin >> a >> b;</span><br><span class="line"> <span class="keyword">if</span>((a == 0) && (b == 0)) </span><br><span class="line"> <span class="built_in">break</span>;</span><br><span class="line"> cout << a+b << endl;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/D" target="_blank" rel="noopener">4. 题目描述</a></strong><br>计算一系列数的和</p>
<p><strong>输入描述:</strong><br>输入数据包括多组。<br>每组数据一行,每行的第一个整数为整数的个数n(1 <= n <= 100), n为0的时候结束输入。<br>接下来n个正整数,即需要求和的每个正整数。<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">4 1 2 3 4</span><br><span class="line">5 1 2 3 4 5</span><br><span class="line">0</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">10</span><br><span class="line">15</span><br></pre></td></tr></table></figure>
<p>这个直接判断输入第一个数即可,跟上面几乎没有区别:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n, a, b;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span>(1)</span><br><span class="line"> {</span><br><span class="line"> int tmp = 0, sum = 0;</span><br><span class="line"> cin >> n;</span><br><span class="line"> <span class="keyword">if</span>(n <= 0) </span><br><span class="line"> <span class="built_in">break</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < n; i++)</span><br><span class="line"> {</span><br><span class="line"> cin >> tmp;</span><br><span class="line"> sum += tmp;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cout << sum << endl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/E" target="_blank" rel="noopener">5. 题目描述</a></strong><br>计算一系列数的和</p>
<p><strong>输入描述:</strong><br>输入的第一行包括一个正整数t(1 <= t <= 100), 表示数据组数。<br>接下来t行, 每行一组数据。<br>每行的第一个整数为整数的个数n(1 <= n <= 100)。<br>接下来n个正整数, 即需要求和的每个正整数。<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">2</span><br><span class="line">4 1 2 3 4</span><br><span class="line">5 1 2 3 4 5</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">10</span><br><span class="line">15</span><br></pre></td></tr></table></figure>
<p>贴答案:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int t, n, a, b;</span><br><span class="line"> cin >> t;</span><br><span class="line"> <span class="keyword">if</span>(t <= 0) <span class="built_in">return</span> 0;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < t; i++)</span><br><span class="line"> {</span><br><span class="line"> int tmp = 0, sum = 0;</span><br><span class="line"> cin >> n;</span><br><span class="line"> <span class="keyword">if</span>(n <= 0) <span class="built_in">break</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span>(int j = 0; j < n; j++)</span><br><span class="line"> {</span><br><span class="line"> cin >> tmp;</span><br><span class="line"> sum += tmp;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> cout << sum << endl;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/F" target="_blank" rel="noopener">6. 题目描述</a></strong><br>计算一系列数的和</p>
<p><strong>输入描述:</strong><br>输入数据有多组, 每行表示一组输入数据。<br>每行的第一个整数为整数的个数n(1 <= n <= 100)。<br>接下来n个正整数, 即需要求和的每个正整数。<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">4 1 2 3 4</span><br><span class="line">5 1 2 3 4 5</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">10</span><br><span class="line">15</span><br></pre></td></tr></table></figure>
<p>同上,添加一个EOF,如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n = 0;</span><br><span class="line"> <span class="keyword">while</span>(scanf(<span class="string">"%d"</span>, &n) != EOF)</span><br><span class="line"> {</span><br><span class="line"> int sum = 0, tmp = 0;</span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < n; i++)</span><br><span class="line"> {</span><br><span class="line"> cin >> tmp;</span><br><span class="line"> sum += tmp;</span><br><span class="line"> }</span><br><span class="line"> cout << sum << endl;</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong><a href="https://ac.nowcoder.com/acm/contest/5650/G" target="_blank" rel="noopener">6. 题目描述</a></strong><br>计算一系列数的和</p>
<p><strong>输入描述:</strong><br>输入数据有多组, 每行表示一组输入数据。</p>
<p>每行不定有n个整数,空格隔开。(1 <= n <= 100)。<br>示例示例:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">1 2 3</span><br><span class="line">4 5</span><br><span class="line">0 0 0 0 0</span><br></pre></td></tr></table></figure>
<p><strong>输出描述:</strong><br>输出a+b的结果。示例如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">6</span><br><span class="line">9</span><br><span class="line">0</span><br></pre></td></tr></table></figure>
<p>这个就是我最先开始说的输入问题,我最先使用的输入字符串然后去解析的方式实在很笨,看了一些帖子以后发现scanf的标准输入输出非常好用,在输入的信息的时候scanf会默认用空格或者换行来区分数据,因此直接强行判断即可,题目默认也是一个数字一个字符,碰到换行符’\n’就输出并且清空就行,如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n, sum = 0;</span><br><span class="line"> char c;</span><br><span class="line"> <span class="keyword">while</span>(scanf(<span class="string">"%d%c"</span>, &n, &c) != EOF)</span><br><span class="line"> {</span><br><span class="line"> sum += n;</span><br><span class="line"> <span class="keyword">if</span>(c == <span class="string">'\n'</span>)</span><br><span class="line"> cout << sum << endl, sum = 0;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>关于笔试的刷题,我觉得<a href="https://ac.nowcoder.com/acm/contest/5650?from=hr_test#question" target="_blank" rel="noopener">牛客的这个帖子</a>是必做的,题目虽然不难,但是真的是受益匪浅!!!!</p>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>输入输出</tag>
</tags>
</entry>
<entry>
<title>C++大数取余和快速幂</title>
<url>/2020/28.Big-number/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近遇到的一些笔试问题,关于大数的情况还是很多,因此在这里做一个小的说明,关于大数取余的过程,典型的运算就是幂!</p>
<h1 id="大数取模"><a href="#大数取模" class="headerlink" title="大数取模"></a>大数取模</h1><p>一般而言,取模的数字是1000000007(一般也会写作1e9+7,一共十位数),对于这个数的一些问题,我只能做一个小的总结吧,有很多的数学解释我在后面就直接放链接了。</p>
<p>首先我觉得他是一个质数,而且足够大,因此在计算的时候不会很多麻烦,取余也比较方便;<br>其次int32的最大值是2147483647,所以对于int32位来说1000000007足够大;<br>最后int64的最大值是2^63-1,对于1000000007来说它的平方不会在int64中溢出 所以在大数相乘的时候,因为(a∗b) % c=((a%c) ∗ (b%c)) % c,所以相乘时两边都对1000000007取模,再保存在int64里面不会溢出。</p>
<p>这句话在做题的时候看上去只需要取模就可以了,但是在实际计算中还是有一些小坑,因此还是小小总结一下。</p>
<h1 id="关于快速幂"><a href="#关于快速幂" class="headerlink" title="关于快速幂"></a>关于快速幂</h1><p>快速幂运算其实就是二分法。假设要求x^n,如果n = 2^k,那么原题可以很轻松的表示为:x^n = ((x^2)^2)^2…。这样只要做k次平方运算就能解决,时间复杂度就从O(n)下降到log(n)。<br>示例代码如下(中间还做了大数取余的过程):</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">long long mod(long long a, long long b) {</span><br><span class="line"> long long ans = 1;</span><br><span class="line"> long long c = 1000000007;</span><br><span class="line"> <span class="keyword">while</span>(b > 0) {</span><br><span class="line"> <span class="keyword">if</span>(b & 1) ans = ans * a % c; </span><br><span class="line"> a = a * a % c;</span><br><span class="line"> b >>= 1; //位运算:b /= 2; </span><br><span class="line"> } </span><br><span class="line"> <span class="built_in">return</span> ans;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="两个易错点"><a href="#两个易错点" class="headerlink" title="两个易错点"></a>两个易错点</h1><h2 id="求最大值时先取模"><a href="#求最大值时先取模" class="headerlink" title="求最大值时先取模"></a>求最大值时先取模</h2><p>取mod的时候,如果题目要求你算最大值,并且说由于答案可能很大,输出结果请对1e9+7取,那你千万不能在max函数更新最大值时就取模,这样很可能会出错!</p>
<p>比如:题目过程中有四个数据</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">2e9+7,1e9+6,1e9+5,1e9+4</span><br></pre></td></tr></table></figure>
<p>然后算法中你用max求最大值时,如果先模上1e9+7,那你会得到1e9,1e9+6,1e9+5,1e9+4,并且max函数算出的最大值是1e9+6,可是这四个数的最大值应该是2e9 + 7才对。</p>
<p>正确做法:在求max的时候不要先取mod,而是都以long long型数据比大小,最后得到最大值是2e9 + 7,再对它取mod,得到结果是1e9 + 7。</p>
<h2 id="直到return才取模"><a href="#直到return才取模" class="headerlink" title="直到return才取模"></a>直到return才取模</h2><p>如果让你算1+2+…+n的值(由于答案可能很大,输出结果请对1e9+7取)<br>n的取值范围是1 ~ 10^10000。</p>
<p>那显然如果在中间过程中不先取mod,必然会爆数据范围,因为不管是int还是long long甚至是double(最大10^308)都无法存下这个数据。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// ...</span><br><span class="line">long long res = 0;</span><br><span class="line"><span class="keyword">for</span>(int i = 1; i <= n ; i++) </span><br><span class="line"> res = res + i; // n巨大,res无法存下这个数据</span><br><span class="line"><span class="built_in">return</span> res % (1e9 + 7);</span><br><span class="line">// ...</span><br></pre></td></tr></table></figure>
<p>正确的做法应该是计算的过程中取模:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">// ...</span><br><span class="line">long long res = 0;</span><br><span class="line"><span class="keyword">for</span>(int i = 1; i <= n ; i++) </span><br><span class="line"> res = (res + i) % (1000000007); // 计算的过程中取模</span><br><span class="line"><span class="built_in">return</span> res;</span><br><span class="line">// ...</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>如果回想上面,做幂运算的时候就是这样的过程,也是在运算的过程中进行取余的。总结起来就是在做题的开始就需要想好,到底是先取余还是计算以后取余。</p>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>大数取余</tag>
<tag>快速幂</tag>
</tags>
</entry>
<entry>
<title>老毛子路由器解锁网易云音乐</title>
<url>/2020/27.UnblockCloudmusic/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>怎么说呢,网易云音乐是我一直在用的音乐app,黑色的主题我是真的很喜欢的呀,个人觉得非常好看,但是最近这两年来网易云音乐悦来月拉垮了,版权和直播那一块,让这个已经变得不想一个音乐app了。疫情在家的时候完了一下路由器,然后在大佬编译的OpenWrt的版本中有解锁网易云音乐的选项,然后我就开始了一系列的收集工作。</p>
<p>下面仅仅是我个人的小记录,如果不是很懂或者零基础的话请看<a href="https://www.52pojie.cn/forum.php?mod=viewthread&tid=1234066&highlight=%CD%F8%D2%D7%D4%C6%BD%E2%CB%F8" target="_blank" rel="noopener">52PJ</a>。</p>
<h1 id="系统说明"><a href="#系统说明" class="headerlink" title="系统说明"></a>系统说明</h1><p>硬件是联想的NeWifi3,这个路由器怎么说呢,也算是矿渣之一吧,不过全千兆和512m的内存,足够运行很多东西,刷了老毛子挂一个网站然后用花生壳直接映射到外网可以说是绰绰有余,但是我个人觉得不太稳定,于是打算做简单的小Nas使用,反正也不算啥,够用就行。</p>
<p>下面开始说正题,使用脚本来解锁网易云。先放大佬的<a href="https://github.com/nondanee/UnblockNeteaseMusic" target="_blank" rel="noopener">github链接</a>,下载下来直接解压即可,然后使用FTP复制到路由器,然后开始配置环境就行了。</p>
<h1 id="安装Node"><a href="#安装Node" class="headerlink" title="安装Node"></a>安装Node</h1><p>上面的脚本就是使用Node来运行的,但是老毛子一般的话可能没有编译进去,于是便要自行安装,打开SSH链接路由器,一次输入下列:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="meta">#!/bin/sh</span></span><br><span class="line"><span class="built_in">unset</span> LD_LIBRARY_PATH</span><br><span class="line"><span class="built_in">unset</span> LD_PRELOAD</span><br><span class="line">mount -t tmpfs tmpfs /opt -o size=60M</span><br><span class="line"><span class="keyword">for</span> folder <span class="keyword">in</span> bin etc lib/opkg tmp var/lock</span><br><span class="line"><span class="keyword">do</span></span><br><span class="line">[ ! -d <span class="string">"/opt/<span class="variable">$folder</span>"</span> ] && mkdir -p /opt/<span class="variable">$folder</span></span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure>
<p>下面安装OPkg</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">wget http://pkg.entware.net/binaries/mipsel/installer/opkg -O /opt/bin/opkg</span><br><span class="line">wget http://bin.entware.net/mipselsf-k3.4/installer/opkg.conf -O /opt/etc/opkg.conf | chmod 755 /opt/bin/opkg</span><br></pre></td></tr></table></figure>
<p>update并且安装node</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">/opt/bin/opkg update</span><br><span class="line">/opt/bin/opkg install node</span><br></pre></td></tr></table></figure>
<p>此时可以使用下列指令查看node版本,并且确认node已经安装成功:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">node -v</span><br></pre></td></tr></table></figure>
<h1 id="开始运行脚本"><a href="#开始运行脚本" class="headerlink" title="开始运行脚本"></a>开始运行脚本</h1><p>首先获取网易云音乐的ip,使用ping即可:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">ping music.163.com</span><br></pre></td></tr></table></figure>
<p>会返回相应的ip和延迟等数据,记住那个ip,然后在SSH中找到相应的脚本文件,可以看看我下图的。<br><img src="/images/RaspberryPi/3.1.png" alt="P3.1"><br>然后使用上面记录的ip,运行node即可:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">node /home/root/UNM/app.js -p 8888 -f 59.111.181.60</span><br></pre></td></tr></table></figure>
<h1 id="设置APP代理"><a href="#设置APP代理" class="headerlink" title="设置APP代理"></a>设置APP代理</h1><p>打开网易云音乐后台的设置,找到工具中的代理选项,使用自定义代理,如下所示:<br><img src="/images/RaspberryPi/3.2.png" alt="P3.2"></p>
<h1 id="完结撒花"><a href="#完结撒花" class="headerlink" title="完结撒花"></a>完结撒花</h1><p>完结撒花,感觉有这个脚本的花还是很好用的,关键是比如周杰伦的新歌都是有资源的,感觉很不错。</p>
]]></content>
<categories>
<category>解锁网易云音乐</category>
</categories>
<tags>
<tag>老毛子</tag>
<tag>解锁网易云音乐</tag>
</tags>
</entry>
<entry>
<title>小小总结一下C/C++的进制转换</title>
<url>/2020/26.Hexadecimal-conversion/</url>
<content><![CDATA[<h1 id="首先说要求"><a href="#首先说要求" class="headerlink" title="首先说要求"></a>首先说要求</h1><p>题目要求输入一个字符串,只有数字和大写字母,然后需要转换成十进制的没,需要判定的是基数和偶数,然后默认的进制需要自己设计,ok下面开始简答分析。</p>
<h1 id="进制转换的说明"><a href="#进制转换的说明" class="headerlink" title="进制转换的说明"></a>进制转换的说明</h1><p>其实进制转换也就是乘以基数的多少次方,然后相加即可。下面直接上代码:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int StrtoBool(string &str, int r)</span><br><span class="line">{</span><br><span class="line"> int ans = 0;</span><br><span class="line"> // 进制转换</span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i != str.size(); i ++)</span><br><span class="line"> {</span><br><span class="line"> ans *= r;</span><br><span class="line"> <span class="keyword">if</span>(str[i] >= <span class="string">'0'</span> && str[i] <= <span class="string">'9'</span>)</span><br><span class="line"> ans += str[i] - <span class="string">'0'</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(str[i] >= <span class="string">'A'</span> && str[i] <= <span class="string">'Z'</span>)</span><br><span class="line"> ans += str[i] - <span class="string">'A'</span> + 10;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">return</span> ans % 2; //结果是只看奇数和偶数的</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="十进制转换为任意进制"><a href="#十进制转换为任意进制" class="headerlink" title="十进制转换为任意进制"></a>十进制转换为任意进制</h1><p>一般算法是除以基数,然后倒着取数,显然是栈的结构,先入后出。下面直给出完整版的代码:</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">#include<iostream></span><br><span class="line">#include<stack></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> int n = 0, r = 10; </span><br><span class="line"> stack<char> s; //全部存大写字母</span><br><span class="line"> cin >> n >> r; //数字和进制(都是int类型的)</span><br><span class="line"></span><br><span class="line"> while(n)</span><br><span class="line"> {</span><br><span class="line"> char tmp ;</span><br><span class="line"> tmp = n%r;</span><br><span class="line"> </span><br><span class="line"> if(tmp >= 0 && tmp <= 9)</span><br><span class="line"> tmp += 48; // 得到字符的0-9</span><br><span class="line"> else </span><br><span class="line"> tmp += 55; // 得到大写的数字(暂时没有处理Z以后的)</span><br><span class="line"> s.push(tmp);</span><br><span class="line"> n /= r;</span><br><span class="line"> }</span><br><span class="line"> for(;!s.empty();)</span><br><span class="line"> {</span><br><span class="line"> cout << s.top();</span><br><span class="line"> s.pop();</span><br><span class="line"> }</span><br><span class="line"> return 0;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>Hexadecimal Conversion</tag>
</tags>
</entry>
<entry>
<title>使用循环链表解决约瑟夫问题(Josephus Problem)</title>
<url>/2020/25.C-Josephus-Problem/</url>
<content><![CDATA[<h1 id="问题说明"><a href="#问题说明" class="headerlink" title="问题说明"></a>问题说明</h1><p>约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。<br>同理还有丢手绢,猴子称王都是一模一样的问题,首先用循环就可以直接一次性解决,记录当前位置的数并且循环取余即可,但是直观而言,肯定是循环数组更加的直观!</p>
<h1 id="代码分析"><a href="#代码分析" class="headerlink" title="代码分析"></a>代码分析</h1><p>不哆嗦了,直接贴上,里面注释还是很多的:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <stdio.h></span></span><br><span class="line"><span class="comment">#include <stdlib.h></span></span><br><span class="line">//定义循环链表</span><br><span class="line">typedef struct node//定义node结构体</span><br><span class="line">{</span><br><span class="line"> int data;</span><br><span class="line"> struct node* next;</span><br><span class="line">}cLinkList;//typedef struct node* cLinkList;定义一个struct node类型的循环链表</span><br><span class="line"></span><br><span class="line">//主函数</span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> cLinkList *head, *p, *s, *temp;</span><br><span class="line"> int n, k;</span><br><span class="line"> int i = 1;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Please enter the total number n:\n"</span>);</span><br><span class="line"> scanf(<span class="string">"%d"</span>, &n);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Please enter the key value:\n"</span>);</span><br><span class="line"> scanf(<span class="string">"%d"</span>, &k);</span><br><span class="line"> k %= n;</span><br><span class="line"> head = (cLinkList *)malloc(sizeof(cLinkList));</span><br><span class="line"> p = head;</span><br><span class="line"> p->next = p;//这里要赋值为p,不能赋值为head,要保持head的位置不变</span><br><span class="line"> p->data = i;</span><br><span class="line"> <span class="keyword">for</span>(i = 2; i <= n; i++)</span><br><span class="line"> {</span><br><span class="line"> s = (cLinkList *)malloc(sizeof(cLinkList));</span><br><span class="line"> s->data = i;</span><br><span class="line"> s->next = p->next;</span><br><span class="line"> p->next = s;</span><br><span class="line"> p = s;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> p = head;</span><br><span class="line"> int total = n;</span><br><span class="line"> <span class="keyword">while</span>(n--)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">for</span>(i = 1; i < k - 1; i++)</span><br><span class="line"> {</span><br><span class="line"> p = p->next;</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d->"</span>, p->next->data);</span><br><span class="line"> temp = p->next;//temp为要删除的元素</span><br><span class="line"> p->next = temp->next;//链表中跳过temp</span><br><span class="line"> free(temp);//释放temp</span><br><span class="line"> p = p->next;//p向前移动继续寻找</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Done!\n"</span>);</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>Josephus Problem</tag>
</tags>
</entry>
<entry>
<title>空指针、野指针与悬垂指针</title>
<url>/2020/24.C-point/</url>
<content><![CDATA[<h1 id="空指针"><a href="#空指针" class="headerlink" title="空指针"></a>空指针</h1><p>空指针:指针指向的地址为空的指针叫空指针/NULL指针</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int *p1;</span><br><span class="line">p1 = NULL;</span><br><span class="line"></span><br><span class="line">char *p2;</span><br><span class="line">p2 = NULL;</span><br></pre></td></tr></table></figure>
<h1 id="野指针"><a href="#野指针" class="headerlink" title="野指针"></a>野指针</h1><p>当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针(也叫迷途指针)。<br>某些编程语言允许未初始化的指针的存在,而这类指针即为野指针。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int a = 1;</span><br><span class="line">int *p1; //这里p1没有初始化的赋值,随机只想一个地址,是野指针</span><br><span class="line">p1 = &a; //指向了值</span><br><span class="line"></span><br><span class="line">// 指针在申请的时候一定要赋值,至少要给NULL!</span><br><span class="line">char *p2 = NULL;</span><br></pre></td></tr></table></figure>
<h1 id="悬垂指针"><a href="#悬垂指针" class="headerlink" title="悬垂指针"></a>悬垂指针</h1><p>悬垂指针:指针所指向的对象已经被释放或者回收了,但是指向该对象的指针没有作任何的修改,仍旧指向已经回收的内存地址。 此类指针称为垂悬指针。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> char *dp = NULL;</span><br><span class="line"> {</span><br><span class="line"> char c;</span><br><span class="line"> dp = &c;</span><br><span class="line"> } /* c falls out of scope */</span><br><span class="line"> /* dp is now a dangling pointer */</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>一个很常见的失误是返回一个栈分配的局部变量:一旦调用的函数返回了,分配给这些变量的空间被回收,此时它们拥有的是“垃圾值”。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int *func(void)</span><br><span class="line">{</span><br><span class="line"> int num = 1234;</span><br><span class="line"> /* ... */</span><br><span class="line"> <span class="built_in">return</span> &num;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>调用 func 后,尝试从该指针暂时能读取到正确的值(1234),但是再次调用函数后将会重写栈为 num 分配的的值,再从该指针读取的值就不正确了。如果必须要返回一个指向 num 的指针,num 的作用域必须大于这个函数——它也许被声明为 static。</p>
<h1 id="避免悬垂指针错误"><a href="#避免悬垂指针错误" class="headerlink" title="避免悬垂指针错误"></a>避免悬垂指针错误</h1><p>在 C/C++ 中,一种最简单的技术是实现一个 free()(或类似的)替代版本或者 delete 析构器来保证指针的重置。然后,这个技术不会清除其他指针变量,它们含有该指针的副本。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">/* Alternative version <span class="keyword">for</span> <span class="string">'free()'</span> */</span><br><span class="line">void safefree(void **pp)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (pp != NULL) { /* safety check */</span><br><span class="line"> free(*pp); /* deallocate chunk, note that free(NULL) is valid */</span><br><span class="line"> *pp = NULL; /* reset original pointer */</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line">int f(int i)</span><br><span class="line">{</span><br><span class="line"> char *p = NULL, *p2;</span><br><span class="line"> p = (char *)malloc(1000); /* get a chunk */</span><br><span class="line"> p2 = p; /* copy the pointer */</span><br><span class="line"> /* use the chunk here */</span><br><span class="line"> safefree(&p); /* safety freeing; does not affect p2 variable */</span><br><span class="line"> safefree(&p); /* this second call won<span class="string">'t fail */</span></span><br><span class="line"><span class="string"> char c = *p2; /* p2 is still a dangling pointer, so this is undefined behavior. */</span></span><br><span class="line"><span class="string">}</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>CRC Check</tag>
</tags>
</entry>
<entry>
<title>空指针、野指针与悬垂指针</title>
<url>/2020/24.C-point-DESKTOP-GRPI1FR/</url>
<content><![CDATA[<h1 id="空指针"><a href="#空指针" class="headerlink" title="空指针"></a>空指针</h1><p>空指针:指针指向的地址为空的指针叫空指针/NULL指针</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int *p1;</span><br><span class="line">p1 = NULL;</span><br><span class="line"></span><br><span class="line">char *p2;</span><br><span class="line">p2 = NULL;</span><br></pre></td></tr></table></figure>
<h1 id="野指针"><a href="#野指针" class="headerlink" title="野指针"></a>野指针</h1><p>当所指向的对象被释放或者收回,但是对该指针没有作任何的修改,以至于该指针仍旧指向已经回收的内存地址,此情况下该指针便称悬垂指针(也叫迷途指针)。<br>某些编程语言允许未初始化的指针的存在,而这类指针即为野指针。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int a = 1;</span><br><span class="line">int *p1; //这里p1没有初始化的赋值,随机只想一个地址,是野指针</span><br><span class="line">p1 = &a; //指向了值</span><br><span class="line"></span><br><span class="line">// 指针在申请的时候一定要赋值,至少要给NULL!</span><br><span class="line">char *p2 = NULL;</span><br></pre></td></tr></table></figure>
<h1 id="悬垂指针"><a href="#悬垂指针" class="headerlink" title="悬垂指针"></a>悬垂指针</h1><p>悬垂指针:指针所指向的对象已经被释放或者回收了,但是指向该对象的指针没有作任何的修改,仍旧指向已经回收的内存地址。 此类指针称为垂悬指针。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">{</span><br><span class="line"> char *dp = NULL;</span><br><span class="line"> {</span><br><span class="line"> char c;</span><br><span class="line"> dp = &c;</span><br><span class="line"> } /* c falls out of scope */</span><br><span class="line"> /* dp is now a dangling pointer */</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>一个很常见的失误是返回一个栈分配的局部变量:一旦调用的函数返回了,分配给这些变量的空间被回收,此时它们拥有的是“垃圾值”。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int *func(void)</span><br><span class="line">{</span><br><span class="line"> int num = 1234;</span><br><span class="line"> /* ... */</span><br><span class="line"> <span class="built_in">return</span> &num;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>调用 func 后,尝试从该指针暂时能读取到正确的值(1234),但是再次调用函数后将会重写栈为 num 分配的的值,再从该指针读取的值就不正确了。如果必须要返回一个指向 num 的指针,num 的作用域必须大于这个函数——它也许被声明为 static。</p>
<h1 id="避免悬垂指针错误"><a href="#避免悬垂指针错误" class="headerlink" title="避免悬垂指针错误"></a>避免悬垂指针错误</h1><p>在 C/C++ 中,一种最简单的技术是实现一个 free()(或类似的)替代版本或者 delete 析构器来保证指针的重置。然后,这个技术不会清除其他指针变量,它们含有该指针的副本。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">/* Alternative version <span class="keyword">for</span> <span class="string">'free()'</span> */</span><br><span class="line">void safefree(void **pp)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span> (pp != NULL) { /* safety check */</span><br><span class="line"> free(*pp); /* deallocate chunk, note that free(NULL) is valid */</span><br><span class="line"> *pp = NULL; /* reset original pointer */</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line">int f(int i)</span><br><span class="line">{</span><br><span class="line"> char *p = NULL, *p2;</span><br><span class="line"> p = (char *)malloc(1000); /* get a chunk */</span><br><span class="line"> p2 = p; /* copy the pointer */</span><br><span class="line"> /* use the chunk here */</span><br><span class="line"> safefree(&p); /* safety freeing; does not affect p2 variable */</span><br><span class="line"> safefree(&p); /* this second call won<span class="string">'t fail */</span></span><br><span class="line"><span class="string"> char c = *p2; /* p2 is still a dangling pointer, so this is undefined behavior. */</span></span><br><span class="line"><span class="string">}</span></span><br></pre></td></tr></table></figure>
]]></content>
<categories>
<category>The C/CPP language</category>
</categories>
<tags>
<tag>The C/CPP language</tag>
<tag>CRC Check</tag>
</tags>
</entry>
<entry>
<title>C++笔试中的获取数据问题</title>
<url>/2020/23.GetData-C/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近做字节笔试的时候经常会出现一些数据解析的问题,比如输入”(1,2)”这种数据,要求提取其中的坐标,还有就是输入一长串数据,如”1 2 3 4 5”说是遗传数据,没有指定长度,前面一直死在数据的获取上面,可能半个小时都没有获取到数据,后面机制知道怎么做也不可能有通过率。后面进行了了一些小总结,有了后面的结果,也想做一个小小的开源分享吧。</p>
<h1 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h1><p>仔细分析上面的内容,发现两个点,一个使输入的长度不固定,而且数组的多少也不固定,因此没有办法用固定的方法去解析。</p>
<p>看了一下C++的常用数据类型,发现容器使可以很方便实现变长的类似数组功能,然后就是输入的数据,这个好办,直接输入字符串解析就好了,下面开写,具体代码如下。首先是main.c:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line"><span class="comment">#include <vector></span></span><br><span class="line"><span class="comment">#include "GetData.h"</span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main(void)</span><br><span class="line">{</span><br><span class="line"> // cout << isNumber(<span class="string">'.'</span>) <<endl;</span><br><span class="line"> // GetData_Print();</span><br><span class="line"></span><br><span class="line"> string str;</span><br><span class="line"> getline(cin, str);</span><br><span class="line"> GetData(str);</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其次是GetData.cpp:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line"><span class="comment">#include <vector></span></span><br><span class="line"><span class="comment">#include <string></span></span><br><span class="line"><span class="comment">#include "GetData.h"</span></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">void GetData_Print(void)</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"GetData test!"</span> << endl;</span><br><span class="line"> <span class="built_in">return</span> ;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">bool isNumber(char tmp)</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">return</span> ( (tmp >= <span class="string">'0'</span>) && (tmp <= <span class="string">'9'</span>) ) ? <span class="literal">true</span> : <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">//从一行字符串获取相应的数据,解析到动态的容器中</span><br><span class="line">int GetData(string str)</span><br><span class="line">{</span><br><span class="line"> int i = 0, data = 0;</span><br><span class="line"> bool update = <span class="literal">false</span>; //是否存储数据</span><br><span class="line"> int symbol = 1 ; //正负号的判定(+1或者-1)</span><br><span class="line"> vector <int> array1; //存储不定长的数据</span><br><span class="line"> <span class="keyword">for</span>(int i = 0; i < str.size(); i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span>(str[i] == <span class="string">'-'</span> && isNumber(str[i+1]))</span><br><span class="line"> symbol = -1;</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">if</span> (str[i] >= <span class="string">'0'</span> && str[i] <= <span class="string">'9'</span>)</span><br><span class="line"> data = 10*data + (str[i] - <span class="string">'0'</span>), update = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span>(update)</span><br><span class="line"> array1.push_back(symbol*data), data = 0, update = <span class="literal">false</span>, symbol = 1;</span><br><span class="line"> <span class="keyword">if</span>(update&&i == str.size() - 1)//需对字符串最后的数字进行判断</span><br><span class="line"> array1.push_back(symbol*data), symbol = 1;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> cout << <span class="string">"Result:"</span> << endl;</span><br><span class="line"> <span class="keyword">for</span>(int j = 0; j < array1.size(); j++)</span><br><span class="line"> cout << array1[j] << endl;</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>最后是GetData.h</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#ifndef GETDATA_H</span></span><br><span class="line"><span class="comment">#define GETDATA_H</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#include <iostream></span></span><br><span class="line"><span class="comment">#include <vector></span></span><br><span class="line"><span class="comment">#include <string></span></span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">void GetData_Print(void);</span><br><span class="line">bool isNumber(char tmp);</span><br><span class="line">int GetData(string str);</span><br><span class="line"></span><br><span class="line"><span class="comment">#endif</span></span><br></pre></td></tr></table></figure>
<h1 id="测试结果"><a href="#测试结果" class="headerlink" title="测试结果"></a>测试结果</h1><p>上面的已经是改的第二版了,已经完美支持负数的解析了,而且个人比较喜欢代码行数比较少,因此if里面很多的幅值部分就直接用都好隔开了,我知道不是一个好习惯,但是我个人看着的确好看写,勿喷勿喷。测是结果如下:<img src="/images/C-Language/2-2.png" alt="2.2"></p>
<p>可以看到已经解析了数据,但是其中有一个小问题,就是实际操作中判断符号哪里我用到了[i+1],如果测试代码中只有一个字符是会溢出的,但是笔试的用例好像没有这个情况,因为他们都是给的指定的输入,对这个还是比较放心的,只是做一个简单的分享吧。</p>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>C/C++</tag>
<tag>Getdata</tag>
</tags>
</entry>
<entry>
<title>关于相机的一些记录</title>
<url>/2020/22.Camera/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近花了巨资买了一个相机(现在还有点心疼),型号是索尼的A7m2,刚刚上手还不习惯只能用自动模式,不过我肯定是不想妥协的,所以想写这个博客来记录一些摄影学习之路,所以这个可能是会长期更新的。(其实我是经常忘记内容所以来记录一下2333)</p>
<h1 id="关于照相模式"><a href="#关于照相模式" class="headerlink" title="关于照相模式"></a>关于照相模式</h1><p>索尼的A7m2照相模式是通过旋转顶部的旋钮来的,具体如下:</p>
<table>
<thead>
<tr>
<th>选项</th>
<th>功能</th>
</tr>
</thead>
<tbody><tr>
<td>P</td>
<td>程序自动(自动设置光圈和快门速度,可根据需要设定其他设置)</td>
</tr>
<tr>
<td>A</td>
<td>光圈优先(调节光前以改变对角范围和背景模糊程度,小值:前后模糊,大值:背景对焦)</td>
</tr>
<tr>
<td>S</td>
<td>快门优先(手动调节快门速度已实现移动被摄体的不同效果)</td>
</tr>
<tr>
<td>M</td>
<td>手动曝光(手动调节光圈和快门速度)</td>
</tr>
<tr>
<td>[_]</td>
<td>扫描全景(以固定速度上下左右移动小计)</td>
</tr>
<tr>
<td>SCN</td>
<td>场景选择(选择适合索要拍摄物体和环境的模式)</td>
</tr>
<tr>
<td>AUTO</td>
<td>自动设置(系统根据环境自动设置选项,包括降低模糊和噪点)</td>
</tr>
</tbody></table>
<h1 id="关于人像LR的设置"><a href="#关于人像LR的设置" class="headerlink" title="关于人像LR的设置"></a>关于人像LR的设置</h1><p>目前拍了一些照片了,对修图也有一定的认识吧,下面说说修人像我自己常用到的一些方法。提前声明:我的LR版本是2020的,版本比较新,功能也比较多。</p>
<p>首先是曝光,啥都不管,直接拉曝光,一般而言会显得很白,然后皮肤也会显得比较好看,这个是必调的!</p>
<p>第二是偏好设置中的“纹理”和“清晰度”这两个选项,这两个我会拉到-20左右的值,因为这样会有一个朦胧感和相对的清晰感。纹理拉高了锐化非常严重,清晰度拉高了太亮,也有锐化的那种感觉,显得生硬,对于妹子而言肯定是不合适的,因此我都拉到负值,我觉得-20左右是一个挺不错的数值。</p>
<p>第三是鲜艳度和饱和度,这个的话看整体颜色怎么样,这两个选项适当微调,饱和度一般我给一个-5左右就行。</p>
<p>第四是曲线,这个也是PS调整的精髓之一了,在新手过程中,我只用万能的S型曲线,即高光向上拉,阴影向下即可,这个一直盯着画面,怎么好看怎么来。</p>
<p>第五也是我觉得最好用的选项之一,就是“细节”这个选项中的“噪点消除”,在明亮度我一般选择25-30这样的数值,噪点消除这个功能不仅仅是消除噪点,我个人感觉它使用了均值的算法来消除的,对于妹子的皮肤而言,有一个很好的磨皮效果,真的非常赞!!!</p>
<p>其次还有的细节就是在“HSL/颜色”这个选项中的内容,里面有色相,饱和度,明亮度和全部的选项,这些内容都是需要根据内容微调的。里面的色相中的黄色和绿色可以稍微尝试一下,对于肤色而言可以有较大的改善,还有饱和度中的红色,拉高可以调节口红的颜色深度,如果周围的红色影响不大的话。</p>
<p>以后有好的经验总结也会多写写的~</p>
<h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p>目前打算可能会一直更新,暂时没有结语~</p>
]]></content>
<categories>
<category>Camera</category>
</categories>
<tags>
<tag>Camera</tag>
</tags>
</entry>
<entry>
<title>Ubuntu安装和简单使用CMake</title>
<url>/2020/21.Ubuntu-CMake/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近想简单学习一下CMake,因为比较好用,而且也会偏向多平台,为了方便的话我也是直接就在Ubuntu和Win10都进行了安装,现在介绍的是Ubuntu平台上面的,Win平台上面也是大同小异,而且教程也挺多的,不必纠结。</p>
<h1 id="安装CMake"><a href="#安装CMake" class="headerlink" title="安装CMake"></a>安装CMake</h1><h2 id="直接命令行"><a href="#直接命令行" class="headerlink" title="直接命令行"></a>直接命令行</h2><p>我当时就感觉CMake比较流行,直接尝试了指令,发现真的可以,如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt install cmake</span><br></pre></td></tr></table></figure>
<h2 id="官网下载安装"><a href="#官网下载安装" class="headerlink" title="官网下载安装"></a>官网下载安装</h2><p>这个里面也有两种方法,优点也比较明确。首先是可以选择版本,其次是可以下载源码自己编译,尤其是自己交叉编译Android平台的opencv时会提示版本过低。安装版本的和用指令的一样,下面简单介绍下载源码编译的。</p>
<p>到<a href="https://cmake.org/download/" target="_blank" rel="noopener">CMake官网</a>下载最新的cmake。下载后解压,然后进入目录执行:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">./bootstrap</span><br><span class="line">make -j8</span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure>
<p>然后验证版本:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">cmake --version</span><br></pre></td></tr></table></figure>
<p>如果实用安卓的opencv的话还需要将Android Sdk中的cmake软链接到/usr/local/bin目录中:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo ln -s /home/gavinandre/Android/Sdk/cmake/3.6.4111459/bin/cmake /usr/<span class="built_in">local</span>/bin</span><br></pre></td></tr></table></figure>
<h1 id="CMake示例"><a href="#CMake示例" class="headerlink" title="CMake示例"></a>CMake示例</h1><p>首先编写一个简单的cpp文件,取名 main.cpp, 写一个简单的hello world程序:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include<iostream></span></span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> cout << <span class="string">"hello world!"</span> << endl;</span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>然后编写CMakeLists.txt文件:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">cmake_minimum_required(VERSION 2.8)</span><br><span class="line"><span class="comment">#工程名</span></span><br><span class="line">project(HELLOWORLD)</span><br><span class="line"><span class="comment">#包含原程序,即把给定目录下的源程序复制给变量DIR_SRC</span></span><br><span class="line"><span class="comment">#将指定路径下的源文件储存在指定的变量中</span></span><br><span class="line">aux_source_directory(./ DIR_SRC)</span><br><span class="line"><span class="comment">#生成程序</span></span><br><span class="line">add_executable(helloworld <span class="variable">${DIR_SRC}</span>)</span><br></pre></td></tr></table></figure>
<p>最后编译:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="variable">$mkdir</span> build</span><br><span class="line"><span class="variable">$cd</span> build</span><br><span class="line"><span class="variable">$cmake</span> ..</span><br><span class="line"><span class="variable">$make</span></span><br><span class="line">$./helloworld</span><br></pre></td></tr></table></figure>
<p>可以看到编译结果:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">hello world!</span><br></pre></td></tr></table></figure>
<h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p>可以看到在linux下面安装和使用Cmake还是比较方便的,目前而言我对Cmake的语法也不是很熟悉,但是仍然感觉还是觉得挺好用的。</p>
]]></content>
<categories>
<category>Ubuntu</category>
</categories>
<tags>
<tag>Ubuntu</tag>
<tag>Linux</tag>
<tag>CMake</tag>
</tags>
</entry>
<entry>
<title>汉诺塔问题与递归的思路总结</title>
<url>/2020/20.Recursion%20problem/</url>
<content><![CDATA[<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"></script>
<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>递归问题一直是笔试的重点,下面开始简单总结递归的问题,主要是递归思考的思路,还有就是怎么用编程的方式来实现。</p>
<h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><p>经典的汉诺塔问题就是最好的递归例子,早期相信很多的手机上面也有这个小游戏吧,就是移动圈圈的问题。以三个圈圈移动为例<img src="/images/C-Language/hannuo.gif" alt="P1.1"></p>
<p>递归主要的思路就是找到 n 和 n-1 步的规律,还有就是递归停止的条件。在这个汉诺塔中,显然,n=1就直接移动过去了,主要是关于数量较多的时候的规律。</p>
<p>首先是移动的函数move,写函数的主要思路是A通过B移动到C,这个一定要理解出来:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void move(int n, char c1, char c2, char c3)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span>(n == 1)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %c -> %c \n"</span>, c1, c3);</span><br><span class="line"> // 暂时没写完,后面还有</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>其次是分析规律,汉诺塔的方式其实还比较简简单,就是先将 n-1 行移动到 B,然后将第 n 行移动到 C,最后将 B 上面的 n-1 行移动到 C 即可。具体如下(很抱歉公式编辑器出来的式子好像有点麻烦在这里显示不出来就用图片来代替了):<br> <img src="/images/C-Language/2.1.png" width = "200" height = "110" alt="图片名称" align=center /></p>
<p> 如实就可以写完整的函数了,如下:<br> <figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">void move(int n, char c1, char c2, char c3)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">if</span>(n == 1)</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">" %c -> %c \n"</span>, c1, c3);</span><br><span class="line"> <span class="keyword">else</span> </span><br><span class="line"> {</span><br><span class="line"> move(n-1, c1, c3, c2);</span><br><span class="line"> move(1, c1, c2, c3);</span><br><span class="line"> move(n-1, c2, c1, c3);</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>实际使用中只需要调用move函数即可,如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">int main(void)</span><br><span class="line">{</span><br><span class="line"> move(5,<span class="string">'A'</span>, <span class="string">'B'</span>, <span class="string">'C'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>递归问题其实是一个常用的思路,但是由于其资源的耗费很多,而且堆栈资源的实用巨大,导致在牛客或者力上面扣做题实用递归常常会可能时间太长了。</p>
<p>结论:在实际使用中如果能用循环解决一定不要用递归!</p>
]]></content>
<categories>
<category>The C/C++ language</category>
</categories>
<tags>
<tag>Recursion</tag>
<tag>Hanota</tag>
</tags>
</entry>
<entry>
<title>Ubuntu安装Samba</title>
<url>/2020/19.Ubuntu-Samba/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>Samba在linux的应用应该来说还是非常广泛的,不管是商业用的NAS,还是自己手头分享用的文件共享,Samba由于其良好的共享性能都广受好评,但是新手常常在Ubuntu上面配置的时候经常出现一些小问题,如是广泛阅读了很多资料,最后发现还是<a href="https://ubuntu.com/tutorials/install-and-configure-samba#1-overview" target="_blank" rel="noopener">官网</a>可靠,下面做一个简单的记录,分享Ubuntu上面Samba的使用(16.04-20.04均可用)。</p>
<h1 id="首先安装Samba"><a href="#首先安装Samba" class="headerlink" title="首先安装Samba"></a>首先安装Samba</h1><p>为了安装Samba,我们运行下列指令:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo apt update</span><br><span class="line">sudo apt install samba</span><br></pre></td></tr></table></figure>
<p>为了确保安装成功,我们需要进行简单的确认:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">whereis samba</span><br></pre></td></tr></table></figure>
<p>下面是返回的内容:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">samba: /usr/sbin/samba /usr/lib/samba /etc/samba /usr/share/samba /usr/share/man/man7/samba.7.gz /usr/share/man/man8/samba.8.gz</span><br></pre></td></tr></table></figure>
<h1 id="其次是配置Samba"><a href="#其次是配置Samba" class="headerlink" title="其次是配置Samba"></a>其次是配置Samba</h1><p>目前来说Samba已经安装好了,下面开始新建一个共享的文件夹,这里建议最好就用/home里面自己这个用户的文件夹(下面的“username”记得换成自己的用户名),这样可以避免一些权限的问题,操作如下:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">mkdir /home/<username>/sambashare/</span><br></pre></td></tr></table></figure>
<p>然后就能添加用户信息啦,运行如下指令:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo nano /etc/samba/smb.conf</span><br></pre></td></tr></table></figure>
<p>添加下面的内容到smb.conf文件中,记住下面的“username”还是要换成自己的用户名:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">[sambashare]</span><br><span class="line"> comment = Samba on Ubuntu</span><br><span class="line"> path = /home/username/sambashare</span><br><span class="line"> <span class="built_in">read</span> only = no</span><br><span class="line"> browsable = yes</span><br></pre></td></tr></table></figure>
<p>这里如果对VIM或者nano不熟悉的话也可以用图形化界面的gedit来编辑,简单安装就行,也是非常方便,上面的指令看起来也是非常的简单易懂。</p>
<p>最后我们开始设置Samba服务,首先是开启这个服务:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo service smbd restart</span><br></pre></td></tr></table></figure>
<p>更新防火墙规则来允许Samba通讯:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo ufw allow samba</span><br></pre></td></tr></table></figure>
<p>结尾的一部就是添加用户啦,指令如下(这里的“username”还是要换成自己的用户名,不然不允许共享):</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">sudo smbpasswd -a username</span><br></pre></td></tr></table></figure>
<h1 id="其他设备连接"><a href="#其他设备连接" class="headerlink" title="其他设备连接"></a>其他设备连接</h1><p>一般不同的设备之间可能会有一些不同,但是都大同小异。常用的一般是Win10和MacOS,一般需要获取局域网内需要共享的机器的局域网IP,比如自己的IP是:192.168.175.129,具体如下:</p>
<p>Win10在文件资源管理器直接输入下列指令,输入账号和密码即可访问</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">\\ip-address\sambashare</span><br></pre></td></tr></table></figure>
<p>MaxOs输入的指令略微不同,如下所示:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">smb://ip-address/sambashare</span><br></pre></td></tr></table></figure>
<p>这样Samba的配置就全部完成了,非常使实用!</p>
<h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p>还是看<a href="https://ubuntu.com/tutorials/install-and-configure-samba#1-overview" target="_blank" rel="noopener">官方文档</a>最靠谱!!!</p>
]]></content>
<categories>
<category>Ubuntu</category>
</categories>
<tags>
<tag>Ubuntu</tag>
<tag>Linux</tag>
<tag>Samba</tag>
</tags>
</entry>
<entry>
<title>C语言的一些基础知识</title>
<url>/2020/18.Basics%20of%20C-DESKTOP-GRPI1FR/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近准备在投简历,也是总结总结一下C语言的基础知识,做一些准备。首先说明,下文后面所做的所有的实验都是在win10_1909_x64环境下,gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project),软件使用的是VSCode。在C语言多线程的使用中,在VSCode配置好了C语言的基本环境之后就能直接使用了。</p>
<h1 id="C语言的字与字节"><a href="#C语言的字与字节" class="headerlink" title="C语言的字与字节"></a>C语言的字与字节</h1><p>变量大家肯定都熟悉,我的理解是一块内存存储的可变内容。一般来说,多个数据在内存中是连续存储的,彼此之间没有明显的界限,如果不明确指明数据的长度,计算机就不知道何时存取结束。下面对基础的内容进行说明。</p>
<p>首先是<strong>位</strong>(Bit):表示二进制数码,只有0和1,是计算机处理和保存信息的最基本的单位。</p>
<p>其次是<strong>字节</strong>(Byte):一个字节由8个位组成,他是作为一个完整单位的8个二进制数码,最开始学习的C语言内容之一就是ASCII编码/《美国国家信息交换标准代码》,下面的图展示了AscII编码的一些信息,里面我觉得印象深刻的圈出来了。</p>
<p>最后是<strong>字</strong>(Word):一个字由两个字节组成,它表示计算机处理指令或者数据的二进制位数。通常称16位是一个字,32位是一个双字,64位是两个双字。<br><img src="/images/C-Language/1.1.png" alt="P1.1"></p>
<h1 id="C语言的变量长度"><a href="#C语言的变量长度" class="headerlink" title="C语言的变量长度"></a>C语言的变量长度</h1><p>变量的长度,准确来说应该是便来那个类型所占的字节数,也做一个小小的总结吧,具体内容如下所示:</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度</th>
</tr>
</thead>
<tbody><tr>
<td>char</td>
<td>1</td>
</tr>
<tr>
<td>char[1]</td>
<td>1</td>
</tr>
<tr>
<td>char[2]</td>
<td>2</td>
</tr>
<tr>
<td>short</td>
<td>2</td>
</tr>
<tr>
<td>short[1]</td>
<td>2</td>
</tr>
<tr>
<td>short[2]</td>
<td>4</td>
</tr>
<tr>
<td>int</td>
<td>4</td>
</tr>
<tr>
<td>int[1]</td>
<td>4</td>
</tr>
<tr>
<td>int[2]</td>
<td>8</td>
</tr>
<tr>
<td>float</td>
<td>4</td>
</tr>
<tr>
<td>float[1]</td>
<td>4</td>
</tr>
<tr>
<td>float[2]</td>
<td>8</td>
</tr>
<tr>
<td>double</td>
<td>8</td>
</tr>
<tr>
<td>double[1]</td>
<td>8</td>
</tr>
<tr>
<td>double[2]</td>
<td>16</td>
</tr>
</tbody></table>
<p>尤其注意的是C语言中的bool变量,在C98是标准中是没有定义bool类型变量的,直接引用会报错,一般可以用define或者枚举型便来那个来表示,还有一种方法是在头文件中添加”stdbool.h”这个头文件来引用即可,下面是具体的一些代码:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include "stdio.h"</span></span><br><span class="line"><span class="comment">#include "stdbool.h"</span></span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line"></span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(int)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(int[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(int[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(char)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(char[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(char[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(double)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(double[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(double[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(<span class="built_in">float</span>)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(<span class="built_in">float</span>[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(<span class="built_in">float</span>[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(short)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(short[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(short[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(bool)); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(bool[1])); </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(bool[2])); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d\n"</span>, sizeof(long)); </span><br><span class="line"> </span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="数据结构的字节对齐"><a href="#数据结构的字节对齐" class="headerlink" title="数据结构的字节对齐"></a>数据结构的字节对齐</h1><p>这个是一个非常重要的知识点,面试经常考,具体是个什么意思呢,跑一下下面的代码就知道了。</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include "stdio.h"</span></span><br><span class="line"><span class="comment">#include "stdbool.h"</span></span><br><span class="line"></span><br><span class="line">struct t1</span><br><span class="line">{</span><br><span class="line"> char a1;</span><br><span class="line"> char b1;</span><br><span class="line"> char c1;</span><br><span class="line"> int d1;</span><br><span class="line"> char e1;</span><br><span class="line">}T1;</span><br><span class="line"></span><br><span class="line">struct t2</span><br><span class="line">{</span><br><span class="line"> char a2;</span><br><span class="line"> char b2;</span><br><span class="line"> char c2;</span><br><span class="line"> char e2;</span><br><span class="line"> int d2;</span><br><span class="line">}T2;</span><br><span class="line"></span><br><span class="line">struct t3</span><br><span class="line">{</span><br><span class="line"> double a2;</span><br><span class="line"> char b2;</span><br><span class="line"> int c3;</span><br><span class="line">}T3;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d %d %d"</span>, sizeof(T1), sizeof(T2), sizeof(T3));</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>上面的输出分别是 “12 8 16”,两个基本相同的两个结构体长度是不一样,这个就是字节对齐。现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。</p>
<p>对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。</p>
<p>揭示了原因,现在上面的例子应该就比较好分析了,<strong>windows 64 位默认 结构体对齐系数为8,32位 结构体对齐系数为4,而且在VC/C++和GNU GCC中都是默认是4字节对齐</strong>。<br>T1结构体分三段:</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度</th>
</tr>
</thead>
<tbody><tr>
<td>1+1+1</td>
<td>4 [对齐4]</td>
</tr>
<tr>
<td>4</td>
<td>4</td>
</tr>
<tr>
<td>1</td>
<td>4 [对齐4]</td>
</tr>
</tbody></table>
<p>T2结构体分两段:</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度</th>
</tr>
</thead>
<tbody><tr>
<td>1+1+1+1</td>
<td>4</td>
</tr>
<tr>
<td>4</td>
<td>4</td>
</tr>
</tbody></table>
<p>T3结构体分两段:</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度</th>
</tr>
</thead>
<tbody><tr>
<td>8</td>
<td>8</td>
</tr>
<tr>
<td>1+4</td>
<td>8</td>
</tr>
</tbody></table>
<p>现在对字节对齐已经有了一个比较深刻的认识了大,他是由于计算机在高速读取的时候为了保证读取效率而设计的,但是我们在做嵌入式开发钟数据处理和传输数据的时候,经常设计一些自定义的通信协议,如果按照这种设计反而会降低通信效率,而且如果接收方不清楚这些内容可能会引起一些问题,因此也有一定的方法来取消字节对齐或者自行设计对齐的长度。</p>
<p> · 使用伪指令#pragma pack (n),编译器将按照n个字节对齐;<br> · 使用伪指令#pragma pack (),取消自定义字节对齐方式。 </p>
<p>注意:如果#pragma pack (n)中指定的n大于结构体中最大成员的size,则其不起作用,结构体仍然按照size最大的成员进行对界。</p>
<p>另一种方式比较简单,直接在结构体后面加上<code>__attribute__((packed))</code>,这个是直接取消字节对齐的,或者用<code>__attribute__((aligned(n)))</code>,这个跟<code>pragma pack (n)</code>效果相同。</p>
<p>可以尝试下面的例子:</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line"><span class="comment">#include "stdio.h"</span></span><br><span class="line"><span class="comment">#include "stdbool.h"</span></span><br><span class="line"></span><br><span class="line">struct t1</span><br><span class="line">{</span><br><span class="line"> char a1;</span><br><span class="line"> char b1;</span><br><span class="line"> char c1;</span><br><span class="line"> int d1;</span><br><span class="line"> char e1;</span><br><span class="line">}__attribute__((packed)) T1;</span><br><span class="line"></span><br><span class="line">struct t2</span><br><span class="line">{</span><br><span class="line"> char a2;</span><br><span class="line"> char b2;</span><br><span class="line"> char c2;</span><br><span class="line"> char e2;</span><br><span class="line"> int d2;</span><br><span class="line">}__attribute__((aligned(2))) T2;</span><br><span class="line"></span><br><span class="line">struct t3</span><br><span class="line">{</span><br><span class="line"> double a2;</span><br><span class="line"> char b2;</span><br><span class="line"> int c3;</span><br><span class="line"> int d3;</span><br><span class="line">}__attribute__((aligned(4))) T3;</span><br><span class="line"></span><br><span class="line">int main()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%d %d %d"</span>, sizeof(T1), sizeof(T2), sizeof(T3));</span><br><span class="line"></span><br><span class="line"> <span class="built_in">return</span> 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>输出为”8 8 24”,有兴趣可以自己对比前面的内容并且简单计算一下。</p>
]]></content>
<categories>
<category>The C language</category>
</categories>
<tags>
<tag>C语言</tag>
<tag>Some basics</tag>
<tag>变量长度</tag>
<tag>字节对齐</tag>
</tags>
</entry>
<entry>
<title>C语言的一些基础知识</title>
<url>/2020/18.Basics%20of%20C/</url>
<content><![CDATA[<h1 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h1><p>最近准备在投简历,也是总结总结一下C语言的基础知识,做一些准备。首先说明,下文后面所做的所有的实验都是在win10_1909_x64环境下,gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project),软件使用的是VSCode。在C语言多线程的使用中,在VSCode配置好了C语言的基本环境之后就能直接使用了。</p>
<h1 id="C语言的字与字节"><a href="#C语言的字与字节" class="headerlink" title="C语言的字与字节"></a>C语言的字与字节</h1><p>变量大家肯定都熟悉,我的理解是一块内存存储的可变内容。一般来说,多个数据在内存中是连续存储的,彼此之间没有明显的界限,如果不明确指明数据的长度,计算机就不知道何时存取结束。下面对基础的内容进行说明。</p>
<p>首先是<strong>位</strong>(Bit):表示二进制数码,只有0和1,是计算机处理和保存信息的最基本的单位。</p>
<p>其次是<strong>字节</strong>(Byte):一个字节由8个位组成,他是作为一个完整单位的8个二进制数码,最开始学习的C语言内容之一就是ASCII编码/《美国国家信息交换标准代码》,下面的图展示了AscII编码的一些信息,里面我觉得印象深刻的圈出来了。</p>
<p>最后是<strong>字</strong>(Word):一个字由两个字节组成,它表示计算机处理指令或者数据的二进制位数。通常称16位是一个字,32位是一个双字,64位是两个双字。<br><img src="/images/C-Language/1.1.png" alt="P1.1"></p>
<h1 id="C语言的变量长度"><a href="#C语言的变量长度" class="headerlink" title="C语言的变量长度"></a>C语言的变量长度</h1><p>变量的长度,准确来说应该是便来那个类型所占的字节数,也做一个小小的总结吧,具体内容如下所示:</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>长度</th>
</tr>
</thead>
<tbody><tr>
<td>char</td>
<td>1</td>
</tr>
<tr>
<td>char[1]</td>
<td>1</td>
</tr>
<tr>
<td>char[2]</td>
<td>2</td>
</tr>
<tr>
<td>short</td>
<td>2</td>
</tr>
<tr>
<td>short[1]</td>