【STM32】最后一刷-江科大Flash閃存-學習筆記

FLASH簡介

  1. STM32F1系列的FLASH包含程序存儲器、系統存儲器和選項字節三個部分,通過閃存存儲器接口(外設)可以對程序存儲器和選項字節進行擦除和編程,(系統存儲器用于存儲原廠寫入的BootLoader程序,用于串口下載,不允許我們修改)
  2. 讀寫FLASH的用途: ?? ?
  • 利用程序存儲器的剩余空間來保存掉電不丟失的用戶數據 ?? ?
  • 通過在程序中編程(IAP),實現程序的自我更新

在線編程(In-Circuit Programming – ICP)用于更新程序存儲器的全部內容,它通過JTAG、SWD協議或系統加載程序(Bootloader)下載程序

在程序中編程(In-Application Programming – IAP)可以使用微控制器支持的任一種通信接口下載程序

?存儲器映像參考這篇:【江協科技STM32】DMA直接存儲器存儲-學習筆記_江科 stm32 dma-CSDN博客

?閃存模塊組織

對應主存儲器,進行了分頁,分頁是為了更好地管理閃存,擦除和寫保護都是以頁為單位的,這一點和之前的W25Q64的閃存一樣,寫入前必須擦除等等。具體參考Flash操作注意事項:【STM32】SPI通信協議&W25Q64Flash存儲器芯片(學習筆記)_spi存儲芯片-CSDN博客

?FLASH基本結構

?FLASH解鎖(解除閃存鎖)

?FPEC共有三個鍵值: ?? ?

  • RDPRT鍵 = 0x000000A5(解除讀保護密鑰)
  • KEY1 = 0x45670123 ?? ?
  • KEY2 = 0xCDEF89AB
  • 解鎖: ?? ?
  • 復位后,FPEC被保護,不能寫入FLASH_CR ?? ?
  • 在FLASH_KEYR先寫入KEY1,再寫入KEY2,解鎖 ?? ?
  • 錯誤的操作序列會在下次復位前鎖死FPEC和FLASH_CR

加鎖: ?? ?

  • 置FLASH_CR中的LOCK位鎖住FPEC和FLASH_CR

?

?使用指針訪問存儲器

uint16_t Data = *((__IO uint16_t *)(0x08000000));?

這行代碼是在 C 語言中用于從特定內存地址讀取數據,并將其賦值給變量Data。解釋如下:

  1. uint16_t是一種無符號 16 位整數類型,定義在<stdint.h>頭文件中,確保了數據類型的寬度為 16 位,可表示的范圍是 0 到 65535。
  2. Data是定義的一個uint16_t類型的變量,用于存儲從特定內存地址讀取的數據。
  3. (__IO uint16_t *)(0x08000000):這部分是一個強制類型轉換。(__IO uint16_t *)0x08000000這個地址值轉換為指向__IO uint16_t類型的指針。其中__IO通常是由編譯器定義的宏,可能表示該內存地址是可讀寫(volatile)的,防止編譯器對該地址的訪問進行優化,確保每次訪問都是真實地從該內存地址讀寫數據。0x08000000是一個十六進制表示的內存地址。
  4. *((__IO uint16_t *)(0x08000000)):這部分通過指針解引用操作,從0x08000000這個內存地址讀取一個uint16_t類型的數據。
  5. 最后,將從指定內存地址讀取的數據賦值給Data變量。

?*((__IO uint16_t *)(0x08000000)) = 0x1234;

  1. 指針類型強制轉換
    (__IO uint16_t *)(0x08000000)?這部分代碼將地址值?0x08000000?強制轉換為一個指向?__IO uint16_t?類型的指針。其中?__IO?可能是一個特定的修飾符,通常用于表示該內存位置具有特殊的讀寫屬性(例如可能是與外設寄存器相關,允許讀寫操作),uint16_t?表示無符號 16 位整數類型。通過這種強制類型轉換,告訴編譯器把?0x08000000?這個地址當作是一個?__IO uint16_t?類型數據的起始地址。
  2. 賦值操作
    在完成指針類型強制轉換后,使用?*?運算符對這個指針進行解引用,然后將值?0x1234?賦給該指針所指向的內存位置。也就是將?0x1234?這個 16 位無符號整數值寫入到了內存地址?0x08000000?開始的兩個字節(因為?uint16_t?是 16 位,占兩個字節)。

