解鎖STM32外設:開啟嵌入式開發新世界

???這里是小韓學長yyds的BLOG(喜歡作者的點個關注吧)

???想要了解更多內容可以訪問我的主頁 小韓學長yyds-CSDN博客

目錄

探索 STM32 強大的外設家族

初窺門徑:STM32 外設開發基礎

開發方式與工具

外設配置基礎步驟

深入剖析:常見外設應用實例

GPIO:最基礎的數字接口

定時器:精準時間掌控者

串口通信:數據傳輸的橋梁

ADC:模擬世界的數字化窗口

進階之路:外設驅動開發與優化

驅動開發步驟

優化策略

實戰演練:綜合項目開發

項目背景與需求分析

硬件設計與選型

軟件實現與調試


探索 STM32 強大的外設家族

在嵌入式系統的廣闊天地中,STM32 系列微控制器憑借其卓越的性能和豐富的外設資源,占據著舉足輕重的地位。意法半導體(STMicroelectronics)精心打造的 STM32,基于 ARM Cortex-M 內核,猶如一把萬能鑰匙,能開啟從基礎日常應用到復雜嵌入式系統開發的大門。

STM32 擁有種類繁多的外設,宛如一個龐大而有序的家族,每個成員都各司其職,在不同的應用場景中發揮著關鍵作用。GPIO(通用輸入輸出口)作為其中最基礎且常用的外設,如同微控制器與外部世界溝通的橋梁。它可配置為 8 種輸入輸出模式 ,通過簡單的高低電平變化,就能輕松實現對 LED 燈的控制。比如在智能照明系統中,通過控制 GPIO 口的電平,就能讓 LED 燈按照預設的模式亮起、熄滅或閃爍,為用戶營造出溫馨舒適的燈光環境;在按鍵檢測方面,GPIO 口能敏銳地捕捉到按鍵按下或松開時產生的電平變化,將用戶的操作指令準確無誤地傳遞給微控制器,進而實現各種功能的切換。

定時器則像是一位精準的時間管家,在許多場景中都不可或缺。在工業自動化領域,電機的轉速控制至關重要,定時器可以通過精確的計時,為電機提供穩定的 PWM(脈沖寬度調制)信號,從而實現對電機轉速的精準調控,確保生產過程的高效與穩定;在智能家居系統中,定時開關電器的功能為用戶帶來了極大的便利,定時器能夠按照用戶設定的時間,準時開啟或關閉電器設備,實現智能化的家居控制。

串口通信,作為一種經典的通信方式,在 STM32 的外設家族中也有著重要的地位。它就像一條無形的紐帶,將 STM32 與各種外部設備緊密相連。在嵌入式系統中,常常需要與顯示屏進行數據交互,串口通信能夠將微控制器中的數據準確地傳輸到顯示屏上,實現信息的直觀展示;與傳感器的通信也是串口的重要應用場景之一,傳感器采集到的數據通過串口源源不斷地傳輸到 STM32 中,經過微控制器的分析和處理,為系統的決策提供依據。

初窺門徑:STM32 外設開發基礎

開發方式與工具

在 STM32 外設開發的領域中,開發者宛如置身于一個充滿選擇的寶庫,擁有多種趁手的開發方式與工具,它們各自閃耀著獨特的光芒,為不同需求的開發者提供了多樣化的選擇。

標準外設庫是意法半導體為 STM32 系列微控制器精心打造的官方開發庫,猶如一座連接開發者與底層硬件的堅實橋梁。它涵蓋了豐富的 API 和示例代碼,全方位覆蓋了 STM32 微控制器的各種外設,從基礎的 GPIO 到復雜的定時器,再到 CAN、I2C、SPI、UART 和 ADC 等,一應俱全。以 GPIO 操作為例,在使用標準外設庫時,開發者只需通過簡單的函數調用,如GPIO_Init()函數,就可以輕松配置 GPIO 的工作模式、速度和上下拉電阻等參數 ,無需深入了解底層寄存器的復雜操作。這種方式極大地提高了開發效率,讓開發者能夠將更多的精力集中在應用層的邏輯設計上。而且,標準外設庫的 API 設計巧妙地遵循了面向對象的編程思想,使得代碼結構清晰、易于理解和維護。例如,在對定時器進行配置時,開發者可以通過一系列相關的函數和結構體,清晰地設置定時器的時鐘源、分頻系數、計數模式等關鍵參數,從而實現精確的定時控制。

HAL 庫,即 Hardware Abstraction Layer(硬件抽象層),則是 ST 公司主推的一款更高級的開發庫,它像是一位貼心的助手,將底層硬件操作巧妙地封裝起來,以高級函數調用的形式呈現給開發者。這使得開發過程變得異常簡單,即使是對硬件底層知識了解有限的開發者,也能快速上手。以串口通信為例,在 HAL 庫中,初始化串口只需定義一個UART_HandleTypeDef類型的句柄,然后調用HAL_UART_Init()函數進行初始化配置即可 。在數據收發時,使用HAL_UART_Transmit()和HAL_UART_Receive()函數就能輕松實現數據的發送和接收,大大簡化了開發流程。而且,HAL 庫具有出色的跨平臺支持能力,它允許開發者在不同型號的 STM32 微控制器上使用相同的 API 進行開發,這不僅提高了代碼的可移植性和復用性,還能有效減少重復開發工作,為開發者節省大量的時間和精力。

