嵌入式開發STM32 -- 江協科技筆記

1.背景介紹及基礎認知

8大輸入輸出

斯密特觸發器:高于設定閾值輸出高電平,低于設定閾值輸出低電平

有關上拉輸入、下拉輸入、推挽輸出、開漏輸出、復用開漏輸出、復用推挽輸出以及浮空輸入、模擬輸入的區別

1、上拉輸入:上拉就是把電位拉高,比如拉到Vcc。上拉就是將IO口上不確定的信號通過一個上拉電阻把IO上拉為高電平!電阻同時起限流作用!弱強只是上拉電阻的阻值不同,沒有什么嚴格區分。

2、下拉輸入:就是把電壓拉低,拉到GND。與上拉原理相似。

3、浮空輸入:浮空(floating)就是邏輯器件的輸入引腳即不接高電平,也不接低電平。由于邏輯器件的內部結構,當它輸入引腳懸空時,相當于該引腳接了高電平。一般實際運用時,引腳不建議懸空,易受干擾。?通俗講就是讓管腳什么都不接,浮空著。

4、模擬輸入:模擬輸入是指傳統方式的輸入.數字輸入是輸入PCM數字信號,即0,1的二進制數字信號,通過數模轉換,轉換成模擬信號,經前級放大進入功率放大器,功率放大器還是模擬的。

5、推挽輸出:可以輸出高,低電平,連接數字器件;?推挽結構一般是指兩個三極管分別受兩互補信號的控制,總是在一個三極管導通的時候另一個截止。高低電平由IC的電源低定。

6、開漏輸出:輸出端相當于三極管的集電極.?要得到高電平狀態需要上拉電阻才行.?適合于做電流型的驅動,其吸收電流的能力相對強(一般20ma以內)。

7、復用開漏輸出、復用推挽輸出:可以理解為GPIO口被用作第二功能時的配置情況(即并非作為通用IO口使用)。

在STM32中選用IO模式,下面是參考網上的總結一下。
(1)?浮空輸入_IN_FLOATING?——浮空輸入,可以做KEY識別,RX
(2)帶上拉輸入_IPU——IO內部上拉電阻輸入
(3)帶下拉輸入_IPD——?IO內部下拉電阻輸入
(4)?模擬輸入_AIN?——應用ADC模擬輸入,或者低功耗下省電
(5)開漏輸出_OUT_OD?——IO輸出0接GND,IO輸出1,懸空,需要外接上拉電阻,才能實現輸出高電平。當輸出為1時,IO口的狀態由上拉電阻拉高電平,但由于是開漏輸出模式,這樣IO口也就可以由外部電路改變為低電平或不變。可以讀IO輸入電平變化,實現C51的IO雙向功能。
(6)推挽輸出_OUT_PP?——IO輸出0-接GND,?IO輸出1?-接VCC,讀輸入值是未知的
(7)復用功能的推挽輸出_AF_PP?——片內外設功能(I2C的SCL,SDA)

(8)復用功能的開漏輸出_AF_OD——片內外設功能(TX1,MOSI,MISO.SCK.SS)

1.1.內核劃分

A: 應用在手機?R: 實時性很高的領域 M: 應用在單片機

1.2.外設

1.3.在線安裝支持包

2.新建工程文件

2.1.正確插線

2.2.添加必要的工程文件

2.2.1.在工程文件下新建一個Start文件夾,講必要的工程文件添加到此文件夾

2.2.2.添加頭文件路徑?

2.2.3.創建User 文件夾創建Main函數

2.2.4.添加庫文件 :工程下創建Library文件夾,把庫函數都添加進去,創建Library組,在添加Library下的現有項

2.2.5.復制到工程User文件夾,再在Keil下添加現有項

2.2.6.定義宏配置工程文件

2.2.7.添加library和User頭文件的路徑

2.2.8.如何選擇啟動文件?

2.2.9.新建工程的步驟?

2.2.10.工程架構

3.GPIO

3.1.元氣件兩端有高低電平才可以形成電流:上:單片機低電平形成電流 下:單片機高電平形成電流

3.2.二極管:PN結

二極管有顏色的一極為負極:P為正極,N為負極;電流只能從正極流到負極,電子只能從負極客流到正極?

3.2.1.整流橋

3.3.三極管:NPN

PNP:

3.3.1.三極管發射極和集電極為什么不能互換

3.3.2.三極管連接的元器件位置(漏電問題):防止基極的小電流流過

3.3.3.開關電路

3.4.面包板的構造

3.5.清除工程文件

4.GPIO輸入輸出

4.1.RCC、GPIO最常用的3個函數

RCC簡介:RCC是Reset and Clock Control (復位和時鐘控制)的縮寫,它是STM32內部的一個重要外設,負責管理各種時鐘源和時鐘分頻,以及為各個外設提供時鐘使能。RCC模塊可以通過寄存器操作或者庫函數來配置。

4.2.使用GPIO的函數點亮和熄滅燈

	//設置時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//初始化GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//輸入低電平//GPIO_ResetBits(GPIOA,GPIO_Pin_0);//輸入高電平//GPIO_SetBits(GPIOA, GPIO_Pin_0);//輸入低電平//GPIO_WriteBit(GPIOA,GPIO_Pin_0, Bit_RESET);//輸入高電平GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);

4.3.使用延時函數達到使用燈閃爍的效果

4.3.1.在工程添加延時函數庫

電路將LED接到A0

代碼

int main(void)
{//設置時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//初始化GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);while(1){//輸入低電平//GPIO_WriteBit(GPIOA,GPIO_Pin_0, Bit_RESET);Delay_ms(100);//輸入高電平GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);Delay_ms(100);}return 0;
}

4.4.蜂鳴器

4.4.1.VCC/VSS/VEE等含義

一文讀懂電路中VCC、VDD、VEE、VSS的區別 - 知乎 (zhihu.com)

在電子電路設計中,VCC、VDD、VEE和VSS是常見的電源和地線標識,它們各自代表不同的電源電壓和地線類型。理解這些術語的區別對于正確設計和分析電路至關重要。

VCC

  • 定義:VCC是“Collector Voltage”或“Circuit Voltage”的縮寫,通常用于雙極型晶體管(如NPN晶體管)的集電極電源電壓。在數字電路中,VCC通常指代正電源電壓,用于為電路提供所需的正電壓。
  • 應用:VCC廣泛應用于模擬電路和數字電路中,提供電路所需的正電壓。例如,在NPN晶體管電路中,VCC為正電壓。
  • 特點:VCC通常用于模擬電源,提供穩定的電壓。

VDD

  • 定義:VDD是“Drain Voltage”或“Device Voltage”的縮寫,主要用于MOS晶體管和CMOS電路。它表示器件內部的工作電壓。
  • 應用:VDD常見于集成電路(IC)和數字電路中,提供芯片的正電源電壓。例如,在CMOS電路中,VDD通常連接到PMOS晶體管的源極。
  • 特點:VDD通常用于數字電源,提供芯片內部的工作電壓。

VEE

  • 定義:VEE是“Emitter Voltage”或“Emitter-Emitter Voltage”的縮寫,通常用于ECL電路的負電源電壓。
  • 應用:VEE一般用于模擬電路中,提供負電源電壓。例如,在PNP型晶體管電路中,VEE表示連接到發射極的電源電壓。
  • 特點:VEE在放大電路中較為常見,用于提供對稱電源。

VSS

  • 定義:VSS是“Source Voltage”或“Supply Voltage”的縮寫,表示電源地或0V。
  • 應用:VSS通常用于數字電路中,作為電路的參考點或接地。在CMOS電路中,VSS指負電源。
  • 特點:VSS是電路的公共接地端,用于消除噪聲和提供參考電平。

總結

  • 電壓極性:VCC和VDD均表示正電源引腳,而VEE表示負電源引腳。VSS則代表接地引腳,不涉及電壓極性。
  • 應用領域:VCC和VDD主要用于數字電路中,提供操作所需的正電壓;VEE通常用于模擬電路中,提供負電壓;VSS則用于連接電路到地,確保電路工作正常。
  • 傳統用法:VCC和VSS這對術語通常用于晶體管和集成電路中;VDD和VEE則更常見于模擬電路設計中。

