日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

STM32F429第四篇之跑马灯程序详解

發(fā)布時(shí)間:2023/12/10 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32F429第四篇之跑马灯程序详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 前言
  • 硬件
  • 軟件
    • 編寫代碼
      • 主程序
        • HAL庫(kù)初始化
        • RCC時(shí)鐘初始化
        • 延時(shí)函數(shù)初始化
      • LED驅(qū)動(dòng)
    • HAL庫(kù)詳解
      • GPIO
        • GPIO初始化
        • GPIO位操作
      • RCC
        • 振蕩器參數(shù)設(shè)置
        • 時(shí)鐘初始化
      • systick

前言

本文以上篇博文<STM32F429第三篇之GPIO的模板工程構(gòu)建>構(gòu)建的項(xiàng)目為歷程,講解在HAL庫(kù)中如何操作控制GPIO的輸出,以及STM32編程的步驟。

本文主要參考文獻(xiàn)為:

  • 正點(diǎn)原子.STM32F429開發(fā)指南——HAL庫(kù)版本
  • STM32F429xx中文數(shù)據(jù)手冊(cè)——DocID024030 Rev 4
  • RM0090 參考手冊(cè)——文檔 ID 018909 第 4 版
  • RM0090 Reference manual——RM0090 Rev 18
  • Cortex-M3 權(quán)威指南

本文更新順序:

  • 20200911——更新LED驅(qū)動(dòng)程序部分,以及HAL庫(kù)講解中的GPIO部分。
  • 20201020——更新主程序中的RCC時(shí)鐘初始化部分,延時(shí)函數(shù)初始化部分。
  • 20201023——更新RCC時(shí)鐘初始化部分和RCC部分。
  • 20201104——更新振蕩器初始化程序部分。
  • 20201106——更新了時(shí)鐘初始化部分。

硬件

軟件

編寫代碼

在該程序中,主要需要編寫兩個(gè)部分的代碼:

  • 主程序
  • led初始化程序

下面分別講解:

主程序

#include "sys.h" #include "delay.h" #include "led.h"int main(void) {HAL_Init(); //初始化HAL庫(kù) Stm32_Clock_Init(360,25,2,8); //設(shè)置時(shí)鐘,180Mhzdelay_init(180); //初始化延時(shí)函數(shù)LED_Init(); //初始化LEDwhile(1){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //LED0對(duì)應(yīng)引腳PB1拉低,亮HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); //LED1對(duì)應(yīng)引腳PB0拉高,滅delay_ms(500); //延時(shí)500msHAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); //LED0對(duì)應(yīng)引腳PB1拉高,滅HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET); //LED1對(duì)應(yīng)引腳PB0拉低,亮delay_ms(500); //延時(shí)500ms}}

主程序很簡(jiǎn)單,可以概括為以下幾個(gè)步驟:

  • HAL庫(kù)初始化
  • RCC時(shí)鐘初始化
  • 相關(guān)外設(shè)初始化
    • 延時(shí)函數(shù)初始化
    • LED相關(guān)的GPIO初始化
  • while循環(huán)

HAL庫(kù)初始化

HAL初始化部分比較復(fù)雜,涉及的內(nèi)容比較多,這部分的詳細(xì)講解以后補(bǔ)上。這里大致說明其所實(shí)現(xiàn)的功能有4個(gè)方面:

  • 初始化FLASH部分。使能FLASH的預(yù)存,數(shù)據(jù)緩存,指令緩存。
  • 設(shè)置NVIC組的優(yōu)先級(jí)為4;
  • 將systick(系統(tǒng)定時(shí)器)作為time base的時(shí)鐘源,且將其配置為1ms。
  • Msp初始化。

其源程序如下:

/*** @brief This function is used to initialize the HAL Library; it must be the first * instruction to be executed in the main program (before to call any other* HAL function), it performs the following:* Configure the Flash prefetch, instruction and Data caches.* Configures the SysTick to generate an interrupt each 1 millisecond,* which is clocked by the HSI (at this stage, the clock is not yet* configured and thus the system is running from the internal HSI at 16 MHz).* Set NVIC Group Priority to 4.* Calls the HAL_MspInit() callback function defined in user file * "stm32f4xx_hal_msp.c" to do the global low level hardware initialization * * @note SysTick is used as time base for the HAL_Delay() function, the application* need to ensure that the SysTick time base is always set to 1 millisecond* to have correct HAL operation.* @retval HAL status*/ HAL_StatusTypeDef HAL_Init(void) {/* Configure Flash prefetch, Instruction cache, Data cache */ #if (INSTRUCTION_CACHE_ENABLE != 0U)__HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); #endif /* INSTRUCTION_CACHE_ENABLE */#if (DATA_CACHE_ENABLE != 0U)__HAL_FLASH_DATA_CACHE_ENABLE(); #endif /* DATA_CACHE_ENABLE */#if (PREFETCH_ENABLE != 0U)__HAL_FLASH_PREFETCH_BUFFER_ENABLE(); #endif /* PREFETCH_ENABLE *//* Set Interrupt Group Priority */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */HAL_InitTick(TICK_INT_PRIORITY);/* Init the low level hardware */HAL_MspInit();/* Return function status */return HAL_OK; }

RCC時(shí)鐘初始化

RCC時(shí)鐘初始化主要通過函數(shù)Stm32_Clock_Init實(shí)現(xiàn),需要注意的是,該函數(shù)并非是HAL庫(kù)官方提供的函數(shù),而是由正點(diǎn)原子實(shí)現(xiàn)。其源程序如下:

void Stm32_Clock_Init(u32 plln, u32 pllm, u32 pllp, u32 pllq) {HAL_StatusTypeDef ret = HAL_OK;/***********************************1.使能PWR時(shí)鐘*****************************************************/__HAL_RCC_PWR_CLK_ENABLE();/***********************************2.設(shè)置調(diào)壓器輸出電壓級(jí)別*******************************************/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); //設(shè)置調(diào)壓器輸出電壓級(jí)別1/***********************************3.配置時(shí)鐘源相關(guān)參數(shù)**********************************************/RCC_OscInitTypeDef RCC_OscInitStructure;RCC_OscInitStructure.OscillatorType = RCC_OSCILLATORTYPE_HSE; //振蕩器類型為HSE(外部高速振蕩器)RCC_OscInitStructure.HSEState = RCC_HSE_ON; //打開HSERCC_OscInitStructure.PLL.PLLState = RCC_PLL_ON; //打開PLLRCC_OscInitStructure.PLL.PLLSource = RCC_PLLSOURCE_HSE; //PLL時(shí)鐘源選擇HSERCC_OscInitStructure.PLL.PLLM = pllm; //主PLL和音頻PLL分頻系數(shù)(PLL之前的分頻),取值范圍:2~63.RCC_OscInitStructure.PLL.PLLN = plln; //主PLL倍頻系數(shù)(PLL倍頻),取值范圍:64~432.RCC_OscInitStructure.PLL.PLLP = pllp; //系統(tǒng)時(shí)鐘的主PLL分頻系數(shù)(PLL之后的分頻),取值范圍:2,4,6,8.(僅限這4個(gè)值!)RCC_OscInitStructure.PLL.PLLQ = pllq; //USB/SDIO/隨機(jī)數(shù)產(chǎn)生器等的主PLL分頻系數(shù)(PLL之后的分頻),取值范圍:2~15.ret = HAL_RCC_OscConfig(&RCC_OscInitStructure); //振蕩器參數(shù)初始化if(ret != HAL_OK) while(1);/***********************************4.開啟over-driver功能**********************************************/ret = HAL_PWREx_EnableOverDrive(); //開啟Over-Driver功能if(ret != HAL_OK) while(1);/***********************************5.配置系統(tǒng)時(shí)鐘相關(guān)參**********************************************/RCC_ClkInitTypeDef RCC_ClkInitStructure;//選中PLL作為系統(tǒng)時(shí)鐘源并且配置HCLK,PCLK1和PCLK2RCC_ClkInitStructure.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);RCC_ClkInitStructure.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //設(shè)置系統(tǒng)時(shí)鐘時(shí)鐘源為PLLRCC_ClkInitStructure.AHBCLKDivider = RCC_SYSCLK_DIV1; //AHB分頻系數(shù)為1RCC_ClkInitStructure.APB1CLKDivider = RCC_HCLK_DIV4; //APB1分頻系數(shù)為4RCC_ClkInitStructure.APB2CLKDivider = RCC_HCLK_DIV2; //APB2分頻系數(shù)為2ret = HAL_RCC_ClockConfig(&RCC_ClkInitStructure, FLASH_LATENCY_5); //同時(shí)設(shè)置FLASH延時(shí)周期為5WS,也就是6個(gè)CPU周期。if(ret != HAL_OK) while(1); }

上述代碼可以大致分成以下五個(gè)部分:

  • 使能PWR時(shí)鐘。
  • 設(shè)置調(diào)壓器輸出的電壓級(jí)別。
  • 配置時(shí)鐘源相關(guān)參數(shù)。
  • 開啟Over-Driver功能。
  • 配置系統(tǒng)時(shí)鐘相關(guān)參數(shù)。
  • 其中,第1,2,4步驟與PWR模塊有關(guān)系。此處不再詳細(xì)解釋。第1步之所以需要使能PWR時(shí)鐘,是因?yàn)樵诘?步和第4步都需要電源相關(guān)的配置。
    我們確定電源電壓和HCLK時(shí)鐘頻率之后,電壓幾倍VOS,Over-Driver功能和FLASH的延時(shí)Latency參數(shù)是固定的。VOS的參數(shù)含義官方解釋為:

    通過查詢數(shù)據(jù)手冊(cè)可以得到:

    通過以上官方文檔可以了解,若需要將STM32F429運(yùn)行在最高時(shí)鐘頻率180MHz,則需要選擇電源級(jí)別為1,且打開 超載(Over-Driver) 功能。而上述的第1,2,4步驟即實(shí)現(xiàn)該功能,讓ARM可以運(yùn)行在頻率180MHz處。
    步驟3和步驟5是通過HAL庫(kù)中RCC功能實(shí)現(xiàn)時(shí)鐘分配,關(guān)于此處使用到的結(jié)構(gòu)體和函數(shù)的用法可以參考博客<STM32F429第八篇之stm32f4xx_hal_rcc>。關(guān)于RCC時(shí)鐘配置的更多信息,可以參考博客<STM32F429第七篇之RCC(復(fù)位與時(shí)鐘)>

    Flash等待周期可以通過下表確定:

    一般地,我們開發(fā)板工作在3.3V,180MHz的環(huán)境下,因此可知,等待周期為5WS(6CPU周期)。

    延時(shí)函數(shù)初始化

    //初始化延遲函數(shù) //當(dāng)使用ucos的時(shí)候,此函數(shù)會(huì)初始化ucos的時(shí)鐘節(jié)拍 //SYSTICK的時(shí)鐘固定為AHB時(shí)鐘 //SYSCLK:系統(tǒng)時(shí)鐘頻率 void delay_init ( u8 SYSCLK ) { #if SYSTEM_SUPPORT_OS //如果需要支持OS.u32 reload; #endifHAL_SYSTICK_CLKSourceConfig ( SYSTICK_CLKSOURCE_HCLK ); //SysTick頻率為HCLKfac_us = SYSCLK; //不論是否使用OS,fac_us都需要使用#if SYSTEM_SUPPORT_OS //如果需要支持OS.reload = SYSCLK; //每秒鐘的計(jì)數(shù)次數(shù) 單位為Kreload *= 1000000 / delay_ostickspersec; //根據(jù)delay_ostickspersec設(shè)定溢出時(shí)間//reload為24位寄存器,最大值:16777216,在180M下,約合0.745s左右fac_ms = 1000 / delay_ostickspersec; //代表OS可以延時(shí)的最少單位SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk; //開啟SYSTICK中斷SysTick->LOAD = reload; //每1/OS_TICKS_PER_SEC秒中斷一次SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK #else #endif }

    LED驅(qū)動(dòng)

    頭文件

    #ifndef _LED_H #define _LED_Hextern void LED_Init(void);#endif

    C文件

    #include "led.h" #include "stm32f4xx.h"void LED_Init(void) {__HAL_RCC_GPIOB_CLK_ENABLE(); //開啟GPIOB時(shí)鐘GPIO_InitTypeDef GPIO_Initure;GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1; //PB1,0GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出GPIO_Initure.Pull=GPIO_PULLUP; //上拉GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速HAL_GPIO_Init(GPIOB,&GPIO_Initure);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET); //PB0置1,默認(rèn)初始化后燈滅HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); //PB1置1,默認(rèn)初始化后燈滅 }

    led驅(qū)動(dòng)程序主要實(shí)現(xiàn)以下幾個(gè)功能:

    • 開啟GPIOB的時(shí)鐘。
    • 對(duì)led相關(guān)的引腳PB0和PB1進(jìn)行功能初始化。
    • 初始化LED的初始狀態(tài)為熄滅狀態(tài)。

    其主要的初始化步驟本質(zhì)上為GPIO的初始化步驟,其官方的步驟可以參考博客<STM32F429第六篇之stm32f4xx_hal_gpio>中的使用方法 節(jié)。

    HAL庫(kù)詳解

    GPIO

    通過編寫代碼部分,我們可以總結(jié)出,該例程關(guān)于GPIO部分主要使用了兩個(gè)HAL庫(kù)函數(shù):

    • HAL_GPIO_Init();//GPIO初始化程序
    • HAL_GPIO_WritePin();//GPIO位操作

    關(guān)于兩個(gè)函數(shù)的使用方法,可以參考博客<STM32F429第六篇之stm32f4xx_hal_gpio>中 函數(shù) 節(jié)。

    GPIO初始化

    /*** @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.* @param GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F429X device or* x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.* @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains* the configuration information for the specified GPIO peripheral.* @retval None*/ void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) {uint32_t position;uint32_t ioposition = 0x00U;uint32_t iocurrent = 0x00U;uint32_t temp = 0x00U;/* Check the parameters */assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));assert_param(IS_GPIO_PIN(GPIO_Init->Pin));assert_param(IS_GPIO_MODE(GPIO_Init->Mode));assert_param(IS_GPIO_PULL(GPIO_Init->Pull));//此處沒有檢查所有的參數(shù)/* Configure the port pins *///進(jìn)入循環(huán),GPIO_NUMBER為16,表示端口有16個(gè)引腳for(position = 0U; position < GPIO_NUMBER; position++){/* Get the IO position */ioposition = ((uint32_t)0x01U) << position; //當(dāng)前處理數(shù)據(jù)位的位置/* Get the current IO position */iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition; //獲取當(dāng)前位的PIN值是否置1if(iocurrent == ioposition) //當(dāng)前數(shù)據(jù)數(shù)據(jù)位需要初始化{/*--------------------- GPIO Mode Configuration ------------------------*//* In case of Alternate function mode selection *///判斷引腳是否為復(fù)用功能,若是,將該引腳對(duì)應(yīng)的復(fù)用功能寫入。if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)){/* Check the Alternate function parameter */assert_param(IS_GPIO_AF(GPIO_Init->Alternate)); //此處檢測(cè)復(fù)用功能是否參數(shù)正確/* Configure Alternate function mapped with the current IO */temp = GPIOx->AFR[position >> 3U]; //AFR數(shù)組有兩個(gè)元素,分別對(duì)應(yīng)AFRL和AFRH。position取值為0-15,其中0-7對(duì)應(yīng)AFRL,8-15對(duì)應(yīng)AFRH。//因?yàn)橐呀?jīng)區(qū)分成兩個(gè)元素。所以,第一步,取低三位的二進(jìn)制數(shù)即可。(position & (uint32_t)0x07U),例如,第3位和第11位的處理方法相同//position的取值為[0,15]。其對(duì)應(yīng)的AFRL/AFRH的二進(jìn)制數(shù)位為position*4。每個(gè)數(shù)位占有4個(gè)寄存器AFRL/AFRH二進(jìn)制位。//例如,當(dāng)position=3時(shí)。對(duì)應(yīng)AFRL[15:12]。即(0xF<<(3*4))對(duì)應(yīng)二進(jìn)制位0000 1111 0000 0000。其中數(shù)據(jù)1的位置恰好對(duì)應(yīng)AFRL[15:12]。//最后,再將結(jié)果進(jìn)行取反,相位與。即將寄存器AFRL/AFRH的對(duì)應(yīng)二進(jìn)制位清0。其余位不變。temp &= ~((uint32_t)0xFU << ((uint32_t)(position & (uint32_t)0x07U) * 4U)) ;//和上面執(zhí)行相同。將GPIO_Init->Alternate的數(shù)值寫入寄存器AFRL/AFRH的對(duì)應(yīng)二進(jìn)制位。temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07U) * 4U));GPIOx->AFR[position >> 3U] = temp; //將改變后的值,復(fù)原到AFR寄存器。}/* Configure IO Direction mode (Input, Output, Alternate or Analog) *///將引腳的對(duì)應(yīng)模式寫入temp = GPIOx->MODER;temp &= ~(GPIO_MODER_MODER0 << (position * 2U)); //先將對(duì)應(yīng)位清零,GPIO_MODER_MODER0=3(0b11)temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U)); //再將將對(duì)應(yīng)位置1,GPIO_MODE=3(0b11)GPIOx->MODER = temp;/* In case of Output or Alternate function mode selection *///判斷是否為輸出或者復(fù)用功能。若是,則需要設(shè)置引腳的類型與速度。if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) ||(GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD)){//寫入速度/* Check the Speed parameter */assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));/* Configure the IO Speed */temp = GPIOx->OSPEEDR;temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U));temp |= (GPIO_Init->Speed << (position * 2U));GPIOx->OSPEEDR = temp;//寫入輸出類型:推挽輸出還是開漏輸出/* Configure the IO Output Type */temp = GPIOx->OTYPER;temp &= ~(GPIO_OTYPER_OT_0 << position) ; // GPIO_OTYPER_OT_0=0x00000001U(0b0000 0001)temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4U) << position); // GPIO_OUTPUT_TYPE=0x00000010U(0b0001 0000)GPIOx->OTYPER = temp;}//寫入上拉,下拉還是浮空功能/* Activate the Pull-up or Pull down resistor for the current IO */temp = GPIOx->PUPDR;temp &= ~(GPIO_PUPDR_PUPDR0 << (position * 2U));temp |= ((GPIO_Init->Pull) << (position * 2U));GPIOx->PUPDR = temp;/*--------------------- EXTI Mode Configuration ------------------------*//* Configure the External Interrupt or event for the current IO */if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE){/* Enable SYSCFG Clock */__HAL_RCC_SYSCFG_CLK_ENABLE();temp = SYSCFG->EXTICR[position >> 2U];temp &= ~(((uint32_t)0x0FU) << (4U * (position & 0x03U)));temp |= ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4U * (position & 0x03U)));SYSCFG->EXTICR[position >> 2U] = temp;/* Clear EXTI line configuration */temp = EXTI->IMR;temp &= ~((uint32_t)iocurrent);if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT){temp |= iocurrent;}EXTI->IMR = temp;temp = EXTI->EMR;temp &= ~((uint32_t)iocurrent);if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT){temp |= iocurrent;}EXTI->EMR = temp;/* Clear Rising Falling edge configuration */temp = EXTI->RTSR;temp &= ~((uint32_t)iocurrent);if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE){temp |= iocurrent;}EXTI->RTSR = temp;temp = EXTI->FTSR;temp &= ~((uint32_t)iocurrent);if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE){temp |= iocurrent;}EXTI->FTSR = temp;}}} }

    通過上文源程序可知,GPIO初始化共分成兩個(gè)部分:

    • GPIO模式初始化
    • EXIT模式初始化

    本文只涉及到第一部分,所以第二部分略過不談。

    在GPIO初始化的函數(shù)總體思路是:

    • 調(diào)用一次函數(shù),初始化循環(huán)一組端口所有位。
    • 因?yàn)橐唤M端口有16個(gè)引腳,所以,函數(shù)循環(huán)16次, 依次判斷該引腳Pin對(duì)應(yīng)位是否置1。
    • 若當(dāng)前引腳對(duì)應(yīng)位置1,那么對(duì)該位進(jìn)行初始化,否則,跳過該位,循環(huán)至下一個(gè)引腳。
    • 直到16個(gè)引腳循環(huán)結(jié)束。

    在GPIO模式初始化部分,基本流程如下所示:

    • 判斷該引腳是否為復(fù)用功能。若是,將復(fù)用功能對(duì)應(yīng)數(shù)據(jù)寫入復(fù)用功能寄存器AFRL/AFRH。
    • 將引腳對(duì)應(yīng)的模式(Mode)寫入GPIO端口模式寄存器(MODER)。
    • 判斷該引腳是否為輸出或者復(fù)用功能。若是,則將引腳的速度和輸出類型分別寫入GPIO輸出速度寄存器(OSPEEDR)和GPIO端口輸出類型寄存器(OTYPER)。
    • 將引腳對(duì)應(yīng)的上拉/下拉功能寫入GPIO端口上拉/下拉寄存器(PUPDR)。

    其中,寫入寄存器一般分成兩個(gè)步驟:

    • 將引腳對(duì)應(yīng)寄存器數(shù)據(jù)位清零。
    • 將引腳對(duì)應(yīng)寄存器數(shù)據(jù)位寫入數(shù)據(jù)。

    以復(fù)用功能寄存器為例,其源程序如下:

    temp = GPIOx->AFR[position >> 3U]; temp &= ~((uint32_t)0xFU << ((uint32_t)(position & (uint32_t)0x07U) * 4U)) ; temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07U) * 4U)); GPIOx->AFR[position >> 3U] = temp;

    總共分成四個(gè)語句,如下:

  • 因?yàn)楣δ軓?fù)位寄存器有兩個(gè)(AFRL和AFRH)。其中AFRH對(duì)應(yīng)端口引腳的高8位,AFRL對(duì)應(yīng)端口引腳低8位。所以,根據(jù)position是大于等于8或者小于7來獲取對(duì)應(yīng)復(fù)用功能寄存器的數(shù)值,且保存在temp中。
  • 將引腳的寄存器對(duì)應(yīng)位清零。
  • 因?yàn)楦?位與低8位在上一步已經(jīng)區(qū)分。所以此時(shí),高8位應(yīng)該以第8位為基點(diǎn)。即第8位等同于第0位,就9位等同于第1位,以此類推。 position & (uint32_t)0x07U相當(dāng)于將大于8的position減去8,小于8的position不變。
  • 因?yàn)槊總€(gè)引腳對(duì)應(yīng)的復(fù)位寄存器是4個(gè)二進(jìn)制位,((uint32_t)(position & (uint32_t)0x07U) * 4U)),將處理過的偏移量*4。即第0偏移到0,第1位偏移到4,從而對(duì)應(yīng)其在寄存器中的二進(jìn)制對(duì)應(yīng)位。
  • (uint32_t)0xFU << ((uint32_t)(position & (uint32_t)0x07U) * 4U)。因?yàn)?strong>0xF 二進(jìn)制形式為 0b1111,即四個(gè)二進(jìn)制位為1,其余所有位為0。所以,將其左移上一步計(jì)算出的偏移量,即將引腳對(duì)應(yīng)的復(fù)用功能寄存器位置1,其余位置0。假設(shè)position為3的情況下,此時(shí),計(jì)算結(jié)果二進(jìn)制形式為 0x 0000 0000 0000 0000 0000 1111 0000 0000
  • 最后將上一步計(jì)算結(jié)果取反,且與temp相位與。則,將引腳對(duì)應(yīng)的復(fù)位功能寄存器對(duì)應(yīng)位清0,其余位不變。
  • 該步驟和上一步處理方式基本相同 。即將復(fù)用功能數(shù)據(jù)寫入到復(fù)位功能寄存器對(duì)應(yīng)的temp二進(jìn)制位中。
  • 最后,將temp寫入AFR寄存器中。
  • GPIO位操作

    /*** @brief Sets or clears the selected data port bit.** @note This function uses GPIOx_BSRR register to allow atomic read/modify* accesses. In this way, there is no risk of an IRQ occurring between* the read and the modify access.** @param GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F429X device or* x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.* @param GPIO_Pin: specifies the port bit to be written.* This parameter can be one of GPIO_PIN_x where x can be (0..15).* @param PinState: specifies the value to be written to the selected bit.* This parameter can be one of the GPIO_PinState enum values:* @arg GPIO_PIN_RESET: to clear the port pin* @arg GPIO_PIN_SET: to set the port pin* @retval None*/ void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) {/* Check the parameters */assert_param(IS_GPIO_PIN(GPIO_Pin));assert_param(IS_GPIO_PIN_ACTION(PinState));if(PinState != GPIO_PIN_RESET){GPIOx->BSRR = GPIO_Pin;}else{GPIOx->BSRR = (uint32_t)GPIO_Pin << 16U;} }

    該函數(shù)比較簡(jiǎn)單,即判斷是需要清零還是置位。

    • 若是需要置位,將GPIO端口置位/復(fù)位寄存器(BSRR)對(duì)應(yīng)位置1.
    • 若是需要清零,將GPIO端口置位/復(fù)位寄存器(BSRR)對(duì)應(yīng)位+16置1.

    RCC

    通過編寫代碼部分,我們可以總結(jié)出,該例程關(guān)于RCC部分主要使用了兩個(gè)HAL庫(kù)函數(shù):

    • HAL_RCC_OscConfig();//初始化振蕩器相關(guān)參數(shù)
    • HAL_RCC_ClockConfig();//初始化系統(tǒng)時(shí)鐘

    關(guān)于此兩個(gè)函數(shù)的使用方法,可以參考博客<STM32F429第八篇之stm32f4xx_hal_rcc>

    另外還有一個(gè)外設(shè)初始化的宏,如:

    • __HAL_RCC_PWR_CLK_ENABLE();
    • ___HAL_RCC_GPIOB_CLK_ENABLE();

    關(guān)于外設(shè)初始化宏部分比較簡(jiǎn)單,此處不再詳細(xì)展開,可以參考博客<STM32F429第九篇之stm32f4xx_hal_rcc_ex>。

    下面重點(diǎn)分析兩個(gè)函數(shù)的源代碼。

    振蕩器參數(shù)設(shè)置

    __weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct) {uint32_t tickstart = 0U;/* Check the parameters */assert_param(IS_RCC_OSCILLATORTYPE(RCC_OscInitStruct->OscillatorType));//檢測(cè)振蕩器類型/*------------------------------- HSE Configuration ------------------------*/if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSE) == RCC_OSCILLATORTYPE_HSE)//判斷是否有HSE{/* Check the parameters *//********************1.檢測(cè)參數(shù)狀態(tài)**************************************/assert_param(IS_RCC_HSE(RCC_OscInitStruct->HSEState));//判斷HSE狀態(tài)/* When the HSE is used as system clock or clock source for PLL in these cases HSE will not disabled *//********************2.條件判斷:若HSE用作系統(tǒng)時(shí)鐘,則不可以禁用HSE**************************************/if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE) || \((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL) && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSE)))//判斷HSE是否已經(jīng)直接或者間接用于系統(tǒng)時(shí)鐘{if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))//若HSE用做系統(tǒng)時(shí)鐘,則不可以禁用HSE。{return HAL_ERROR;}//若HSE已經(jīng)成為系統(tǒng)時(shí)鐘,且并非禁用HSE,則無須任何操作。}/********************3.設(shè)置HSE狀態(tài)**************************************/else//HSE并未直接或者間接用做系統(tǒng)時(shí)鐘{/* Set the new HSE configuration ---------------------------------------*/__HAL_RCC_HSE_CONFIG(RCC_OscInitStruct->HSEState);//將HSE狀態(tài)直接寫入寄存器/* Check the HSE State */if((RCC_OscInitStruct->HSEState) != RCC_HSE_OFF)//若設(shè)置的狀態(tài)不是關(guān)閉HSE{/* Get Start Tick*/tickstart = HAL_GetTick();//獲得開始時(shí)間/* Wait till HSE is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)//HSE準(zhǔn)備結(jié)束就退出循環(huán){if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)//等待時(shí)間超過等待最大值(100){return HAL_TIMEOUT;//返回超時(shí)}}}else//若設(shè)置的狀態(tài)為關(guān)閉HSE{/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till HSE is bypassed or disabled */while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET){if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}}}/*----------------------------- HSI Configuration --------------------------*/if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)//判斷是否有HSI{/* Check the parameters */assert_param(IS_RCC_HSI(RCC_OscInitStruct->HSIState));//兩種狀態(tài)RCC_HSI_OFF或者RCC_HSI_ON,此處存疑。assert_param(IS_RCC_CALIBRATION_VALUE(RCC_OscInitStruct->HSICalibrationValue));//值小于等于0x1F/* Check if HSI is used as system clock or as PLL source when PLL is selected as system clock */if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSI) || \((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL)&& ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSI)))//判斷HSI是否已經(jīng)直接或者間接用于系統(tǒng)時(shí)鐘{/* When HSI is used as system clock it will not disabled */if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET) && (RCC_OscInitStruct->HSIState != RCC_HSI_ON))//HSI已經(jīng)直接或者間接作為系統(tǒng)時(shí)鐘,不可以清零。{return HAL_ERROR;}/* Otherwise, just the calibration is allowed */else//當(dāng)系統(tǒng)時(shí)鐘已經(jīng)直接或者間接使用HSI,而HSI尚未打開或者設(shè)置狀態(tài)不是RCC_HSI_ON{/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);//設(shè)置內(nèi)部高速時(shí)鐘的微調(diào)}}else//若HSI并沒有直接或者間接用于系統(tǒng)時(shí)鐘。{/* Check the HSI State */if((RCC_OscInitStruct->HSIState) != RCC_HSI_OFF)//需要使能RCC{/* Enable the Internal High Speed oscillator (HSI). */__HAL_RCC_HSI_ENABLE();//通過改變RCC_CR寄存器使能HSION/* Get Start Tick*/tickstart = HAL_GetTick();//得到當(dāng)前時(shí)間/* Wait till HSI is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)//等待HSI啟動(dòng){if((HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE)//若是啟動(dòng)時(shí)間超時(shí),則返回錯(cuò)誤{return HAL_TIMEOUT;}}/* Adjusts the Internal High Speed oscillator (HSI) calibration value.*/__HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);//設(shè)置HSI的微調(diào)}else//需要禁用RCC{/* Disable the Internal High Speed oscillator (HSI). */__HAL_RCC_HSI_DISABLE();//禁用RCC/* Get Start Tick*/tickstart = HAL_GetTick();//獲取當(dāng)前時(shí)間/* Wait till HSI is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) != RESET)//等待HSI禁用{if((HAL_GetTick() - tickstart ) > HSI_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}}}/*------------------------------ LSI Configuration -------------------------*/if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI)//判斷是否有LSI{/* Check the parameters */assert_param(IS_RCC_LSI(RCC_OscInitStruct->LSIState));//判斷LSI狀態(tài)為RCC_LSI_OFF或RCC_LSI_ON/* Check the LSI State */if((RCC_OscInitStruct->LSIState) != RCC_LSI_OFF)//要使能LSI{/* Enable the Internal Low Speed oscillator (LSI). */__HAL_RCC_LSI_ENABLE();//通過改變RCC_CSR使能LSI/* Get Start Tick*/tickstart = HAL_GetTick();//得到當(dāng)前時(shí)間值/* Wait till LSI is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET)//等待LSI準(zhǔn)備好{if((HAL_GetTick() - tickstart ) > LSI_TIMEOUT_VALUE){return HAL_TIMEOUT;//超時(shí)返回錯(cuò)誤}}}else//要禁止LSI{/* Disable the Internal Low Speed oscillator (LSI). */__HAL_RCC_LSI_DISABLE();//禁止LSI/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till LSI is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)//等待LSI準(zhǔn)備好{if((HAL_GetTick() - tickstart ) > LSI_TIMEOUT_VALUE){return HAL_TIMEOUT;//超時(shí)返回錯(cuò)誤}}}}/*------------------------------ LSE Configuration -------------------------*/if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE)//判斷是否有LSE{/* Check the parameters */assert_param(IS_RCC_LSE(RCC_OscInitStruct->LSEState));//LSE三種狀態(tài):RCC_LSE_OFF,RCC_LSE_ON,RCC_LSE_BYPASS/* Enable Power Clock*/__HAL_RCC_PWR_CLK_ENABLE();//因?yàn)橐獙?duì)寄存器RCC_PWR進(jìn)行操作,所以對(duì)該時(shí)鐘進(jìn)行使能。/* Enable write access to Backup domain */PWR->CR |= PWR_CR_DBP; //使能RTC以及RTC備份寄存器和備份SRAM的訪問 /* Wait for Backup domain Write protection enable */tickstart = HAL_GetTick();//記錄當(dāng)前時(shí)間while((PWR->CR & PWR_CR_DBP) == RESET)//等待寫入信息生效{if((HAL_GetTick() - tickstart ) > RCC_DBP_TIMEOUT_VALUE){return HAL_TIMEOUT;}}/* Set the new LSE configuration -----------------------------------------*/__HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState);//直接設(shè)置LSE狀態(tài)/* Check the LSE State */if((RCC_OscInitStruct->LSEState) != RCC_LSE_OFF)//等待LSE狀態(tài)生效{/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till LSE is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET){if((HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}else{/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till LSE is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET){if((HAL_GetTick() - tickstart ) > RCC_LSE_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}}/*-------------------------------- PLL Configuration -----------------------*//* Check the parameters */assert_param(IS_RCC_PLL(RCC_OscInitStruct->PLL.PLLState));//檢測(cè)PLL狀態(tài):RCC_PLL_NONE,RCC_PLL_OFF,RCC_PLL_ONif ((RCC_OscInitStruct->PLL.PLLState) != RCC_PLL_NONE)//判斷是否需要設(shè)置PLL{/* Check if the PLL is used as system clock or not */if(__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_PLL)//若PLL不是系統(tǒng)時(shí)鐘{if((RCC_OscInitStruct->PLL.PLLState) == RCC_PLL_ON)//需要將PLL設(shè)置為使能{/* Check the parameters */assert_param(IS_RCC_PLLSOURCE(RCC_OscInitStruct->PLL.PLLSource));//RCC_PLLSOURCE_HSI或者RCC_PLLSOURCE_HSEassert_param(IS_RCC_PLLM_VALUE(RCC_OscInitStruct->PLL.PLLM));//0~63assert_param(IS_RCC_PLLN_VALUE(RCC_OscInitStruct->PLL.PLLN));//50~432assert_param(IS_RCC_PLLP_VALUE(RCC_OscInitStruct->PLL.PLLP));//2,4,6,8assert_param(IS_RCC_PLLQ_VALUE(RCC_OscInitStruct->PLL.PLLQ));//4~15/* Disable the main PLL. */__HAL_RCC_PLL_DISABLE();//禁止PLL/* Get Start Tick*/tickstart = HAL_GetTick();//記錄當(dāng)前時(shí)間/* Wait till PLL is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)//等待設(shè)置生效{if((HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE){return HAL_TIMEOUT;}}/* Configure the main PLL clock source, multiplication and division factors. */WRITE_REG(RCC->PLLCFGR, (RCC_OscInitStruct->PLL.PLLSource | \RCC_OscInitStruct->PLL.PLLM | \(RCC_OscInitStruct->PLL.PLLN << POSITION_VAL(RCC_PLLCFGR_PLLN)) | \(((RCC_OscInitStruct->PLL.PLLP >> 1U) - 1U) << POSITION_VAL(RCC_PLLCFGR_PLLP)) | \(RCC_OscInitStruct->PLL.PLLQ << POSITION_VAL(RCC_PLLCFGR_PLLQ))));//配置PLL信息/* Enable the main PLL. */__HAL_RCC_PLL_ENABLE();//將PLL打開/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till PLL is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)//等待PLL設(shè)置生效{if((HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}else{/* Disable the main PLL. */__HAL_RCC_PLL_DISABLE();//禁止PLL/* Get Start Tick*/tickstart = HAL_GetTick();/* Wait till PLL is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) != RESET)//等待PLL設(shè)置生效{if((HAL_GetTick() - tickstart ) > PLL_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}}else//若PLL已經(jīng)成為系統(tǒng)時(shí)鐘,則PLL的狀態(tài)只能為RCC_PLL_NONE,否則報(bào)錯(cuò){return HAL_ERROR;}}return HAL_OK; }

    該函數(shù)總體分成5個(gè)部分:

  • HSE設(shè)置
  • HSI設(shè)置
  • LSI設(shè)置
  • LSE設(shè)置
  • PLL設(shè)置
  • 其中,以HSE設(shè)置為典型,詳細(xì)介紹該函數(shù)實(shí)現(xiàn)過程。HSE設(shè)置大致可以分成三個(gè)部分:

  • 檢測(cè)參數(shù)數(shù)據(jù)。
  • 條件判斷:若HSE用作系統(tǒng)時(shí)鐘,則不可以禁用HSE。
  • HSE并沒有用作系統(tǒng)時(shí)鐘 ,則設(shè)置HSE的狀態(tài)。
  • 在判斷HSE是否直接或者間接用于系統(tǒng)時(shí)鐘的時(shí)候,源代碼如下:

    if((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_HSE) ||\((__HAL_RCC_GET_SYSCLK_SOURCE() == RCC_CFGR_SWS_PLL) && ((RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) == RCC_PLLCFGR_PLLSRC_HSE)))

    第一行的含義是:判斷系統(tǒng)時(shí)鐘為RCC_CFGR_SWS_HSE。
    第二行的含義是:判斷系統(tǒng)時(shí)鐘為RCC_CFGR_SWS_PLL且PLL的時(shí)鐘源為HSE。
    所以,綜合以上兩行語句,則表示HSE直接或者間接用于系統(tǒng)時(shí)鐘。

    其中,宏__HAL_RCC_GET_SYSCLK_SOURCE()的定義為:

    /** @brief Macro to get the clock source used as system clock.* @retval The clock source used as system clock. The returned value can be one* of the following:* - RCC_SYSCLKSOURCE_STATUS_HSI: HSI used as system clock.* - RCC_SYSCLKSOURCE_STATUS_HSE: HSE used as system clock.* - RCC_SYSCLKSOURCE_STATUS_PLLCLK: PLL used as system clock.* - RCC_SYSCLKSOURCE_STATUS_PLLRCLK: PLLR used as system clock.*/ #define __HAL_RCC_GET_SYSCLK_SOURCE() ((uint32_t)(RCC->CFGR & RCC_CFGR_SWS))

    若當(dāng)HSE直接或者間接用做系統(tǒng)時(shí)鐘時(shí),則不可以禁用HSE,如下圖參考手冊(cè)所示:

    這個(gè)條件由以下程序給出判定:

    if((__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) != RESET) && (RCC_OscInitStruct->HSEState == RCC_HSE_OFF))//若HSE用做系統(tǒng)時(shí)鐘,則不可以禁用HSE。 {return HAL_ERROR; }

    其中兩個(gè)判斷條件分別為:

  • HSE已經(jīng)啟動(dòng)。
  • 將要進(jìn)制HSE。
  • 其中,第二條語句比較簡(jiǎn)單,這里不再詳述。第一條語句的宏定義為:

    /** @brief Check RCC flag is set or not.* @param __FLAG__: specifies the flag to check.* This parameter can be one of the following values:* @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready.* @arg RCC_FLAG_HSERDY: HSE oscillator clock ready.* @arg RCC_FLAG_PLLRDY: Main PLL clock ready.* @arg RCC_FLAG_PLLI2SRDY: PLLI2S clock ready.* @arg RCC_FLAG_LSERDY: LSE oscillator clock ready.* @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready.* @arg RCC_FLAG_BORRST: POR/PDR or BOR reset.* @arg RCC_FLAG_PINRST: Pin reset.* @arg RCC_FLAG_PORRST: POR/PDR reset.* @arg RCC_FLAG_SFTRST: Software reset.* @arg RCC_FLAG_IWDGRST: Independent Watchdog reset.* @arg RCC_FLAG_WWDGRST: Window Watchdog reset.* @arg RCC_FLAG_LPWRRST: Low Power reset.* @retval The new state of __FLAG__ (TRUE or FALSE).*/ #define RCC_FLAG_MASK ((uint8_t)0x1FU) #define __HAL_RCC_GET_FLAG(__FLAG__) (((((((__FLAG__) >> 5U) == 1U)? RCC->CR :((((__FLAG__) >> 5U) == 2U) ? RCC->BDCR :((((__FLAG__) >> 5U) == 3U)? RCC->CSR :RCC->CIR))) & ((uint32_t)1U << ((__FLAG__) & RCC_FLAG_MASK)))!= 0U)? 1U : 0U)/*** @}*/

    這條語句很難讀懂,是因?yàn)閼?yīng)用了很多三目運(yùn)算符,可以將上述定義用條件語句改寫為:

    int __HAL_RCC_GET_FLAG(uint8_t __FLAG__) {flag = __FLAG__ >> 5U;//將__FLAG__右移5位,為新的判斷條件。uint32_t x = 0;//x用于存儲(chǔ)對(duì)應(yīng)的寄存器數(shù)據(jù)//根據(jù)__FLAG__高3位數(shù)據(jù)的不同,來選擇對(duì)應(yīng)的寄存器if(flag == 1){x = RCC->CR;}else if (flag == 2){x = RCC->BDCR;}else if(flag == 3){x = RCC->CSR;}else{x = RCC->CIR;}di5wei = __FLAG__ & 0x1FU; //獲取低5位,低5位是用來確定是寄存器的哪一個(gè)二進(jìn)制位。y = 1 << di5wei;//將1移動(dòng)到對(duì)應(yīng)的二進(jìn)制位if(x & y == 0)//返回值為1或者0return 0;elsereturn 1; }

    根據(jù)以上代碼可以分析出,宏__HAL_RCC_GET_FLAG(__FLAG__)的參數(shù)由兩部分組成:

  • 高三位,對(duì)應(yīng)其所在的寄存器
  • 低五位,對(duì)應(yīng)其在寄存器的二進(jìn)制位
  • 通過該宏就可以根據(jù)標(biāo)志位得知系統(tǒng)的狀態(tài)。

    最后,看一下設(shè)置HSE狀態(tài),該部分大致可以分成兩個(gè)部分:

  • 設(shè)置HSE的新狀態(tài)寫入寄存器。
  • 等待寫入的HSE狀態(tài)有效。
  • 寫入寄存器的宏定義為:

    /*** @brief Macro to configure the External High Speed oscillator (HSE).* @note Transition HSE Bypass to HSE On and HSE On to HSE Bypass are not supported by this macro. * User should request a transition to HSE Off first and then HSE On or HSE Bypass.* @note After enabling the HSE (RCC_HSE_ON or RCC_HSE_Bypass), the application* software should wait on HSERDY flag to be set indicating that HSE clock* is stable and can be used to clock the PLL and/or system clock.* @note HSE state can not be changed if it is used directly or through the* PLL as system clock. In this case, you have to select another source* of the system clock then change the HSE state (ex. disable it).* @note The HSE is stopped by hardware when entering STOP and STANDBY modes. * @note This function reset the CSSON bit, so if the clock security system(CSS)* was previously enabled you have to enable it again after calling this* function. * @param __STATE__: specifies the new state of the HSE.* This parameter can be one of the following values:* @arg RCC_HSE_OFF: turn OFF the HSE oscillator, HSERDY flag goes low after* 6 HSE oscillator clock cycles.* @arg RCC_HSE_ON: turn ON the HSE oscillator.* @arg RCC_HSE_BYPASS: HSE oscillator bypassed with external clock.*/ #define __HAL_RCC_HSE_CONFIG(__STATE__) (*(__IO uint8_t *) RCC_CR_BYTE2_ADDRESS = (__STATE__))

    此處比較簡(jiǎn)單,不再詳述。

    因?yàn)閷懭氲腍SE狀態(tài)大致可以分成兩類:

  • 打開HSE
  • 關(guān)閉HSE
  • 以打開HSE為例,源代碼為:

    if((RCC_OscInitStruct->HSEState) != RCC_HSE_OFF) {/* Get Start Tick*/tickstart = HAL_GetTick();//記錄當(dāng)前時(shí)間/* Wait till HSE is ready */while(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)//判斷是否生效{if((HAL_GetTick() - tickstart ) > HSE_TIMEOUT_VALUE)//用當(dāng)前時(shí)間減去第一次記錄的時(shí)間,計(jì)算消耗時(shí)間{return HAL_TIMEOUT;}} }

    若上述代碼所示,記錄當(dāng)前的時(shí)間。若設(shè)置并未生效,則循環(huán)等待且等待時(shí)間超過最大等待時(shí)間,則報(bào)錯(cuò) HAL_TIMEOUT。至此HSE部分基本結(jié)束。其余四個(gè)部分與其基本一致,不再詳細(xì)展開,只是其中幾點(diǎn)需要特別注意為:

  • HSI 需要設(shè)置微調(diào)信息。
  • PLL設(shè)置需要寫入分頻與倍頻的參數(shù)。需要注意的是,需要首先關(guān)閉PLL,然后將PLL倍頻與分頻的參數(shù)寫入,最后在將PLL打開。
  • 下面重點(diǎn)講述HSI設(shè)置微調(diào)信息的過程,其對(duì)應(yīng)的源碼為:

    __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(RCC_OscInitStruct->HSICalibrationValue);

    則宏定義為:

    /** @brief Macro to adjust the Internal High Speed oscillator (HSI) calibration value.* @note The calibration is used to compensate for the variations in voltage* and temperature that influence the frequency of the internal HSI RC.* @param __HSICalibrationValue__: specifies the calibration trimming value.* (default is RCC_HSICALIBRATION_DEFAULT).* This parameter must be a number between 0 and 0x1F.*/ #define __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(__HSICalibrationValue__) (MODIFY_REG(RCC->CR,\RCC_CR_HSITRIM, (uint32_t)(__HSICalibrationValue__) << POSITION_VAL(RCC_CR_HSITRIM)))

    若想理解該宏的意思,需要了解的有:

  • MODIFY_REG宏定義
  • RCC_CR_HSITRIM
  • POSITION_VAL宏定義
  • 其中,第二點(diǎn)最簡(jiǎn)單,源代碼為:

    #define RCC_CR_HSITRIM ((uint32_t)0x000000F8U)

    RCC_CR_HSITRIM 為HSI微調(diào)偏移量在CR中的掩碼,換句話說, RCC_CR_HSITRIM中二進(jìn)制1對(duì)應(yīng)的數(shù)據(jù)位就是RCC_CR寄存器中HSI微調(diào)偏移量對(duì)應(yīng)的數(shù)據(jù)位。

    MODIFY_REG宏定義如下所示:

    #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

    可以大致分成兩個(gè)步驟:

  • 通過CLEARMASK將REG對(duì)應(yīng)位清零。
  • 在將SETMASK對(duì)應(yīng)的二進(jìn)位置一。
  • POSITION_VAL宏定義最難理解,其對(duì)應(yīng)的宏定義為

    #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))

    其中__RBIT()和__CLA()都對(duì)應(yīng)著匯編指令,可以通過查詢keil幫助文檔或者<權(quán)威指南>來獲得指令的意思如下:

    __RBIT()//ARM 32位數(shù)據(jù)匯編指令,將數(shù)據(jù)的二進(jìn)制值進(jìn)行反轉(zhuǎn)。 __CLA()//ARM 32位數(shù)據(jù)匯編指令,計(jì)算二進(jìn)制數(shù)前導(dǎo)零的個(gè)數(shù)


    注意:

    兩個(gè)指令只適用于32位整形。

    其中,__RBIT()即將二進(jìn)制數(shù)最高位和最低位調(diào)換位置,次高位和次低位調(diào)換位置,以此類推。__CLA(),計(jì)算從最高位到第一個(gè)0,該二進(jìn)制數(shù)中有多少個(gè)零。所以,POSITION_VAL即求取該32位二進(jìn)制數(shù)從從最位開始,到第一個(gè)1,共有多少個(gè)0.

    綜上所述,可以理解

    #define __HAL_RCC_HSI_CALIBRATIONVALUE_ADJUST(__HSICalibrationValue__) (MODIFY_REG(RCC->CR,\RCC_CR_HSITRIM, (uint32_t)(__HSICalibrationValue__) << POSITION_VAL(RCC_CR_HSITRIM)))

    程序的含義就是先將CR寄存器對(duì)應(yīng)HSI微調(diào)部分進(jìn)行清零,然后將微調(diào)數(shù)據(jù)__HSICalibrationValue__左移適當(dāng)位置,寫入對(duì)應(yīng)的寄存器位中。

    時(shí)鐘初始化

    HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency) {uint32_t tickstart = 0U;/* Check the parameters */assert_param(IS_RCC_CLOCKTYPE(RCC_ClkInitStruct->ClockType));//IS_RCC_CLOCKTYPE(CLK) ((1U <= (CLK)) && ((CLK) <= 15U))assert_param(IS_FLASH_LATENCY(FLatency));//FLASH_LATENCY_0-FLASH_LATENCY_15/* To correctly read data from FLASH memory, the number of wait states (LATENCY)must be correctly programmed according to the frequency of the CPU clock(HCLK) and the supply voltage of the device. *//**************************************1.調(diào)高Flash延時(shí)時(shí)間 *******************************************//* Increasing the number of wait states because of higher CPU frequency */if(FLatency > (FLASH->ACR & FLASH_ACR_LATENCY))//若設(shè)定值比原有值大{/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */__HAL_FLASH_SET_LATENCY(FLatency);//將設(shè)定值寫入寄存器/* Check that the new number of wait states is taken into account to access the Flashmemory by reading the FLASH_ACR register */if((FLASH->ACR & FLASH_ACR_LATENCY) != FLatency)//檢查寫入值是否有效{return HAL_ERROR;}}/**************************************2.HCLK設(shè)置 *******************************************//*-------------------------- HCLK Configuration --------------------------*/if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK){assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));//分頻數(shù)可以為1,2,4,8,16,64,128,256,512。注意沒有32分頻MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);//將分頻數(shù)寫入對(duì)應(yīng)的寄存器}/**************************************3.SYSCLK設(shè)置 *******************************************//*------------------------- SYSCLK Configuration ---------------------------*/if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK){assert_param(IS_RCC_SYSCLKSOURCE(RCC_ClkInitStruct->SYSCLKSource));//檢測(cè)范圍/* HSE is selected as System Clock Source */if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE)//若HSE作為系統(tǒng)時(shí)鐘{/*3.1檢測(cè)選擇系統(tǒng)時(shí)鐘是否處于禁用狀態(tài),需要注意的是設(shè)置PLL源的時(shí)候沒有這個(gè)步驟*//* Check the HSE ready flag */if(__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)//若HSE處于禁用狀態(tài),則返回錯(cuò)誤HAL_ERROR{return HAL_ERROR;}}/* PLL is selected as System Clock Source */else if((RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK) ||(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLRCLK)){/* Check the PLL ready flag */if(__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)//若PLL處于禁用狀態(tài),則返回錯(cuò)誤HAL_ERROR{return HAL_ERROR;}}/* HSI is selected as System Clock Source */else{/* Check the HSI ready flag */if(__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)//若HSI處于禁用狀態(tài),則返回錯(cuò)誤HAL_ERROR{return HAL_ERROR;}}//若選擇的系統(tǒng)時(shí)鐘處于啟動(dòng)狀態(tài),則使其生效。__HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);/* Get Start Tick*/tickstart = HAL_GetTick();//開始計(jì)時(shí),記錄當(dāng)前的時(shí)間//判斷設(shè)置是否生效,若等待時(shí)間超時(shí),返回錯(cuò)誤HAL_TIMEOUTif(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE){while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_HSE){if((HAL_GetTick() - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}else if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK){while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLCLK){if((HAL_GetTick() - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}else if(RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLRCLK){while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_PLLRCLK){if((HAL_GetTick() - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}else{while(__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_SYSCLKSOURCE_STATUS_HSI){if((HAL_GetTick() - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE){return HAL_TIMEOUT;}}}}/**************************************4.降低Flash延時(shí)時(shí)間 *******************************************//* Decreasing the number of wait states because of lower CPU frequency */if(FLatency < (FLASH->ACR & FLASH_ACR_LATENCY)){/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */__HAL_FLASH_SET_LATENCY(FLatency);/* Check that the new number of wait states is taken into account to access the Flashmemory by reading the FLASH_ACR register */if((FLASH->ACR & FLASH_ACR_LATENCY) != FLatency){return HAL_ERROR;}}/**************************************5.PCLK1設(shè)置 *******************************************//*-------------------------- PCLK1 Configuration ---------------------------*/if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1){assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB1CLKDivider));//1,2,4,8,16MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);//設(shè)置APB1分頻數(shù)}/**************************************6.PCLK2設(shè)置 *******************************************//*-------------------------- PCLK2 Configuration ---------------------------*/if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2){assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB2CLKDivider));//1,2,4,8,16MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3U));//設(shè)置APB2分頻數(shù)}/* Configure the source of time base considering new system clocks settings*/HAL_InitTick (TICK_INT_PRIORITY);return HAL_OK; }

    這部分代碼比較簡(jiǎn)單,比較難理解的地方在上面一節(jié)已經(jīng)提到了。所以,本部分代碼不再詳細(xì)展開,只是添加了中文備注,如上所示。

    時(shí)鐘初始化總共分成六個(gè)部分:

  • 提高Flash延時(shí)時(shí)間
  • HCLK設(shè)置
  • SYSCLK設(shè)置
  • 降低Flash延時(shí)時(shí)間
  • PCLK1設(shè)置
  • PCLK2設(shè)置
  • 需要注意的是,每個(gè)不同的模塊對(duì)于分頻數(shù)和倍頻數(shù)設(shè)置的限制是不同的。所以,為了得到想要的主頻,還需要自己配合不同模塊的限制。另外一點(diǎn)是關(guān)于Flash延時(shí)時(shí)間的設(shè)置,若想要提高Flash延時(shí)時(shí)間,則先進(jìn)行Flash時(shí)間設(shè)置,再進(jìn)行主頻設(shè)置。若想要降低Flash延時(shí)時(shí)間,則需要先進(jìn)行主頻設(shè)置,再進(jìn)行Flash延時(shí)時(shí)間設(shè)置。這是因?yàn)閷捲5腇lash延時(shí)時(shí)間是更加安全的。
    最后,關(guān)于SYSCLK源設(shè)置還需要注意,在設(shè)置之前,需要保證SYSCLK源是處于啟動(dòng)狀態(tài)。

    systick

    這部分內(nèi)容請(qǐng)參考博客<STM32F429第十篇之systick>

    總結(jié)

    以上是生活随笔為你收集整理的STM32F429第四篇之跑马灯程序详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

    色婷婷福利 | 天堂在线一区 | 97精品一区二区三区 | www.天天成人国产电影 | 成人羞羞视频在线观看免费 | 亚洲精选国产 | 欧美一级片 | 国产剧情一区二区在线观看 | 亚洲天堂网在线视频观看 | 成人动漫一区二区三区 | 中字幕视频在线永久在线观看免费 | 国产一级电影网 | 免费看黄视频 | 一级电影免费在线观看 | 国产午夜激情视频 | 国产网红在线观看 | 在线国产91 | 黄色影院在线免费观看 | 91网页版在线观看 | 中文字幕在线播出 | 日韩视频免费观看高清完整版在线 | 国产成人黄色av | 婷婷综合网 | 亚洲精品国产精品国自产观看浪潮 | 天天操天天曰 | 97超碰人人澡 | 国内久久久久久 | 激情综合亚洲 | 日韩经典一区二区三区 | 亚洲国产日韩欧美 | 婷婷综合国产 | 久艹在线免费观看 | 狠狠色网 | 久草在线资源免费 | 国产亚洲精品久久19p | 日韩视频一区二区在线 | 日韩有码网站 | 国产精品福利无圣光在线一区 | 亚洲精品欧美视频 | 懂色av一区二区在线播放 | 午夜视频在线观看一区二区 | .国产精品成人自产拍在线观看6 | 一区二区三区影院 | 国产亚洲精品久久久久久网站 | 欧美日韩中文字幕综合视频 | 香蕉影院在线 | 亚州激情视频 | 国产在线看一区 | 精品福利视频在线观看 | 99久久婷婷国产综合亚洲 | 国产一区二区手机在线观看 | 国产黄色片久久 | 91av免费观看 | 日韩精品一区电影 | 日韩毛片在线播放 | 免费进去里的视频 | 日本三级久久 | 久久精品视频播放 | 国产精品中文在线 | 久久精品福利视频 | 六月激情 | 激情丁香在线 | 亚洲男男gaygay无套同网址 | 三级视频日韩 | av福利免费 | 国产精品久久久久永久免费看 | 91人人爽久久涩噜噜噜 | 免费h漫在线观看 | 久久久99精品免费观看 | 在线观看成人小视频 | 久草在线观看 | 国产精品久久久久久久毛片 | 天天亚洲 | 亚洲精品乱码久久久久久蜜桃91 | 国产精品久久久久9999 | 国语精品视频 | 激情综合电影网 | 久久伊人爱 | 亚洲天堂网在线视频 | 国产黄色片网站 | 麻花传媒mv免费观看 | 在线激情小视频 | 中文不卡视频 | 成人午夜电影网站 | 国产精品麻豆免费版 | 热久久免费视频 | 亚洲色图27p | 一级黄色片在线 | 成人久久久久久久久久 | 国产精品久久久免费看 | 国产99在线播放 | av电影免费观看 | 天天操比| 色婷婷福利视频 | 日韩免费视频播放 | 午夜三级福利 | 五月天色站 | 久久久精品亚洲 | 欧美日韩国产一区二区三区在线观看 | 在线视频 精品 | 日韩专区 在线 | 日本久久久久久久久久 | 国产精品正在播放 | 天天碰天天操 | 国产一二三区在线观看 | 国产亚洲视频中文字幕视频 | 91丨九色丨高潮 | 久久综合在线 | 8x成人免费视频 | 日韩免费观看一区二区 | 五月婷婷开心 | 天天操天天射天天爽 | 一级黄色大片 | 国产在线中文 | 91你懂的 | 五月综合婷 | 中文在线字幕免 | 欧美福利网站 | 中文字幕精品www乱入免费视频 | 六月激情丁香 | 四虎欧美 | 国产小视频你懂的 | 国产视频一区二区在线观看 | 97国产视频 | 一区久久久| 色偷偷88欧美精品久久久 | 97免费中文视频在线观看 | 美女黄久久 | 国产精品麻 | 最近中文字幕免费大全 | 欧美性久久久久久 | 99精品欧美一区二区蜜桃免费 | 在线免费国产视频 | 欧美精选一区二区三区 | 伊人五月婷 | 成人黄色在线观看视频 | 免费观看91视频 | 成人午夜性影院 | 四虎成人av | 国产精品 久久 | 视频在线观看亚洲 | 国产在线观看免 | 国产成人亚洲在线观看 | 国产午夜麻豆影院在线观看 | 久久久久人人 | 天天综合入口 | 激情亚洲综合在线 | 一级理论片在线观看 | 91中文在线 | 国产精品成人a免费观看 | 少妇bbw搡bbbb搡bbb | 97成人在线视频 | 久草在线观看视频免费 | 97超碰人人干 | 一本色道久久综合亚洲二区三区 | 西西44人体做爰大胆视频 | 久草视频视频在线播放 | 欧美日韩二三区 | 久久超| 在线观看国产中文字幕 | 欧美一级高清片 | a√国产免费a | 中文字幕日韩伦理 | 91九色视频 | 国产亚洲精品久久久久5区 成人h电影在线观看 | 国产麻豆精品在线观看 | 国产精品刺激对白麻豆99 | 久久麻豆视频 | 91在线最新 | 婷婷成人亚洲综合国产xv88 | 看片网站黄色 | 日韩一区在线播放 | 国产一区二区久久久 | 日韩欧美高清在线观看 | 久久老司机精品视频 | 国产激情久久久 | 国产69久久久欧美一级 | 99 视频 高清 | 91在线资源 | 成年人免费在线观看 | 一区二区三区四区影院 | 精品国产免费观看 | 九九视频精品在线 | 久久国产精品99久久人人澡 | av大全在线 | 99久久日韩精品视频免费在线观看 | 国产精品自拍在线 | 亚洲三级在线免费观看 | 久久综合综合久久综合 | 色六月婷婷 | 国产伦精品一区二区三区照片91 | 国产在线播放一区二区三区 | 日韩一级理论片 | 在线免费黄色毛片 | av黄色免费看| 日本精品视频免费观看 | 亚洲精品国产精品久久99热 | 香蕉视频久久 | 黄色成人av| 国产精品婷婷 | 久久999精品 | 国产精品va | 麻豆国产网站 | 国产黄色片免费看 | 夜添久久精品亚洲国产精品 | 成人午夜网| 国产专区在线视频 | 91九色视频在线 | www.福利视频| 日韩在线视频网站 | 天天色天天爱天天射综合 | 久久一区二区三区超碰国产精品 | 日韩欧美视频在线观看免费 | 日韩欧美综合在线视频 | 久久久久国产精品免费免费搜索 | 成年人免费观看国产 | 久久精品91视频 | 国产成人av网 | 日本在线观看一区二区三区 | 日日夜夜网 | 日韩理论电影在线 | 久久综合色一综合色88 | 国产永久免费高清在线观看视频 | 免费在线观看av的网站 | 久久国产精品免费看 | 丝袜足交在线 | 国产黄影院色大全免费 | 啪一啪在线 | 亚洲电影第一页av | 国产精品日韩高清 | 久久97久久97精品免视看 | 在线日韩亚洲 | 久久视频精品在线 | 99久久99久久精品 | 色综合久久久久综合体桃花网 | 精品久久久久久久久中文字幕 | 美女精品久久久 | 99久久精品无码一区二区毛片 | 天天爽夜夜操 | 91精品网站在线观看 | 日韩三级免费观看 | 午夜91视频 | 免费看片亚洲 | 久久久精品欧美一区二区免费 | 成人欧美一区二区三区黑人麻豆 | 99精品影视| 国产综合在线视频 | 日本黄色一级电影 | 美女久久久 | 91久久人澡人人添人人爽欧美 | 夜夜澡人模人人添人人看 | 午夜精品一区二区三区可下载 | 99视频精品全部免费 在线 | 日韩精品在线视频免费观看 | 黄色大片日本免费大片 | 99夜色 | 久久久久麻豆v国产 | 97狠狠操 | 久草久视频 | 91精品办公室少妇高潮对白 | 黄色大片免费网站 | 日韩试看 | 亚洲国产三级在线观看 | 婷婷丁香七月 | 99精品久久久久 | 亚洲精品一区二区三区在线观看 | 成人 亚洲 欧美 | 亚洲综合干| 狠狠狠色 | 91精品在线免费观看 | 黄色三级免费观看 | 国产黄色成人av | 女人魂免费观看 | 久久综合操 | 一区二区激情视频 | a天堂在线看 | 亚洲 欧美变态 另类 综合 | 一色屋精品视频在线观看 | 99视频这里有精品 | 精品综合久久久 | 久草网站在线 | 国产在线中文字幕 | 日韩一区二区三区观看 | 久久黄色小说 | 丁香5月婷婷久久 | www黄| 国产一区二区免费看 | 亚洲特级片 | 美国人与动物xxxx | 中文视频在线看 | 国产精品第 | 欧美激情视频免费看 | 久草线 | 国色天香永久免费 | 免费福利在线播放 | 色婷婷婷 | 国产精品久久99精品毛片三a | 美女一区网站 | 中文字幕欧美三区 | 91亚洲精品久久久中文字幕 | 免费69视频| 国产精品99久久久久久宅男 | 国产精品欧美久久久久三级 | 国产.精品.日韩.另类.中文.在线.播放 | 韩国av不卡 | 亚洲欧美成人综合 | 国产亚洲精品久久久久久久久久 | 丁香婷婷激情五月 | 中文字幕2021| 国产黄色在线观看 | 国产一级视频 | www.狠狠操.com | 日韩欧美成 | 天天干天天天 | 国产精品麻 | 国产91电影在线观看 | 国产午夜精品福利视频 | 91最新网址在线观看 | 久久九精品 | 日本动漫做毛片一区二区 | 精品久久美女 | 午夜成人影视 | 五月天亚洲精品 | 九九免费在线观看 | 一区二区三区在线观看 | av免费在线网站 | 亚洲aⅴ免费在线观看 | 国产亚洲精品成人 | www.在线观看av | 中文字幕999 | 日韩精品中字 | 成人国产一区 | 国产福利精品一区二区 | av电影在线免费观看 | 国产精品久久一区二区无卡 | 日韩精品字幕 | 波多野结衣日韩 | 亚洲成人av一区 | 91精品国产综合久久福利不卡 | 色.com| 91在线精品秘密一区二区 | 四虎影视精品永久在线观看 | 日韩在线第一 | 欧美一级片在线免费观看 | 中文字幕免费观看 | 日韩激情小视频 | 在线导航av | 天天操天天爱天天爽 | 亚洲高清91 | 久久se视频 | 免费看黄电影 | 超碰在线94| 久久精品久久久精品美女 | 久久美女高清视频 | 夜夜躁狠狠躁日日躁视频黑人 | 中文字幕在线免费看 | 亚洲国产欧洲综合997久久, | 久久久久区| 99精品黄色| 亚洲国产精彩中文乱码av | 欧美日韩在线观看一区二区三区 | 久久不卡日韩美女 | 天天射射天天 | 免费亚洲黄色 | 久久视频国产精品免费视频在线 | 国内精品久久久久影院男同志 | 欧美激情精品久久久久久 | 免费手机黄色网址 | 亚洲爱爱视频 | 在线黄色国产电影 | 成人天堂网 | 国产98色在线 | 日韩 | 久久久精品久久 | 久久精品一区二区三 | 天天干天天操天天射 | 97视频在线观看免费 | 808电影免费观看三年 | 久草资源在线观看 | 不卡av在线 | 欧美成人影音 | 中文字幕在线观看完整 | 欧美91在线| 日韩电影在线观看一区二区三区 | 久久深夜 | 中文在线字幕免费观看 | 国产在线a | 91福利视频在线 | 国产91精品高清一区二区三区 | 亚洲精品视频一二三 | 中文乱幕日产无线码1区 | 国产精品系列在线观看 | 狠狠色狠狠色合久久伊人 | 超碰人人干人人 | 亚洲精品66 | 国产成人在线免费观看 | 有码中文在线 | 久久国产精品一区二区 | 久久九九国产视频 | 国产精品99久久久精品免费观看 | 久久久国产一区 | 狠狠夜夜 | 久草五月| 免费人做人爱www的视 | 97电院网手机版 | 91在线九色| 国产成人61精品免费看片 | 久热av在线 | 99999精品 | 亚洲撸撸| 在线观看免费成人 | 日韩精品免费一区二区三区 | 青青久视频 | 亚洲欧洲国产精品 | 久久久免费毛片 | 91在线免费播放 | 天天操月月操 | 亚洲理论电影 | 精品亚洲视频在线观看 | 日韩三级中文字幕 | 日韩欧美一区二区三区在线观看 | 久草视频免费观 | 亚洲国产日韩av | 久久免费看 | 92精品国产成人观看免费 | 国产精品密入口果冻 | wwwwwww色| 香蕉视频色 | 久久99精品久久久久久秒播蜜臀 | 激情综合亚洲精品 | 日韩av免费大片 | 黄色av电影 | 黄色www| ,午夜性刺激免费看视频 | 蜜臀精品久久久久久蜜臀 | 国产精品成人久久久久 | 伊人五月婷 | 97人人澡人人爽人人模亚洲 | 激情久久网 | 婷婷激情综合网 | 99婷婷| 欧洲精品码一区二区三区免费看 | 亚洲 综合 激情 | 最近高清中文字幕 | 精品国产一区二区三区四区在线观看 | 日韩精品视频一二三 | 黄污视频网站大全 | 国产一性一爱一乱一交 | 麻豆精品视频在线观看免费 | 日本久久高清视频 | 黄色a在线 | 91亚洲精品在线观看 | 国产一卡在线 | 韩日精品在线 | 香蕉影院在线观看 | 日日干天夜夜 | 成 人 黄 色 视频播放1 | 最近高清中文字幕在线国语5 | 欧美色精品天天在线观看视频 | 最新国产精品视频 | 中文字幕日本电影 | 天天操天天爱天天爽 | 国产精品久久久久久久久久久久久 | 热久久免费国产视频 | 嫩小bbbb摸bbb摸bbb | 国产黄色片一级三级 | 亚洲成人精品 | 日韩成人在线免费观看 | 国产91亚洲精品 | 亚洲2019精品 | 在线观看免费黄色 | 丁香婷婷在线 | 中文字幕在线影院 | 色综合久久中文字幕综合网 | 精品毛片在线 | 99视频偷窥在线精品国自产拍 | 一级精品视频在线观看宜春院 | 久久国产精品系列 | 欧美黄色高清 | 91porny九色91啦中文 | 日韩av午夜在线观看 | 午夜三级在线 | 色com网 | a成人v在线 | 精品久久久久免费极品大片 | wwxxxx日本 | 日本韩国在线不卡 | 国产精品夜夜夜一区二区三区尤 | 国产中文字幕在线看 | 在线观看视频日韩 | 免费国产在线观看 | 9i看片成人免费看片 | 精品国产不卡 | 91资源在线视频 | 五月天久久久久 | a天堂一码二码专区 | 久久亚洲综合国产精品99麻豆的功能介绍 | 欧美日韩综合在线观看 | 日韩久久久久久久久久久久 | 久久久91精品国产一区二区精品 | 免费高清影视 | 69av免费视频 | 日黄网站 | 欧美性超爽 | 东方av在 | 久久久久久蜜av免费网站 | 久久久久国产视频 | 在线小视频你懂得 | 久久国产亚洲视频 | 99视频精品免费视频 | 欧美 日韩 国产 成人 在线 | 成人黄色在线视频 | 亚洲欧美国产精品久久久久 | 黄色片免费看 | 99热在线观看| 国产精品乱码久久久 | 亚洲一区二区观看 | 美女视频黄色免费 | 日韩精品视频第一页 | 五月开心婷婷网 | 天天操天天吃 | 精品美女国产在线 | 在线免费中文字幕 | 久久丝袜视频 | 狠狠夜夜 | 五月天久久综合网 | 99热精品久久 | 亚洲精品国产视频 | 天天色天天色天天色 | 国产91精品高清一区二区三区 | 亚洲aⅴ一区二区三区 | 日本中文字幕在线播放 | 超碰大片| 久久婷婷开心 | 欧美网址在线观看 | 视频在线99| 久久精品成人热国产成 | 五月婷婷狠狠 | 91精品欧美| 三级av在线播放 | 精品久久久久一区二区国产 | 香蕉久草在线 | 综合国产在线观看 | 天天干天天操天天操 | 丁香在线视频 | 蜜臀久久99精品久久久久久网站 | 亚洲一区二区三区毛片 | 国产美女在线观看 | 男女拍拍免费视频 | 天天干,天天插 | 热re99久久精品国产66热 | 亚洲日本在线一区 | 蜜臀av网址 | 亚洲伊人天堂 | 日韩欧美电影 | 欧美日韩在线免费观看视频 | 99久久夜色精品国产亚洲 | 98超碰在线 | 婷婷久久一区二区三区 | 国产成人精品av久久 | 精品国产一区二区三区四 | 国产精品99爱 | 日韩免费福利 | 手机av看片 | 麻豆视频免费播放 | 欧美极品xxxxx | 在线观看国产www | 一本一道波多野毛片中文在线 | 青青河边草观看完整版高清 | www91在线观看| 一本色道久久精品 | 日韩影视在线观看 | 91在线免费视频观看 | 国产精品久久二区 | 免费色婷婷 | 国产看片网站 | av亚洲产国偷v产偷v自拍小说 | 亚洲高清视频一区二区三区 | 91精品国产92久久久久 | 亚洲精选在线观看 | 18pao国产成视频永久免费 | 久久夜夜操 | 99热网站| 免费在线观看的av网站 | 91污污视频在线观看 | 国产精品第二十页 | 91九色蝌蚪国产 | 五月婷婷开心中文字幕 | 最近中文字幕完整视频高清1 | 日韩丝袜视频 | 夜夜干天天操 | a色视频| 国产精品毛片久久久久久久 | 国产高清中文字幕 | 黄色亚洲片 | 免费成人av | 国产亚洲在线观看 | www免费视频com| 五月开心网 | 一区二区三区四区精品视频 | 亚洲精品午夜久久久 | 成人羞羞视频在线观看免费 | 日韩av免费一区二区 | 精品国产一区二区三区四区在线观看 | 国产资源网 | 99精品欧美一区二区三区黑人哦 | 日韩欧美综合视频 | 免费久久99精品国产婷婷六月 | 热久久免费视频精品 | 久久精品男人的天堂 | 2019精品手机国产品在线 | 国产夫妻性生活自拍 | 五月婷婷亚洲 | 精品国产综合区久久久久久 | 日韩视频免费观看高清 | 成人在线一区二区三区 | 91亚洲视频在线观看 | 黄色一级大片免费看 | 丁香 久久 综合 | 久久高清 | 国产精品国内免费一区二区三区 | 在线一区二区三区 | 国产亚洲精品久久久久久久久久久久 | 久久人人爽爽 | 国精产品999国精产品视频 | 日本女人的性生活视频 | 国产特级毛片 | 久久精品国产久精国产 | 国产h在线播放 | 久久夜夜操 | 2018好看的中文在线观看 | 91大神精品视频在线观看 | 97精品国产 | 在线免费av播放 | 久久久久国产一区二区 | 美女免费黄网站 | 亚洲免费永久精品国产 | 欧美色就是色 | 国产小视频在线免费观看视频 | 亚洲精品乱码久久久久久按摩 | 日韩欧美精品一区 | 成人福利在线 | 国产日韩视频在线 | 中文字幕在线视频一区二区三区 | 国产一区在线观看视频 | 最近乱久中文字幕 | 午夜在线资源 | 4438全国亚洲精品观看视频 | 欧美精品一区在线发布 | av一区在线播放 | 日韩视频在线观看视频 | 久久激情视频免费观看 | av片中文字幕 | 色婷婷精品大在线视频 | 丁香激情视频 | 国产精品第一页在线观看 | 97免费在线观看视频 | 成人永久免费 | 久久人人97超碰国产公开结果 | 人人超碰97| 欧美日韩精品影院 | 久久一区二区三区超碰国产精品 | 亚欧日韩av | 黄色大片日本免费大片 | 97av色 | 欧美精品在线观看一区 | 99精品热视频只有精品10 | 激情丁香综合五月 | 特级黄色视频毛片 | 国产成人一区二区三区久久精品 | 亚洲精品视频国产 | 国产美女永久免费 | 亚洲黄色av| 97免费 | 一级特黄av | 中文字幕在线播放日韩 | 狠狠的操你| 亚洲成人二区 | 免费看黄20分钟 | 精品亚洲一区二区三区 | av电影中文 | 在线免费观看黄色小说 | 精油按摩av | 一级片视频在线 | 婷婷成人综合 | 五月婷婷一级片 | 91av片| 国产精品一区二区电影 | 亚洲精品视频在线免费 | 亚洲乱码久久久 | 中文不卡视频 | 99精品免费在线 | 九九热免费精品视频 | 久久综合九色综合欧美就去吻 | 国产一区二区三区视频在线 | 国产又粗又猛又色又黄视频 | 色网站国产精品 | 婷婷性综合 | 久久精品视频国产 | h视频日本 | 久久久久久久久久久久久国产精品 | 日韩欧美国产成人 | 成人精品国产免费网站 | 日韩免费视频在线观看 | 欧美日韩不卡在线 | 成人av电影免费观看 | 久久久久久久免费看 | 91国内在线视频 | 一区二区激情视频 | 中文字幕成人在线 | 久久av免费观看 | av免费黄色 | 狠狠色丁香久久婷婷综 | 亚洲免费av一区二区 | 国产中文字幕大全 | 色婷婷久久久综合中文字幕 | 免费观看黄 | 国产在线美女 | 色网站中文字幕 | 在线看小早川怜子av | 国产精品久久久久久久久久新婚 | 久久综合狠狠综合久久综合88 | 日韩高清av | 日韩亚洲精品电影 | 草久中文字幕 | 韩国av一区二区 | 成人国产电影在线观看 | 久久中文字幕导航 | 国产美女免费视频 | 国产精品扒开做爽爽的视频 | 国内外成人在线 | 久久九九久久 | 欧美日韩电影在线播放 | 日韩mv欧美mv国产精品 | 亚洲女人天堂成人av在线 | 成年人免费看片网站 | 日韩精品短视频 | 国产精品2019 | 日韩精品在线播放 | 亚洲第五色综合网 | 欧美福利视频 | 91最新视频在线观看 | 久久久久国产精品一区二区 | 成人免费观看大片 | 国精产品999国精产 久久久久 | 开心激情五月网 | 亚洲成人蜜桃 | 伊人干综合| 国产美女免费 | 99精品视频在线观看免费 | 午夜精品久久久久久 | 成人国产在线 | 日本久久精品视频 | 这里只有精品视频在线观看 | 国产成人一区二区精品非洲 | 亚在线播放中文视频 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 午夜精品福利一区二区三区蜜桃 | 亚洲成人av电影在线 | 成人一区电影 | 国产精品成久久久久三级 | 看污网站| 久久精品中文字幕 | 欧美巨大| 国产a国产a国产a | av在线网站大全 | 国产精品毛片久久久久久久 | 黄色av电影免费观看 | 国产中文字幕av | 久久婷婷综合激情 | 91高清完整版在线观看 | 日日日日干| 久热久草 | 婷婷av色综合 | 成人国产精品久久久久久亚洲 | 久久成人国产精品免费软件 | 欧美日韩午夜爽爽 | 超碰大片 | 精品国模一区二区 | 96精品高清视频在线观看软件特色 | 在线观看视频一区二区三区 | 日本精品视频一区 | av在线进入| 国产专区免费 | 在线韩国电影免费观影完整版 | 欧美日韩国产页 | 色综合久久88色综合天天人守婷 | 99精品影视 | 亚洲激情网站免费观看 | 黄色小网站在线 | 国产精品国产三级国产专区53 | 国产专区视频在线观看 | 日韩视频一区二区在线 | 麻豆国产精品va在线观看不卡 | 久久久久免费精品 | 91在线影院 | 国产精品乱码一区二三区 | 在线观看黄色国产 | 国产精品成人av久久 | 丁香婷婷综合五月 | 中日韩男男gay无套 日韩精品一区二区三区高清免费 | 中文字幕精品一区二区三区电影 | 91国内在线 | 国产专区在线视频 | 国产99久久久精品视频 | 九九久久影院 | 日韩r级电影在线观看 | 美女久久久久久久久久 | 婷婷福利影院 | 香蕉视频在线免费 | 国产91九色视频 | 婷婷在线色 | 天天干天天想 | 久草在线在线精品观看 | 亚洲视频免费 | 国内精品在线观看视频 | 丁香六月婷婷激情 | 色综合天天视频在线观看 | 国产亚洲成人精品 | 色资源在线观看 | 日韩中文字幕亚洲一区二区va在线 | 国产亚洲一区二区三区 | 日韩久久精品一区二区三区 | 在线观看日韩 | 久久国产精品99久久久久 | 久久久久免费精品国产小说色大师 | 国产超碰在线观看 | 国产成人精品福利 | 国产自在线 | 亚洲撸撸 | 欧洲亚洲国产视频 | 亚洲国产久 | 国产福利电影网址 | 国产精品福利午夜在线观看 | 欧美色888 | 中文字幕亚洲精品日韩 | 亚洲va综合va国产va中文 | 久久综合九色99 | 国产精品日韩欧美 | 视频在线观看入口黄最新永久免费国产 | 69视频永久免费观看 | 日韩精品播放 | 欧美日韩免费观看一区二区三区 | 国产精品国产三级国产专区53 | 久操综合| 91精品国产综合久久婷婷香蕉 | 日韩 在线a| 日韩高清国产精品 | 444av| 国产精品日韩欧美一区二区 | 成人97视频一区二区 | 在线观看免费成人av | 六月丁香婷婷网 | 玖玖玖精品 | a视频在线播放 | 欧洲黄色片 | 91一区啪爱嗯打偷拍欧美 | 免费看的黄色 | 一区二区在线不卡 | 奇米网8888 | 黄色91免费观看 | 99热国产在线中文 | 亚洲一区网 | 国产区精品在线观看 | 久久国产一区 | 免费aa大片 | 久久久久高清 | 成人黄色免费观看 | 欧美小视频在线观看 | 91传媒免费在线观看 | 久久精品亚洲精品国产欧美 | 99热精品国产 | 激情五月婷婷 | 久久99精品久久久久久清纯直播 | 久久久久免费精品国产 | 亚洲视频综合在线 | 国产精品99免视看9 国产精品毛片一区视频 | 在线精品视频免费观看 | 成人h动漫在线看 | 91麻豆精品国产午夜天堂 | 欧美性黑人 | 久久夜色精品国产亚洲aⅴ 91chinesexxx | 亚洲免费婷婷 | 制服丝袜在线91 | 欧美综合国产 | 欧美91片| 国产精品视频永久免费播放 | 国产69精品久久99的直播节目 | 国产女教师精品久久av | 99精品国产视频 | 91麻豆网站 | 国产美女免费视频 | 欧美日韩在线视频免费 | 日韩综合一区二区三区 | 日本精品视频一区 | 国产色女| www.伊人网| 色中文字幕在线观看 | www..com毛片 | 五月天伊人 | 久久久高清视频 | 国产精品久久久久久久毛片 | 在线观看免费成人 | 国产精品乱码一区二区视频 | avav99| 亚洲一区尤物 | 中文字幕丰满人伦在线 | 99久久精品国 | 最近中文字幕国语免费高清6 | 久久亚洲精品电影 | 亚洲区精品 | 国产精品美乳一区二区免费 | 91麻豆精品国产91久久久久久久久 | 97精品国产97久久久久久久久久久久 | 天天射天天操天天干 | 一区二区三区日韩视频在线观看 | 在线有码中文字幕 | 国产亚洲人成网站在线观看 | 国产在线播放观看 | 99久久婷婷国产综合亚洲 | 夜色资源网 | 少妇bbbb搡bbbb桶| 成人午夜网址 | 国产69精品久久99的直播节目 | 久久免费毛片视频 | 亚洲电影图片小说 | 中文字幕在线视频免费播放 | 日韩欧美在线一区 | 亚洲国产精品va在线 | 国产一级二级在线 | 久久国产精品免费视频 | 中文字幕免费在线 | 99这里都是精品 | 亚洲精品永久免费视频 | 国产亚洲精品久久19p | 欧美最爽乱淫视频播放 | 欧美日韩精品在线观看 | 天天曰夜夜操 | 在线看片a| 免费看黄电影 | 天干啦夜天干天干在线线 | 99热国内精品 | 丁香影院在线 | 久久综合影视 | 国产色a在线观看 | 欧美一区二区在线免费看 | 成人免费视频a | 亚洲 欧美 精品 | 五月天精品视频 | 国产剧情在线一区 | 二区三区在线视频 | 久久久精品网 | 丁香久久五月 | 国产成人黄色在线 | 三级黄色大片在线观看 | 伊人色综合久久天天 | 91精品1区2区 | www.大网伊人| 精品国产伦一区二区三区观看体验 | 97中文字幕 | 91亚洲精品久久久蜜桃 | 丁香综合 | 美女网站视频免费都是黄 | 久久综合桃花 | 91精品国产综合久久久久久久 | 亚洲二区精品 | 免费在线观看成年人视频 | 久久久久视 | 中文字幕有码在线观看 | www.久久爱.cn | 久久免费激情视频 | 成年人在线免费看视频 | 黄色av一区二区三区 | 国产成人一二三 | 久久三级视频 | 一区二区三区在线不卡 | 一级成人网 | 国产999精品| 人人操日日干 | 国产精品久久久久久久久软件 | 国产精品久久久久久久久久了 | 96精品在线 | 99在线热播精品免费99热 | 欧美精品一区二区性色 | 亚洲成 人精品 | 欧美色噜噜 | 人人舔人人舔 | 中文字幕 婷婷 | 国产96在线 | 成人免费网站视频 | 精品av网站 | 国产精品视频免费在线观看 | 国产手机免费视频 | 在线观看免费91 | 国产在线黄色 | 国产午夜视频在线观看 | 成人视屏免费看 | 99视频在线观看视频 | 国产在线精 |