詳解樹莓派Model B+控制蜂鳴器演奏樂曲

来源:http://www.cnblogs.com/zhaoweiwei/archive/2017/01/04/RaspberryMusic.html
-Advertisement-
Play Games

最近看到Arduino可以利用pwm及蜂鳴器播放音樂,想到樹莓派上也有類似的pwm輸出,所以決定把相應的內容移植到樹莓派上,並給出了樹莓派播放鐵血丹心的例子! ...


步進電機以及無源蜂鳴器這些都需要脈衝信號才能夠驅動,這裡將用GPIO的PWM介面驅動無源蜂鳴器彈奏樂曲,本文基於樹莓派Mode B+,其他版本樹莓派實現時需參照相關資料進行修改!

1 預備知識

1.1 無源蜂鳴器和有源蜂鳴器

無源蜂鳴器:內部沒有震蕩源,直流信號無法讓它鳴叫。必須用去震蕩的電流驅動它,2K-5KHZ的方波PWM (Pulse Width Modulation脈衝寬度調製)。5KHZ的電流方波就是每秒震動5K次,每一個完整的周期占用200us的時間,高點平占一部分時間,低電平占一部分時間。聲音頻率可控,可以做出不同的音效。

有源蜂鳴器:內部帶震蕩電路,一通電就鳴叫,所以可以跟前面LED一樣,給個高電平就能響,編程比無源的更方便。

本文利用無源蜂鳴器彈奏樂曲,用的就是淘寶上普通的電磁式阻抗16歐交流/2KHz 3V 5V 12V通用無源蜂鳴器,如果手邊沒有無源蜂鳴器,用普通的耳機也可以來代替無源蜂鳴器。

1.2 PWM

PWM(Pulse Width Modulation)即脈衝寬度調製,是一種利用微處理器的數字輸出來控制模擬電路的控制技術。可以用下麵的一幅圖來形象地說明PWM:

圖中tpwm就是一個周期的時間長度。對於2KHz頻率來說,那麼周期就是1s/2K=500us。圖中的D叫做占空比,指的是高電平的時間占用整個周期時間的百分比。第一個周期D=50%,那麼就是高電平低電平的時間各占一半。接下來的D為33%,那就是通電時間為33%,剩餘的不通電時間占用67%。樹莓派Model B+有4個PIN腳支持PWM輸出,如下圖最右側:

但是,需要註意的是BCM2835晶元只支持兩路PWM輸出,所以以上12 Pin腳和32 Pin腳對應的都是channel 1的PWM輸出,即如果這兩個Pin的功能都選擇的是PWM輸出,則它們輸出的PWM是完全相同的,同理33 Pin腳和35 Pin腳對應晶元channel 2的PWM輸出。

博通公司公佈的BCM2835晶元資料BCM2835 ARM Peripherals中第9章比較詳細的介紹了PWM相關內容,此外還可參考網上整理好的寄存器介紹資料rip-registers,通過閱讀可以得知樹莓派Model B+支持兩種模式的PWM輸出:一種是Balanced mode(平衡模式),一種是Mark-Space mode(MS模式)。另外樹莓派的PWM輸出基礎頻率是19.2MHz,PWM輸出頻率受這個基礎頻率的限制。

1.3 樹莓派PWM分析

進行分析前先看一下實驗的物理電路連接:

圖中,紅色杜邦線一頭連接樹莓派的32 Pin腳(PWM0),一頭連接示波器的探針;綠色杜邦線一頭連接樹莓派的12 Pin腳(PWM0),一頭連接無源蜂鳴器的正極;黃色杜邦線一頭連接樹莓派的6 Pin腳(ground),一頭連接無源蜂鳴器的負極,此外示波器探針的ground也連接到黃色杜邦線,結合bcm2835 C library來進行分析:

(1)下載bcm2835庫:wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz

(2)解壓:tar -zxvf bcm2835-1.50.tar.gz

(3)進入目錄:cd bcm2835-1.35

(4)編譯:./configure && make

(5)安裝:sudo make install