通過理解VCC、VDD、VEE和VSS的區別,可以更好地設計和調試電子設備和電路,確保電路的穩定性和可靠性。

代碼:設置時鐘 初始化對應接口 使用延時函數

	//蜂鳴器int main(){RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);while(1){GPIO_ResetBits(GPIOB, GPIO_Pin_13);Delay_ms(100);GPIO_SetBits(GPIOB, GPIO_Pin_13);Delay_ms(100);GPIO_ResetBits(GPIOB, GPIO_Pin_13);Delay_ms(100);GPIO_SetBits(GPIOB, GPIO_Pin_13);Delay_ms(700);}return 0;}

4.4.分壓電路

R1變小U0變大,R2變小U0變小

4.5.每一個開關控制一個LED的點亮和熄滅

線路圖

?main

	//開關uint8_t keyNum;int main(){LED_Init();Key_Init();LED1_Off();LED2_Off();while(1){keyNum = GetKeyNum();if(keyNum == 1)LED1_turn();if(keyNum == 2)LED2_turn();}return 0;}

LED函數:LED取反:讀取對應端口的高低電平,再設置取反的電平

#include "stm32f10x.h"   void LED_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);
}//LED的熄滅和點開
void LED1_ON()
{GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
void LED1_Off()
{GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
void LED2_ON()
{GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
void LED2_Off()
{GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
void LED1_turn()
{//如果為低電平變為高電平if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)GPIO_SetBits(GPIOA, GPIO_Pin_1);	elseGPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
void LED2_turn()
{//如果為低電平變為高電平if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)GPIO_SetBits(GPIOA, GPIO_Pin_2);	elseGPIO_ResetBits(GPIOA, GPIO_Pin_2);
}

Key函數:按下/松開開關會有抖動,使用延遲函數消除

#include "stm32f10x.h"   
#include "Delay.h"void Key_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = 	GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}uint8_t GetKeyNum()
{uint8_t keyNum = 0;//LED2if( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11 ) == 0 ){//消除抖動Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);//等松手//消除抖動Delay_ms(20);keyNum = 2;}//LED1if( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 ) == 0 ){//消除抖動Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);//等松手//消除抖動Delay_ms(20);keyNum = 1;}return keyNum;
}

4.6. 光敏電阻控制蜂鳴器

電路圖

main?

	//關敏電阻驅動蜂鳴器int main(){Buzzer_Init();LightSensor_Init();Buzzer_Off();while(1){if(GetLightSenNum() == 1)Buzzer_ON();elseBuzzer_Off();}return 0;}

Lightsensor?

#include "stm32f10x.h"   
#include "Delay.h"void LightSensor_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = 	GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}uint8_t GetLightSenNum()
{return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}

?Buzzer

#include "stm32f10x.h"   void Buzzer_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);
}void Buzzer_ON()
{GPIO_ResetBits(GPIOB, GPIO_Pin_12);
}
void Buzzer_Off()
{GPIO_SetBits(GPIOB, GPIO_Pin_12);
}
void Buzzer_turn()
{//如果為低電平變為高電平if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_12) == 0)GPIO_SetBits(GPIOB, GPIO_Pin_12);	elseGPIO_ResetBits(GPIOB, GPIO_Pin_12);
}

?4.7.OLED調試

OLED驅動函數

接線線路圖

?4.6.1.調試

5.EXIT外部中斷

5.1.中斷的理論

不能使用pin相同的端口:例,PA1、PB1

5.2.對射式紅外傳感器

配置中斷:初始化配置此4項

AFIO沒有專門的庫,內容和GPIO寫在GPIO.h庫內

NVIC函數在雜項文件內

main

	//對射式紅外傳感器int main(){CountSensor_Init();OLED_Init();OLED_ShowString(1, 1, "Count:");while(1){uint16_t countSensor_Count = CountSensor_Get();OLED_ShowNum(1, 7, countSensor_Count, 5);}return 0;}

countSensor

#include "stm32f10x.h"    uint16_t countSensor_Count = 0;
void CountSensor_Init()
{//設置時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//初始化端口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入,未檢測到輸入時默認為高電平GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//輸入不需要速度GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//配置外部中斷引腳選擇//配置EXTIEXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line14;//那個端口EXTI_InitStructure.EXTI_LineCmd = ENABLE;//開啟EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下拉觸發:遮擋時觸發,上拉觸發:遮擋移開后觸發EXTI_Init(&EXTI_InitStructure);//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//選擇通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//搶占優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//響應優先級NVIC_Init(&NVIC_InitStructure);
}void EXTI15_10_IRQHandler()
{if(EXTI_GetITStatus(EXTI_Line14) == SET)//檢測14端口,是否發生異常{countSensor_Count++;EXTI_ClearITPendingBit(EXTI_Line14);//清除標志位,防止死循環}
}uint16_t CountSensor_Get()
{return countSensor_Count;
}

5.3.編碼器計次

電路圖

main

	int16_t encoderCount = 0;//編碼器改變數值int main(){Encoder_Init();OLED_Init();OLED_ShowString(1, 1, "Count:");while(1){encoderCount += EncoderNum_Get();OLED_ShowSignedNum(1, 7, encoderCount, 5);}return 0;}

encoder

#include "stm32f10x.h"    int16_t encoderNum = 0;
void Encoder_Init()
{//設置時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//初始化端口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉輸入,未檢測到輸入時默認為高電平GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//輸入不需要速度GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//配置外部中斷引腳選擇GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//配置EXTIEXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;//那個端口EXTI_InitStructure.EXTI_LineCmd = ENABLE;//開啟EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下拉觸發:遮擋時觸發,上拉觸發:遮擋移開后觸發EXTI_Init(&EXTI_InitStructure);//配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//選擇通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//搶占優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//響應優先級NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//選擇通道NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//搶占優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;//響應優先級NVIC_Init(&NVIC_InitStructure);
}void EXTI0_IRQHandler()
{if(EXTI_GetITStatus(EXTI_Line0) == SET)//檢測0端口,是否發生異常{if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)encoderNum--;EXTI_ClearITPendingBit(EXTI_Line0);//清除標志位,防止死循環}
}
void EXTI1_IRQHandler()
{if(EXTI_GetITStatus(EXTI_Line1) == SET)//檢測1端口,是否發生異常{if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)encoderNum++;EXTI_ClearITPendingBit(EXTI_Line1);//清除標志位,防止死循環}
}uint16_t EncoderNum_Get()
{int16_t tmp = encoderNum;encoderNum =0;return tmp;
}

6.定時器

TIM ( Timer )定時器

  • 定時器可以對輸入的時鐘進行計數,并在計數值達到設定值時觸發中斷
  • 16 位計數器、預分頻器、自動重裝寄存器的時基單元,在 72MHz 計數時鐘下可以實現最大 59.65s 的定時
  • 不僅具備基本的定時中斷功能,而且還包含內外時鐘源選擇、輸入 捕獲、輸出比較、編碼器接口、主從觸發模式等多種功能
  • 根據復雜度和應用場景分為了高級定時器、通用定時器、基本定時器三種類型

基礎定時器:只有向上計時模式

通用定時器:向上計數、向下計數、中央對齊模式

6.1.定時器內部中斷和定時器外部中斷

time.h?

	#include "stm32f10x.h"  //定時器內部中斷
//	void Time_Init()
//	{
//		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//定時器1時鐘開啟
//		TIM_InternalClockConfig(TIM2);
//		
//		//初始化時基單位
//		TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
//		TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//時鐘分頻
//		TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//時鐘模式
//		TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;//預分頻器,此值和下值上限都為2^16
//		TIM_TimeBaseInitStructure.TIM_Prescaler =7200 - 1;//自動重裝器
//		TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重復計時器,高級定時器才需要
//		TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);
//		
//		//清除一下標志位,防止一上電就進中斷
//		TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//		
//		TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//中斷配置
//		
//		//NVIC中斷配置
//		NVIC_InitTypeDef NVIC_InitStructure;
//		NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
//		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
//		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
//		NVIC_Init(&NVIC_InitStructure);
//		
//		TIM_Cmd(TIM2, ENABLE);//使能控制
//	}//定時器外部中斷void Time_Init(){RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//定時器1時鐘開啟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_Initstructure;GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Initstructure.GPIO_Pin = GPIO_Pin_0;GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//初始化時基單位TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//時鐘分頻TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//時鐘模式TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;//預分頻器,此值和下值上限都為2^16TIM_TimeBaseInitStructure.TIM_Prescaler =1 - 1;//自動重裝器TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重復計時器,高級定時器才需要TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);//清除一下標志位,防止一上電就進中斷TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//中斷配置//NVIC中斷配置NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2, ENABLE);//使能控制}

main.h

	//時鐘中斷uint32_t num = 0; int main(){OLED_Init();Time_Init();while(1){OLED_ShowNum(1, 5, num, 5);OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);//獲取自動重裝值}return 0;}void TIM2_IRQHandler()//對應的中斷函數{if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET ){TIM_ClearITPendingBit(TIM2, TIM_IT_Update);num++;}}	

6.2. PWM

6.2.1.PWM的基礎概念

OC ( Output Compare )輸出比較?

  • 輸出比較可以通過比較 CNT(計數器) 與 CCR(捕獲比較寄存器) 寄存器值的關系,來對輸出電平進行置1 、置0或翻轉的操作,用于輸出一定頻率和占空比的 PWM 波形
  • 每個高級定時器和通用定時器都擁有 4 個輸出比較通道
  • 高級定時器的前 3 個通道額外擁有死區生成和互補輸出的功能

計算一個頻率為1KHZ、占空比為50%、分辨率為1%的ARR、CCR、PSC?

6.2.2.呼吸燈
#include "stm32f10x.h"void PWM_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//選擇時鐘TIM_InternalClockConfig(TIM2);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //TIM_OCPolarity_High極性不翻轉 TIM_OCPolarity_Low極性翻轉TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能TIM_OCInitStructure.TIM_Pulse = 100; //CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//修改CCR的值
void PWM_SetCompare1(uint32_t compare)
{TIM_SetCompare1(TIM2, compare);
}
	void LightClink(int ms1, int ms2){PWM_SetCompare1(100);Delay_ms(ms1);PWM_SetCompare1(0);Delay_ms(ms2);}//時鐘內部/外部中斷int main(){PWM_Init();while(1){LightClink(2000, 1000);LightClink(2000, 1000);LightClink(2000, 1000);LightClink(1000, 1000);LightClink(1000, 1000);//			for(int i = 0; i <=100; i++)
//			{
//				PWM_SetCompare1(i);
//				Delay_ms(40);
//			}
//			PWM_SetCompare1(0);
//			Delay_ms(40);
//			for(int i =0; i < 100 ; i++)
//			{
//				PWM_SetCompare1(100 - i);
//				Delay_ms(40);
//			}
//			PWM_SetCompare1(100);
//			Delay_ms(20);}return 0;}
6.2.3.端口重映射
	//重映射端口RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO);GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE);

6.2.4.PWM操作舵機

void PWM_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//選擇時鐘TIM_InternalClockConfig(TIM2);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrucure;TIM_TimeBaseInitStrucure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStrucure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStrucure.TIM_Period = 20000 - 1;TIM_TimeBaseInitStrucure.TIM_Prescaler = 72 - 1;TIM_TimeBaseInitStrucure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrucure);//輸出比較TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//修改CCR的值
void PWM_SetCompare2(uint16_t compare)
{TIM_SetCompare2(TIM2, compare);
}
void Set_Angle(int angle)
{PWM_SetCompare2(angle * 2000 / 180 + 500);
}

	uint8_t keyNum ;int angle;//時鐘內部/外部中斷int main(){PWM_Init();Key_Init();OLED_Init();while(1){keyNum = GetKeyNum();if(keyNum == 1){angle += 30;if(angle > 180)angle = 0;}Set_Angle(angle);OLED_ShowString(1, 1, "angle:");OLED_ShowNum(1, 7, angle, 3);OLED_ShowString(2, 1, "num:");OLED_ShowNum(2, 5, keyNum, 1);}return 0;}
6.4.3.PWM操作電機

	int8_t speed;int8_t keyNum;//PWM操作電機int main(){PWM_Init();Key_Init();OLED_Init();while(1){keyNum = GetKeyNum();if(keyNum == 1){speed += 20;if(speed > 100) speed = -100;Set_MotorSpeed(speed);}OLED_ShowString(1,1,"Speed:");OLED_ShowSignedNum(1, 7, speed, 4);}return 0;}
void PWM_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//選擇時鐘TIM_InternalClockConfig(TIM2);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrucure;TIM_TimeBaseInitStrucure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStrucure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStrucure.TIM_Period = 100 - 1;TIM_TimeBaseInitStrucure.TIM_Prescaler = 36 - 1;TIM_TimeBaseInitStrucure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrucure);//輸出比較TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//修改CCR的值
void PWM_SetCompare3(uint16_t compare)
{TIM_SetCompare3(TIM2, compare);
}
void Set_MotorSpeed(int8_t speed)
{if(speed >= 0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(speed);}else{GPIO_SetBits(GPIOA, GPIO_Pin_5);GPIO_ResetBits(GPIOA, GPIO_Pin_4);PWM_SetCompare3(-speed);//speed當前小于0		}
}
6.4.4.?輸入捕獲測頻率和占空比

輸入捕獲流程

輸入捕獲檢測方法

PSC數值修改?

	//輸入捕獲測頻率int main(){PWM_Init();IC_Init();OLED_Init();PWM_SetCompare1(0);PWM_SetPrescaler(720 - 1);OLED_ShowString(1, 1, "Freq:00000Hz");OLED_ShowString(2, 1, "Duty:00%");while(1){OLED_ShowNum(1, 6, GetFreq(), 5);OLED_ShowNum(2, 6, GetDuty(), 2);}return 0;}

#include "stm32f10x.h"void PWM_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//選擇時鐘TIM_InternalClockConfig(TIM2);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);//TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //TIM_OCPolarity_High極性不翻轉 TIM_OCPolarity_Low極性翻轉TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //使能TIM_OCInitStructure.TIM_Pulse = 100; //CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}//輸入捕獲測頻率和占空比void IC_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//選擇時鐘TIM_InternalClockConfig(TIM3);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);//配置通道1TIM_ICInitTypeDef TIM_ICInitstructure;TIM_ICInitstructure.TIM_Channel = TIM_Channel_1;TIM_ICInitstructure.TIM_ICFilter = 0xf;//濾波器,參數數值增大可以消除噪音和毛刺的干擾TIM_ICInitstructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//邊沿檢測、極性選擇;上沿觸發TIM_ICInitstructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器TIM_ICInitstructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//數據選擇器,直連輸入TIM_ICInit(TIM3, &TIM_ICInitstructure);//配置通道2TIM_PWMIConfig(TIM3, &TIM_ICInitstructure);//等同于下面的代碼,函數內部進行ifelse判斷TIM_ICInitstructure.TIM_Channel = TIM_Channel_2;TIM_ICInitstructure.TIM_ICFilter = 0xf;//濾波器,參數數值增大可以消除噪音和毛刺的干擾TIM_ICInitstructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//邊沿檢測、極性選擇;上沿觸發TIM_ICInitstructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器TIM_ICInitstructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;//數據選擇器,交叉輸入TIM_ICInit(TIM3, &TIM_ICInitstructure);	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//選擇觸發源TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//選擇從模式TIM_Cmd(TIM3, ENABLE);
}//修改CCR的值
void PWM_SetCompare1(uint16_t compare)
{TIM_SetCompare1(TIM2, compare);
}
//修改PSC
void PWM_SetPrescaler(uint16_t prescaler)
{TIM_PrescalerConfig(TIM2, prescaler, TIM_PSCReloadMode_Immediate);
}//獲取頻率
uint32_t GetFreq()
{return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}//獲取占空比
uint32_t GetDuty()
{return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}
6.4.5.編碼器接口
		//輸入捕獲測頻率int main(){Encoder_Init();OLED_Init();OLED_ShowString(1, 1, "CNT:");while(1){OLED_ShowSignedNum(1, 5, Get_Encoder(), 5);Delay_ms(1000);}return 0;}
void Encoder_Init()
{//打開時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//初始化GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter =  0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);//配置通道1TIM_ICInitTypeDef TIM_ICInitstructure;TIM_ICStructInit(&TIM_ICInitstructure);TIM_ICInitstructure.TIM_Channel = TIM_Channel_1;TIM_ICInitstructure.TIM_ICFilter = 0xf;//濾波器,參數數值增大可以消除噪音和毛刺的干擾TIM_ICInitstructure.TIM_Channel = TIM_Channel_2;TIM_ICStructInit(&TIM_ICInitstructure);TIM_ICInitstructure.TIM_ICFilter = 0xf;//濾波器,參數數值增大可以消除噪音和毛刺的干擾TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);TIM_Cmd(TIM3, ENABLE);
}int16_t Get_Encoder()
{int tmp = TIM_GetCounter(TIM3);TIM_SetCounter(TIM3, 0);return tmp;
}

7.AD模數轉換

7.1.AD的概念

4種轉換模式

  • 單次轉換, 非 掃 描模式
  • 連續轉換,非掃描模式
  • 單次轉換,掃描模式
  • 連續轉換, 掃描模式

//	//AD
//	uint16_t ADValue;
//	float voltage;
//	int main()
//	{
//		OLED_Init();
//		OLED_ShowString(1 ,1 , "ADValue:");
//		OLED_ShowString(2 ,1 , "Voltage:0.00V");
//		AD_Init();
//		while(1)
//		{
//			ADValue = AD_GetValue();
//			voltage = (float)ADValue / 4095 * 3.3;//需先轉為浮點數進行除法運算
//			
//			OLED_ShowNum(1, 9, ADValue, 5);
//			OLED_ShowNum(2, 9, voltage, 1);
//			OLED_ShowNum(2, 11, (uint16_t)( voltage * 100 ) % 100, 2);
//			
//		}
//		return 0;
//	}//多ADuint16_t ad1, ad2, ad3, ad4;int main(){OLED_Init();OLED_ShowString(1 ,1 , "ad1:");OLED_ShowString(2 ,1 , "ad2:");OLED_ShowString(3 ,1 , "ad3:");OLED_ShowString(4 ,1 , "ad4:");AD_Init();while(1){ad1 = AD_GetValue(ADC_Channel_0);ad2 = AD_GetValue(ADC_Channel_1);ad3 = AD_GetValue(ADC_Channel_2);ad4 = AD_GetValue(ADC_Channel_3);OLED_ShowNum(1, 5, ad1, 5);OLED_ShowNum(2, 5, ad2, 5);OLED_ShowNum(3, 5, ad3, 5);OLED_ShowNum(4, 5, ad4, 5);}return 0;}
#include "stm32f10x.h"//void AD_Init()
//{
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//	
//	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHz / 6 = 12MHz
//	
//	//配置GPIO口
//	GPIO_InitTypeDef GPIO_InitStructure;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init(GPIOA, &GPIO_InitStructure);
//	
//	//規則組通道配置
//	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//ADC_Channel_0根據引腳定義表選擇 ADC_SampleTime_55Cycles5采樣周期數值越小速度越快,數值越大數據轉換越穩定
//	
//	//初始化ADC
//	ADC_InitTypeDef ADC_InitStructure;
//	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//獨立轉換模式
//	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右對齊
//	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//無外部源即軟件觸發
//	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//連續模式
//	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//掃描模式
//	ADC_InitStructure.ADC_NbrOfChannel = 1;
//	ADC_Init(ADC1, &ADC_InitStructure);
//	
//	//運行控制
//	ADC_Cmd(ADC1, ENABLE);
//	
//	//校準復位
//	ADC_ResetCalibration(ADC1);
//	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
//	ADC_StartCalibration(ADC1);
//	while(ADC_GetCalibrationStatus(ADC1) == SET);
//}//uint16_t AD_GetValue()
//{
//	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//啟動
//	while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待
//	return ADC_GetConversionValue(ADC1);//獲取
//}//連續轉換模式
//void AD_Init()
//{
//	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//連續模式
//	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//連續轉換模式,只需要觸發啟動一次
//}//uint16_t AD_GetValue()
//{
//	return ADC_GetConversionValue(ADC1);//獲取
//}//非連續非掃描實現多AD
void AD_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHz / 6 = 12MHz//配置GPIO口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//規則組通道配置ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//ADC_Channel_0根據引腳定義表選擇 ADC_SampleTime_55Cycles5采樣周期數值越小速度越快,數值越大數據轉換越穩定//初始化ADCADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//獨立轉換模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//無外部源即軟件觸發ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//連續模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;//掃描模式ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);//運行控制ADC_Cmd(ADC1, ENABLE);//校準復位ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);
}uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);ADC_SoftwareStartConvCmd(ADC1, ENABLE);//啟動while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待return ADC_GetConversionValue(ADC1);//獲取
}

8.DMA ( Direct Memory Access )直接存儲器存取

DMA數據轉運

	//DMA數據轉運uint8_t arr1[] = {0x12, 0x23, 0xa1, 0x3b};uint8_t arr2[4];int main(){OLED_Init();MyDMA_Init((uint32_t)arr1, (uint32_t)arr2, 4);//數據轉運while(1){OLED_ShowString(1, 1, "arr1:");OLED_ShowString(3, 1, "arr2:");OLED_ShowNum(1, 7, (uint32_t)arr1, 8); OLED_ShowNum(3, 7, (uint32_t)arr1, 8); OLED_ShowHexNum(2, 1, arr1[0], 2);OLED_ShowHexNum(2, 4, arr1[1], 2);OLED_ShowHexNum(2, 7, arr1[2], 2);OLED_ShowHexNum(2, 10, arr1[3], 2);Delay_s(1);	MyDMA_Transfer();arr1[0]++;arr1[1]++;arr1[2]++;arr1[3]++;OLED_ShowHexNum(4, 1, arr2[0], 2);OLED_ShowHexNum(4, 4, arr2[1], 2);OLED_ShowHexNum(4, 7, arr2[2], 2);OLED_ShowHexNum(4, 10, arr2[3], 2);Delay_s(1);}return 0;}
#include "stm32f10x.h"//ADC數據轉移
uint32_t mySize;
void MyDMA_Transfer()
{DMA_Cmd(DMA1_Channel1, DISABLE);//失能DMA_SetCurrDataCounter(DMA1_Channel1, mySize);//修改計數器DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA_GetFlagStatus(DMA1_FLAG_TC1);//等待轉運完成DMA_ClearFlag(DMA1_FLAG_TC1);
}
void MyDMA_Init(uint32_t addrA, uint32_t addrB, uint32_t size)
{//時鐘開啟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = addrA;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;DMA_InitStructure.DMA_MemoryBaseAddr = addrB;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;mySize = size;DMA_InitStructure.DMA_BufferSize = mySize;//計數器DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外部是來源還是目的地DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;//是否使用軟件觸發DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//是否自動重裝DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//優先級DMA_Init(DMA1_Channel1, &DMA_InitStructure);//DMA使能DMA_Cmd(DMA1_Channel1, DISABLE);MyDMA_Transfer();
}
	//DMA數據轉運ADCint main(){OLED_Init();MyDMA_Init();//數據轉運OLED_ShowString(1 ,1 , "ad1:");OLED_ShowString(2 ,1 , "ad2:");OLED_ShowString(3 ,1 , "ad3:");OLED_ShowString(4 ,1 , "ad4:");while(1){
//			ADDMA_GetValue();OLED_ShowNum(1, 5, AD_Value[0], 5);OLED_ShowNum(2, 5, AD_Value[1], 5);OLED_ShowNum(3, 5, AD_Value[2], 5);OLED_ShowNum(4, 5, AD_Value[3], 5);}return 0;}

uint16_t AD_Value[4];void MyDMA_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//時鐘開啟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHz / 6 = 12MHz//配置GPIO口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//規則組通道配置ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//ADC_Channel_0根據引腳定義表選擇 ADC_SampleTime_55Cycles5采樣周期數值越小速度越快,數值越大數據轉換越穩定ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);//初始化ADCADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//獨立轉換模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右對齊ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//無外部源即軟件觸發ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//連續模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;//掃描模式ADC_InitStructure.ADC_NbrOfChannel = 4;ADC_Init(ADC1, &ADC_InitStructure);DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_BufferSize = 4;//計數器DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外部是來源還是目的地DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//是否使用軟件觸發DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//是否自動重裝DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//優先級DMA_Init(DMA1_Channel1, &DMA_InitStructure);//不可以在未使能前校準復位
//		//校準復位
//	ADC_ResetCalibration(ADC1);
//	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
//	ADC_StartCalibration(ADC1);
//	while(ADC_GetCalibrationStatus(ADC1) == SET);//DMA使能DMA_Cmd(DMA1_Channel1, ENABLE);ADC_DMACmd(ADC1, ENABLE);//開啟DMA到ADC信號//ADC使能ADC_Cmd(ADC1, ENABLE);//校準復位ADC_ResetCalibration(ADC1);while(ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while(ADC_GetCalibrationStatus(ADC1) == SET);//自動轉換轉運的情況下使用ADC_SoftwareStartConvCmd(ADC1, ENABLE);//啟動
}
void ADDMA_GetValue(void)
{DMA_Cmd(DMA1_Channel1, DISABLE);//失能DMA_SetCurrDataCounter(DMA1_Channel1, 4);//修改計數器DMA_Cmd(DMA1_Channel1, ENABLE);//使能ADC_SoftwareStartConvCmd(ADC1, ENABLE);//啟動//等待轉運完成while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);DMA_ClearFlag(DMA1_FLAG_TC1);
}

