16.Linux-LCD驅動(詳解)

来源:http://www.cnblogs.com/lifexy/archive/2017/09/27/7604011.html
-Advertisement-
Play Games

在上一節LCD層次分析中,得出寫個LCD驅動入口函數,需要以下4步: 1) 分配一個fb_info結構體: framebuffer_alloc(); 2) 設置fb_info 3) 設置硬體相關的操作 4) 使能LCD,並註冊fb_info: register_framebuffer() 本節需要用 ...


在上一節LCD層次分析中,得出寫個LCD驅動入口函數,需要以下4步:

1) 分配一個fb_info結構體: framebuffer_alloc();

2) 設置fb_info

3) 設置硬體相關的操作

4) 使能LCD,並註冊fb_info: register_framebuffer()

 

本節需要用到的函數:

void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);  //分配DMA緩存區給顯存
//參數如下:

//*dev:指針,這裡填0,表示這個申請的緩衝區里沒有內容

//size:分配的地址大小(位元組單位)

//*handle:申請到的物理起始地址

//gfp:分配出來的記憶體參數,標誌定義在<linux/gfp.h>,常用標誌如下:
    //GFP_ATOMIC    用來從中斷處理和進程上下文之外的其他代碼中分配記憶體. 從不睡眠.
    //GFP_KERNEL    內核記憶體的正常分配. 可能睡眠.
    //GFP_USER      用來為用戶空間頁來分配記憶體; 它可能睡眠.    

分配一段DMA緩存區,分配出來的記憶體不使用cache緩存(因為DMA傳輸不需要CPU)

它和 dma_alloc_coherent ()函數相似,不過 dma_alloc_coherent ()函數是分配出來的記憶體會禁止cache緩存以及禁止寫入緩衝區


 

dma_free_writecombine(dev,size,cpu_addr,handle);   //釋放緩存
//cpu_addr:虛擬地址, 
//handle:物理地址

釋放DMA緩衝區, dev和size參數和上面的一樣


 

struct fb_info *framebuffer_alloc(size_t size, struct device *dev);      //申請一個fb_info結構體,
//size:額外的記憶體,
//*dev:指針, 這裡填0,表示這個申請的結構體里沒有內容

int register_framebuffer(struct fb_info *fb_info);  

                      //向內核中註冊fb_info結構體,若記憶體不夠,註冊失敗會返回負數

int unregister_framebuffer(struct fb_info *fb_info) ;

                      //註銷內核中fb_info結構體

 


 

本節需要用到的結構體:

fb_info結構體如下:

struct fb_info {
        ... ...
       struct fb_var_screeninfo var;       //可變的參數
       struct fb_fix_screeninfo fix;        //固定的參數
       ... ...
       struct fb_ops *fbops;              //操作函數
       ... ...
       char __iomem *screen_base;        //顯存虛擬起始地址
       unsigned long screen_size;          //顯存虛擬地址長度
  
void *pseudo_palette; //假的16色調色板,裡面存放了16色的數據,可以通過8bpp數據來找到調色板裡面的16色顏色索引值,模擬出16色顏色來,節省記憶體,不需要的話就指向一個不用的數組即可 ... ... };

其中操作函數fb_info-> fbops 結構體寫法如下:

static struct fb_ops s3c_lcdfb_ops = {
         .owner                = THIS_MODULE,
.fb_setcolreg
= my_lcdfb_setcolreg,//設置調色板fb_info-> pseudo_palette,自己構造該函數 .fb_fillrect = cfb_fillrect, //填充矩形,用/drivers/video/ cfbfillrect.c里的函數即可 .fb_copyarea = cfb_copyarea, //複製數據, 用/drivers/video/cfbcopyarea.c里的函數即可 .fb_imageblit = cfb_imageblit, //繪畫圖形, 用/drivers/video/imageblit.c里的函數即可 };

固定的參數fb_info-> fix 結構體如下:

struct fb_fix_screeninfo {
       char id[16];                   //id名字
       unsigned long smem_start;  //framebuffer物理起始地址                          
       __u32 smem_len;           //framebuffer長度,位元組為單位
       __u32 type;                 //lcd類型,預設值0即可
       __u32 type_aux;               //附加類型,為0
       __u32 visual;                     //畫面設置,常用參數如下
// FB_VISUAL_MONO01             0   單色,0:白色,1:黑色
// FB_VISUAL_MONO10             1    單色,1:白色,0:黑色
// FB_VISUAL_TRUECOLOR          2     真彩(TFT:真彩)
// FB_VISUAL_PSEUDOCOLOR     3     偽彩
// FB_VISUAL_DIRECTCOLOR        4     直彩

