nandflash驅動程式編寫

来源:http://www.cnblogs.com/veryStrong/archive/2016/12/10/6155502.html
-Advertisement-
Play Games

NAND FLASH是一個存儲晶元 那麼: 這樣的操作很合理"讀地址A的數據,把數據B寫到地址A" 問1. 原理圖上NAND FLASH和S3C2440之間只有數據線, 怎麼傳輸地址? 答1.在DATA0~DATA7上既傳輸數據,又傳輸地址 當ALE為高電平時傳輸的是地址, ... ...


NAND FLASH是一個存儲晶元
那麼: 這樣的操作很合理"讀地址A的數據,把數據B寫到地址A"

問1. 原理圖上NAND FLASH和S3C2440之間只有數據線,
     怎麼傳輸地址?
答1.在DATA0~DATA7上既傳輸數據,又傳輸地址
     當ALE為高電平時傳輸的是地址,

問2. 從NAND FLASH晶元手冊可知,要操作NAND FLASH需要先發出命令
     怎麼傳入命令?

答2.在DATA0~DATA7上既傳輸數據,又傳輸地址,也傳輸命令
     當ALE為高電平時傳輸的是地址,
     當CLE為高電平時傳輸的是命令
     當ALE和CLE都為低電平時傳輸的是數據

問3. 數據線既接到NAND FLASH,也接到NOR FLASH,還接到SDRAM、DM9000等等
     那麼怎麼避免干擾?
答3. 這些設備,要訪問之必須"選中",
     沒有選中的晶元不會工作,相當於沒接一樣

問4. 假設燒寫NAND FLASH,把命令、地址、數據發給它之後,
     NAND FLASH肯定不可能瞬間完成燒寫的,
     怎麼判斷燒寫完成?
答4. 通過狀態引腳RnB來判斷:它為高電平表示就緒,它為低電平表示正忙

問5. 怎麼操作NAND FLASH呢?
答5. 根據NAND FLASH的晶元手冊,一般的過程是:
     發出命令
     發出地址
     發出數據/讀數據

          NAND FLASH                      S3C2440
發命令    選中晶元                   
          CLE設為高電平                   NFCMMD=命令值     
          在DATA0~DATA7上輸出命令值
          發出一個寫脈衝
            
發地址    選中晶元                        NFADDR=地址值
          ALE設為高電平
          在DATA0~DATA7上輸出地址值
          發出一個寫脈衝

發數據    選中晶元                        NFDATA=數據值
          ALE,CLE設為低電平
          在DATA0~DATA7上輸出數據值
          發出一個寫脈衝

讀數據    選中晶元                        val=NFDATA
          發出讀脈衝
          讀DATA0~DATA7的數據

用UBOOT來體驗NAND FLASH的操作:

1. 讀ID
                               S3C2440                 u-boot 
選中                           NFCONT的bit1設為0   md.l 0x4E000004 1; mw.l 0x4E000004  1
發出命令0x90                   NFCMMD=0x90         mw.b 0x4E000008 0x90 
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
讀數據得到0xEC                 val=NFDATA          md.b 0x4E000010 1
讀數據得到device code          val=NFDATA          md.b 0x4E000010 1
          0xda
退出讀ID的狀態                 NFCMMD=0xff         mw.b 0x4E000008 0xff
     
2. 讀內容: 讀0地址的數據
使用UBOOT命令:
nand dump 0
Page 00000000 dump:
        17 00 00 ea 14 f0 9f e5  14 f0 9f e5 14 f0 9f e5

                               S3C2440                 u-boot 
選中                           NFCONT的bit1設為0   md.l 0x4E000004 1; mw.l 0x4E000004  1
發出命令0x00                   NFCMMD=0x00         mw.b 0x4E000008 0x00 
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
發出地址0x00                   NFADDR=0x00         mw.b 0x4E00000C 0x00
發出命令0x30                   NFCMMD=0x30         mw.b 0x4E000008 0x30 
讀數據得到0x17                 val=NFDATA          md.b 0x4E000010 1
讀數據得到0x00                 val=NFDATA          md.b 0x4E000010 1
讀數據得到0x00                 val=NFDATA          md.b 0x4E000010 1
讀數據得到0xea                 val=NFDATA          md.b 0x4E000010 1
退出讀狀態                     NFCMMD=0xff         mw.b 0x4E000008 0xff