STM32CubeMX 工具則是一款極具創新性的圖形化配置工具,它為 STM32 外設開發帶來了前所未有的便捷體驗,仿佛是為開發者打開了一扇通往高效開發的魔法之門。通過直觀的圖形界面,開發者可以像搭建積木一樣,輕松地配置 STM32 微控制器的引腳、時鐘樹、電源設置以及各種外設。在配置 GPIO 時,只需在圖形界面中點擊相應的引腳,即可選擇其工作模式、輸出類型和上下拉電阻等參數 ,操作簡單直觀,無需手動查閱復雜的數據手冊。更令人驚喜的是,STM32CubeMX 能夠根據用戶的配置,自動生成高度優化的初始化 C 代碼,并且這些代碼能夠完美兼容 IAR、Keil 以及 STM32CubeIDE 等主流編譯環境,極大地加速了軟件開發的前期準備階段,讓開發者能夠更快地將精力投入到核心功能的開發中。

外設配置基礎步驟

在 STM32 的世界里,要讓各個外設正常工作,就需要按照一定的步驟進行精心配置,這就如同搭建一座高樓,每一步都至關重要。

使能外設時鐘是開啟外設工作的第一步,就像為機器注入動力。在 STM32 中,每個外設都有獨立的時鐘控制,這樣的設計可以有效降低系統功耗,當某個外設暫時不需要使用時,關閉其時鐘即可。以 GPIO 外設為例,假設要使用 GPIOA 端口,就需要通過 RCC(復位和時鐘控制)寄存器來使能 GPIOA 的時鐘。在標準外設庫中,可以使用RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);函數來實現;在 HAL 庫中,則可以使用__HAL_RCC_GPIOA_CLK_ENABLE();宏定義來完成這一操作 。這一步驟的原理是,時鐘信號就如同外設運行的脈搏,只有在時鐘信號的驅動下,外設內部的寄存器才能正常工作,從而實現各種功能。

配置引腳功能是外設配置的關鍵環節,它決定了引腳的用途。STM32 的引腳具有豐富的復用功能,一個引腳可以作為普通 GPIO 使用,也可以復用為其他外設的功能引腳,如串口、SPI、定時器等。在配置引腳功能時,需要根據具體的應用需求,通過復用器來配置引腳。比如,要將 PA0 引腳配置為串口通信的 TX 引腳,在標準外設庫中,需要先配置 GPIO 的模式為復用推挽輸出,然后設置復用功能寄存器,使 PA0 引腳復用為串口功能;在 HAL 庫中,可以通過GPIO_InitTypeDef結構體來配置引腳的模式、速度和復用功能等參數,然后調用HAL_GPIO_Init()函數進行初始化 。這一過程就像是為引腳選擇了一條特定的工作路徑,使其能夠準確地實現相應的功能。

配置外設控制寄存器是實現外設功能的核心步驟,它就像是為外設設定工作規則。不同的外設具有不同的控制寄存器,這些寄存器用于設置外設的各種工作參數。以定時器為例,需要配置定時器的預分頻器、自動重裝載寄存器、計數模式等參數。在標準外設庫中,通過TIM_TimeBaseInit()函數來配置定時器的基本參數;在 HAL 庫中,則使用HAL_TIM_Base_Init()函數來完成這一操作 。通過合理配置這些寄存器,定時器就能夠按照設定的時間間隔產生中斷或輸出 PWM 信號,實現精確的時間控制和信號生成。

深入剖析:常見外設應用實例

GPIO:最基礎的數字接口

GPIO 作為 STM32 最基礎的外設,其應用極為廣泛。以控制 LED 燈為例,這是學習 GPIO 的入門級應用。在硬件連接上,將 LED 的陰極接地,陽極通過限流電阻連接到 STM32 的 GPIO 引腳 。在軟件配置方面,使用 HAL 庫時,首先要定義一個GPIO_InitTypeDef結構體變量,用于配置 GPIO 的參數。例如:

GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA時鐘
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

上述代碼中,先使能了 GPIOA 的時鐘,然后對 GPIOA 的引腳 5 進行配置,將其模式設置為推挽輸出模式,無上拉下拉電阻,速度設置為低速。之后,通過HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);函數即可控制 LED 燈的點亮,使用HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);函數則可控制 LED 燈熄滅。

讀取按鍵狀態也是 GPIO 的常見應用。在硬件連接上,將按鍵的一端連接到 STM32 的 GPIO 引腳,另一端接地或接高電平。以按鍵一端接地為例,當按鍵未按下時,GPIO 引腳為高電平;當按鍵按下時,GPIO 引腳被拉低為低電平。在軟件配置上,同樣使用GPIO_InitTypeDef結構體進行配置,不過此時模式應設置為輸入模式。例如:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

在上述代碼中,將 GPIOA 的引腳 0 配置為輸入模式,并使能上拉電阻,這樣在按鍵未按下時,引腳處于高電平狀態。在主程序中,可以通過HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)函數來讀取按鍵狀態,若返回值為GPIO_PIN_RESET,則表示按鍵被按下 。

定時器:精準時間掌控者

定時器在 STM32 的應用中起著至關重要的作用,其原理基于計數器對時鐘信號進行計數。當計數器的值達到預設的自動重裝載值時,就會產生溢出事件,進而觸發中斷或執行其他預設操作。

定時中斷是定時器的常見應用之一。以 STM32 的通用定時器 TIM3 為例,使用 HAL 庫進行配置。首先,需要使能 TIM3 的時鐘,代碼如下:

__HAL_RCC_TIM3_CLK_ENABLE();

然后,定義一個TIM_HandleTypeDef結構體變量,用于配置 TIM3 的參數,如預分頻器、自動重裝載值、計數模式等。例如:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 7199;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 9999;htim3.Init.ClockDivision = 0;if (HAL_TIM_Base_Init(&htim3)!= HAL_OK){Error_Handler();}

