本篇文章內容總結下來就是
- 讀卡 使用默認密碼讀卡所有扇區所有塊的資料
- 寫ID 使用默認密碼讀取卡一的0扇區的第一塊資料并寫入到卡二的0扇區的第一塊里
- 密碼讀卡 不同廠家的初始密碼不同,整理了一些默認密碼,如果有收集到新的也可以補充進去
- 寫全卡 使用默認密碼讀取卡一的全部扇區全部塊資料并寫入到卡二的全部扇區的全部塊里
目錄
從來不按套路出牌的我
一.前期準備
STM32f103c8t6開發板
Keil5編譯器
串口工具
我就問你們什么叫專業
二.代碼
簡介RC522
代碼功能
代碼
總結
三.原始碼
從來不按套路出牌的我
沒用的前言,看干貨跳過這段
想必看到這篇文章的人都是已經翻閱了大量的文章資料,已經厭倦了那種通篇都是百度百科,通篇都是復制官方資料,通篇都是怎樣點亮led燈的沒有多少營養的文章
本篇文章除了插科打諢與耐人尋味的笑點之外盡可能的把干貨提供給大家學習,我在學習RC522時大量的時間都花在查找資料上了,真正的編程時間可能只有找資料的三分之一,所以為了不讓同樣抱有學習熱情的人因為找不到合適的資料而失去耐心最終失去學習的熱情,我準備把我整理的干貨拿出來與大家分享
沒錯,不務正業的我又回來了,這回是玩一玩Stm32單片機
當然也是從基礎的C語言開始學習,大概自學了小半個月的C語言就開始上手Stm32了
自學是在B站看的視頻,一邊寫筆記一邊敲代碼,好在有java的基礎,不然我就和這行無緣了
好了廢話不多說直接干貨
一.前期準備
- Stm32f103c8t6開發板 1塊
- RC522 1杯
- 杜邦線 適量
- 輕觸開關 3g
- led燈 根據個人喜好添加
- ST-LINK V2 一根 也可以使用 CH340替代(根據個人喜好調整)
- 一臺計算機 低于30噸的
- Keil5編譯器 1千克
- 串口燒錄程式 1匙
- 串口除錯程式 1伊普西龍
- M1 CUID卡 2開爾文
STM32f103c8t6開發板

RC522模塊

RC522相關資料:
鏈接: https://pan.baidu.com/s/1Qob5o4tv0_gBXrRk6AvLSQ
提取碼: fkjt
接線圖
每個人接線的引腳不同,我這里是因為接入了其他無關緊要的模塊才分開接線,不影響單獨RC522連接STM32
RC522接線
RC522_RST ====== GPIOA_Pin_0
RC522_MISO ====== GPIOA_Pin_1
RC522_MOSI ====== GPIOA_Pin_2
RC522_SCK ====== GPIOA_Pin_3
RC522_SDA(NSS) == GPIOA_Pin_4
GND ====== GND
ACC ====== ACC
按鈕接線
KEY1_ACC === GPIOB_Pin_0
KEY2_ACC === GPIOB_Pin_1
GND === GND
燈接線(也可以使用板載燈,這里使用板載燈)
LED5_ACC === GPIOA_Pin_5 //模式燈 在選擇模式時用于顯示當前模式用
LED6_ACC === GPIOA_Pin_6 //確認燈 在識別到卡1時會亮起提示換卡
GND === GND
Keil5編譯器
Keil5編譯器
鏈接: https://pan.baidu.com/s/10jR0g10jxdosawc49IOazQ
提取碼: uizh
Keil5開發環境
自己收集整理并添加一些自己常用的方法的Stm32f103c8t6開發環境,解壓即用
Keil5開發環境
鏈接: https://pan.baidu.com/s/1U5sOv9lvs3wwKkisiAFYAA
提取碼: z1ih
串口工具
串口除錯程式 串口燒錄程式
鏈接: https://pan.baidu.com/s/11VCAXnfmO1FCQQVjirIkrQ
提取碼: h1uz
失效私信我
我就問你們什么叫專業

硬體配置,開發環境詳細到這個地步,初學者能夠直接上手學習
這就是專業
這就是一條龍服務,以后你們給其他人分享這篇文章時都可以說被一條龍服務過
二.代碼
簡介RC522