9.串口通信(USART)?

9.1.基礎概率

9.2.串口通信

使用printf函數,先打開Use MicroLIB

//此函數是printf函數底層調用打印的函數
int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}	//串口int main(){Serial_Init();//printf函數移植方法printf("Num = %d\r\n",666);char str[100];sprintf(str, "Num = %d\r\n", 666);//指定打印位置Serial_SendString(str);while(1){}return 0;}

?串口接收

1.查詢

	//串口發送int main(){Serial_Init();OLED_Init();while(1){//查詢if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){receiveData = USART_ReceiveData(USART1);//讀取后標志位自動置空OLED_ShowHexNum(1, 1, receiveData, 2);}}return 0;}

2.中斷

	//串口發送int main(){Serial_Init();OLED_Init();while(1){//中斷if(Serial_GetRxFLag() == 1){receiveData = Serial_GetRxData();//讀取后標志位自動置空OLED_ShowHexNum(1, 1, receiveData, 2);//回傳Serial_SendByte(receiveData);}}return 0;}
uint8_t serial_RxData,serial_RxFlag;uint8_t Serial_GetRxFLag(void)
{if(serial_RxFlag == 1){serial_RxFlag = 0;return 1;}return 0;
}uint8_t Serial_GetRxData()
{return serial_RxData;
}//串口接收和發送
void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//開啟gpio口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化串口USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;//效驗位USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位長度USART_InitStructure.USART_WordLength = USART_WordLength_8b;//報文8bitUSART_Init(USART1, &USART_InitStructure);//中斷USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_Initstructure;NVIC_Initstructure.NVIC_IRQChannel = USART1_IRQn;NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_Initstructure);USART_Cmd(USART1, ENABLE);
}void USART1_IRQHandler(void)
{if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){serial_RxFlag = 1;serial_RxData = USART_ReceiveData(USART1);}
}