    __u16 xpanstep;                /*如果沒有硬體panning就賦值為0 */
    __u16 ypanstep;                /*如果沒有硬體panning就賦值為0 */
    __u16 ywrapstep;                 /*如果沒有硬體ywrap就賦值為0 */

    __u32 line_length;                 /*一行的位元組數 ,例:(RGB565)240*320,那麼這裡就等於240*16/8 */

    /*以下成員都可以不需要*/     unsigned
long mmio_start; /*記憶體映射IO的起始地址,用於應用層直接訪問寄存器,可以不需要*/ __u32 mmio_len; /* 記憶體映射IO的長度,可以不需要*/ __u32 accel; __u16 reserved[3]; };

可變的參數fb_info-> var 結構體如下:

structfb_var_screeninfo{                                    
   __u32xres;                    /*可見屏幕一行有多少個像素點*/
    __u32 yres;                      /*可見屏幕一列有多少個像素點*/
    __u32 xres_virtual;         /*虛擬屏幕一行有多少個像素點 */       
    __u32  yres_virtual;       /*虛擬屏幕一列有多少個像素點*/
    __u32 xoffset;                 /*虛擬到可見屏幕之間的行偏移,若可見和虛擬的解析度一樣,就直接設為0*/
    __u32 yoffset;                 /*虛擬到可見屏幕之間的列偏移*/
    __u32  bits_per_pixel;    /*每個像素的位數即BPP,比如:RGB565則填入16*/
    __u32 grayscale;           /*非0時,指的是灰度,真彩直接填0即可*/

    struct fb_bitfield red;          //fb緩存的R位域, fb_bitfield結構體成員如下:
//__u32 offset;          區域偏移值,比如RGB565中的R,就在第11位
//__u32 length;                   區域長度,比如RGB565的R,共有5位
//__u32 msb_right;  msb_right ==0,表示數據左邊最大, msb_right!=0,表示數據右邊最大

struct fb_bitfield green; /*fb緩存的G位域*/ struct fb_bitfield blue; /*fb緩存的B位域*/

   /*以下參數都可以不填,預設為0*/ struct fb_bitfield transp; /*透明度,不需要填0即可*/
__u32nonstd;
/* != 0表示非標準像素格式*/ __u32 activate; /*設為0即可*/ __u32height; /*外設高度(單位mm),一般不需要填*/ __u32width; /*外設寬度(單位mm),一般不需要填*/ __u32 accel_flags; /*過時的參數,不需要填*/ /* 除了pixclock本身外,其他的都以像素時鐘為 單位*/ __u32pixclock; /*像素時鐘(皮秒)*/ __u32 left_margin; /*行切換,從同步到繪圖之間的延遲*/ __u32right_margin; /*行切換,從繪圖到同步之間的延遲*/ __u32upper_margin; /*幀切換,從同步到繪圖之間的延遲*/ __u32lower_margin; /*幀切換,從繪圖到同步之間的延遲*/ __u32hsync_len; /*水平同步的長度*/ __u32 vsync_len; /*垂直同步的長度*/ __u32 sync; __u32 vmode; __u32 rotate; __u32reserved[5]; /*保留*/ }

 

1.寫驅動程式:

(驅動設置:參考自帶的LCD平臺驅動drivers/video/s3c2410fb.c )

(LCD控制寄存器設置:參考之前的LCD裸機驅動:http://www.cnblogs.com/lifexy/p/7144890.html)

1.1 步驟如下:

在驅動init入口函數中:

1)分配一個fb_info結構體

2)設置fb_info

  2.1)設置固定的參數fb_info-> fix

  2.2) 設置可變的參數fb_info-> var

  2.3) 設置操作函數fb_info-> fbops

  2.4) 設置fb_info 其它的成員

3)設置硬體相關的操作    

  3.1)配置LCD引腳

  3.2)根據LCD手冊設置LCD控制器

  3.3)分配顯存(framebuffer),把地址告訴LCD控制器和fb_info

4)開啟LCD,並註冊fb_info: register_framebuffer()

  4.1) 直接在init函數中開啟LCD(後面講到電源管理,再來優化)

    控制LCDCON5允許PWREN信號,

    然後控制LCDCON1輸出PWREN信號,

    輸出GPB0高電平來開背光,

  4.2) 註冊fb_info

 

在驅動exit出口函數中:

1)卸載內核中的fb_info