在上述代碼中,將 TIM3 的預分頻器設置為 7199,這樣經過預分頻后,定時器的時鐘頻率為 1kHz(假設系統時鐘為 72MHz) ;計數模式設置為向上計數模式;自動重裝載值設置為 9999,意味著定時器每 10000 個時鐘周期產生一次溢出中斷,即定時時間為 1 秒。接下來,配置中斷優先級并使能中斷:

HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);HAL_NVIC_EnableIRQ(TIM3_IRQn);HAL_TIM_Base_Start_IT(&htim3);

在中斷服務函數中,可以編寫需要定時執行的代碼,例如控制 LED 燈的閃爍:

void TIM3_IRQHandler(void){HAL_TIM_IRQHandler(&htim3);}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){if (htim->Instance == TIM3){HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);}}

上述代碼中,當 TIM3 的定時時間到達時,會進入中斷服務函數TIM3_IRQHandler,進而調用HAL_TIM_PeriodElapsedCallback函數,在該函數中通過HAL_GPIO_TogglePin函數實現 GPIOA 引腳 5 的電平翻轉,從而控制連接在該引腳上的 LED 燈閃爍。

PWM 輸出也是定時器的重要應用。在電機調速、燈光亮度調節等場景中,PWM 技術被廣泛應用。同樣以 TIM3 為例,配置其通道 1 輸出 PWM 信號。首先,除了使能 TIM3 時鐘外,還需要使能相關 GPIO 的時鐘,因為 PWM 輸出需要使用特定的 GPIO 引腳。假設使用 PA6 引腳作為 TIM3 通道 1 的 PWM 輸出引腳:

__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引腳為復用功能輸出模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_6;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接著,配置 TIM3 的 PWM 模式,包括預分頻器、自動重裝載值、計數模式以及 PWM 模式等:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 71;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 999;htim3.Init.ClockDivision = 0;if (HAL_TIM_PWM_Init(&htim3)!= HAL_OK){Error_Handler();}

在上述代碼中,預分頻器設置為 71,自動重裝載值設置為 999,此時 PWM 信號的頻率為 1kHz(假設系統時鐘為 72MHz) 。最后,配置 PWM 的占空比,并啟動 PWM 輸出:

TIM_OC_InitTypeDef sConfigOC;sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 500;sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1)!= HAL_OK){Error_Handler();}HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

上述代碼中,將 PWM 模式設置為 PWM1 模式,占空比設置為 50%(通過Pulse的值為 500,自動重裝載值為 999 計算得出) ,極性設置為高電平有效,然后啟動 TIM3 通道 1 的 PWM 輸出。通過調整Pulse的值,就可以改變 PWM 信號的占空比,從而實現對電機轉速或燈光亮度的控制。

串口通信:數據傳輸的橋梁

串口通信是 STM32 與外部設備進行數據傳輸的常用方式之一,其原理是通過 TX(發送)和 RX(接收)引腳,按照一定的波特率、數據位、停止位和校驗位等參數,將數據一位一位地進行傳輸。

在 STM32 中配置串口通信,以 USART1 為例,使用 HAL 庫時,首先需要使能 USART1 和相關 GPIO 的時鐘。假設 USART1 的 TX 引腳為 PA9,RX 引腳為 PA10:

__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引腳為復用功能模式,分別設置 TX 引腳為復用推挽輸出,RX 引腳為浮空輸入:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF7_USART1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接著,配置 USART1 的參數,包括波特率、數據位、停止位、校驗位等:

UART_HandleTypeDef huart1;huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1)!= HAL_OK){Error_Handler();}

在上述代碼中,將波特率設置為 115200,數據位設置為 8 位,停止位設置為 1 位,無校驗位,工作模式為收發模式,無硬件流控制,過采樣率設置為 16 倍。配置完成后,就可以使用HAL_UART_Transmit函數發送數據,使用HAL_UART_Receive函數接收數據。例如,發送一個字符串:

uint8_t tx_data[] = "Hello, STM32!";HAL_UART_Transmit(&huart1, tx_data, sizeof(tx_data), HAL_MAX_DELAY);

接收數據時,可以定義一個接收緩沖區,然后使用HAL_UART_Receive函數進行接收:


uint8_t rx_data[10];HAL_UART_Receive(&huart1, rx_data, sizeof(rx_data), HAL_MAX_DELAY);

在實際應用中,還可以通過中斷方式來處理串口數據的接收和發送,以提高系統的實時性。例如,配置 USART1 的接收中斷:

HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);HAL_UART_Receive_IT(&huart1, rx_data, 1);

在中斷服務函數USART1_IRQHandler中,處理接收到的數據:

void USART1_IRQHandler(void){HAL_UART_IRQHandler(&huart1);}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if (huart->Instance == USART1){// 處理接收到的數據HAL_UART_Receive_IT(&huart1, rx_data, 1);}}

上述代碼中,當接收到一個字節的數據后,會進入中斷服務函數USART1_IRQHandler,進而調用HAL_UART_RxCpltCallback函數,在該函數中可以對接收到的數據進行處理,然后再次啟動接收中斷,以便接收下一個字節的數據。

ADC:模擬世界的數字化窗口

ADC(Analog - to - Digital Converter)即模擬數字轉換器,其工作原理是將連續變化的模擬信號轉換為離散的數字信號,以便微控制器進行處理。在 STM32 中,ADC 模塊通過采樣保持電路對模擬輸入信號進行采樣,然后利用逐次逼近寄存器(SAR)將采樣得到的模擬電壓值轉換為對應的數字值。

以電壓采集為例,介紹 ADC 的配置和數據處理方法。首先,需要使能 ADC 和相關 GPIO 的時鐘。假設使用 PA0 引腳作為 ADC 的輸入通道:

__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();

然后,配置 GPIO 引腳為模擬輸入模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

接著,配置 ADC 的參數,包括分辨率、采樣時間、轉換模式等:

ADC_HandleTypeDef hadc1;hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion = 1;if (HAL_ADC_Init(&hadc1)!= HAL_OK){Error_Handler();}

在上述代碼中,將 ADC 的時鐘預分頻器設置為 4,分辨率設置為 12 位,關閉掃描模式、連續轉換模式和不連續轉換模式,無外部觸發轉換,數據對齊方式設置為右對齊,轉換通道數設置為 1。接下來,配置 ADC 的通道:

ADC_ChannelConfTypeDef sConfig;sConfig.Channel = ADC_CHANNEL_0;sConfig.Rank = 1;sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig)!= HAL_OK){Error_Handler();}

在上述代碼中,將 ADC 的通道 0 配置為要轉換的通道,采樣時間設置為 56 個周期。配置完成后,就可以啟動 ADC 轉換,并讀取轉換結果:

if (HAL_ADC_Start(&hadc1)!= HAL_OK){Error_Handler();}HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);uint16_t adc_value = HAL_ADC_GetValue(&hadc1);

在上述代碼中,首先啟動 ADC 轉換,然后通過HAL_ADC_PollForConversion函數等待轉換完成,最后使用HAL_ADC_GetValue函數讀取轉換結果。得到的adc_value即為轉換后的數字值,該值與輸入的模擬電壓值成正比關系。假設參考電壓為 3.3V,那么可以通過以下公式將數字值轉換為實際的電壓值:

float voltage = (float)adc_value * 3.3f / 4096.0f;

上述公式中,4096 是 12 位 ADC 的滿量程數字值(\(2^{12}\)) ,通過該公式可以將 ADC 轉換得到的數字值轉換為對應的實際電壓值,從而實現對模擬電壓的精確測量和處理。

進階之路:外設驅動開發與優化

驅動開發步驟

在 STM32 外設開發中,驅動程序的編寫是實現硬件功能的關鍵環節。以 HAL 庫為例,其驅動開發步驟嚴謹且有序,為開發者提供了清晰的思路和方法。

確定外設類型是驅動開發的首要任務。在項目開始前,開發者需要深入了解目標外設的特性和需求,這就如同探險家在出發前要明確目的地的特點一樣。例如,當開發一個基于 STM32 的智能溫度控制系統時,需要使用 ADC 外設來采集溫度傳感器的模擬信號,此時就需要仔細查閱 ADC 外設的數據手冊,了解其寄存器的地址、位域描述以及各種功能特性,從而為后續的開發工作奠定堅實的基礎。

創建驅動程序文件是使代碼結構清晰、易于維護的重要舉措。為每個外設創建獨立的.c和.h文件,就像為每個工具打造一個專屬的收納盒,方便管理和使用。比如在開發 SPI 外設驅動時,在工程目錄中新建spi_driver.c和spi_driver.h文件 。在spi_driver.h文件中,主要聲明函數接口與宏定義,如:

#ifndef __SPI_DRIVER_H#define __SPI_DRIVER_Hvoid SPI_Init(void);void SPI_Transmit(uint8_t *data, uint16_t len);void SPI_Receive(uint8_t *data, uint16_t len);#endif

在spi_driver.c文件中,則實現具體的功能,包括包含頭文件、定義相關變量以及實現函數功能等,如下所示:

#include "spi_driver.h"#include "stm32f4xx_hal.h"SPI_HandleTypeDef hspi;void SPI_Init(void){hspi.Instance = SPI1;hspi.Init.Mode = SPI_MODE_MASTER;hspi.Init.Direction = SPI_DIRECTION_2LINES;hspi.Init.DataSize = SPI_DataSize_8BIT;hspi.Init.CLKPolarity = SPI_POLARITY_LOW;hspi.Init.CLKPhase = SPI_PHASE_1EDGE;hspi.Init.NSS = SPI_NSS_SOFT;hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi.Init.TIMode = SPI_TIMODE_DISABLE;hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi)!= HAL_OK){Error_Handler();}}void SPI_Transmit(uint8_t *data, uint16_t len){HAL_SPI_Transmit(&hspi, data, len, HAL_MAX_DELAY);}void SPI_Receive(uint8_t *data, uint16_t len){HAL_SPI_Receive(&hspi, data, len, HAL_MAX_DELAY);}

配置外設時鐘是確保外設正常工作的關鍵步驟。使用 RCC(Reset and Clock Control)庫函數來配置外設的時鐘源和分頻系數,就像為機器調整合適的動力供應。以 GPIO 外設為例,使用__HAL_RCC_GPIOA_CLK_ENABLE()宏定義來啟用 GPIOA 外設的時鐘 ,確保 GPIOA 端口能夠正常工作。在配置時鐘時,需要根據外設的工作頻率要求,合理設置分頻系數,以保證外設的穩定運行。

初始化外設是讓外設按照預期工作模式運行的重要操作。使用 HAL 庫函數提供的初始化函數,根據外設的功能需求,配置其工作模式、輸入輸出模式、中斷設置等參數。例如,對于 GPIO 外設,使用HAL_GPIO_Init()函數來配置 GPIO 引腳的模式和上下拉設置。假設要將 PA0 引腳配置為輸出模式,無上拉下拉電阻,速度為低速,代碼如下:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