9.3.串口通信數據包·

數據包

串口發送HEX數據包

	uint8_t receiveData;//串口發送HEX數據包int main(){Serial_Init();OLED_Init();Key_Init();serial_TxPacket[0] = 0x12;serial_TxPacket[1] = 0x23;serial_TxPacket[2] = 0x34;serial_TxPacket[3] = 0x45;uint8_t keyNum;//按鍵while(1){keyNum = GetKeyNum();if(keyNum == 1){serial_TxPacket[0]++;serial_TxPacket[1]++;serial_TxPacket[2]++;serial_TxPacket[3]++;Serial_SendPacket();OLED_ShowHexNum(2, 1, serial_TxPacket[0], 2); OLED_ShowHexNum(2, 4, serial_TxPacket[1], 2); OLED_ShowHexNum(2, 7, serial_TxPacket[2], 2); OLED_ShowHexNum(2, 10, serial_T xPacket[3], 2); }if(Serial_GetRxFLag()){OLED_ShowHexNum(1, 1, serial_RxPacket[0], 2); OLED_ShowHexNum(1, 4, serial_RxPacket[1], 2); OLED_ShowHexNum(1, 7, serial_RxPacket[2], 2); OLED_ShowHexNum(1, 10, serial_RxPacket[3], 2); }}return 0;}