2) 控制LCDCON1關閉PWREN信號,關背光,iounmap註銷地址

3)釋放DMA緩存地址dma_free_writecombine()

4)釋放註冊的fb_info

1.2 具體代碼如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/clk.h> 
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/div64.h> 
#include <asm/mach/map.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/fb.h>

/*LCD :  480*272     */
#define   LCD_xres     480        //LCD 行解析度
#define   LCD_yres     272          //LCD列解析度
 

/* GPIO prot   */
static unsigned long  *GPBcon;
static unsigned long  *GPCcon;
static unsigned long  *GPDcon;
static unsigned long  *GPGcon;  //GPG4:控制LCD信號 
static unsigned long  *GPBdat;   //GPB0: 控制背光

/* LCD control */ struct lcd_reg{ unsigned long lcdcon1; unsigned long lcdcon2; unsigned long lcdcon3; unsigned long lcdcon4; unsigned long lcdcon5; unsigned long lcdsaddr1; unsigned long lcdsaddr2; unsigned long lcdsaddr3 ; unsigned long redlut; unsigned long greenlut; unsigned long bluelut; unsigned long reserved[9]; unsigned long dithmode; unsigned long tpal ; unsigned long lcdintpnd; unsigned long lcdsrcpnd; unsigned long lcdintmsk; unsigned long tconsel; }; static struct lcd_reg *lcd_reg; static struct fb_info *my_lcd; //定義一個全局變數 static u32 pseudo_palette[16]; //調色板數組,被fb_info->pseudo_palette調用 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) { /*內核中的單色都是16位,預設從左到右排列,比如G顏色[0x1f],那麼chan就等於0XF800*/ chan &= 0xffff; chan >>= 16 - bf->length; //右移,將數據靠到位0上 return chan << bf->offset; //左移一定偏移值,放入16色數據中對應的位置 } static int my_lcdfb_setcolreg(unsigned int regno, unsigned int red,unsigned int green, unsigned int blue,unsigned int transp, struct fb_info *info) //設置調色板函數,供內核調用 { unsigned int val; if (regno >=16) //調色板數組不能大於15 return 1; /* 用red,green,blue三個顏色值構造出16色數據val */ val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); ((u32 *)(info->pseudo_palette))[regno] = val; //放到調色板數組中 return 0; } static struct fb_ops my_lcdfb_ops = { .owner = THIS_MODULE, .fb_setcolreg = my_lcdfb_setcolreg,//調用my_lcdfb_setcolreg()函數,來設置調色板fb_info-> pseudo_palette .fb_fillrect = cfb_fillrect, //填充矩形 .fb_copyarea = cfb_copyarea, //複製數據 .fb_imageblit = cfb_imageblit, //繪畫圖形, }; static int lcd_init(void) { /*1.申請一個fb_info結構體*/ my_lcd= framebuffer_alloc(0,0); /*2.設置fb_info*/ /* 2.1設置固定的參數fb_info-> fix */ /*my_lcd->fix.smem_start 物理地址後面註冊MDA緩存區設置*/ strcpy(my_lcd->fix.id, "mylcd"); //名字 my_lcd->fix.smem_len =LCD_xres*LCD_yres*2; //地址長 my_lcd->fix.type =FB_TYPE_PACKED_PIXELS; my_lcd->fix.visual =FB_VISUAL_TRUECOLOR; //真彩色 my_lcd->fix.line_length =LCD_xres*2; //LCD 一行的位元組 /* 2.2 設置可變的參數fb_info-> var */ my_lcd->var.xres =LCD_xres; //可見屏X 解析度 my_lcd->var.yres =LCD_yres; //可見屏y 解析度 my_lcd->var.xres_virtual =LCD_xres; //虛擬屏x解析度 my_lcd->var.yres_virtual =LCD_yres; //虛擬屏y解析度 my_lcd->var.xoffset = 0; //虛擬到可見屏幕之間的行偏移 my_lcd->var.yoffset =0; //虛擬到可見屏幕之間的行偏移 my_lcd->var.bits_per_pixel=16; //像素為16BPP my_lcd->var.grayscale = 0; //灰色比例 my_lcd->var.red.offset = 11; my_lcd->var.red.length = 5; my_lcd->var.green.offset = 5; my_lcd->var.green.length = 6; my_lcd->var.blue.offset = 0; my_lcd->var.blue.length = 5; /* 2.3 設置操作函數fb_info-> fbops */ my_lcd->fbops = &my_lcdfb_ops; /* 2.4 設置fb_info 其它的成員 */ /*my_lcd->screen_base 虛擬地址在後面註冊MDA緩存區設置*/ my_lcd->pseudo_palette =pseudo_palette; //保存調色板數組 my_lcd->screen_size =LCD_xres * LCD_yres *2; //虛擬地址長 /*3 設置硬體相關的操作*/ /*3.1 配置LCD引腳*/ GPBcon = ioremap(0x56000010, 8); GPBdat = GPBcon+1; GPCcon = ioremap(0x56000020, 4); GPDcon     = ioremap(0x56000030, 4); GPGcon      = ioremap(0x56000060, 4); *GPBcon &=~(0x03<<(0*2)); *GPBcon |= (0x01<<(0*2)); //PGB0背光 *GPBdat &=~(0X1<<0); //關背光 *GPCcon =0xaaaaaaaa; *GPDcon =0xaaaaaaaa; *GPGcon |=(0x03<<(4*2)); //GPG4:LCD信號 /*3.2 根據LCD手冊設置LCD控制器,參考之前的裸機驅動*/ lcd_reg=ioremap(0X4D000000, sizeof( lcd_reg) ); /*HCLK:100Mhz */ lcd_reg->lcdcon1 = (4<<8) | (0X3<<5) | (0x0C<<1) ; lcd_reg->lcdcon2 = ((3)<<24) | (271<<14) | ((1)<<6) |((0)<<0); lcd_reg->lcdcon3 = ((16)<<19) | (479<<8) | ((10)); lcd_reg->lcdcon4 = (4); lcd_reg->lcdcon5 = (1<<11) | (1<<9) | (1<<8) |(1<<0); lcd_reg->lcdcon1 &=~(1<<0); // 關閉PWREN信號輸出 lcd_reg->lcdcon5 &=~(1<<3); //禁止PWREN信號 /* 3.3 分配顯存(framebuffer),把地址告訴LCD控制器和fb_info*/ my_lcd->screen_base=dma_alloc_writecombine(0,my_lcd->fix.smem_len, &my_lcd->fix.smem_start, GFP_KERNEL); /*lcd控制器的地址必須是物理地址*/ lcd_reg->lcdsaddr1 =(my_lcd->fix.smem_start>>1)&0X3FFFFFFF; //保存緩衝起始地址A[30:1] lcd_reg->lcdsaddr2 =((my_lcd->fix.smem_start+my_lcd->screen_size)>>1)&0X1FFFFF; //保存存緩衝結束地址A[21:1] lcd_reg->lcdsaddr3 =LCD_xres& 0x3ff;        //OFFSIZE[21:11]:保存LCD上一行結尾和下一行開頭的地址之間的差
                               //PAGEWIDTH [10:0]:保存LCD一行占的寬度(半字數為單位) /*4開啟LCD,並註冊fb_info: register_framebuffer()*/ /*4.1 直接在init函數中開啟LCD(後面講到電源管理,再來優化)*/ lcd_reg->lcdcon1 |=1<<0; //輸出PWREN信號 lcd_reg->lcdcon5 |=1<<3; //允許PWREN信號 *GPBdat |=(0X1<<0); //開背光 /*4.2 註冊fb_info*/ register_framebuffer(my_lcd); return 0; }