?實例

?指定地址下讀:

/*** 函    數:FLASH讀取一個32位的字* 參    數:Address 要讀取數據的字地址* 返 回 值:指定地址下的數據*/
uint32_t HerFlash_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address)); //使用指針訪問指定地址下的數據并返回
}/*** 函    數:FLASH讀取一個16位的半字* 參    數:Address 要讀取數據的半字地址* 返 回 值:指定地址下的數據*/
uint16_t HerFlash_ReadHalfWord(uint32_t Address)
{return *((__IO uint16_t *)(Address)); //使用指針訪問指定地址下的數據并返回
}/*** 函    數:FLASH讀取一個8位的字節* 參    數:Address 要讀取數據的字節地址* 返 回 值:指定地址下的數據*/
uint8_t HerFlash_ReadByte(uint32_t Address)
{return *((__IO uint8_t *)(Address));//使用指針訪問指定地址下的數據并返回
}

?

?程序存儲器全擦除

  1. 第一步:讀 FLASH_CR 的 LOCK 位

    • 理由:LOCK 位用于鎖定閃存控制寄存器(FLASH_CR),在對閃存進行擦除等操作前,需要先了解其鎖定狀態。如果 LOCK 位 = 1,表示閃存處于鎖定狀態,不能直接進行后續的擦除操作,需要先執行解鎖過程;若 LOCK 位 = 0,則可跳過解鎖過程直接進行擦除設置。
    • 操作及結果:讀取該位,得到 LOCK 位 = 1,說明閃存處于鎖定狀態。
  2. 第二步:執行解鎖過程

    • 理由:因為第一步檢測到 LOCK 位為 1,閃存鎖定,所以必須執行解鎖過程才能對閃存控制寄存器進行操作,以實現擦除等功能。
    • 操作及結果:執行解鎖過程后,將 LOCK 位置為 0,此時閃存解鎖,可以對相關寄存器進行設置。
  3. 第三步:置 FLASH_CR 的 MER = 1

    • 理由:MER(Mass Erase)位用于選擇是否進行全擦除操作。將 MER 位置 1,表示要進行閃存全擦除操作。
    • 操作及結果:將 MER 位置 1,準備執行全擦除。
  4. 第四步:置 FLASH_CR 的 STRT = 1

    • 理由:STRT(Start)位用于啟動閃存擦除操作。當 MER 位已置 1 準備好全擦除,再將 STRT 位置 1,就可以正式啟動全擦除過程。
    • 操作及結果:將 STRT 位置 1,閃存全擦除操作開始執行。
  5. 第五步:關注 FLASH_SR 的 BSY 位

    • 理由:BSY(Busy)位用于指示閃存操作是否正在進行。在全擦除操作啟動后,需要監測該位來判斷擦除操作是否完成。當 BSY = 1 時,表示閃存操作正在進行中;當 BSY = 0 時,表示閃存操作已完成。
    • 操作及結果:在全擦除操作執行過程中,BSY 位會變為 1,表示操作正在進行。等待一段時間后,當 BSY 位變為 0,說明全擦除操作完成。
  6. 第六步:讀出并驗證所有頁的數據

    • 理由:全擦除操作完成后,需要驗證是否所有頁的數據都已被正確擦除。通過讀出所有頁的數據,并與預期的擦除后數據(一般為全 1 或特定的擦除后狀態)進行比較,來驗證擦除操作的正確性。
    • 操作及結果:讀出所有頁的數據,與預期的擦除后數據進行對比,若完全一致,則說明全擦除操作成功;若有不一致的地方,則說明擦除操作可能存在問題。