//串口發送HEX數據包uint8_t serial_RxPacket[4], serial_TxPacket[4];
uint8_t serial_Flag;uint8_t Serial_GetRxFLag(void)
{if(serial_Flag == 1){serial_Flag = 0;return 1;}return 0;
}
//發送數據包
void Serial_SendPacket()
{Serial_SendByte(0xFF);//報頭Serial_SendArray(serial_TxPacket, 4);Serial_SendByte(0xFE);//報尾
}
//接受數據包//串口接收和發送
void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//開啟gpio口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化串口USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;//效驗位USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位長度USART_InitStructure.USART_WordLength = USART_WordLength_8b;//報文8bitUSART_Init(USART1, &USART_InitStructure);//中斷USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_Initstructure;NVIC_Initstructure.NVIC_IRQChannel = USART1_IRQn;NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_Initstructure);USART_Cmd(USART1, ENABLE);
}void USART1_IRQHandler(void)
{if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){static uint8_t serial_State = 0;//當前狀態static uint8_t pRxData = 0;//接受到第幾個數據uint8_t rxData = USART_ReceiveData(USART1);//讀取當前數據if(serial_State == 0){if(rxData == 0xFF){serial_State = 1;}}else if (serial_State == 1){serial_RxPacket[pRxData] = rxData;pRxData++;if(pRxData == 4){pRxData %= 4;serial_State = 2;}}else if(serial_State == 2){if(rxData == 0xFE){serial_State = 0;//狀態改變serial_Flag = 1;//標志位可讀}}}
}

串口發送文本數據包

//串口發送文本數據包char serial_RxPacket[100];
uint8_t serial_Flag;uint8_t Serial_GetRxFLag(void)
{if(serial_Flag == 1){serial_Flag = 0;return 1;}return 0;
}
//接受數據包//串口接收和發送
void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//開啟gpio口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化串口USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;USART_InitStructure.USART_Parity = USART_Parity_No;//效驗位USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位長度USART_InitStructure.USART_WordLength = USART_WordLength_8b;//報文8bitUSART_Init(USART1, &USART_InitStructure);//中斷USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitTypeDef NVIC_Initstructure;NVIC_Initstructure.NVIC_IRQChannel = USART1_IRQn;NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_Initstructure);USART_Cmd(USART1, ENABLE);
}void USART1_IRQHandler(void)
{if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET){static uint8_t serial_State = 0;//當前狀態static uint8_t pRxData = 0;//接受到第幾個數據uint8_t rxData = USART_ReceiveData(USART1);//讀取當前數據if(serial_State == 0){if(rxData == '@'){serial_State = 1;pRxData = 0;}}else if (serial_State == 1){if(rxData == '\r')serial_State = 2;else{serial_RxPacket[pRxData] = rxData;pRxData++;}}else if(serial_State == 2){if(rxData == '\n'){serial_State = 0;//狀態改變serial_RxPacket[pRxData] = '\0';//c串以'\0'結尾serial_Flag = 1;//標志位可讀}}}
}
	uint8_t receiveData;//串口發送文本數據包int main(){Serial_Init();OLED_Init();LED_Init();Key_Init();OLED_ShowString(1, 1, "TxPacket:");OLED_ShowString(3, 1, "RxPacket:");while(1){if(Serial_GetRxFLag()){OLED_ShowString(4, 1, "                ");OLED_ShowString(4, 1, serial_RxPacket);if(strcmp(serial_RxPacket, "LED_ON") == 0){LED1_ON();Serial_SendString("LED_ON\r\n");OLED_ShowString(2, 1, "                ");OLED_ShowString(2, 1, "LED_ON_OK");}else if(strcmp(serial_RxPacket, "LED_OFF") == 0){LED1_Off();Serial_SendString("LED_OFF\r\n");OLED_ShowString(2, 1, "                ");OLED_ShowString(2, 1, "LED_OFF_OFF");}else{Serial_SendString("ERROR_COMMOD\r\n");OLED_ShowString(2, 1, "                ");OLED_ShowString(2, 1, "ERROR_COMMOD");}}}return 0;}