修改examples/pwm/pwm.c的內容如下:

 1 // pwm.c
 2 //
 3 // Example program for bcm2835 library
 4 // Shows how to use PWM to control GPIO pins
 5 //
 6 // After installing bcm2835, you can build this 
 7 // with something like:
 8 // gcc -o pwm pwm.c -l bcm2835 
 9 // sudo ./pwm
10 //
11 // Or you can test it before installing with:
12 // gcc -o pwm -I ../../src ../../src/bcm2835.c pwm.c
13 // sudo ./pwm
14 //
15 // Author: Mike McCauley
16 // Copyright (C) 2013 Mike McCauley
17 // $Id: RF22.h,v 1.21 2012/05/30 01:51:25 mikem Exp $
18 
19 #include <bcm2835.h>
20 #include <stdio.h>
21 
22 // PWM output on RPi Plug P1 pin 12 (which is GPIO pin 18)
23 // in alt fun 5.
24 // Note that this is the _only_ PWM pin available on the RPi IO headers
25 #define PIN RPI_GPIO_P1_12
26 // and it is controlled by PWM channel 0
27 #define PWM_CHANNEL 0
28 // This controls the max range of the PWM signal
29 #define RANGE 1024
30 
31 #define PIN2 RPI_BPLUS_GPIO_J8_32
32 
33 int main(int argc, char **argv)
34 {
35     if (!bcm2835_init())
36         return 1;
37 
38     // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
39     bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);
40     
41     bcm2835_gpio_fsel(PIN2, BCM2835_GPIO_FSEL_ALT0);    // 打開PI 32 Pin腳的PWM0輸出功能
42 
43     // Clock divider is set to 16.
44     // With a divider of 16 and a RANGE of 1024, in MARKSPACE mode,
45     // the pulse repetition frequency will be
46     // 1.2MHz/1024 = 1171.875Hz, suitable for driving a DC motor with PWM
47     bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_16);
48     bcm2835_pwm_set_mode(PWM_CHANNEL, 0, 1);
49     bcm2835_pwm_set_range(PWM_CHANNEL, RANGE);
50     
51     printf("this is banlance mode, anykey will change to markspace mode\n");
52     bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/4);
53     getchar();
54     
55     printf("change to markspace mode, anykey to exit\n");
56     bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1);
57     bcm2835_pwm_set_range(PWM_CHANNEL, RANGE);
58     bcm2835_pwm_set_data(PWM_CHANNEL, RANGE/4);
59     getchar();
60 
61     bcm2835_close();
62     return 0;
63 }
pwm.c

 代碼中首先設置PWM輸出為平衡模式,之後按任意鍵切換為MS模式,編譯:gcc -o pwm pwm.c -lbcm2835,運行:sudo ./pwm,示波器分別捕獲到如下波形圖:

balance modemarkspace mode

代碼第47行用divider=16對19.2MHz的基礎頻率進行調整,調整後的pwm頻率為19.2MHz/16=1.2MHz,根據BCM2835晶元資料及代碼49行和52行內容可知占空比應為N/M=(RANGE/4)/RANGE=256/1024,平衡模式力求任意一段時間占空比都最接近N/M=1/4,即把256個高電平時鐘周期平均的分配到1024個之中周期中,可以這樣進行處理,每4個時鐘周期為一組,其中的一個周期內為高電平,這樣即可實現“平衡”,這時真實的PWM輸出幀率為1.2MHz/4=300KHz,如以上左圖所示;對於MarkSpace模式來說,占空比為M/S=(RANGE/4)/RANGE=256/1024,這種模式不需要進行平衡,即可以認為1024個時鐘周期的前256個為高電平,其餘的為低電平,這時真實的PWM輸出幀率為1.2MHz/1024=1171.875Hz,如以上右圖所示。

2 樹莓派播放音樂

2.1 樂理知識

一首樂曲有若幹音符組成,每個音符由音調和演奏時間組成。不同的音調在物理上就對應不同頻率的音波。所以我們只要控制輸出的頻率和時長就能輸出一首音樂了。當然實際的音樂很複雜,又有連接,還有重音什麼的,這個就先不在討論範圍內了。