配置外設寄存器是實現外設特定功能的核心步驟。使用 HAL 庫函數提供的寄存器操作函數來讀寫外設寄存器,根據外設的工作模式和需求,設置相應的寄存器位。例如,對于定時器外設,使用HAL_TIM_Base_Init()函數來配置定時器的基本參數,如預分頻器、自動重裝載值、計數模式等 ,然后使用HAL_TIM_Base_Start()函數啟動定時器。假設要配置 TIM3 定時器,使其定時時間為 1 秒,代碼如下:

TIM_HandleTypeDef htim3;htim3.Instance = TIM3;htim3.Init.Prescaler = 7199;htim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 9999;htim3.Init.ClockDivision = 0;if (HAL_TIM_Base_Init(&htim3)!= HAL_OK){Error_Handler();}HAL_TIM_Base_Start(&htim3);

實現數據傳輸功能是許多外設的重要任務。對于需要進行數據傳輸的外設,如 SPI 和 UART 等,使用 HAL 庫函數提供的數據傳輸函數來實現數據的發送和接收。這些函數通常包括緩沖區管理、數據傳輸中斷處理和錯誤處理等功能,確保數據傳輸的穩定和可靠。例如,在使用 SPI 進行數據傳輸時,使用SPI_Transmit和SPI_Receive函數來發送和接收數據;在使用 UART 進行數據傳輸時,使用HAL_UART_Transmit和HAL_UART_Receive函數來實現數據的收發。

實現中斷處理函數是使外設能夠及時響應外部事件的關鍵。使用 HAL 庫函數提供的中斷處理函數來實現中斷的配置和處理,當外設產生中斷時,能夠及時調用相應的回調函數進行處理。例如,對于定時器外設,使用HAL_TIM_PeriodElapsedCallback()函數作為定時器溢出中斷的回調函數 ,在該函數中編寫需要在中斷發生時執行的代碼。

提供用戶接口函數是方便用戶使用外設的重要手段。為了讓用戶能夠更便捷地操作外設,提供一組簡單的接口函數來封裝并抽象外設驅動程序的功能,這些接口函數可以實現常見的操作,如初始化、讀取、寫入等。用戶通過調用這些接口函數,無需了解底層的驅動程序實現細節,就能輕松操作外設。例如,在上述 SPI 驅動中,提供SPI_Init、SPI_Transmit和SPI_Receive等接口函數,用戶只需調用這些函數,就能實現 SPI 外設的初始化、數據發送和接收等功能。

測試和調試是確保驅動程序正確性和穩定性的重要環節。完成外設驅動程序的編寫后,通過編寫測試代碼和使用調試工具,如示波器、邏輯分析儀等,對驅動程序進行全面的測試和調試,確保外設在不同工作模式、各種輸入條件和異常情況下都能正常工作。在測試過程中,仔細檢查外設的工作狀態、數據傳輸的準確性以及中斷處理的及時性等,及時發現并解決問題。

優化策略

在 STM32 外設開發中,優化驅動程序對于提升系統性能、降低功耗以及增強穩定性至關重要。以下將深入探討降低功耗、優化算法、合理配置中斷優先級等優化策略。

降低功耗是許多嵌入式系統開發中的關鍵目標,尤其是在電池供電或對功耗有嚴格要求的應用場景中。STM32 微控制器提供了多種低功耗模式,如睡眠模式、停止模式和待機模式,開發者可以根據系統的工作狀態,靈活選擇合適的低功耗模式。在智能手環等可穿戴設備中,當設備處于閑置狀態時,可將 STM32 微控制器切換到停止模式,此時 CPU 停止運行,大部分外設時鐘被關閉,僅保留最低限度的系統功能,從而顯著降低功耗。除了選擇低功耗模式,還可以通過關閉不必要的外設時鐘來減少功耗。在一個基于 STM32 的智能家居控制系統中,當某個時間段內不需要使用 SPI 通信時,可通過__HAL_RCC_SPIx_CLK_DISABLE()函數關閉 SPI 外設的時鐘,避免不必要的功耗浪費。

優化算法是提高驅動程序效率和性能的重要手段。在數據處理過程中,選擇合適的算法可以顯著減少計算量和執行時間。在數字濾波算法中,采用高效的濾波算法,如卡爾曼濾波算法,相比簡單的均值濾波算法,能夠更有效地去除噪聲干擾,同時減少計算量,提高系統的實時性。此外,還可以通過優化代碼結構,減少不必要的循環和條件判斷,提高代碼的執行效率。在一個控制電機轉速的程序中,將一些固定的計算結果提前計算并存儲,避免在循環中重復計算,從而提高程序的執行速度。

合理配置中斷優先級是確保系統實時性和穩定性的關鍵。在多中斷源的系統中,不同的中斷具有不同的緊急程度和重要性。通過合理分配中斷優先級,可以保證重要的中斷能夠及時得到響應,避免因低優先級中斷的干擾而導致系統響應延遲。在一個工業自動化控制系統中,將外部設備的緊急故障中斷設置為高優先級,而將一些定期的數據采集中斷設置為低優先級,這樣當出現緊急故障時,系統能夠立即響應并進行處理,保障系統的安全運行。同時,在中斷處理函數中,應盡量減少處理時間,避免長時間占用 CPU 資源,影響其他中斷的響應。