NAND FLASH驅動程式層次

看內核啟動信息
S3C24XX NAND Driver, (c) 2004 Simtec Electronics
s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Scanning device for bad blocks
Bad eraseblock 256 at 0x02000000
Bad eraseblock 257 at 0x02020000
Bad eraseblock 319 at 0x027e0000
Bad eraseblock 606 at 0x04bc0000
Bad eraseblock 608 at 0x04c00000
Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x00000000-0x00040000 : "bootloader"
0x00040000-0x00060000 : "params"
0x00060000-0x00260000 : "kernel"
0x00260000-0x10000000 : "root"

搜"S3C24XX NAND Driver"
S3c2410.c (drivers\mtd\nand)

s3c2410_nand_inithw
s3c2410_nand_init_chip
nand_scan  // drivers/mtd/nand/nand_base.c 根據nand_chip的底層操作函數識別NAND FLASH,構造mtd_info
    nand_scan_ident
        nand_set_defaults
			if (!chip->select_chip)
				chip->select_chip = nand_select_chip; // 預設值不適用

			if (chip->cmdfunc == NULL)
				chip->cmdfunc = nand_command;
									chip->cmd_ctrl(mtd, command, ctrl);
			if (!chip->read_byte)
				chip->read_byte = nand_read_byte;
									readb(chip->IO_ADDR_R);
			if (chip->waitfunc == NULL)
				chip->waitfunc = nand_wait;
									chip->dev_ready
        
        
        nand_get_flash_type
            chip->select_chip(mtd, 0);
            chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
            *maf_id = chip->read_byte(mtd);
            dev_id = chip->read_byte(mtd);
    nand_scan_tail
    		mtd->erase = nand_erase;
    		mtd->read = nand_read;
    		mtd->write = nand_write;
			
			
			