每個音符都會播放一定的時間,這樣就能構成一首歌曲。在音樂上,音符節奏分為1拍、1/2拍、1/4拍、1/8拍,假設一拍音符的時間為1;半拍為0.5;1/4拍為0.25;1/8拍為0.125……,所以我們可以為每個音符賦予這樣的拍子播放出來,音樂就成了。

Arduino官方網站給出了不同音符對應的不同頻率的頭文件pitches.h,相關內容可以參考博文,在本文我們把pitches.h文件直接應用到樹莓派,該文件內容如下:

 1 /*************************************************
 2  * Public Constants
 3  *************************************************/
 4 
 5 #define NOTE_B0  31
 6 #define NOTE_C1  33
 7 #define NOTE_CS1 35
 8 #define NOTE_D1  37
 9 #define NOTE_DS1 39
10 #define NOTE_E1  41
11 #define NOTE_F1  44
12 #define NOTE_FS1 46
13 #define NOTE_G1  49
14 #define NOTE_GS1 52
15 #define NOTE_A1  55
16 #define NOTE_AS1 58
17 #define NOTE_B1  62
18 #define NOTE_C2  65
19 #define NOTE_CS2 69
20 #define NOTE_D2  73
21 #define NOTE_DS2 78
22 #define NOTE_E2  82
23 #define NOTE_F2  87
24 #define NOTE_FS2 93
25 #define NOTE_G2  98
26 #define NOTE_GS2 104
27 #define NOTE_A2  110
28 #define NOTE_AS2 117
29 #define NOTE_B2  123
30 #define NOTE_C3  131
31 #define NOTE_CS3 139
32 #define NOTE_D3  147
33 #define NOTE_DS3 156
34 #define NOTE_E3  165
35 #define NOTE_F3  175
36 #define NOTE_FS3 185
37 #define NOTE_G3  196
38 #define NOTE_GS3 208
39 #define NOTE_A3  220
40 #define NOTE_AS3 233
41 #define NOTE_B3  247
42 #define NOTE_C4  262
43 #define NOTE_CS4 277
44 #define NOTE_D4  294
45 #define NOTE_DS4 311
46 #define NOTE_E4  330
47 #define NOTE_F4  349
48 #define NOTE_FS4 370
49 #define NOTE_G4  392
50 #define NOTE_GS4 415
51 #define NOTE_A4  440
52 #define NOTE_AS4 466
53 #define NOTE_B4  494
54 #define NOTE_C5  523
55 #define NOTE_CS5 554
56 #define NOTE_D5  587
57 #define NOTE_DS5 622
58 #define NOTE_E5  659
59 #define NOTE_F5  698
60 #define NOTE_FS5 740
61 #define NOTE_G5  784
62 #define NOTE_GS5 831
63 #define NOTE_A5  880
64 #define NOTE_AS5 932
65 #define NOTE_B5  988
66 #define NOTE_C6  1047
67 #define NOTE_CS6 1109
68 #define NOTE_D6  1175
69 #define NOTE_DS6 1245
70 #define NOTE_E6  1319
71 #define NOTE_F6  1397
72 #define NOTE_FS6 1480
73 #define NOTE_G6  1568
74 #define NOTE_GS6 1661
75 #define NOTE_A6  1760
76 #define NOTE_AS6 1865
77 #define NOTE_B6  1976
78 #define NOTE_C7  2093
79 #define NOTE_CS7 2217
80 #define NOTE_D7  2349
81 #define NOTE_DS7 2489
82 #define NOTE_E7  2637
83 #define NOTE_F7  2794
84 #define NOTE_FS7 2960
85 #define NOTE_G7  3136
86 #define NOTE_GS7 3322
87 #define NOTE_A7  3520
88 #define NOTE_AS7 3729
89 #define NOTE_B7  3951
90 #define NOTE_C8  4186
91 #define NOTE_CS8 4435
92 #define NOTE_D8  4699
93 #define NOTE_DS8 4978
pitches.h

可以看到,這是一張類似表格的東西,裡面是定義的大量的巨集,即用巨集名代替了頻率名,對應到鍵盤的各個按鍵上。我們需要對應相應的音符到巨集名上,為了實現這個首先看看鋼琴大譜表與鋼琴琴鍵的對照表:

為了將個音符的音名直觀的看出來,給出以下表格:

2.2 播放音樂

對照以上表格及射雕英雄傳主題曲鐵血丹心簡譜實現樹莓派播放,鐵血丹心簡譜如下:

上面的簡譜中缺少前奏,程式中增加了從其他版本中摘錄的前奏部分,主程式tiexuedanxin.c代碼如下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <stdint.h>
  4 
  5 #include <bcm2835.h>
  6 #include "pitches.h"
  7 
  8 #define PWM_CHANNEL 0
  9 typedef struct _TONE{
 10   int freq;
 11   int t_ms;
 12 } TONE,*PTONE;
 13 
 14 int pin = RPI_GPIO_P1_12;
 15 int baseFreq = 600000;          // BCM2835_PWM_CLOCK_DIVIDER_32 對應600KHz
 16 
 17 typedef struct _melodyNode{ 
 18   int note;
 19   float fDuration;
 20 }melodyNode;
 21 
 22 melodyNode melody[]= {
 23   // 1
 24   {NOTE_A4, 1.5},      // 6
 25   {NOTE_G4, 0.5},      // 5
 26   {NOTE_A4, 1},        // 6
 27   {NOTE_G4, 0.5},      // 5
 28   {NOTE_E4, 0.5},      // 3
 29   
 30   // 2
 31   {NOTE_G4, 1},        // 5
 32   {NOTE_D4, 3},        // 2
 33   
 34   // 3
 35   {NOTE_C4, 1.5},      // 1
 36   {NOTE_A3, 0.5},      // .6
 37   {NOTE_D4, 0.5},      // 2
 38   {NOTE_E4, 0.5},      // 3
 39   {NOTE_G4, 0.5},      // 5
 40   {NOTE_F4, 0.5},      // 4
 41   
 42   // 4
 43   {NOTE_E4, 3},        // 3
 44   {NOTE_E4, 0.5},      // 3
 45   {NOTE_G4, 0.5},      // 5
 46   
 47   // 5
 48   {NOTE_A4, 1.5},      // 6
 49   {NOTE_G4, 0.5},      // 5
 50   {NOTE_A4, 1},        // 6
 51   {NOTE_G4, 0.5},      // 5
 52   {NOTE_E4, 0.5},      // 5
 53   
 54   // 6
 55   {NOTE_G4, 1},        // 5
 56   {NOTE_D4, 3},        // 2
 57   
 58   // 7
 59   {NOTE_C4, 1.5},      // 1
 60   {NOTE_A3, 0.5},      // .6
 61   {NOTE_D4, 0.5},      // 2
 62   {NOTE_E4, 0.5},      // 3
 63   {NOTE_G3, 0.5},      // .5
 64   {NOTE_B3, 0.5},      // .7
 65   
 66   // 8
 67   {NOTE_A3, 4},        // .6
 68   
 69   {0, 1},              // 0
 70   {NOTE_E4, 0.5},      // 3
 71   {NOTE_D4, 0.5},      // 2
 72   {NOTE_C4, 1.5},      // 1
 73   {NOTE_B3, 0.5},      // .7
 74   
 75   //
 76   {NOTE_A3, 1.5},      // .6
 77   {NOTE_E3, 0.5},      // .3
 78   {NOTE_A3, 2},        // .6
 79   
 80   //{NOTE_A3, 1},        // .6
 81   {NOTE_A4, 0.5},      // 6
 82   {NOTE_G4, 0.5},      // 5
 83   {NOTE_E4, 1},        // 3
 84   {NOTE_G4, 0.5},      // 5
 85   {NOTE_D4, 0.5},      // 2
 86   
 87   {NOTE_E4, 3},        // 3
 88   
 89   {NOTE_E4, 0.5},      // 3
 90   {NOTE_D4, 0.5},      // 2
 91   {NOTE_C4, 1.5},      // 1
 92   {NOTE_B3, 0.5},      // .7
 93   
 94   {NOTE_A3, 1.5},        // .6
 95   {NOTE_E3, 0.5},        // .6
 96   {NOTE_A3, 2},          // .6
 97   
 98   {0, 1},              // 0
 99   {NOTE_D4, 0.5},      // 2
100   {NOTE_C4, 0.5},      // 1
101   {NOTE_A3, 1},        // .6
102   {NOTE_C4, 0.5},      // 1
103   {NOTE_D4, 0.5},      // 1
104   
105   {NOTE_E4, 3},        // 3*/
106   {NOTE_E4, 1},        // 3 逐草四方
107   
108   {NOTE_A4, 1.5},      // 6
109   {NOTE_G4, 0.5},      // 5
110   {NOTE_A4, 1},        // 6
111   {NOTE_G4, 0.5},      // 5
112   {NOTE_E4, 0.5},      // 3
113   
114   {NOTE_G4, 1},        // 5
115   {NOTE_D4, 3},        // 2
116   
117   {NOTE_C4, 1.5},      // 1
118   {NOTE_A3, 0.5},      // .6
119   {NOTE_D4, 0.5},      // 2
120   {NOTE_E4, 0.5},      // 3
121   {NOTE_G4, 0.5},      // 5
122   {NOTE_FS4, 0.5},     // #4
123   
124   {NOTE_E4, 3},        // 3
125   {NOTE_E4, 0.5},      // 3
126   {NOTE_G4, 0.5},      // 5
127   
128   {NOTE_A4, 1.5},      // 6
129   {NOTE_G4, 0.5},      // 5
130   {NOTE_A4, 1.0},      // 6
131   {NOTE_G4, 0.5},      // 5
132   {NOTE_E4, 0.5},      // 3
133   
134   {NOTE_G4, 1.0},      // 5
135   {NOTE_D4, 3},        // 2
136   
137   {NOTE_C4, 1.5},      // 1
138   {NOTE_A3, 0.5},      // .6
139   {NOTE_D4, 0.5},      // 2
140   {NOTE_E4, 0.5},      // 3
141   {NOTE_G3, 0.5},      // .5
142   {NOTE_B3, 0.5},      // .7
143   
144   {NOTE_A3, 3},         // .6
145   
146   {0, 1},              // 0
147   {NOTE_E4, 0.5},      // 3 應知愛意似
148   {NOTE_D4, 0.5},      // 2
149   {NOTE_C4, 1.0},      // 1
150   {NOTE_C4, 0.5},      // 1
151   {NOTE_B3, 0.5},      // .7
152   
153   {NOTE_A3, 1.5},      // .6
154   {NOTE_E3, 0.5},      // .3
155   {NOTE_A3, 2.0},      // .6
156   
157   {0, 1},              // 0
158   {NOTE_A3, 0.5},      // .6
159   {NOTE_G3, 0.5},      // .5
160   {NOTE_E3, 1.0},      // .3
161   {NOTE_G3, 0.5},      // .5
162   {NOTE_D3, 0.5},      // .2
163   
164   {NOTE_E3, 3.0},      // .3
165   
166   {0, 1},              // 0
167   {NOTE_E4, 0.5},      // 3 身經百劫也
168   {NOTE_D4, 0.5},      // 2
169   {NOTE_C4, 1.0},      // 1
170   {NOTE_C4, 0.5},      // 1
171   {NOTE_B3, 0.5},      // .7
172   
173   {NOTE_A3, 1.5},      // .6
174   {NOTE_E4, 0.5},      // 3
175   {NOTE_D4, 2.0},      // 2
176   
177   {0, 1},              // 0
178   {NOTE_D4, 0.5},      // 2
179   {NOTE_C4, 0.5},      // 1
180   {NOTE_A3, 1.0},      // .6
181   {NOTE_B3, 0.5},      // .7
182   {NOTE_G3, 0.5},      // .5
183   
184   {NOTE_A3, 3.0},      // .6
185 };
186 
187 void beep(int freq, int t_ms)
188 {
189     int range;
190     /*if(freq<2000||freq>5000)
191     {
192         printf("invalid freq\n");
193         return;
194     }*/
195     if(freq == 0)
196         range=1;
197     else
198         range=baseFreq/freq;
199     printf("will call bcm2835_pwm_set_range freq: %d range: %d\n", freq, range);
200     bcm2835_pwm_set_range(PWM_CHANNEL, range);
201     bcm2835_pwm_set_data(PWM_CHANNEL, range/2);
202     if(t_ms>0)
203     {
204         delay(t_ms);
205     }
206 }
207 
208 void init()
209 {
210     if (!bcm2835_init())
211         exit (1) ;
212     
213     printf("will init pin %d\n", pin);
214     // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
215     bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_ALT5);
216     bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_32);
217     bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1);
218 }
219 
220 int main (void)
221 {
222     int index=0;
223     int nLen = sizeof(melody)/sizeof(melody[0]);
224     init();
225 
226     for ( ; index<nLen; index++) 
227     {
228         int noteDuration = 600*melody[index].fDuration;
229         beep(melody[index].note, noteDuration);
230         printf("will call bcm2835_pwm_set_data 0 after beep\n");
231         bcm2835_pwm_set_data(PWM_CHANNEL, 0);
232         printf("index: %d nLen: %d@@@@@@@@@@@@\n", index, nLen);
233         //delay(100);
234     }
235 
236     bcm2835_pwm_set_data(PWM_CHANNEL, 0);
237     bcm2835_close();
238     
239     return 0 ;
240 }
tiexuedanxin