官方檔案一共有109頁接下來都是復制這個檔案所以大家可以走了[dog]
我就簡單總結一下白話文:
1.RC522能讀卡
2.RC522能寫卡
3.RC522能... 就這樣,就是能讀卡能寫卡,我們要它的功能也就是讀卡寫卡,我沒必要為了實作一個讀卡功能把這一百多也的檔案看完,也沒有必要為了實作一個功能就把它的原理全部吃透
介紹完畢
代碼功能
- 讀卡 使用默認密碼讀卡所有扇區所有塊的資料
- 寫ID 使用默認密碼讀取卡一的0扇區的第一塊資料并寫入到卡二的0扇區的第一塊里
- 密碼讀卡 不同廠家初始密碼不同,整理了一些初始密碼,如果有收集到新的也可以補充進去
- 寫全卡 使用默認密碼讀取卡一的全部扇區全部塊資料并寫入到卡二的全部扇區的全部塊里
怎么樣,干不干,全是干貨,沒有廢話
1.讀卡效果圖
這是一張CUID白卡,一會復制可以用作對比
有人會問扇區啥意思 區塊啥意思,這個就百度去吧好多文章在講RC522或者復制卡的文章都會用很大篇幅講什么是卡什么是扇區什么是區塊什么是密碼段,之后文章就結束了也不說怎么讀怎么寫怎么復制,最后來一句未完待續或者下一篇文章再詳細的寫,之后尸沉東京灣留下一段佳話,在這里因為我是旱鴨子就不寫了
SQ代表扇區 0~15扇區
QK代表區塊 0~3區塊

2.寫ID效果圖
這是一張目標卡,我們要將這張卡的0扇區的0塊資料寫到上面那張空白卡中
1.讀取卡1

進行寫操作 放上卡1=> 讀取卡1=> 識別到卡1后列印卡唯一id,并提示可進行復制=> 放上卡2=> 寫入卡2

讀取卡2