?10.I2C

10.I2C通信

指定地址讀取/寫入一片區域的時序

12.Unix時間戳

12.1.時間戳的基礎概念

12.2.BKP、RTC概念

12.3.BKP讀寫數據

  • BKP掉電數據(主和備用電源不同時掉電)不丟失
uint16_t writeArray[] = {0x1234, 0x5678};
uint16_t readArray[2];//BKP讀寫數據int main(){OLED_Init();Key_Init();//初始化時鐘PWR/BKPRCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);PWR_BackupAccessCmd(ENABLE);//備用電源訪問使能OLED_ShowString(1, 1, "W:");OLED_ShowString(2, 1, "R:");uint8_t keyNum;while(1){keyNum = GetKeyNum();//按鍵按下,寫入數據++并寫入if(keyNum == 1){writeArray[0]++;writeArray[1]++;BKP_WriteBackupRegister(BKP_DR1, writeArray[0]);BKP_WriteBackupRegister(BKP_DR2, writeArray[1]);OLED_ShowHexNum(1, 3, writeArray[0], 4);OLED_ShowHexNum(1, 8, writeArray[1], 4);}//實時讀取數據readArray[0] = BKP_ReadBackupRegister(BKP_DR1);readArray[1] = BKP_ReadBackupRegister(BKP_DR2);OLED_ShowHexNum(2, 3, readArray[0], 4);OLED_ShowHexNum(2, 8, readArray[1], 4);}return 0;}

?12.4.實時時間

	//讀取RTCint main(){OLED_Init();MyRTC_Init();/*顯示靜態字符串*/OLED_ShowString(1, 1, "Date:XXXX-XX-XX");OLED_ShowString(2, 1, "Time:XX:XX:XX");OLED_ShowString(3, 1, "CNT :");OLED_ShowString(4, 1, "DIV :");while(1){struct tm time_data = MyRTC_ReadTime();							//RTC讀取時間,最新的時間存儲到MyRTC_Time數組中OLED_ShowNum(1, 6, time_data.tm_year, 4);		//顯示MyRTC_Time數組中的時間值,年OLED_ShowNum(1, 11, time_data.tm_mon, 2);		//月OLED_ShowNum(1, 14, time_data.tm_mday, 2);		//日OLED_ShowNum(2, 6, time_data.tm_hour, 2);		//時OLED_ShowNum(2, 9, time_data.tm_min, 2);		//分OLED_ShowNum(2, 12, time_data.tm_sec, 2);		//秒OLED_ShowNum(3, 6, RTC_GetCounter(), 10);	//顯示32位的秒計數器OLED_ShowNum(4, 6, RTC_GetDivider(), 10);	//顯示余數寄存器}return 0;}
#include "stm32f10x.h"
#include <time.h>void MyRTC_SetTime(struct tm time_date)
{time_t time_cnt;		//定義秒計數器數據類型time_cnt = mktime(&time_date) - 8 * 60 * 60;	//調用mktime函數,將日期時間轉換為秒計數器格式//- 8 * 60 * 60為東八區的時區調整RTC_SetCounter(time_cnt);						//將秒計數器寫入到RTC的CNT中RTC_WaitForLastTask();							//等待上一次操作完成
}struct tm MyRTC_ReadTime(void)
{time_t time_cnt;		//定義秒計數器數據類型struct tm time_date;	//定義日期時間數據類型time_cnt = RTC_GetCounter() + 8 * 60 * 60;		//讀取RTC的CNT,獲取當前的秒計數器//+ 8 * 60 * 60為東八區的時區調整time_date = *localtime(&time_cnt);				//使用localtime函數,將秒計數器轉換為日期時間格式time_date.tm_year += 1900;time_date.tm_mon += 1;return time_date;
}void MyRTC_Init(void)
{if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)			//通過寫入備份寄存器的標志位,判斷RTC是否是第一次配置//if成立則執行第一次的RTC配置{//初始化時鐘,備用電源訪問打開RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);PWR_BackupAccessCmd(ENABLE);//時鐘源配置,等待時鐘準備好RCC_LSEConfig(RCC_LSE_ON);while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);//選擇時鐘源RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);RCC_RTCCLKCmd(ENABLE);//等待時鐘同步和上一次寫入程序結束RTC_WaitForSynchro();RTC_WaitForLastTask();//設定分頻RTC_SetPrescaler(32768 - 1);//分頻到1HZRTC_WaitForLastTask();//每次操作要等待上一次操作結束//設置起始值struct tm time_data;time_data.tm_year = 2025 - 1900;time_data.tm_mon = 5 -1 ;time_data.tm_mday = 19;time_data.tm_hour = 5;time_data.tm_min = 30;time_data.tm_sec = 15;MyRTC_SetTime(time_data);//RTC_SetCounter(1747599833);RTC_WaitForLastTask();//每次操作要等待上一次操作結束BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);			//在備份寄存器寫入自己規定的標志位,用于判斷RTC是不是第一次執行配置}else													//RTC不是第一次配置{RTC_WaitForSynchro();								//等待同步RTC_WaitForLastTask();								//等待上一次操作完成}
}

13.電源控制

13.1.基礎理論

13.2.修改主頻?

只讀文件,修改權限

	//修改主頻int main(){OLED_Init();OLED_ShowString(1, 1, "SYSCLK:");OLED_ShowNum(1, 8, SystemCoreClock, 8);while(1){OLED_ShowString(2, 1, "Running");Delay_ms(500);OLED_ShowString(2, 1, "       ");Delay_ms(500);}return 0;}

13.3.睡眠模式+串口收發

		uint8_t receiveData;//串口發送int main(){Serial_Init();OLED_Init();while(1){
//			//查詢
//			if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
//			{
//				receiveData = USART_ReceiveData(USART1);
//				//讀取后標志位自動置空
//				OLED_ShowHexNum(1, 1, receiveData, 2);
//			}//中斷if(Serial_GetRxFLag() == 1){receiveData = Serial_GetRxData();//讀取后標志位自動置空OLED_ShowHexNum(1, 1, receiveData, 2);//回傳Serial_SendByte(receiveData);OLED_ShowHexNum(1, 1, receiveData, 2);}OLED_ShowString(2, 1, "Running");Delay_ms(100);OLED_ShowString(2, 1, "       ");Delay_ms(100);__WFI();}return 0;}

?13.4.停機模式

  • 進入停止模式后會使用HSI時鐘,需要重新選擇時鐘
//對射式紅外傳感器 + 停止模式int main(){CountSensor_Init();OLED_Init();OLED_ShowString(1, 1, "Count:");while(1){OLED_ShowNum(1, 7, CountSensor_Get(), 5);OLED_ShowString(2, 1, "Running");Delay_ms(100);OLED_ShowString(2, 1, "       ");Delay_ms(100);//進入停止模式RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);PWR_EnterSTOPMode(PWR_Regulator_ON, PWR_STOPEntry_WFI);//進入停止模式后會使用HSI時鐘,需要重新使用時鐘SystemInit();}return 0;}

13.5.待機模式