註意代碼中195行做了特殊處理,這時候頻率並不是為0,只是讓樹莓派不再發聲。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • HBase定義 HBase 是一個高可靠、高性能、面向列、可伸縮的分散式存儲系統,利用Hbase技術可在廉價PC Server上搭建 大規模結構化存儲集群。 HBase 是Google Bigtable 的開源實現,與Google Bigtable 利用GFS作為其文件存儲系統類似, HBase 利 ...
  • 在連接mysql jdbc時候,拋出了 com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Communication link failure, message from server: "Can't get  ...
  • 如果我想得到這樣一個結果集:分組排序,並且每組限定記錄集的數量,用一條SQL語句能辦到嗎? 比如說,我想找出學生期末考試中,每科的前3名,並按成績排序,只用一條SQL語句,該怎麼寫? 表[TScore]的結構 code 學號 char subject 科目 int score 成績 int 可以這樣 ...
  • 親測配置: 系統:Linux lite 3.2 x86_64(Ubuntu其他版本可參考修改) 筆記本:華碩(asus)1201N 達到的效果: 可以正常使用Fn+F5調暗,Fn+F6調亮. 設置步驟: 修改/etc/default/目錄下文件grub 將15~16行內容: 修改為如下內容 備註:上 ...
  • 出於安全性的考慮,不建議在bash腳本中註釋掉不使用的代碼。也就是說如果某段代碼不使用了,那麼應該刪除掉,而不是簡單地註釋掉。假如你突然意識到這一點,而以前並沒有遵從這個原則,現在需要找出腳本中的註釋性代碼,這可能是一個不小的工作量,讓我們寫一個腳本來幫助你吧,準確性無法達到百分之百,但是能夠提升效 ...
  • 一、共用庫 共用庫使得可執行文件中不再需要包含常用的庫函數,而只需在所有進程都可存取的存儲區中保存這種庫常式的一個副本。程式第一次執行的時候或第一次調用某個庫函數的時候,用動態鏈接方法將程式與共用庫函數相鏈接,這減少了每個可執行文件的長度,但增加了一些運行時間開銷。另一個優點就是可以用庫函數的新版本 ...
  • 一. 準備工作 1. 樹莓派主板 型號:樹莓派3 B型 處理器:四核64位ARM Cortex-A53 CPU 內核架構:ARMv8 2. 一張大於8G的TF卡(本人用的是32G的,也作為PiLFS用) 3. 一臺筆記本電腦,一根網線 4. 點擊此找到並下載 Raspbian 系統 初學者建議推薦選 ...
  • 什麼是Vim? Vim 是經典的 UNIX 編輯器 Vi 的深度改良版本。它增加了許多功能,包括:多級撤銷、格式高亮、命令行歷史、線上幫助、拼寫檢查、文件名補完、塊操作、腳本支持,等等。除了字元界面版本之外,它也有圖形界面版本(比如 gVim)。雖然 Vi 還在繼續維護當中,但是大部分人都只在使用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...