實例?

/*** 函    數:FLASH全擦除* 參    數:無* 返 回 值:無* 說    明:調用此函數后,FLASH的所有頁都會被擦除,包括程序文件本身,擦除后,程序將不復存在*/
void HerFlash_EraseAllPages(void)
{FLASH_Unlock();			//解鎖FLASH_EraseAllPages();	//全擦除FLASH_Lock();			//加鎖
}

void FLASH_Unlock(void)//解鎖FLASH程序擦除控制器(解鎖)?

?void FLASH_Lock(void)//鎖定FLASH程序擦除控制器

?FLASH_Status FLASH_EraseAllPages(void)//擦除所有FLASH頁面

?注意:以上功能可用于所有STM32F10x器件??

??程序存儲器頁擦除

  1. 讀取鎖定狀態:首先讀取閃存控制寄存器(FLASH_CR)的LOCK位,判斷閃存是否處于鎖定狀態。
  2. 解鎖操作(若需):若LOCK位為1(鎖定狀態),執行解鎖過程;若為0,跳過解鎖。
  3. 配置擦除參數
    • FLASH_CRPER(Page Erase,頁擦除使能)位為1
    • FLASH_AR(地址寄存器)中選擇要擦除的閃存頁;
    • FLASH_CRSTRT(Start,啟動)位為1,啟動頁擦除操作。
  4. 等待擦除完成:監測閃存狀態寄存器(FLASH_SR)的BSY(Busy,忙)位。若BSY=1,表示擦除仍在進行,需持續等待;若BSY=0,表示擦除完成。
  5. 驗證擦除結果:擦除完成后,讀出并驗證被擦除頁的數據,確保擦除操作成功。

實例

/*** 函    數:FLASH頁擦除* 參    數:PageAddress 要擦除頁的頁地址* 返 回 值:無*/
void HerFlash_ErasePage(uint32_t PageAddress)
{FLASH_Unlock();FLASH_ErasePage(PageAddress);FLASH_Lock();
}

?FLASH_Status FLASH_ErasePage(uint32_t Page_Address)//擦除指定的FLASH頁面?

?注意:此功能可用于所有STM32F10x器件??

?程序存儲器編程

注意:這種模式下CPU以標準的寫半字的方式燒寫閃存, FLASH_CR寄存器的PG位必須置’1’。 FPEC先讀出指定地址的內容并檢查它是否被擦除如未被擦除則不執行編程在FLASH_SR寄存器的PGERR位提出警告(唯一的例外是當要燒寫的數值是0x0000時, 0x0000可被正確燒入且PGERR位不被置位);如果指定的地址在FLASH_WRPR中設定為寫保護,則不執行編程并在FLASH_SR寄存器的WRPRTERR位置’1’提出警告。 FLASH_SR寄存器的EOP為’1’時表示編程結束。

編程過程講解:

  1. 讀取鎖定狀態:首先讀取閃存控制寄存器(FLASH_CR)的LOCK位,判斷閃存是否處于鎖定狀態。
  2. 解鎖操作(若需):若LOCK位為1(鎖定狀態),執行解鎖序列;若為0,直接進入下一步。
  3. 使能編程模式:將FLASH_CR寄存器的PG位(Program,編程使能)置為1,開啟編程功能。
  4. 寫入數據:在指定的閃存地址中寫入半字(16 位)數據。用到這句代碼 *((__IO uint16_t *)(0x08000000)) = 0x1234;
  5. 等待操作完成:監測閃存狀態寄存器(FLASH_SR)的BSY(Busy,忙)位。若BSY=1,表示編程操作仍在進行,需持續等待;若BSY=0,表示編程操作完成。
  6. 驗證數據:讀取編程地址中的數據,檢查寫入的數據是否正確,確保編程操作成功。

?實例