使用 DMA(直接內存訪問)技術可以有效減輕 CPU 的負擔,提高數據傳輸效率。在數據量較大的傳輸場景中,如將大量數據從內存傳輸到外設或從外設讀取大量數據到內存時,使用 DMA 可以實現數據的直接傳輸,無需 CPU 頻繁參與,從而使 CPU 能夠專注于其他重要任務。在一個圖像采集系統中,使用 DMA 將圖像傳感器采集到的數據直接傳輸到內存中,CPU 可以在 DMA 傳輸數據的同時,進行圖像的預處理和分析等工作,大大提高了系統的整體性能。

實戰演練:綜合項目開發

項目背景與需求分析

在當今科技飛速發展的時代,人們對生活和工作環境的質量要求越來越高,智能環境監測系統應運而生。本項目旨在開發一款基于 STM32 的智能環境監測系統,以滿足對環境參數實時監測和智能控制的需求。

該系統需要具備實時采集多種環境參數的功能,包括溫度、濕度、空氣質量(如有害氣體濃度)、光照強度等。通過高精度的傳感器,將這些環境參數轉化為電信號,再由 STM32 微控制器進行處理。當監測到某些環境參數超出預設的正常范圍時,系統要能夠及時發出警報,提醒用戶采取相應措施。例如,當室內溫度過高或過低、濕度過大或過小、有害氣體濃度超標時,系統可以通過蜂鳴器、指示燈或手機短信等方式通知用戶,保障用戶的健康和安全。

為了實現數據的遠程監控和管理,系統還需具備數據傳輸功能。通過 Wi-Fi 模塊或其他無線通信方式,將采集到的環境數據上傳至云端服務器或用戶的手機 APP,用戶可以隨時隨地通過手機或電腦查看實時環境數據和歷史數據,方便對環境狀況進行分析和決策。同時,系統要能夠對采集到的大量環境數據進行存儲,以便后續查詢和分析。可以使用外部存儲器,如 SD 卡,來存儲數據,確保數據的安全性和完整性。

硬件設計與選型

在硬件設計方面,STM32 微控制器作為整個系統的核心,猶如大腦一般,負責數據的處理和各個外設的控制。它需要與多種傳感器和其他外部設備進行連接,以實現環境參數的采集和數據的傳輸。

DHT11 溫濕度傳感器是采集溫度和濕度的理想選擇,它具有成本低、精度較高、響應速度快等優點。其工作原理是通過內部的電容式感濕元件和熱敏電阻,將環境中的濕度和溫度變化轉化為數字信號輸出。在硬件連接上,將 DHT11 的 VCC 引腳連接到 STM32 的 3.3V 電源引腳,GND 引腳連接到 STM32 的接地引腳,數據引腳連接到 STM32 的一個 GPIO 引腳,如 PA0,用于數據的傳輸。

MQ-135 氣體傳感器可用于檢測空氣中的有害氣體濃度,如氨氣、硫化物、苯系蒸汽等。它的工作原理基于氣敏材料二氧化錫(SnO2),當環境中存在有害氣體時,氣敏材料的電導率會發生變化,從而通過檢測電路將其轉化為電信號輸出。在硬件連接上,將 MQ-135 的 VCC 引腳連接到 STM32 的 5V 電源引腳(因為其工作電壓通常為 5V),GND 引腳連接到 STM32 的接地引腳,信號輸出引腳連接到 STM32 的 ADC 引腳,如 PA1,以便 STM32 能夠采集模擬信號并進行 A/D 轉換。

BH1750 光強度傳感器能夠精確檢測環境光強度,它采用 I2C 通信接口,具有低功耗、高精度的特點。在硬件連接上,將 BH1750 的 VCC 引腳連接到 STM32 的 3.3V 電源引腳,GND 引腳連接到 STM32 的接地引腳,SCL(時鐘線)引腳連接到 STM32 的 I2C 接口的時鐘引腳,如 PB6,SDA(數據線)引腳連接到 STM32 的 I2C 接口的數據引腳,如 PB7,通過 I2C 通信協議與 STM32 進行數據傳輸。

OLED 顯示屏用于實時顯示環境參數,它具有自發光、對比度高、視角廣、功耗低等優點。同樣采用 I2C 通信接口,在硬件連接上,與 BH1750 類似,將 OLED 的 VCC 引腳連接到 STM32 的 3.3V 電源引腳,GND 引腳連接到 STM32 的接地引腳,SCL 和 SDA 引腳分別連接到 STM32 的 I2C 接口的相應引腳,如 PB6 和 PB7,方便 STM32 將處理后的環境數據顯示在 OLED 屏幕上,供用戶直觀查看。

ESP8266 Wi-Fi 模塊則負責實現數據的無線傳輸功能,它可以將 STM32 采集到的環境數據通過 Wi-Fi 網絡上傳至云端服務器或用戶的手機 APP。在硬件連接上,將 ESP8266 的 TX 引腳連接到 STM32 的 USART 串口的 RX 引腳,如 PA10,RX 引腳連接到 STM32 的 USART 串口的 TX 引腳,如 PA9,VCC 引腳連接到 STM32 的 3.3V 電源引腳,GND 引腳連接到 STM32 的接地引腳,通過串口通信實現數據的傳輸。

軟件實現與調試

軟件架構設計采用模塊化的思想,將整個系統的軟件功能劃分為多個獨立的模塊,每個模塊負責特定的功能,如傳感器驅動模塊、數據處理模塊、通信模塊和顯示模塊等。這種設計方式使得代碼結構清晰,易于維護和擴展。

在傳感器驅動模塊中,針對不同的傳感器,編寫相應的驅動代碼。以 DHT11 溫濕度傳感器為例,使用 HAL 庫實現其驅動。首先,初始化與 DHT11 連接的 GPIO 引腳為輸入輸出模式:

GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

然后,編寫讀取 DHT11 數據的函數。DHT11 的數據傳輸采用單總線協議,需要嚴格按照時序進行操作。以下是讀取一個字節數據的函數示例:

uint8_t DHT11_ReadByte(void){uint8_t i, byte = 0;for (i = 0; i < 8; i++){while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);HAL_Delay(30);if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET){byte |= (1 << (7 - i));while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);}}return byte;}

在數據處理模塊中,對傳感器采集到的數據進行濾波、校準等處理,以提高數據的準確性。例如,對于溫度數據,可以采用滑動平均濾波算法,去除噪聲干擾。假設有一個長度為 5 的溫度數據緩沖區temperature_buf,當前采集到的溫度數據為new_temperature,滑動平均濾波的代碼實現如下:

static uint8_t index = 0;static float temperature_buf[5];temperature_buf[index] = new_temperature;index = (index + 1) % 5;float sum = 0;for (uint8_t i = 0; i < 5; i++){sum += temperature_buf[i];}float filtered_temperature = sum / 5;

通信模塊負責實現與 Wi-Fi 模塊的數據傳輸以及與云端服務器或手機 APP 的通信。使用 ESP8266 Wi-Fi 模塊時,通過串口發送 AT 指令來配置其工作模式、連接 Wi-Fi 網絡以及上傳數據。以下是配置 ESP8266 連接 Wi-Fi 網絡的代碼示例:

void ESP8266_ConnectWiFi(const char *ssid, const char *password){char command[50];sprintf(command, "AT+CWJAP=\"%s\",\"%s\"\r\n", ssid, password);HAL_UART_Transmit(&huart1, (uint8_t *)command, strlen(command), HAL_MAX_DELAY);// 等待連接成功的響應uint8_t response[100];HAL_UART_Receive(&huart1, response, sizeof(response), HAL_MAX_DELAY);// 處理響應數據,判斷是否連接成功}

顯示模塊負責將處理后的數據顯示在 OLED 顯示屏上。使用 OLED 的驅動庫,編寫顯示函數。例如,顯示溫度數據的函數如下:

void OLED_ShowTemperature(float temperature){char temp_str[10];sprintf(temp_str, "Temp: %.1f C", temperature);OLED_ShowString(0, 0, temp_str);}

在調試過程中,使用示波器、邏輯分析儀等工具來檢測硬件信號的正確性,通過串口調試助手查看傳感器數據和通信數據,及時發現并解決問題。例如,在調試 DHT11 傳感器時,使用示波器觀察其數據引腳的時序,確保數據傳輸的正確性;在調試 Wi-Fi 模塊時,通過串口調試助手查看 AT 指令的響應,判斷模塊是否正常工作以及網絡連接是否成功。

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

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

相關文章

大模型AI平臺DeepSeek 眼中的SQL2API平臺:QuickAPI、dbapi 和 Magic API 介紹與對比

目錄 1 QuickAPI 介紹 2 dbapi 介紹 3 Magic API 介紹 4 簡單對比 5 總結 統一數據服務平臺是一種低代碼的方式&#xff0c;實現一般是通過SQL能直接生成數據API&#xff0c;同時能對產生的數據API進行全生命周期的管理&#xff0c;典型的SQL2API的實現模式。 以下是針對…

人工智能之數學基礎:對線性代數中逆矩陣的思考?

本文重點 逆矩陣是線性代數中的一個重要概念,它在線性方程組、矩陣方程、動態系統、密碼學、經濟學和金融學以及計算機圖形學等領域都有廣泛的應用。通過了解逆矩陣的定義、性質、計算方法和應用,我們可以更好地理解和應用線性代數知識,解決各種實際問題。 關于逆矩陣的思…

[傻瓜式教學]如何將MathType公式編輯器內嵌到WPS工具欄中

[傻瓜式教學]如何將MathType公式編輯器內嵌到WPS工具欄中 將MathType公式編輯器內嵌到WPS工具欄中 下載好所需文件 我用夸克網盤分享了「mathtype安裝教程超簡單易上手.zip」&#xff0c;點擊鏈接即可保存。打開「夸克APP」 鏈接&#xff1a;https://pan.quark.cn/s/4726c684…

WPF框架---MvvmLight介紹

目錄 1. MvvmLight 框架準備 2. MvvmLight 中的相關基類 3. MvvmLight 中的數據綁定與通知 a. 核心功能 b. 關鍵方法與屬性 c. 完整示例 d. 高級用法 4. MvvmLight 中的命令對象 a. 命令對象的作用 b. 核心接口&#xff1a;ICommand c. MvvmLight 中的 RelayCommand…

【Linux】線程同步與互斥

線程同步與互斥 一.線程互斥1.互斥相關概念2.互斥鎖 Mutex3.互斥鎖接口4.互斥鎖實現原理5.互斥鎖封裝 二.線程同步1.同步相關概念2.條件變量 Condition Variable3.條件變量接口4.條件變量封裝5.信號量 Semaphore6.信號量接口7.信號量封裝8.生產者 - 消費者模型1.基于 Blocking …

URIError: URI malformed

&#x1f90d; 前端開發工程師、技術日更博主、已過CET6 &#x1f368; 阿珊和她的貓_CSDN博客專家、23年度博客之星前端領域TOP1 &#x1f560; 牛客高級專題作者、打造專欄《前端面試必備》 、《2024面試高頻手撕題》、《前端求職突破計劃》 &#x1f35a; 藍橋云課簽約作者、…

linux c++11 gcc4 環境編譯安裝googletest/gtest v1.10

c11對應googletest/gtest 經過測試&#xff0c;c11對應版本是googletest v1.10.x 編譯安裝 編譯環境 sudo apt-get update sudo apt-get install -y build-essential cmake下載或git clone代碼 git clone https://github.com/google/googletest.git cd googletest git che…

鴻蒙與DeepSeek深度整合:構建下一代智能操作系統生態

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到網站。 https://www.captainbed.cn/north 目錄 技術融合背景與價值鴻蒙分布式架構解析DeepSeek技術體系剖析核心整合架構設計智能調度系統實現…

極狐GitLab 17.9 正式發布,40+ DevSecOps 重點功能解讀【二】

GitLab 是一個全球知名的一體化 DevOps 平臺&#xff0c;很多人都通過私有化部署 GitLab 來進行源代碼托管。極狐GitLab 是 GitLab 在中國的發行版&#xff0c;專門為中國程序員服務。可以一鍵式部署極狐GitLab。 學習極狐GitLab 的相關資料&#xff1a; 極狐GitLab 官網極狐…

LeetCode - 28 找出字符串中第一個匹配項的下標

題目來源 28. 找出字符串中第一個匹配項的下標 - 力扣&#xff08;LeetCode&#xff09; 題目解析 暴力解法 本題如果采用暴力解法的話&#xff0c;可以定義兩個指針 i&#xff0c;j&#xff0c;其中 i 指針用于掃描 S&#xff08;haystack&#xff09;串&#xff0c;j 指針…

Spring Boot 異步編程

文章目錄 一、異步方法的使用1. 開啟異步支持2. 定義異步方法3. 調用異步方法踩坑記錄心得體會 二、線程池配置1. 自定義線程池2. 使用自定義線程池踩坑記錄心得體會 三、異步任務的監控與管理1. 日志記錄2. 異常處理3. 線程池監控踩坑記錄心得體會 在現代應用程序開發中&#…

0.大模型開發知識點需求綜述

文章目錄 一、機器學習與深度學習基礎二、自然語言處理&#xff08;NLP&#xff09;基礎三、大模型架構四、訓練優化技術五、數據處理與預處理六、分布式訓練與并行化策略七、微調方法與參數高效微調八、訓練框架、工具與自動化流程九、評估與部署十、前沿技術與未來趨勢 已更新…

docker目錄掛載與卷映射的區別

在 Docker 中&#xff0c;目錄掛載&#xff08;Bind Mount&#xff09;和卷映射&#xff08;Volume Mount&#xff09;的命令語法差異主要體現在路徑格式上&#xff0c;具體表現為是否以斜杠&#xff08;/&#xff09;開頭。以下是兩者的核心區別及使用場景的總結&#xff1a; …

[Java基礎-線程篇]7_線程設計模式與總結

摘要&#xff1a;懶漢單例模式怎么變得線程安全&#xff1f;Master-Worker歸并模式&#xff0c;工作竊取算法。Java線程相關源碼使用了什么設計模式&#xff1f; 資料引用&#xff1a;《Java高并發核心編程卷2》 目錄 線程安全的單例模式 Master-Worker模式 工作竊取算法 …

在【k8s】中部署Jenkins的實踐指南

&#x1f407;明明跟你說過&#xff1a;個人主頁 &#x1f3c5;個人專欄&#xff1a;《Kubernetes航線圖&#xff1a;從船長到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目錄 一、引言 1、Jenkins簡介 2、k8s簡介 3、什么在…

代碼隨想錄算法營Day59 | 尋找存在的路徑, 冗余連接,冗余連接II

尋找存在的路徑 這題使用并查集即可。并查集加路徑壓縮。 #include <iostream> using namespace std; int find(int* father,int u){return father[u] u ? u : father[u] find(father,father[u]); }bool isSame(int* father,int u,int v){return find(father,u) fi…

正則表達式(2)匹配規則

正則表達式的匹配規則定義了如何識別字符串中的特定模式。這些規則包括字符類匹配、元字符匹配、數量詞、字符轉義和分組。 字符類匹配 字符類匹配允許你指定一個字符集合&#xff0c;并匹配該集合中的任意單個字符。這是通過方括號 [] 來實現的。 簡單字符類&#xff1a;[abc…

【QWEN】機器人控制器的控制周期越短精度越高嗎

好的&#xff0c;用戶問的是“機器人控制器的控制周期越短精度越高嗎”。我需要根據提供的知識庫內容來回答這個問題。首先&#xff0c;我得回憶一下知識庫里的相關信息。 知識庫里有幾篇相關的文章。比如&#xff0c;[3]提到控制周期越短&#xff0c;控制性能的上限越高&…

[總概]Vue2/3React Diff算法

根據搜索結果,大部分文檔都詳細描述了Vue的Diff算法原理、優化策略以及實現細節。例如,網頁1詳細介紹了Vue Diff算法的核心設計,包括雙端比較和key的作用;Vue3中的快速Diff算法; 通常,解釋一個算法可以從其基本原理、核心策略、優化手段、源碼實現以及應用場景等方面展開…

【MySQL_03】數據庫基本--核心概念

文章目錄 一、數據庫基礎1.1 數據庫基礎定義1.2 數據庫分類與典型產品1.3 數據庫模型1.4 數據庫層次結構1.5 數據庫核心機制1.6 數據表和視圖1.61 數據表&#xff08;Table&#xff09;1.62 視圖&#xff08;View&#xff09; 1.7 鍵類型1.8 MySQL數據類型1.9 數據庫范式化 二、…