static int lcd_exit(void) { /* 1卸載內核中的fb_info*/ unregister_framebuffer(my_lcd);
/*2 控制LCDCON1關閉PWREN信號,關背光,iounmap註銷地址*/ lcd_reg->lcdcon1 &=~(1<<0); // 關閉PWREN信號輸出 lcd_reg->lcdcon5 &=~(1<<3); //禁止PWREN信號 *GPBdat &=~(0X1<<4); //關背光 iounmap(GPBcon); iounmap(GPCcon); iounmap(GPDcon); iounmap(GPGcon); /*3.釋放DMA緩存地址dma_free_writecombine()*/ dma_free_writecombine(0,my_lcd->screen_size,my_lcd->screen_base,my_lcd->fix.smem_start); /*4.釋放註冊的fb_info*/ framebuffer_release(my_lcd); return 0; } module_init(lcd_init); module_exit(lcd_exit); MODULE_LICENSE("GPL");

 

2.重新編譯內核,去掉預設的LCD

make menuconfig ,進入menu菜單重新設置內核參數:

進入Device Drivers-> Graphics support:
<M> S3C2410 LCD framebuffer support          //將自帶的LCD驅動設為模塊, 不編進內核中

然後make uImage 編譯內核

make modules 編譯模塊

為什麼要編譯模塊?

因為LCD驅動相關的文件也沒有編進內核,而fb_ops里的成員fb_fillrect(), fb_copyarea(), fb_imageblit()用的都是drivers/video下麵的3個文件,所以需要這3個的.ko模塊,如下圖所示:

 

3.掛載驅動

將編譯好的LCD驅動模塊 和drivers/video里的3個.ko模塊 放入nfs文件系統目錄中

然後燒寫內核, 先裝載3個/drivers/video下編譯好的模塊,再來裝載LCD驅動模塊

掛載LCD驅動後, 如下圖,可以通過  ls -l /dev/fb*   命令查看已掛載的LCD設備節點:

 

4.測試運行

測試有兩種: 

(echocat命令詳解入口地址: http://www.cnblogs.com/lifexy/p/7601122.html)

echo hello> /dev/tty1     // LCD上便顯示hello欄位

cat Makefile>/dev/tty1    // LCD上便顯示Makeflie文件的內容

 

4.1使用上節的鍵盤驅動在LCD終端運行linux

vi  /etc/inittab         //修改inittab, inittab:配置文件,用於啟動init進程時,讀取inittab

添加->tty1::askfirst:-/bin/sh   //啟動tty1的-sh進程(開機)之前,在LCD終端上列印提示enter信息

然後重啟,insmod裝載3個/drivers/video下編譯好的模塊,再來insmod裝載LCD驅動模塊,tty1設備便有了,就能看到提示信息:

 

如下圖,我們insmod上一節的鍵盤驅動後,按下enter鍵,便能在LCD終端上操作linux了

(上一節的鍵盤驅動詳解入口地址: http://www.cnblogs.com/lifexy/p/7553861.html)

 

從上圖可以看到按下enter鍵,它就啟動了一個進程號772的-sh進程,如下圖發現這個-sh的描述符都指向了tty1:

 

 


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

-Advertisement-
Play Games
更多相關文章
  • --顯示專員內容的統計 --香港 Geovin Du 塗聚文 select count(*) as 'Tatol',BrandService,ServerName,Qualified=isnull(count(case IsSucces when '合格' then IsSucces end),0)... ...
  • "文章參考" 在Windows上安裝MongoDB 首先,在官網下載安裝包。 "下載地址" 內容如下所示: 配置 1. 創建數據目錄 2. 配置環境變數 運行 1. 命令行下運行 MongoDB 伺服器 2. 新開一個cmd 運行下麵語句 3. 打開網頁 "http://localhost:2701 ...
  • 轉自博客園: 1、獲取當前日期GetDate getdate()函數以datetime數據類型的格式返回當前SQLServer伺服器所在電腦的日期和時間。其語法格式為getdate()。返回值舍入到最近的秒小數部分,精度為.333秒資料庫十七偏移量不包含在內。 示例: 2、GetUTCDate 獲 ...
  • 一.表設計階段: 1.主鍵的使用 a.業務日誌表、安全審計表採用自增長; b.自定義編號用於業務流程類表,根據一定的編號規則; c.int型主鍵 用於基礎數據表; 2.邏輯刪除欄位的設計 a.tinyint類型,1或0; b.聯合主鍵(如ID+starDate),另加starDate,endDate ...
  • 第四章 高級查詢(二) (1)通過在子查詢中使用EXISTS子句,可以對子查詢中的行是否存在進行檢查。子查詢可以出現在表達式出現的如何位置 (2)子查詢語句可以嵌套在SQL語句中任何表達式出現的位置。 一、EXISTS子查詢 1.使用EXISTS語句判斷該資料庫對象是否存在: DROP TABLE ...
  • 在執行mysqldump命令時候報如下錯誤: [root@localhost ~]# mysqldump -uroot -p -d test> test.sql mysqldump: Got error: 2002: Can't connect to local MySQL server throu ...
  • 1 修改network配置文件 vi /etc/sysconfig/network 將配置文件中的HOSTNAME的內容改成需要修改的主機名 2 修改hosts配置文件 vi /etc/hosts 將配置文件中的localhost.localdomain改成需要修改的主機名 3 重啟機器 reboo ...
  • 本文目錄1.1 下載和解決依賴關係1.2 httpd編譯選項1.3 模塊動靜態編譯1.4 動靜態編譯的優先順序規則1.5 MPM的安裝1.6 關於"--enable-so"1.7 開始編譯httpd1.8 編譯後的規範操作 1.1 下載和解決依賴 以httpd 2.4.27為例。 資源下載: apac ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...