?? ??? ??? ?//進入待機模式,程序將從頭開始執行,后續代碼不在執行,這也是不用再選擇開啟主頻的原因

	//對射式紅外傳感器 + 待機模式int main(){MyRTC_Init();//開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);OLED_Init();OLED_ShowString(1, 1, "CNT:");OLED_ShowString(2, 1, "ALR:");OLED_ShowString(3, 1, "ALRF:");uint32_t alarm = RTC_GetCounter() + 10;RTC_SetAlarm(alarm );//鬧鐘設置為10s后OLED_ShowNum(2, 6, alarm , 10);//使用wakeup喚醒PWR_WakeUpPinCmd(ENABLE);while(1){OLED_ShowNum(1, 6, RTC_GetCounter(), 10);OLED_ShowNum(3, 6, RTC_GetFlagStatus(RTC_FLAG_ALR), 1);OLED_ShowString(4, 1, "Running");Delay_ms(100);OLED_ShowString(4, 1, "       ");Delay_ms(100);//進入待機模式,程序將從頭開始執行,后續代碼不在執行,這也是不用再選擇開啟主頻的原因PWR_EnterSTANDBYMode();}return 0;}

14.看門狗

14.1.基礎概念

獨立看門狗?

窗口看門狗

WWDG 工作特性

  • 遞減計數器 T[6:0] 的值小于 0x40 時, WWDG 產生復位
  • 遞減計數器 T[6:0] 在窗口 W[6:0] 外被重新裝載時, WWDG 產生 復位
  • 遞減計數器 T[6:0] 等于 0x40 時可以產生早期喚醒中斷( EWI ), 用于重裝載計數器以避免 WWDG 復位:作用:復位前保護數據,關閉一些危險元器件
  • 定期寫入 WWDG_CR 寄存器(喂狗)以避免 WWDG 復位

獨立看門狗和窗口看門狗的區別

14.2.代碼實現

不用開啟時鐘的原因?

	//獨立看門狗int main(){OLED_Init();Key_Init();OLED_ShowString(1, 1, "IWDG test:");if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET){OLED_ShowString(2, 1, "IWDG RESET");Delay_ms(500);OLED_ShowString(2, 1, "          ");Delay_ms(100);RCC_ClearFlag();}else{OLED_ShowString(3, 1, "ELSE RESET");Delay_ms(500);OLED_ShowString(3, 1, "          ");Delay_ms(100);}IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//取消寫保護IWDG_SetPrescaler(IWDG_Prescaler_16);IWDG_SetReload(2500 - 1);IWDG_ReloadCounter();//啟動前先喂一次狗,第一次就是完整的時間IWDG_Enable();//啟動看門狗會改變鍵寄存器,進入寫保護while(1){GetKeyNum();//函數內有一個等放手的while函數,會導致堵塞IWDG_ReloadCounter();OLED_ShowString(4, 1, "FEED");Delay_ms(600);OLED_ShowString(4, 1, "    ");Delay_ms(200);}return 0;}

窗口看門狗

	//獨立看門狗int main(){OLED_Init();Key_Init();OLED_ShowString(1, 1, "WWDG test:");if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET){OLED_ShowString(2, 1, "WWDG RESET");Delay_ms(500);OLED_ShowString(2, 1, "          ");Delay_ms(100);RCC_ClearFlag();}else{OLED_ShowString(3, 1, "ELSE RESET");Delay_ms(500);OLED_ShowString(3, 1, "          ");Delay_ms(100);}RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);WWDG_SetPrescaler(WWDG_Prescaler_8);WWDG_SetWindowValue(0x40 | 21);WWDG_Enable(0x40 | 54);//啟動看門狗while(1){GetKeyNum();//函數內有一個等放手的while函數,會導致堵塞OLED_ShowString(4, 1, "FEED");Delay_ms(20);OLED_ShowString(4, 1, "    ");Delay_ms(20);WWDG_SetCounter(0x40 | 54);//喂狗}return 0;}

15. flash閃存

  • 使用flash閃存存儲數據時會占用閃存,這是代碼不在執行,因為程序存儲器(閃存的一部分)存儲著可執行程序

15.2.代碼實現使用閃存讀寫

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 = GetKeyNum();		//獲取按鍵鍵碼if (KeyNum == 1)			//按鍵1按下{Store_Data[1] ++;		//變換測試數據Store_Data[2] += 2;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);}
}

?

#include "stm32f10x.h"                  // Device headeruint32_t MyFLASH_ReadWord(uint32_t Address)
{return *((__IO uint32_t *)(Address));	//使用指針訪問指定地址下的數據并返回
}uint16_t MyFLASH_ReadHalfWord(uint32_t Address)
{return *((__IO uint16_t *)(Address));	//使用指針訪問指定地址下的數據并返回
}uint8_t MyFLASH_ReadByte(uint32_t Address)
{return *((__IO uint8_t *)(Address));	//使用指針訪問指定地址下的數據并返回
}void MyFLASH_EraseAllPages(void)
{FLASH_Unlock();					//解鎖FLASH_EraseAllPages();			//全擦除FLASH_Lock();					//加鎖
}void MyFLASH_ErasePage(uint32_t PageAddress)
{FLASH_Unlock();					//解鎖FLASH_ErasePage(PageAddress);	//頁擦除FLASH_Lock();					//加鎖
}void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data)
{FLASH_Unlock();							//解鎖FLASH_ProgramWord(Address, Data);		//編程字FLASH_Lock();							//加鎖
}void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data)
{FLASH_Unlock();							//解鎖FLASH_ProgramHalfWord(Address, Data);	//編程半字FLASH_Lock();							//加鎖
}
#ifndef __MYFLASH_H
#define __MYFLASH_Huint32_t MyFLASH_ReadWord(uint32_t Address);
uint16_t MyFLASH_ReadHalfWord(uint32_t Address);
uint8_t MyFLASH_ReadByte(uint32_t Address);void MyFLASH_EraseAllPages(void);
void MyFLASH_ErasePage(uint32_t PageAddress);void MyFLASH_ProgramWord(uint32_t Address, uint32_t Data);
void MyFLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);#endif
#include "stm32f10x.h"                  // Device header
#include "MyFLASH.h"#define STORE_START_ADDRESS		0x0800FC00		//存儲的起始地址
#define STORE_COUNT				512				//存儲數據的個數uint16_t Store_Data[STORE_COUNT];				//定義SRAM數組void Store_Init(void)
{/*判斷是不是第一次使用*/if (MyFLASH_ReadHalfWord(STORE_START_ADDRESS) != 0xA5A5)	//讀取第一個半字的標志位,if成立,則執行第一次使用的初始化{MyFLASH_ErasePage(STORE_START_ADDRESS);					//擦除指定頁MyFLASH_ProgramHalfWord(STORE_START_ADDRESS, 0xA5A5);	//在第一個半字寫入自己規定的標志位,用于判斷是不是第一次使用for (uint16_t i = 1; i < STORE_COUNT; i ++)				//循環STORE_COUNT次,除了第一個標志位{MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, 0x0000);		//除了標志位的有效數據全部清0}}/*上電時,將閃存數據加載回SRAM數組,實現SRAM數組的掉電不丟失*/for (uint16_t i = 0; i < STORE_COUNT; i ++)					//循環STORE_COUNT次,包括第一個標志位{Store_Data[i] = MyFLASH_ReadHalfWord(STORE_START_ADDRESS + i * 2);		//將閃存的數據加載回SRAM數組}
}void Store_Save(void)
{MyFLASH_ErasePage(STORE_START_ADDRESS);				//擦除指定頁for (uint16_t i = 0; i < STORE_COUNT; i ++)			//循環STORE_COUNT次,包括第一個標志位{MyFLASH_ProgramHalfWord(STORE_START_ADDRESS + i * 2, Store_Data[i]);	//將SRAM數組的數據備份保存到閃存}
}void Store_Clear(void)
{for (uint16_t i = 1; i < STORE_COUNT; i ++)			//循環STORE_COUNT次,除了第一個標志位{Store_Data[i] = 0x0000;							//SRAM數組有效數據清0}Store_Save();										//保存數據到閃存
}

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

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

相關文章

RISC-V 開發板 MUSE Pi Pro RTSP 串流 CSI ov5647 攝像頭