/*** 函    數:FLASH編程字* 參    數:Address 要寫入數據的字地址* 參    數:Data 要寫入的32位數據* 返 回 值:無*/
void HerFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();FLASH_ProgramWord(Address, Data);FLASH_Lock();
}/*** 函    數:FLASH編程字* 參    數:Address 要寫入數據的半字地址* 參    數:Data 要寫入的16位數據* 返 回 值:無*/
void HerFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();FLASH_ProgramHalfWord(Address, Data);FLASH_Lock();
}

?FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data)//在指定地址編程一個字

?注意:以上功能可用于所有STM32F10x器件???

參數說明
Address指定要編程的地址
Data指定要編程的數據

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)//在指定地址上編程半個字?

參數說明
Address指定要編程的地址
Data指定要編程的數據

??注意:以上功能可用于所有STM32F10x器件???

?選擇字節說明

  • RDP:寫入RDPRT鍵(0x000000A5)后解除讀保護
  • USER:配置硬件看門狗和進入停機/待機模式是否產生復位
  • Data0/1:用戶可自定義使用
  • WRP0/1/2/3:配置寫保護,每一個位對應保護4個存儲頁(中容量)

選項字節擦除?

  • 檢查FLASH_SR的BSY位,以確認沒有其他正在進行的閃存操作
  • 解鎖FLASH_CR的OPTWRE位
  • 設置FLASH_CR的OPTER位為1
  • 設置FLASH_CR的STRT位為1
  • 等待BSY位變為0
  • 讀出被擦除的選擇字節并做驗證?

選項字節編程?

  • 檢查FLASH_SR的BSY位,以確認沒有其他正在進行的編程操作
  • 解鎖FLASH_CR的OPTWRE位
  • 設置FLASH_CR的OPTPG位為1
  • 寫入要編程的半字到指定的地址
  • 等待BSY位變為0
  • 讀出寫入的地址并驗證數據?

讀取內部FLASH閃存

要實現數據掉電不丟失的存儲,那就要基于底層代碼,再建一個模塊Store,在Store模塊我們要用SRAM緩存數組來管理FLASH閃存的最后一頁,實現參數的任意讀寫和保存。因為閃存每次都是擦除,再寫入,擦除之后,還容易丟失數據,所以要想靈活管理數據,還是得靠SRAM數組,需要備份的時候,我們再統一轉到閃存里。所以在Store模塊里要先定義一個Store_數組,用于存放備份數據。

?參數存儲模塊初始化

#define  STORE_START_ADDRESS  	0x0800FC00
#define  STORE_DATA  			512uint16_t Store_Data[STORE_DATA];	//定義SRAM數字,512個數據,每個數據16位,2字節,剛好對應閃存一頁1024字節void Store_Init(void)
{/*判斷是不是第一次使用*/if(HerFlash_ReadHalfWord(STORE_START_ADDRESS) != 0xA8A8){HerFlash_ErasePage(STORE_START_ADDRESS);HerFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA8A8);//在第一個半字寫入自己規定的標志位,用于判斷是不是第一次使用for(uint16_t i =1; i < STORE_DATA; i ++)	//循環STORE_COUNT次,除了第一個標志位{HerFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2,0x0000);//除了標志位的有效數據全部清0}}/*上電時,將閃存數據加載回SRAM數組,實現SRAM數組的掉電不丟失*/for(uint16_t i =0;i < STORE_DATA; i ++){Store_Data[i] = HerFlash_ReadHalfWord(STORE_START_ADDRESS + i * 2);//將閃存的數據加載回SRAM數組}
}

?參數存儲模塊保存數據到閃存

/*** 函    數:參數存儲模塊保存數據到閃存* 參    數:無* 返 回 值:無*/
void Store_Save(void)
{HerFlash_ErasePage(STORE_START_ADDRESS);for(uint16_t i = 0;i < STORE_DATA;i ++)	//循環STORE_COUNT次,包括第一個標志位{HerFLASH_ProgramHalfWord(STORE_START_ADDRESS +i*2, Store_Data[i]);//將SRAM數組的數據備份保存到閃存}
}

