void AD_Init(void)
(1)初始化DMA結構體變量
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. */
uint32_t DMA_MemoryBaseAddr; /*!< Specifies the memory base address for DMAy Channelx. */
uint32_t DMA_DIR; /*!< Specifies if the peripheral is the source or destination.This parameter can be a value of @ref DMA_data_transfer_direction */
uint32_t DMA_BufferSize; /*!< Specifies the buffer size, in data unit, of the specified Channel. The data unit is equal to the configuration set in DMA_PeripheralDataSize or DMA_MemoryDataSize members depending in the transfer direction. */
uint32_t DMA_PeripheralInc; /*!< Specifies whether the Peripheral address register is incremented or not.This parameter can be a value of @ref DMA_peripheral_incremented_mode */
uint32_t DMA_MemoryInc; /*!< Specifies whether the memory address register is incremented or not.This parameter can be a value of @ref DMA_memory_incremented_mode */
uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.This parameter can be a value of @ref DMA_peripheral_data_size */
uint32_t DMA_MemoryDataSize; /*!< Specifies the Memory data width.This parameter can be a value of @ref DMA_memory_data_size */
uint32_t DMA_Mode; /*!< Specifies the operation mode of the DMAy Channelx.This parameter can be a value of @ref DMA_circular_normal_mode. @note: The circular buffer mode cannot be used if the memory-to-memodata transfer is configured on the selected Channel */
uint32_t DMA_Priority; /*!< Specifies the software priority for the DMAy Channelx.This parameter can be a value of @ref DMA_priority_level */
uint32_t DMA_M2M; /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.This parameter can be a value of @ref DMA_memory_to_memory */
}DMA_InitTypeDef;
{
}
什么是DMA?其全稱是:Direct Memory Access;根據ST公司提供的相關信息,DMA是STM32中一個獨立與Cortex-M3內核的模塊,有點類似與ADC、PWM、TIMER等模塊;主要功能是通信“橋梁”的作用,可以將所有外設映射的寄存器“連接”起來,這樣就可以高速問各寄存器,其傳輸不受CPU的支配,傳輸還是雙向的;例如,從“表面”上看,它可以將flash中的數據與儲存器中變量建立通訊,還可以將一外設的積存器或緩沖器與另外設的寄存器或緩沖器建立雙向通訊,有點像把外設硬件之間用“導線”連接在一起了。其間的通訊不占CPU資源,訪問速度高,對於實時性強的應用將是一個很好的選擇;就像我們人一樣,我們平常習慣性的動作是不用經過大腦思考的,比如說眨眼睛,呼吸等。DMA就是負責這些工作的,但它沒人這么智能,需要將它設置好了它才會正常工作。當然,對於實時性非常強的,建議還是采用專用的DSP芯片。
(2)初始化ADC結構體變量
typedef struct
{
uint32_t ADC_Mode; /*!< Configures the ADC to operate in independent or dual mode. This parameter can be a value of @ref ADC_mode */
FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel) mode.
This parameter can be set to ENABLE or DISABLE */
FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in Continuous or Single mode.This parameter can be set to ENABLE or DISABLE. */
uint32_t ADC_ExternalTrigConv; /*!< Defines the external trigger used to start the analog to digital conversion of regular channels. This parameter can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */
uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right.This parameter can be a value of @ref ADC_data_align */
uint8_t ADC_NbrOfChannel; /*!< Specifies the number of ADC channels that will be converted using the sequencer for regular channel group.
This parameter must range from 1 to 16. */
}ADC_InitTypeDef;
{
}
(3)初始化GPIO結構體變量
(4)初始化外設GPIOC設置引腳(pin9、pin6、pin7),速度,模式:推挽輸出
(5)初始化外設GPIOA設置引腳PIN11速度,模式:推挽輸出
(6)初始化外設GPIOE設置引腳(pin2,pin4,pin5,pin6,pin7,pin9,pin12),速度,模式:推挽輸出
(7)清除指定的數據端口位(清除外設GPIOE的端口為pin5)
(8)初始化外設GPIOA設置引腳(pin0,pin1,pin5,pin6,pin7),模式:模擬輸入
(9)初始化外設GPIOB設置引腳(pin0,,pin1),模式:模擬輸入
(10)初始化外設GPIOC設置引腳(PIN0,PIN1,PIN2,pin3,pin4,pin5),模式:模擬輸入
(11)DMA1通道1配置
①使通道1缺省
②設置DMA
DMA1外設基地址ADC1_DR_Address
DMA1內存基地址&ADC1ConvertedValue//////INT16U ADC1ConvertedValue[13] = {0}; //用於存放讀取的AD值
規定了外設是作為數據傳輸的來源
DMA1通道的DMA緩存大小為13
設定外設地址寄存器不增值
設定內存地址寄存器遞增
設定了外設數據寬度DMA_PeripheralDataSize_HalfWord
//#define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100)
設定了外設數據寬度DMA_MemoryDataSize_HalfWord
//#define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400)
設置了 CAN 的工作模式:工作在循環緩存模式
設定 DMA 通道 1 的軟件優先級//高優先級
DMA 通道 1 沒有設置為內存到內存傳輸
③根據上面設置初始化DMA1的通道1寄存器
(12)ADC1配置
①設置ADC1
設置 ADC1 工作在獨立
規定了模數轉換工作在掃描模式(多通道)
規定了模數轉換工作在連續
定義了轉換由軟件而不是外部觸發啟動
ADC 數據右對齊
規定了順序進行規則轉換的 ADC 通道的數目13
②根據 ADC_InitStruct 中指定的參數初始化外設 ADC1 的寄存器
(13)配置ADC1正規渠道
設置ADC1外設不同通道的采樣順序及采樣時間
(14)使ADC的DMA請求
(15)使能ADC1
(16)重置指定的 ADC 的校准寄存器·
(17)獲取 ADC 重置校准寄存器的狀態
(18)開始指定 ADC 的校准狀態
(19)獲取指定 ADC 的校准程序
(20)使DMA1的通道1使能
(21)使能指定的 ADC 的軟件轉換啟動功能(連續轉換開始,ADC通過DMA方式不斷的更新RAM區。)
最后一步將ADC的值傳入到之前申明的INT16U ADC1ConvertedValue[13] = {0}; //用於存放讀取的AD值中。
#define ADC1_Chanel0 0
#define ADC1_Chanel1 1
#define ADC1_Chanel2 2
#define ADC1_Chanel3 3
#define ADC1_Chanel4 4
#define ADC1_Chanel5 5
#define ADC1_Chanel6 6
#define ADC1_Chanel7 7
#define ADC1_Chanel8 8
#define ADC1_Chanel9 9
#define ADC1_Chanel10 10
#define ADC1_Chanel11 11
#define ADC1_Chanel12 12
#define ADC1_Chanel13 13
#define ADC1_Chanel14 14
#define ADC1_Chanel15 15
#define ADC1_Chanel16 16
//====AD開啟通道個數======================
#define ADC_ENB_NUM 1
#define ADC_CYC_Cycles5 ADC_SampleTime_55Cycles5 //設置AD轉換速率
uint16_t AD_Value[ADC_ENB_NUM] ;
//DMA存儲數據的區域
#define ADC1_DR_Address ((uint32_t)0x4001244C) //ADC1數據寄存器的基地址
//*************************************
// 函數名稱:ADC1_Config
// 函數功能:adc1 初始化配置
// 入口參數:無
// 出口參數:無
// 返 回 值:無
//***************************************/
void
ADC1_Config(
void
)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);
//使能ADC
/* DMA1 channel1 configuration ----------------------------------------------*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6) ;
//ADC時鍾分頻 72/6 = 12M
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
//獨立的轉換模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
//開啟掃描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//開啟連續轉換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
//ADC外部開關,關閉狀態
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
//對齊方式,ADC為12位中,右對齊方式
ADC_InitStructure.ADC_NbrOfChannel = ADC_ENB_NUM;
//開啟通道數,1個
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular channel9 configuration */
//ADC通道組,第9個通道 采樣順序1,轉換時間
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_CYC_Cycles5);
// ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 2, ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC1, ENABLE);
//ADC命令,使能
ADC_Cmd(ADC1, ENABLE);
//開啟ADC1
ADC_ResetCalibration(ADC1);
//重新校准
while
(ADC_GetResetCalibrationStatus(ADC1));
//等待重新校准完成
ADC_StartCalibration(ADC1);
//開始校准
while
(ADC_GetCalibrationStatus(ADC1));
//等待校准完成
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
//連續轉換開始,ADC通過DMA方式不斷的更新RAM區。
// ADC_TempSensorVrefintCmd(ENABLE);
}
//*************************************
// 函數名稱:DMA_Config_ADC1
// 函數功能:DMA 初始化配置
// 入口參數:無
// 出口參數:無
// 返 回 值:無
//***************************************/
void
DMA_Config_ADC1(
void
)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
//使能DMA時鍾
DMA_DeInit(DMA1_Channel1);
//開啟DMA1的第一通道
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
//DMA對應的外設基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value[0];
//內存存儲基地址 自己開僻的數組
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//DMA的轉換模式為SRC模式,由外設搬移到內存
DMA_InitStructure.DMA_BufferSize = Num_Adc_Chanel;
//DMA緩存大小,N個
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//接收一次數據后,設備地址禁止后移
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//關閉接收一次數據后,目標內存地址后移
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
//定義外設數據寬度為16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//DMA搬移數據尺寸,HalfWord就是為16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//轉換模式,循環緩存模式。
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//DMA優先級高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//M2M模式禁用
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 channel1 */
DMA_Cmd(DMA1_Channel1, ENABLE);
}
//===ADC GPIO 初始化=======
void
ADC1_GPIOInit(
void
)
{
//-----------PB---------------------------------
//VR 端口 PB1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
//管腳1
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//50M時鍾速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
//輸入模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//====實例應用=======
//ADC1初始化設置
ADC1_GPIOInit() ;
ADC1_Config() ;
DMA_Config_ADC1() ;
//dma設置
//--主程序-----
void
mian(
void
)
{
while
(1)
{
while
(!F_10MS);
F_10MS = 0 ;
Tmp = AD_Value[0] ;
//在緩存區中 讀取AD結果
}
}
神通廣大的各位互聯網的網友們、大家早上中午晚上好好好、今早起來很准時的收到了兩條10086的扣月租的信息、心痛不已、懷着這心情、又開始了STM32的研究、早上做了計算機控制的PID實驗,又讓我想起了飛思卡爾的電磁小車、、曾經的電感電壓采集讓我心碎的多少次、又讓我開心了多少次、但已經成為過去、(軟件和硬件都會影響),呵呵、估計有人已經猜到我接下來要介紹什么了、在你們面前、我已無秘密、額、其實標題也直接“表白”了、看到標題,別嚇到哈、並不是要用英文寫、至於原因是什么、請往下看:
好吧、言歸正傳:STM32的ADC模塊,請允許我用如此通俗的語言:普通話 來介紹STM32ADC模塊的特色
1、1MHz轉換速率、12位轉換結果(12位、記住這個12位哈、因為2^12=4096 ,也請記住4096哈)
STM32F103系列:在56MHz時轉換時間為:1μs
在72MHz時轉換時間為:1.17μs
2、轉換范圍:0~3.6V (3.6v---->當你需要將采集的數據用電壓來顯示的話:設你采集的數據為:x[0~4095],此時的計算公式就為:(x / 4096) * 3.6))
3、ADC供電要求:2.4V~3.6 V(可千萬別接到 5V 的石榴裙子底下呀)
4、ADC輸入范圍:VREF-≤ VIN ≤VREF+ (VREF+和VREF-只有LQFP100封裝才有)
5、雙重模式(帶2個ADC的設備): 8種轉換模式
6、最多有18個通道:16個外部通道
2個內部通道:連接到溫度傳感器和內部參考電壓(VREFINT = 1.2V)
......(略,請看參考手冊哈,由於篇幅,就不過多的列出來了、、說到略、讓我想起了月光寶盒諸葛亮的:略懂略懂、、其實我也是略懂略懂而已、、)
12、DMA功能(僅ADC1有)
本博客里,由於篇幅、所以就以獨立模式下的單次轉換為例哈、打開參考手冊可以看到這段話:
單次轉換模式下,ADC只執行一次轉換。
該模式既可通過設置ADC_CR2寄存器的ADON位(只適用於規則通道)啟動也可通過外部觸發啟動(適用於規則通道或注入通道),這時CONT位為0。
一旦選擇通道的轉換完成:
● 如果一個規則通道被轉換: ─ 轉換數據被儲存在16位ADC_DR寄存器中 ─ EOC(轉換結束)標志被設置 ─ 如果設置了EOCIE,則產生中斷。
● 如果一個注入通道被轉換: ─ 轉換數據被儲存在16位的ADC_DRJ1寄存器中 ─ JEOC(注入轉換結束)標志被設置 ─ 如果設置了JEOCIE位,則產生中斷。
然后ADC停止。
此圖形象的表明了其背后那不為人知的秘密轉換關系。。雖然單憑看文字就能想象出來、但是、有圖片是不是更加形象呢???
對於以上的寄存器、在此我稍微提提:免得寄存器大神們產生怨氣:好不容易等到你講我老大ADC,卻不把我這些背后的勤勞者給導出來
好了,那就恕小弟容稟:
1、ADC狀態寄存器(ADC_SR)
2、ADC控制寄存器1(ADC_CR1)
3、ADC控制寄存器2(ADC_CR2)
EXTSEL[2:0]:選擇啟動規則通道組轉換的外部事件 (External event select for regular group)
ALIGN:數據對齊 (Data alignment)
RSTCAL:復位校准 (Reset calibration)
CAL:A/D校准 (A/D Calibration)
CONT:連續轉換 (Continuous conversion)
ADON:開/關A/D轉換器 (A/D converter ON / OFF)
4、ADC采樣時間寄存器1(ADC_SMPR1)
SMPx[2:0]:選擇通道x的采樣時間 (Channel x Sample time selection)
5、ADC規則序列寄存器1(ADC_SQR1)
L[3:0]:規則通道序列長度 (Regular channel sequence length)
SQ1[4:0]:規則序列中的第1個轉換 (1st conversion in regular sequence)(ADC規則序列寄存器3(ADC_SQR3))
6、ADC規則數據寄存器(ADC_DR)
DATA[15:0]:規則轉換的數據 (Regular data)
(由於寄存器過於多,我們就不在這一一列舉了哈、、因為我主要是用庫,所以寄存器相關的位都不具體介紹了哈、請大家參照中文手冊)
在這里,向大家介紹下:數據對齊:
ALIGN位用於設置對齊方式:右或左;
對於注入通道,轉換結果是減去偏移量的值,可以為一個負數,在右對齊時擴展位位符號位。
那我們現在要怎么來實現呢??這個問題、相信大家在看了那么多的寄存器之后急迫想要知道的吧、、前面的只是個熱身、、接下來步驟如下:
1、開啟ADC1的時鍾,由於ADC1是在PA1上,所以同時也要打開PA的時鍾,並進行相關的配置、對於這個配置,要把PA1設置成模擬輸入,為什么呢??大家打開中文參考手冊可以看到
啊哈、、這下子清楚了吧、
2、復位ADC1,(本人覺得沒必要、為什么,待會我會跟你說,留下懸念先),設置ADC1的分頻因子,(記住,這里的ADC的時鍾不能超過14MHZ),而且其采樣周期長點會好點,
ADCCLK---最快可達14MHz, 時鍾來自經過分頻器的PCLK2(2、4、6、8分頻)
整個轉換時間 = 采樣時間 + 12.5個周期(固定時間)
在14MHz和采樣時間位1.5周期時 è 轉換時間:1μs (14個周期 cycles)
當ADCCLK=14MHz和1.5周期的采樣時間:
TCONV = 1.5 + 12.5 = 14周期 = 14×(1 / (14 × 1000000)) = 1μs
其采樣周期一覽表:
涉及到采樣周期、這里來看看轉換序列:
最多達16個轉換通道且可以采樣不同的順序排列,不同的采樣時間和過采樣的可能性。
例如:- 轉換通道:1、2、8、4、7、3、11
- 不同的采樣時間;
- Oversampling of channel 7。
3、初始化ADC1的參數、設置ADC1的工作模式和規則序列的相關信息;
大家通過打開"stm32f10.adc.h"可以看到:
typedef struct
{
uint32_t ADC_Mode; //設置ADC模式-->獨立模式
FunctionalState ADC_ScanConvMode; //設置是否開啟掃描模式 --->否
FunctionalState ADC_ContinuousConvMode; //設置是否開啟連續轉換模式 ---->否
uint32_t ADC_ExternalTrigConv; //設置啟動規則轉換組轉換模式---->軟件觸發
uint32_t ADC_DataAlign; //設置數據對齊方式----->右對齊
uint8_t ADC_NbrOfChannel; //設置規則序列的長度---->順序進行規則轉換的ADC通道數目1
}ADC_InitTypeDef;
4、使能ADC並校准
注:在設置完了以上信息后,使能AD轉換器,執行復位校准和AD校准(這兩步校准一定要,否則數據將不准)
還有記住,每次進行校准之后都要等待校准結束,但是通過什么方式知道校准結束呢?
這里是通過獲取校准狀態來判斷是否校准結束,相關的庫函數請看代碼
分別的庫函數請看待會的代碼。(請用比較老外的方式去看,也就是用英語啦,為什么呢?請看下文)
5、讀取AD的值
當然,這里說讀取AD值並不是那么的簡單,以上我們只是准備好了AD,還沒有設置相關的規則序列通道,采樣順序,以及采樣周期,設置完之后啟動AD轉換就行了、然后才直接讀取哈、、
相關的庫函數請看代碼、
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable ADC1 and GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//12MHZ
/* Configure PA.1 (ADC Channel) as analog input -------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//ADC_DeInit(ADC1);//在這里復位被我注釋掉了、至於為什么,我待會會說
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//這里對應上面所講的配置,在這里就不給出注釋了
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* Enable ADC1 *///知道我為啥要在上面提醒大家要用老外的方式來看了吧、因為這里的注釋都是用英文的
//請不要以為我裝逼,我這樣做是有原因的、、原因我待會會說、你也會明白我最初的標題為何那樣寫
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_val(u8 ch)
{
u16 DataValue; //又是英文注釋、、啊哈 /* ADC1 regular channel14 configuration */
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5);
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
/* Test if the ADC1 EOC flag is set or not */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
//FlagStatus Status;
//Status = ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC);
//while(!Status);---->這樣做實現不了、請注意
/*Returns the ADC1 Master data value of the last converted channel*/
DataValue = ADC_GetConversionValue(ADC1);
return DataValue;
}
u16 ADC_Get_aveg(u8 ch,u8 n)
{
u32 ad_sum = 0;
u8 i;
for(i=0;i<n;i++)
{
ad_sum += Get_val(ch);
delay_ms(5);
}
return (ad_sum / n);
}
adcx=ADC_Get_aveg(ADC_Channel_1,10);//獲取AD數值(0~4095)
temp=(float)adcx*(3.3/4096);//獲取相應的電壓值
到了這一步,我們已經完成了AD采集數據的任務、接下來,有人可能有時候會覺得很納悶,為什么有些人知道要完成特定的功能,它的步驟是怎么樣的、為什么我就不知道??這個問題嘛、、接下來我講的希望能稍微幫你,也希望你能好好的借鑒、
步驟小技巧:其實也沒啥的、大家知道下載庫的文件的時候,里面都有包含每個模塊的例子和一個模版、拿ADC這個模塊來舉例:
點擊main.c可以看到神奇的一幕:
大家仔細看看,可以發現在官方給的歷程中的步驟里並沒有復位ADC的函數,個人覺得所以沒有必要去復位當然復位也不是什么壞事哈、看你個人、、看到這、應該明白了我前面的說法了吧、還有、大家應該也注意到了、都是英文的注釋、、所以看到這大家也清楚了,前面不是我裝逼、、所以呢、其實英語對於我們來說還是很重要的、、那有人問,時鍾的分頻因子呢?怎么沒有設置??不急哈、、請看:
對於分頻因子的設置,也在這個函數里:而這個RCC_Configuration()在最開始已經使用 了、、
所以大家要好好利用官方給的歷程、說到這、你猜我詞窮了嗎?
答案是否定的、、我還有話要說:
做一件事要有一個目的、、才不會顯得自己做的很空泛、、我寫博客也一樣、、我想讓我自己理清思路、也希望自己在寫的過程中能領悟到自己在學的時候沒領悟到的知識點、、也希望能幫到跟我有一樣困惑的人、、我把我不懂的理解后寫下來、我也知道會有人跟我一樣遇到同樣不懂的地方、、所以這就是我的目的哈、、希望能幫到你們、、盡管不認識你們、、啊哈、、初學者、難免有出錯、、所以、寫錯或理解錯的請幫我指出來、臣不甚感激,今當遠離,零表涕零,不知所言、、