s3c2410_nand_add_partition
    add_mtd_partitions
        add_mtd_device
            list_for_each(this, &mtd_notifiers) { // 問. mtd_notifiers在哪設置
                                                  // 答. drivers/mtd/mtdchar.c,mtd_blkdev.c調用register_mtd_user
                struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
                not->add(mtd);
                // mtd_notify_add  和 blktrans_notify_add
                先看字元設備的mtd_notify_add
                        class_device_create
                        class_device_create
                再看塊設備的blktrans_notify_add
                    list_for_each(this, &blktrans_majors) { // 問. blktrans_majors在哪設置
                                                            // 答. drivers\mtd\mdblock.c或mtdblock_ro.c   register_mtd_blktrans
                        struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);              
                        tr->add_mtd(tr, mtd);
                                mtdblock_add_mtd (drivers\mtd\mdblock.c)
                                    add_mtd_blktrans_dev
                                        alloc_disk
                                        gd->queue = tr->blkcore_priv->rq; // tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
                                        add_disk            



測試4th:
1. make menuconfig去掉內核自帶的NAND FLASH驅動
-> Device Drivers
  -> Memory Technology Device (MTD) support
    -> NAND Device Support
   < >   NAND Flash support for S3C2410/S3C2440 SoC
2. make uImage
   使用新內核啟動, 並且使用NFS作為根文件系統
3. insmod s3c_nand.ko
4. 格式化 (參考下麵編譯工具)
   flash_eraseall  /dev/mtd3  // yaffs
   
5. 掛接
   mount -t yaffs /dev/mtdblock3 /mnt
6. 在/mnt目錄下建文件   



編譯工具:
1. tar xjf mtd-utils-05.07.23.tar.bz2 
2. cd mtd-utils-05.07.23/util
修改Makefile:
#CROSS=arm-linux-
改為
CROSS=arm-linux-
3. make
4. cp flash_erase flash_eraseall /work/nfs_root/first_fs/bin/


 


  

 

struct nand_chip {
/*8 位NAND 晶元的讀寫地址*/
void __iomem    *IO_ADDR_R;
void __iomem    *IO_ADDR_W;

uint8_t    (*read_byte)(struct mtd_info *mtd);
u16    (*read_word)(struct mtd_info *mtd);

void    (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
void    (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
/*讀取數據並驗證*/
int    (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
/*選定晶元*/
void    (*select_chip)(struct mtd_info *mtd, int chip);
/*檢查壞塊*/
int    (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
/*mark(標記)bad block*/
int    (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
/*發送命令/地址*/
void    (*cmd_ctrl)(struct mtd_info *mtd, int dat,unsigned int ctrl);
/*讀取晶元狀態*/
int    (*dev_ready)(struct mtd_info *mtd);
/*發送命令*/
void    (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
/*等待就緒*/
int    (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
/*擦除命令函數*/
void    (*erase_cmd)(struct mtd_info *mtd, int page);
/*掃描壞塊表*/
int    (*scan_bbt)(struct mtd_info *mtd);
int    (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
/*高級頁面寫功能*/
int    (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,const uint8_t *buf, int page, int cached, int raw);

int    chip_delay;
struct nand_ecc_ctrl ecc;
struct nand_buffers *buffers;
...................
};


struct nand_ecc_ctrl {
nand_ecc_modes_t    mode;
int    steps;
int    size;
int    bytes;
int    total;
int    prepad;
int    postpad;
struct nand_ecclayout    *layout;

/*hwctl函數:
*這個函數用來控制硬體產生ecc 
*其實它主要的工作就是控制NAND controller 向 NAND 晶元發出NAND_ECC_READ 、NAND_ECC_WRITE 和NAND_ECC_READSYN *等命令,與struct nand_chip 結構體中的cmdfunc 類似
*/
void    (*hwctl)(struct mtd_info *mtd, int mode);

/*根據data 計算ecc 值*/
int    (*calculate)(struct mtd_info *mtd,const uint8_t *dat,uint8_t *ecc_code);
/*根據ecc 值,判斷讀寫數據時是否有錯誤發生,若有錯,則立即試著糾正,糾正失敗則返回錯誤*/
int    (*correct)(struct mtd_info *mtd, uint8_t *dat,uint8_t *read_ecc,uint8_t *calc_ecc);


/*read_page_raw write_page_raw函數
*從NAND 晶元中讀取一個page 的原始數據和向NAND 晶元寫入一個page 的原始數據,所謂的原始數據,即不對讀寫的數據做ecc處理 *該讀寫什麼值就讀寫什麼值。另外,這兩個函數會讀寫整個page 中的所有內容,即不但會讀寫一個page 中MAIN部分,還會讀寫OOB 部分。
*/
int    (*read_page_raw)(struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf);
void    (*write_page_raw)(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf);

/*
*read_page 和write_page 在讀寫過程中會加入ecc 的計算,校驗,和糾正等處理。
*/
int    (*read_page)(struct mtd_info *mtd,struct nand_chip *chip,uint8_t *buf);
void    (*write_page)(struct mtd_info *mtd,struct nand_chip *chip,const uint8_t *buf);

/*
*讀寫oob 中的內容,不包括MAIN 部分。
*/
int    (*read_oob)(struct mtd_info *mtd,struct nand_chip *chip,int page,int sndcmd);
int    (*write_oob)(struct mtd_info *mtd,struct nand_chip *chip,int page);
};
其實,以上提到的這幾個read_xxx 和write_xxx 函數,最終都會調用struct nand_chip 中的read_buf 和write_buf 這兩個函數,所以如果沒有特殊需求的話,我認為不必自己實現,使用MTD 提供的default 的函數即可。

 

 

 

  1 #include <linux/module.h>
  2 #include <linux/types.h>
  3 #include <linux/init.h>
  4 #include <linux/kernel.h>
  5 #include <linux/string.h>
  6 #include <linux/ioport.h>
  7 #include <linux/platform_device.h>
  8 #include <linux/delay.h>
  9 #include <linux/err.h>
 10 #include <linux/slab.h>
 11 #include <linux/clk.h>
 12 
 13 #include <linux/mtd/mtd.h>
 14 #include <linux/mtd/nand.h>
 15 #include <linux/mtd/nand_ecc.h>
 16 #include <linux/mtd/partitions.h>
 17 
 18 #include <asm/io.h>
 19 
 20 #include <asm/arch/regs-nand.h>
 21 #include <asm/arch/nand.h>
 22 
 23 struct s3c_nand_regs {
 24     unsigned long nfconf  ;
 25     unsigned long nfcont  ;
 26     unsigned long nfcmd   ;
 27     unsigned long nfaddr  ;
 28     unsigned long nfdata  ;
 29     unsigned long nfeccd0 ;
 30     unsigned long nfeccd1 ;
 31     unsigned long nfeccd  ;
 32     unsigned long nfstat  ;
 33     unsigned long nfestat0;
 34     unsigned long nfestat1;
 35     unsigned long nfmecc0 ;
 36     unsigned long nfmecc1 ;
 37     unsigned long nfsecc  ;
 38     unsigned long nfsblk  ;
 39     unsigned long nfeblk  ;
 40 };
 41 
 42 static struct nand_chip *s3c_nand_chip;
 43 static struct mtd_info *s3c_mtd;
 44 static struct s3c_nand_regs *s3c_nand_regs;
 45 
 46 static struct mtd_partition s3c_nand_parts[] = {
 47     [0] = {
 48         .name   = "bootloader",
 49         .size   = 0x00040000,
 50         .offset    = 0,
 51     },
 52     [1] = {
 53         .name   = "params",
 54         .offset = MTDPART_OFS_APPEND,
 55         .size   = 0x00020000,
 56     },
 57     [2] = {
 58         .name   = "kernel",
 59         .offset = MTDPART_OFS_APPEND,
 60         .size   = 0x00200000,
 61     },
 62     [3] = {
 63         .name   = "root",
 64         .offset = MTDPART_OFS_APPEND,
 65         .size   = MTDPART_SIZ_FULL,
 66     }
 67 };
 68 
 69 
 70 /*判斷忙*/
 71 static int s3c_dev_ready(struct mtd_info *mtd)
 72 {
 73     /*返回"NFSTAT的bit[0]";*/
 74     return (s3c_nand_regs->nfstat & (1<<0));
 75 }
 76 
 77 static void s3c_cmd_ctrl(struct mtd_info *mtd, int dat,unsigned int ctrl)
 78 {
 79 
 80     if (ctrl & NAND_CLE)
 81     {
 82         /* 發命令: NFCMMD=dat */
 83         s3c_nand_regs->nfcmd = dat;
 84         //writeb(cmd, host->io_base + (1 << host->board->cle));/*命令*/
 85     }
 86     else
 87     {
 88         /* 發地址: NFADDR=dat */
 89         s3c_nand_regs->nfaddr = dat;
 90         //writeb(cmd, host->io_base + (1 << host->board->ale));/*地址*/
 91     }
 92 }
 93 
 94 
 95 static void s3c_select_chip(struct mtd_info *mtd, int chip)
 96 {
 97     if(chip ==-1)
 98     {
 99         /*表示取消選中 NFCONT[1]設為1  */
100         s3c_nand_regs->nfcont |=(1<<1);    
101     }
102     else
103     {
104         s3c_nand_regs->nfcont &=~(1<<1);
105         /*選中晶元 NFCONT[1]設為0 */
106     }    
107 }
108 
109 
110 static int s3c_nand_init(void)
111 {
112 
113     struct clk *clk;
114     
115     /*1.分配一個nand_chip結構體*/
116     s3c_nand_chip =  kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
117     
118     s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
119     
120     /*2.設置nandc_chip結構體*/
121     s3c_nand_chip->IO_ADDR_R = &s3c_nand_regs->nfdata;
122     s3c_nand_chip->IO_ADDR_W = &s3c_nand_regs->nfdata;
123     s3c_nand_chip->cmd_ctrl = s3c_cmd_ctrl;
124     s3c_nand_chip->dev_ready = s3c_dev_ready;
125     s3c_nand_chip->select_chip = s3c_select_chip;
126     s3c_nand_chip->ecc.mode    = NAND_ECC_SOFT;
127     //s3c_nand_chip->chip_delay = 20;
128 
129     /* 使能NAND FLASH控制器的時鐘 */
130     clk = clk_get(NULL, "nand");
131     clk_enable(clk);              /* CLKCON'bit[4] */
132     
133 
134     /*初始化nand控制器 設置寄存器*/
135 #define TACLS   0
136 #define TWRPH0  3
137 #define TWRPH1  0
138     /* HCLK=100MHz
139      * TACLS:  發出CLE/ALE之後多長時間才發出nWE信號, 從NAND手冊可知CLE/ALE與nWE可以同時發出,所以TACLS=0
140      * TWRPH0: nWE的脈衝寬度, HCLK x ( TWRPH0 + 1 ), 從NAND手冊可知它要>=12ns, 所以TWRPH0>=1
141      * TWRPH1: nWE變為高電平後多長時間CLE/ALE才能變為低電平, 從NAND手冊可知它要>=5ns, 所以TWRPH1>=0
142      */
143     s3c_nand_regs->nfconf=(TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
144 
145     /* NFCONT: 
146      * BIT1-設為1, 取消片選 
147      * BIT0-設為1, 使能NAND FLASH控制器
148      * BIT4-設為0, 未初始化hardware ECC
149      */
150     s3c_nand_regs->nfcont = (1<<1) | (1<<0);
151     
152     /*分配一個mtd_info結構體*/
153     s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
154 
155     /*設置s3c_mtd結構體*/
156     s3c_mtd->owner = THIS_MODULE;
157     s3c_mtd->priv = s3c_nand_chip;
158 
159     /* 識別NAND FLASH, 構造mtd_info */
160     nand_scan(s3c_mtd, 1); 
161 
162     /*設置分區表*/
163     add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);
164     
165     add_mtd_device(s3c_mtd);
166     return 0;
167 }
168 
169 static void s3c_nand_exit(void)
170 {
171     kfree(s3c_mtd);
172     kfree(s3c_nand_chip);
173     iounmap(s3c_nand_regs);
174 }
175 
176 module_init(s3c_nand_init);
177 module_exit(s3c_nand_exit);
178 MODULE_LICENSE("GPL");

 


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

-Advertisement-
Play Games
更多相關文章
  • 一.jdk的安裝與配置 3.創建軟鏈接方便原目錄/usr/local/src/jdk1.8.0_60 配置到/etc/profile,先創建兩個軟鏈接 : (1)原目錄/usr/local/src/jdk1.8.0_60 ln -s /usr/local/src/jdk1.8.0_60 java ( ...
  • 今天想用一下顯示器自帶的喇叭,忽然發現聲音輸出選項里HDMI的聲音設備沒了。之前開始使用這台顯示器的時是用過一段時間的。 百度了一番,沒發現什麼線索。後來去谷歌找到這麼一段文字: I'm not sure where to report this, but after I upgraded a Le ...
  • 問題描述:當安裝好Ubuntu系統的時候,root用戶沒有密碼,需要設置。 解決方法: ...
  • 本文由ilanniweb提供友情贊助,首發於爛泥行天下 想要獲得更多的文章,可以關註我的微信ilanniweb 最近沒有時間好久沒有寫文章了,今天由於需要安裝docker學習虛擬容器的知識,需要升級OS的內核。目前我這邊使用的OS是centos6.5,內核是2.6版本的,如下: cat /etc/i... ...
  • 字元設備是3大類設備(字元設備、塊設備和網路設備)中較簡單的一類設備,其驅動程式中完成的主要工作是初始化、添加和刪除cdev結構體,申請和釋放設備號,以及填充 file_operations結構體中的操作函數,實現file_operations結構體中的read()、write()和ioctl()等... ...
  • 問題描述:在Windows10下安裝Ubuntu。 使用工具:Windows10、Ubuntu16.04 LTS安裝包、UltraISO、easyBCD。 操作步驟: 1、安裝之前要給Ubuntu分出一定大小的磁碟空間。我用170G來安裝Ubuntu。我的硬碟比較大,如果硬碟較小,可以選擇50G等大 ...
  • 問題概述:在裝系統的時候有時候並不能一下分出完全符合我們使用習慣的分區大小,我們可能需要在後期調整分區大小。以下是有關分區大小調整的操作。 使用工具:Windows磁碟管理工具。 操作步驟: 1、使用組合鍵win+x,彈出菜單,選中“電腦管理”,選擇“磁碟管理”。 2、這裡簡要說明一下Window ...
  • 問題概述:因為在自己學習Linux的時候,按照網上的教程錯誤的刪除了Ubuntu的一個內核驅動,導致Ubuntu不能啟動。我想到的辦法是重新安裝系統,重裝系統的第一步便是將Ubuntu從電腦中卸載。該筆記是有關如何刪除Ubuntu啟動項的。 使用工具:Windows10,Ubuntu16.04 LT ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...