視頻鏈接&#xff1a;RISC-V 開發板 MUSE Pi Pro RTSP 串流 CSI ov5647 攝像頭_嗶哩嗶哩_bilibili RISC-V 開發板 MUSE Pi Pro RTSP 串流 CSI ov5647 攝像頭 RTSP&#xff08;Real-Time Streaming Protocol&#xff0c;實時流傳輸協議&#xff09; 是一種基于文本的應用層協議&…

Python面試1

1. 解釋型語言和編譯型語言的區別 編譯型語言&#xff1a; 將程序編譯成二進制可執行程序&#xff08;C、C) 解釋型語言&#xff1a; 將程序逐行解釋運行&#xff08;python&#xff09; Java不是將源程序直接編譯機器語言&#xff0c;而是編譯成字節碼文件&#xff0c;然后用…

輸入一串字符,統計其中字母的個數

#include <stdio.h> int main() { char ch; int count 0; printf("請輸入一串字符&#xff1a;\n"); while ((ch getchar())! \n) { if ((ch > a && ch < z) || (ch > A && ch < Z)) { count; } } printf("字母的個數為&a…

git基礎語法回顧

1. 初始化與克隆 git init 初始化一個新的本地倉庫。git clone <repo-url> 克隆遠程倉庫到本地&#xff08;如 git clone https://github.com/user/repo.git&#xff09;。 2. 基礎操作 git add <file> 將文件添加到暫存區&#xff08;如 git add main.py&#x…

華為倉頡語言初識:結構體struct和類class的異同

前言 華為倉頡語言是鴻蒙原生應用的一種新的編程語言&#xff0c;采用面向對象的編程思想&#xff0c;為開發者帶來新的開發體驗。不僅可以和 ArkTs 相互調用&#xff0c;更能提升應用程序的性能&#xff0c;更重要的是倉頡語言的特點結合了 java 和 C 的特點。對開發者來說比…

電池預測 | 第28講 基于CNN-GRU的鋰電池剩余壽命預測

電池預測 | 第28講 基于CNN-GRU的鋰電池剩余壽命預測 目錄 電池預測 | 第28講 基于CNN-GRU的鋰電池剩余壽命預測預測效果基本描述程序設計參考資料 預測效果 基本描述 電池預測 | 第28講 基于CNN-GRU的鋰電池剩余壽命預測 運行環境Matlab2023b及以上&#xff0c;鋰電池剩余壽…

在 Ubuntu 24.04 LTS 上 Docker 部署 DB-GPT

一、DB-GPT 簡介 DB-GPT 是一個開源的AI原生數據應用開發框架(AI Native Data App Development framework with AWEL(Agentic Workflow Expression Language) and Agents)。目的是構建大模型領域的基礎設施&#xff0c;通過開發多模型管理(SMMF)、Text2SQL效果優化、RAG框架以及…

早停策略和模型權重的保存

知識點回顧&#xff1a; 過擬合的判斷&#xff1a;測試集和訓練集同步打印指標模型的保存和加載 僅保存權重保存權重和模型保存全部信息checkpoint&#xff0c;還包含訓練狀態 早停策略 作業&#xff1a;對信貸數據集訓練后保存權重&#xff0c;加載權重后繼續訓練50輪&#xf…

DeepSpeed-Ulysses:支持極長序列 Transformer 模型訓練的系統優化方法

DeepSpeed-Ulysses&#xff1a;支持極長序列 Transformer 模型訓練的系統優化方法 flyfish 名字 Ulysses “Ulysses” 和 “奧德修斯&#xff08;Odysseus&#xff09;” 指的是同一人物&#xff0c;“Ulysses” 是 “Odysseus” 的拉丁化版本 《尤利西斯》&#xff08;詹姆…

Redis-基礎-總結

一、概述 Remote Dictionary Server(遠程字典服務)是完全開源的&#xff0c;使用ANSIC語言編寫遵守BSD協議&#xff0c;是一個高性能的Key-Value數據庫提供了豐富的數據結構&#xff0c;例如String、Hash、List、Set、sortedset等等。數據是存在內存中的&#xff0c;同時Redis…

尚硅谷redis7 28-32 redis持久化之理論介紹

28redis持久化之理論介紹 redis持久化&#xff1a;redis如何將內存數據寫入磁盤中 為什么需要持久化&#xff1f; 內存數據一斷電就會消失&#xff0c;那么所有的請求都會打到數據庫中。因此讓redis中的數據長期持有&#xff0c;不管是重啟、故障、恢復、宕機&#xff0c;還…

JS逆向【抖查查】逆向分析 | sign | secret簽名驗證

1.目標 目標網址&#xff1a;https://www.douchacha.com/bloggerRankingRise 切換日期出現目標請求 import requests import jsonheaders {"accept": "application/json, text/plain, */*","accept-language": "zh-CN,zh;q0.9","…

【數據倉庫面試題合集④】SQL 性能調優:面試高頻場景 + 調優策略解析

隨著業務數據規模的持續增長,SQL 查詢的執行效率直接影響到數據平臺的穩定性與數據產出效率。因此,在數據倉庫類崗位的面試中,SQL 性能調優常被作為重點考察內容。 本篇將圍繞常見 SQL 調優問題,結合實際經驗,整理出高頻面試題與答題參考,助你在面試中游刃有余。 ?? 高…

python打卡訓練營打卡記錄day37

知識點回顧&#xff1a; 過擬合的判斷&#xff1a;測試集和訓練集同步打印指標模型的保存和加載 僅保存權重保存權重和模型保存全部信息checkpoint&#xff0c;還包含訓練狀態 早停策略 作業&#xff1a;對信貸數據集訓練后保存權重&#xff0c;加載權重后繼續訓練50輪&#xf…

卷積神經網絡(CNN)深度講解

卷積神經網絡&#xff08;CNN&#xff09; 本篇博客參考自大佬的開源書籍&#xff0c;幫助大家從頭開始學習卷積神經網絡&#xff0c;謝謝各位的支持了&#xff0c;在此期待各位能與我共同進步? 卷積神經網絡&#xff08;CNN&#xff09;是一種特殊的深度學習網絡結構&#x…

深度體驗:海螺 AI,開啟智能創作新時代

人工智能 AI 工具如雨后春筍般涌現&#xff0c;而海螺 AI 以其獨特的魅力與卓越的性能&#xff0c;迅速在眾多產品中嶄露頭角&#xff0c;成為了無數創作者、辦公族以及各行業人士的得力助手。近期&#xff0c;我對海螺 AI 進行了深入的使用體驗&#xff0c;接下來就為大家詳細…

哈希表day5

242 有效的字母異位詞 思路就是轉為ASCII碼&#xff0c;然后用一個數組記錄26位字母出現的次數 #include <string> class Solution{ public:bool isAnagram(string s,string t){int record[26]{0};for (int i0;i<s.size();i){record[s[i]-a];}for (int i0;i<t.si…

【Python數據庫全棧指南】從SQL到ORM深度實踐

目錄 &#x1f31f; 前言&#x1f3d7;? 技術背景與價值&#x1fa79; 當前技術痛點&#x1f6e0;? 解決方案概述&#x1f465; 目標讀者說明 &#x1f9e0; 一、技術原理剖析&#x1f4ca; 核心概念圖解&#x1f4a1; 核心作用講解&#x1f527; 關鍵技術模塊說明?? 技術選…

Android磁盤占用優化全解析:從監控到治理的存儲效率革命

引言 隨著移動應用功能的復雜化&#xff0c;磁盤占用問題日益突出。據統計&#xff0c;國內頭部應用的平均安裝包大小已超100MB&#xff0c;運行時緩存、日志、圖片等數據更可能使磁盤占用突破GB級。過度的磁盤消耗不僅影響用戶設備空間&#xff0c;還可能觸發系統的“應用數據…

AJAX-讓數據活起來(一):入門

目錄 一、AJAX概念和axios使用 1.1 什么是AJAX ? 1.2 怎么用AJAX ? 1.3 axios使用 二、認識URL 2.1 什么是URL? 2.2 URL的組成 組成 協議 域名 資源路徑 獲取-新聞列表 三、URL查詢參數 URL查詢參數 axios - 查詢參數 四、常用請求方法和數據提交 常用請求…