?參數存儲模塊將所有有效數據清0

/*** 函    數:參數存儲模塊將所有有效數據清0* 參    數:無* 返 回 值:無*/
void Store_Clear(void)
{for(uint16_t i = 1;i < STORE_DATA;i ++){Store_Data[i] = 0x0000;	//SRAM數組有效數據清0}                           Store_Save();               //保存數據到閃存
}

?最終梳理思路:梳理思路

其實就是,在主函數對SRAM數組Store_Data進行修改,然后在放到閃存,防止SRAM掉電丟失,然后在上電初始化的時候在把閃存的數據再讀取到SRAMStore_Data數組,實現SRAM掉電不丟失?

main函數?

#uint8_t KeyNum;					//定義用于接收按鍵鍵碼的變量int main(void)
{/*模塊初始化*/OLED_Init();				//OLED初始化Key_Init();					//按鍵初始化Store_Init();				//參數存儲模塊初始化,在上電的時候將閃存的數據加載回Store_Data,實現掉電不丟失/*顯示靜態字符串*/OLED_ShowString(1, 1, "Flag:");OLED_ShowString(2, 1, "Data:");while (1){KeyNum = Key_GetNum();		//獲取按鍵鍵碼if (KeyNum == 1)			//按鍵1按下{Store_Data[1] = 0x1234;		//變換測試數據,斷電丟失Store_Data[2] = 0xABCD;Store_Data[3] += 3;Store_Data[4] += 4;Store_Save();			//將Store_Data的數據備份保存到閃存,實現掉電不丟失}if (KeyNum == 2)			//按鍵2按下{Store_Clear();			//將Store_Data的數據全部清0}OLED_ShowHexNum(1, 6, Store_Data[0], 4);	//顯示Store_Data的第一位標志位OLED_ShowHexNum(3, 1, Store_Data[1], 4);	//顯示Store_Data的有效存儲數據OLED_ShowHexNum(3, 6, Store_Data[2], 4);OLED_ShowHexNum(4, 1, Store_Data[3], 4);OLED_ShowHexNum(4, 6, Store_Data[4], 4);}
}

結果?

?

注意一個問題:程序文件大小和用戶數據大小的沖突?

程序占用空間大小

?

器件電子簽名&讀取芯片ID

電子簽名存放在閃存存儲器模塊的系統存儲區域,包含的芯片識別信息在出廠時編寫,不可更改,使用指針讀指定地址下的存儲器可獲取電子簽名

閃存容量寄存器: ?? ?

  • 基地址:0x1FFF F7E0 ?? ?
  • 大小:16位

產品唯一身份標識寄存器: ?? ?

  • 基地址: 0x1FFF F7E8 ?? ?
  • 大小:96位?

int main(void)
{OLED_Init();						OLED_ShowString(1, 1, "F_SIZE:");	OLED_ShowHexNum(1, 8, *((__IO uint16_t *)(0x1FFFF7E0)), 4);		//使用指針讀取指定地址下的閃存容量寄存器OLED_ShowString(2, 1, "U_ID:");		OLED_ShowHexNum(2, 6, *((__IO uint16_t *)(0x1FFFF7E8)), 4);		//使用指針讀取指定地址下的產品唯一身份標識寄存器OLED_ShowHexNum(2, 11, *((__IO uint16_t *)(0x1FFFF7E8 + 0x02)), 4);OLED_ShowHexNum(3, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x04)), 8);OLED_ShowHexNum(4, 1, *((__IO uint32_t *)(0x1FFFF7E8 + 0x08)), 8);while (1){}
}

結果?

最后記得看數據手冊,這東西是真的能看懂 學會 學到知識!!!!?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/74189.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/74189.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/74189.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

梯度(Gradient)與步長(Step Size)

梯度&#xff08;Gradient&#xff09;與步長&#xff08;Step Size&#xff09; 梯度與步長是優化算法&#xff08;如梯度下降法&#xff09;的核心概念。以下是它們的詳細解釋&#xff1a; 梯度&#xff08;Gradient&#xff09; ?定義 梯度是一個向量&#xff0c;表示多元…

freecad二開 xmlrpc接口api qtgui

FreeCAD.ConfigGet("UserAppData") 文件夾下創建mod文件夾 mod文件夾底下創建插件文件夾my_server: freecad_server.py&#xff1a; from xmlrpc.server import SimpleXMLRPCServer import FreeCADGui import FreeCADimport queue from PySide2.QtCore import QTi…

鴻蒙NEXT開發日志工具類(ArkTs)

import hilog from ohos.hilog; import { JSON } from kit.ArkTS; import { BusinessError } from kit.BasicServicesKit; import { StrUtil } from ./StrUtil;/*** 日志工具類* author: 鴻蒙布道師* since: 2024/03/31*/ export class LogUtil {private static logSize: numbe…

《Linux運維總結:基于銀河麒麟V10+ARM64架構CPU源碼編譯部署單實例redis7.2.6》

總結&#xff1a;整理不易&#xff0c;如果對你有幫助&#xff0c;可否點贊關注一下&#xff1f; 更多詳細內容請參考&#xff1a;《Linux運維篇&#xff1a;Linux系統運維指南》 一、環境信息 環境信息如下&#xff1a; 主機IP 操作系統 Redis版本 CPU架構 192.168.1.111 K…

基于LSTM的文本分類1——模型搭建

源碼 # coding: UTF-8 import torch import torch.nn as nn import torch.nn.functional as F import numpy as npclass Config(object):"""配置參數類&#xff0c;用于存儲模型和訓練的超參數"""def __init__(self, dataset, embedding):self.…

小了 60,500 倍,但更強;AI 的“深度詛咒”

作者&#xff1a;Ignacio de Gregorio 圖片來自 Unsplash 的 Bahnijit Barman 幾周前&#xff0c;我們看到 Anthropic 嘗試訓練 Claude 去通關寶可夢。模型是有點進展&#xff0c;但離真正通關還差得遠。 但現在&#xff0c;一個獨立的小團隊用一個只有一千萬參數的模型通關了…

nextjs使用02

并行路由 同一個頁面&#xff0c;放多個路由&#xff0c;&#xff0c; 目錄前面加,layout中可以當作插槽引入 import React from "react";function layout({children,notifications,user}:{children:React.ReactNode,notifications:React.ReactNode,user:React.Re…

github 無法在shell里鏈接

當我在shell端git push時&#xff0c;我發現總是22 timeout的問題。 我就進行了以下步驟的嘗試并最終得到了解決。 第一步&#xff0c;我先確定我可以curl github&#xff0c;也就是我網絡沒問題 curl -v https://github.com 如果這個時候不超時和報錯&#xff0c;說明網絡…

當前主流的大模型知識庫軟件對比分析

以下是當前主流的大模型知識庫軟件對比分析&#xff0c;涵蓋功能特性、適用場景及優劣勢&#xff0c;結合最新技術動態和行業實踐提供深度選型參考&#xff1a; 一、企業級智能知識庫平臺 1. 阿里云百煉&#xff08;Model Studio&#xff09; 核心能力&#xff1a;基于RAG技…

Java的比較器 Comparable 和 Comparator

在 Java 中&#xff0c;Comparable 和 Comparator 是用于對象排序的重要接口。它們提供了不同的排序方式&#xff0c;適用于不同的需求&#xff0c;同時在 Java 底層排序算法中發揮著關鍵作用。本文將從基礎概念、使用方法、排序實現&#xff08;包括升序、降序&#xff09;、底…

基于Qlearning強化學習的太赫茲信道信號檢測與識別matlab仿真

目錄 1.算法仿真效果 2.算法涉及理論知識概要 2.1 太赫茲信道特性 2.2 Q-learning強化學習基礎 2.3 基于Q-learning 的太赫茲信道信號檢測與識別系統 3.MATLAB核心程序 4.完整算法代碼文件獲得 1.算法仿真效果 matlab2024b仿真結果如下&#xff08;完整代碼運行后無水印…

力扣刷題————199.二叉樹的右視圖

給定一個二叉樹的 根節點 root&#xff0c;想象自己站在它的右側&#xff0c;按照從頂部到底部的順序&#xff0c;返回從右側所能看到的節點值。 示例 1&#xff1a; 輸入&#xff1a;root [1,2,3,null,5,null,4] 輸出&#xff1a;[1,3,4] 解題思路&#xff1a;我們可以想到這…

文件包含漏洞的小點總結

文件本地與遠程包含&#xff1a; 文件包含有本地包含與遠程包含的區別&#xff1a;本地包含只能包含服務器已經有的問題&#xff1b; 遠程包含可以包含一切網絡上的文件。 本地包含&#xff1a; ①無限制 感受一下使用phpstudy的文件上傳&#xff0c;開啟phpstudy的apache…

深度學習處理時間序列(5)

Keras中的循環層 上面的NumPy簡單實現對應一個實際的Keras層—SimpleRNN層。不過&#xff0c;二者有一點小區別&#xff1a;SimpleRNN層能夠像其他Keras層一樣處理序列批量&#xff0c;而不是像NumPy示例中的那樣只能處理單個序列。也就是說&#xff0c;它接收形狀為(batch_si…

操作系統相關知識點

操作系統在進行線程切換時需要進行哪些動作&#xff1f; 保存當前線程的上下文 保存寄存器狀態、保存棧信息。 調度器選擇下一個線程 調度算法決策&#xff1a;根據策略&#xff08;如輪轉、優先級、公平共享&#xff09;從就緒隊列選擇目標線程。 處理優先級&#xff1a;實時…

從0到1:Rust 如何用 FFmpeg 和 OpenGL 打造硬核視頻特效

引言&#xff1a;視頻特效開發的痛點&#xff0c;你中了幾個&#xff1f; 視頻特效如今無處不在&#xff1a;短視頻平臺的濾鏡美化、直播間的實時美顏、影視后期的電影級調色&#xff0c;甚至 AI 生成內容的動態效果。無論是個人開發者還是團隊&#xff0c;視頻特效都成了吸引…

【并發編程 | 第一篇】線程相關基礎知識

1.并發和并行有什么區別 并發是指多核CPU上的多任務處理&#xff0c;多個任務在同一時刻真正同時執行。 并行是指單核CPU上的多任務處理&#xff0c;多個任務在同一時間段內交替執行&#xff0c;通過時間片輪轉實現交替執行&#xff0c;用于解決IO密集型瓶頸。 如何理解線程安…

Kafka 偏移量

在 Apache Kafka 中&#xff0c;偏移量&#xff08;Offset&#xff09;是一個非常重要的概念。它不僅用于標識消息的位置&#xff0c;還在多種場景中發揮關鍵作用。本文將詳細介紹 Kafka 偏移量的核心概念及其使用場景。 一、偏移量的核心概念 1. 定義 偏移量是一個非負整數…

18.redis基本操作

Redis(Remote Dictionary Server)是一個開源的、高性能的鍵值對(Key-Value)存儲數據庫,廣泛應用于緩存、消息隊列、實時分析等場景。它以其極高的讀寫速度、豐富的數據結構和靈活的應用方式而受到開發者的青睞。 Redis 的主要特點 ?高性能: ?內存存儲:Redis 將所有數…

歷年跨鏈合約惡意交易詳解(一)——THORChain退款邏輯漏洞

漏洞合約函數 function returnVaultAssets(address router, address payable asgard, Coin[] memory coins, string memory memo) public payable {if (router address(this)){for(uint i 0; i < coins.length; i){_adjustAllowances(asgard, coins[i].asset, coins[i].a…