已經寫到卡2中了
3.密碼讀卡
每個扇區的3號區塊存盤的就是該扇區的密碼,只有讀取時攜帶相同的密碼才能看到并修改該扇區的資料,如果沒有密碼都不會讀到該扇區
因為廠家為了卡片的資料安全各廠會定義自己的讀卡密碼
個人收集了一部分密碼分享一下
unsigned char KEY[14][6]={
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
{0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5},
{0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5},
{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x4D, 0x3A, 0x99, 0xC3, 0x51, 0xDD},
{0x1A, 0x98, 0x2C, 0x7E, 0x45, 0x9A},
{0x71, 0x4C, 0x5C, 0x88, 0x6E, 0x97},
{0x58, 0x7E, 0xE5, 0xF9, 0x35, 0x0F},
{0xA0, 0x47, 0x8C, 0xC3, 0x90, 0x91},
{0x53, 0x3C, 0xB6, 0xC7, 0x23, 0xf6},
{0x8F, 0xD0, 0xA4, 0xF2, 0x56, 0xE9},
{0x66, 0x55, 0x44, 0x11, 0x22, 0x33},
{0x66, 0x55, 0x44, 0x33, 0x22, 0x11}
};
4.寫全卡效果
效果就是兩張一模一樣的卡
代碼
磨嘰了半天終于到了重點
代碼里出現的 if(EN) if(CN) if(OLED) 代表是否列印對應語言,
EN 代表列印英文
CN 代表列印中文
OLED 代表在螢屏顯示(因為接入一塊OLED螢屏)
尋卡
要點:每次對卡進行操作時呼叫,兩個方法一模一樣,就是第二種去掉了列印
驗證卡片資訊,防沖撞,選卡
//
// 尋卡方法
//
char Pcdmain(){
u8 status;
u8 ID_num[9];
u8 *ID; //卡號
status= PcdRequest(REQ_ALL,TagType);//尋卡
if(!status){
status = PcdAnticoll(SelectedSnr);//防沖撞
if(!status){
status=PcdSelect(SelectedSnr);//選卡
if(!status){
if(EN)printf("Read the success !! \r\n");
if(CN)printf("尋找卡片成功 !! \r\n");
if(OLED)GUI_ShowString(0,16,"1",16,1);
ID = Card_ID(SelectedSnr,ID_num); //獲取卡ID
if(EN)printf("ID:%s !! \r\n",ID_num);
if(CN)printf("卡號:%s !! \r\n",ID_num);
if(OLED)GUI_ShowString(16,16,"ID:",16,1);
if(OLED)GUI_ShowString(40,16,ID,16,1);
return status;
}else{
if(EN)printf("The selected card \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"2",16,1);
return status;
}
}else{
if(EN)printf("Anti-collision \r\n");
if(CN)printf("卡片沖突 \r\n");
if(OLED)GUI_ShowString(0,16,"3",16,1);
return status;
}
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
return status;
}
}
//
// 尋卡方法
//
char Pcdmain_3(){
u8 status;
status= PcdRequest(REQ_ALL,TagType);//尋卡
if(!status){
status = PcdAnticoll(SelectedSnr);//防沖撞
if(!status){
status=PcdSelect(SelectedSnr);//選卡
if(!status){
return status;
}else{
return status;
}
}else{
return status;
}
}else{
return status;
}
}
讀卡
要點:密碼密碼密碼 如果密碼不對那就結束了,初始密碼需要在成員變數中定義
//
// notarize = 1 讀卡
//
unsigned char DefaultKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //默認密碼
void notarize_type1(){
u8 status;
u8 section=0;
u8 block = 0;
unsigned char block_value[16];
u8 i=0;
status = Pcdmain();
if(!status){
if(EN)printf("function NO1 Read the card ...\r\n");
if(CN)printf("功能1 讀取卡片 \r\n");
if(OLED)GUI_ShowString(48,0,"NO_1",16,1);
for( section = 0 ; section <16 ; section++ ){
status = PcdAuthState(KEYA, (section*4+3), DefaultKey, SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊
if(!status)
{
for(block = 0; block< 4 ; block++){
status = PcdRead((section*4+block), block_value); // 讀卡,讀取1扇區0塊資料到buf[0]-buf[16]
if(EN)printf("SQ:%d , QK:%d ",section,block);
if(EN)printf("passA ");
for (i = 0 ; i<6; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf(" Value ");
for (i = 6; i<10; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf(" passB ");
for (i = 10; i<16; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf("\r\n");
}
}else {
if(EN)printf("wrong password \r\n");
if(CN)printf("密碼錯誤 \r\n");
if(OLED)GUI_ShowString(0,16,"5",16,1);
}
}
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("\r\n");
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
}
}
復制ID
ID的重要性就不用我多說了,因為通常的ID卡扇區0是出廠就定義好的ID不能再修改,所以也是唯一性的保障,大多數的系統也只會記錄ID作為驗證使用
而除了0扇區之外的扇區多為詳細資訊存盤使用,如取電卡的電量值,水卡的水量值,飯卡的余額之類,因為這部分可以讀寫所以密碼會與出廠密碼不同
//
// notarize = 2 復制卡id
//
void notarize_type2(){
u8 status;
u8 test_status = 0; //id在0扇區 , 測驗使用其他扇區
u8 block_num=0;
u8 copy_tf = 1;
unsigned char copy_value[16];
status = Pcdmain_3();
if(!status){
if(EN)printf("function NO1 Read the card ...\r\n");
if(CN)printf("功能2 復制卡片 \r\n");
if(OLED)GUI_ShowString(48,0,"NO_2",16,1);
//讀取并復制卡1 指定扇區指定塊資料
status = PcdAuthState(KEYA, (test_status*4+3), DefaultKey, SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊 DefaultKey為默認密碼
if(!status)
{
status = PcdRead((test_status*4+0), copy_value); // 讀卡,讀取1扇區0塊資料到buf[0]-buf[16]
if(!status)
{
if(EN)printf("COPY: SQ:%d , QK:%d ",test_status,0);
if(EN)printf("passA ");
for (block_num = 0; block_num<6; block_num++)
{
if(EN)printf("%X ",copy_value[block_num]);
}
if(EN)printf(" Value ");
for (block_num = 6; block_num<10; block_num++)
{
if(EN)printf("%X ",copy_value[block_num]);
}
if(EN)printf(" passB ");
for (block_num = 10; block_num<16; block_num++)
{
if(EN)printf("%X ",copy_value[block_num]);
}
if(EN)printf("\r\n");
}
if(EN)printf("Read over \r\n");
if(CN)printf("復制成功 替換目標卡片 \r\n");
delay_ms(500);
if(OLED)GUI_ShowString(0,16,"COPY OK, CARD_2",16,1);
//讀取第二張卡片
do{
LED6S; //PC13輸出低電平
//delay_ms(200);
//LED6S; //PC13輸出高電平
if(KEY1==0){
status = Pcdmain_3();
if(!status){
if(EN)printf("Ready to write card 2 ...\r\n");
if(CN)printf("寫卡2\r\n");
if(OLED)GUI_ShowString(0,0,"CARD2...",16,1);
status = PcdAuthState(KEYA, (test_status*4+3), DefaultKey, SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊
if(!status){
status = PcdWrite((test_status*4+0), copy_value); // 寫卡,將buf[0]-buf[16]寫入1扇區0塊
if(!status){
LED6R; //PC13輸出高電平
delay_ms(20);
LED6S; //PC13輸出低電平
delay_ms(20);
LED6R; //PC13輸出高電平
delay_ms(20);
LED6S; //PC13輸出低電平
delay_ms(20);
LED6R; //PC13輸出高電平
if(EN)printf("Copy success (*^▽^*) \r\n");
if(CN)printf("寫入成功 (*^▽^*) \r\n");
if(OLED)GUI_ShowString(0,16,"Copy SUCC (*^▽^*)",16,1);
}else{
if(EN)printf("Copy the failure (╯‵□′)╯︵┻━┻ \r\n");
if(CN)printf("復制失敗 (╯‵□′)╯︵┻━┻ \r\n");
if(OLED)GUI_ShowString(0,16,"Copy the failure",16,1);
}
}else{
if(EN)printf("card 2 wrong password \r\n");
if(CN)printf("卡2密碼錯誤 \r\n");
if(OLED)GUI_ShowString(0,16,"card 2 PASS WRONG",16,1);
}
LED6R; //PC13輸出高電平
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片2未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
LED6R; //PC13輸出高電平
}
LED6R; //PC13輸出高電平
copy_tf = 0;
}
}while(copy_tf);
}else{
if(EN)printf("wrong password \r\n");
if(CN)printf("密碼錯誤 \r\n");
if(OLED)GUI_ShowString(0,16,"5",16,1);
}
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
}
}
密碼測驗
測驗每個扇區的第3區塊密碼,當然幸運的話就是初始密碼,點背的話也沒關系只需要255*255*255*255*255*255 = 274,941,996,890,625次嘗試也可以得到密碼
//
// notarize = 3 常規密碼測驗
//
void notarize_type3(){
u8 status;
u8 section=0;
u8 block_num=0;
u8 KEY_num = 0 ;
unsigned char block_value[16];
u8 i=0;
status = Pcdmain_3();
if(!status){
if(EN)printf("function NO3 Password test ...\r\n");
if(CN)printf("功能3 常規密碼測驗 \r\n");
if(OLED)GUI_ShowString(48,0,"NO_3",16,1);
for( section = 0 ; section <16 ; section++ ){
for( KEY_num =0 ; KEY_num < 13 ; KEY_num++){
status = Pcdmain_3();
if(!status){
//printf("section:%d KEY:%d %d %d %d %d %d ",section,KEY[KEY_num][0],KEY[KEY_num][1],KEY[KEY_num][2],KEY[KEY_num][3],KEY[KEY_num][4],KEY[KEY_num][5]);
status = PcdAuthState(KEYA, (section*4+3), KEY[KEY_num], SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊
if(!status)
{
status = 1;
//for(block_num = 0; block_num< 4 ; block_num++){
status = PcdRead((section*4+3), block_value); // 讀卡,讀取1扇區0塊資料到buf[0]-buf[16]
if(EN)printf("SQ:%d , QK:%d KEY:%X %X %X %X %X %X ",section,3,KEY[KEY_num][0],KEY[KEY_num][1],KEY[KEY_num][2],KEY[KEY_num][3],KEY[KEY_num][4],KEY[KEY_num][5]);
if(EN)printf("passA ");
for (i = 0 ; i<6; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf(" Value ");
for (i = 6; i<10; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf(" passB ");
for (i = 10; i<16; i++)
{
if(EN)printf("%X ",block_value[i]);
}
if(EN)printf("\r\n");
//}
}else {
}
}
status = 1;
}
}
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("\r\n");
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
}
}
復制全卡
由于全卡每個扇區的密碼不同所以復制全卡用處不大
//
// notarize = 4 復制全卡
//
void notarize_type4(){
u8 status;
u8 section=0;
u8 block = 0;
u8 block_num=0;
u8 copy_tf = 1;
unsigned char block_value[16];
unsigned char copy_value[16][3][16];
status = Pcdmain_3();
if(!status){
if(EN)printf("function NO1 Read the card ...\r\n");
if(CN)printf("功能1 讀取卡片 \r\n");
if(OLED)GUI_ShowString(48,0,"NO_4",16,1);
for( section = 0; section <16 ; section++ ){
status = PcdAuthState(KEYA, (section*4+3), DefaultKey, SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊
if(!status)
{
for(block = 0; block< 3 ; block++){
status = PcdRead((section*4+block), block_value); // 讀卡,讀取1扇區0塊資料到buf[0]-buf[16]
for( block_num = 0; block_num < 16 ; block_num++){
copy_value[section][block][block_num] = block_value[block_num];
}
}
}
}
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("\r\n");
for(section = 0 ; section < 16 ; section++){
for(block = 0 ; block < 3 ; block++){
//for(block_num = 0 ; block_num < 16 ; block_num++){
if(EN)printf("SQ:%d , QK:%d ",section,block);
if(EN)printf("passA ");
for (block_num = 0; block_num<6; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf(" Value ");
for (block_num = 6; block_num<10; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf(" passB ");
for (block_num = 10; block_num<16; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf("\r\n");
//}
}
if(EN)printf("\r\n");
}
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("\r\n");
if(EN)printf("Read over \r\n");
if(CN)printf("復制成功 替換目標卡片 \r\n");
if(OLED)GUI_ShowString(0,16,"COPY OK, CARD_2",16,1);
//讀取第二張卡片
do{
if(KEY1==0){
status = Pcdmain_3();
if(!status){
if(EN)printf("Ready to write card 2 ...\r\n");
if(CN)printf("寫卡2\r\n");
if(OLED)GUI_ShowString(0,0,"CARD2...",16,1);
for(section = 0 ; section < 16 ; section++){
//status = Pcdmain_3();
//if(!status){
status = PcdAuthState(KEYA, (section*4+3), DefaultKey, SelectedSnr);// 校驗1扇區密碼,密碼位于每一扇區第3塊
if(!status){
for(block = 0 ; block < 3 ; block++){
//status = PcdWrite((section*4+block), copy_value[section][block]); // 寫卡,將buf[0]-buf[16]寫入1扇區0塊
//status = PcdWrite((section*4+block), zero); // 寫卡,將buf[0]-buf[16]寫入1扇區0塊
status = PcdWrite((4*4+3), setkey); // 寫卡,將buf[0]-buf[16]寫入1扇區0塊
if(EN)printf("SQ:%d , QK:%d ",section,block);
if(EN)printf("passA ");
for (block_num = 0; block_num<6; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf(" Value ");
for (block_num = 6; block_num<10; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf(" passB ");
for (block_num = 10; block_num<16; block_num++)
{
if(EN)printf("%X ",copy_value[section][block][block_num]);
}
if(EN)printf("\r\n");
if(!status){
if(EN)printf("SQ:%d , QK:%d Copy success (*^▽^*) \r\n",section,block);
if(CN)printf("SQ:%d , QK:%d 寫入成功 (*^▽^*) \r\n",section,block);
if(OLED)GUI_ShowString(0,16,"Copy SUCC ",16,1);
}else{
if(EN)printf("SQ:%d , QK:%d Copy the failure (* ̄︿ ̄) \r\n",section,block);
if(CN)printf("SQ:%d , QK:%d 復制失敗 (* ̄︿ ̄) \r\n",section,block);
if(OLED)GUI_ShowString(0,16,"Copy the failure",16,1);
}
if(CN)printf("SQ:%d , QK:%d (*^▽^*) \r\n",section,block);
}
}else{
if(EN)printf("card 2 wrong password \r\n");
if(CN)printf("卡2密碼錯誤 \r\n");
if(OLED)GUI_ShowString(0,16,"5",16,1);
}
}
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片2未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
}
copy_tf = 0;
}
}while(copy_tf);
}else{
if(EN)printf("Looking for failure \r\n");
if(CN)printf("卡片未找到 \r\n");
if(OLED)GUI_ShowString(0,16,"4",16,1);
}
}
總結
最后顯擺一下我的手工

這篇文章寫一半的時候就停了下來,在草稿中存了小半年,最后在年末穿上秋褲的時候想了想還是補全發出來吧
讓我寫文章的動力是因為C語言可以對這類單片機進行編程,進而讀取環境資料,簡單的溫濕度模塊,人體紅外感應模塊,觸摸模塊,光敏模塊等等
而這與網路爬蟲的作用很相似,一個是獲取網路資訊的自動程式,一個是獲取現實世界資訊的自動程式,這也是我為什么寫爬蟲寫著寫著就學起C的原因
當然爬蟲這方面也在找一些有趣有挑戰的網站,如果有人能分享有挑戰的專案我也會嘗試的
三.原始碼

閑聊到這里,想要原始碼的兩種途徑
1.積分下載 鏈接我會放上來
2.私信我 陪我聊聊天好么 秋梨膏
那么終于能完結這篇文章了,主要是我太懶,沒有什么動力能刺激到我創作
預告一下,下次我要做......等一下有人敲門 我去看看......
完
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/242451.html
標籤:其他
上一篇:程式員經常看的開源月刊《HelloGitHub》第 57 期
下一篇:【51單片機】心形流水燈
