stm32中断优先级分组
生活随笔
收集整理的這篇文章主要介紹了
stm32中断优先级分组
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
STM32中斷優先級和開關總中斷一,中斷優先級:STM32(Cortex-M3)中的優先級概念
STM32(Cortex-M3)中有兩個優先級的概念——搶占式優先級和響應優先級,有人把響應優先級稱作'亞優先級'或'副優先級',每個中斷源都需要被指定這兩種優先級。具有高搶占式優先級的中斷可以在具有低搶占式優先級的中斷處理過程中被響應,即中斷嵌套,或者說高搶占式優先級的中斷可以嵌套低搶占式優先級的中斷。當兩個中斷源的搶占式優先級相同時,這兩個中斷將沒有嵌套關系,當一個中斷到來后,如果正在處理另一個中斷,這個后到來的中斷就要等到前一個中斷處理完之后才能被處理。如果這兩個中斷同時到達,則中斷控制器根據他們的響應優先級高低來決定先處理哪一個;如果他們的搶占式優先級和響應優先級都相等,則根據他們在中斷表中的排位順序決定先處理哪一個。既然每個中斷源都需要被指定這兩種優先級,就需要有相應的寄存器位記錄每個中斷的優先級;在Cortex-M3中定義了8個比特位用于設置中斷源的優先級,這8個比特位可以有8種分配方式,如下:所有8位用于指定響應優先級
最高1位用于指定搶占式優先級,最低7位用于指定響應優先級
最高2位用于指定搶占式優先級,最低6位用于指定響應優先級
最高3位用于指定搶占式優先級,最低5位用于指定響應優先級
最高4位用于指定搶占式優先級,最低4位用于指定響應優先級
最高5位用于指定搶占式優先級,最低3位用于指定響應優先級
最高6位用于指定搶占式優先級,最低2位用于指定響應優先級
最高7位用于指定搶占式優先級,最低1位用于指定響應優先級這就是優先級分組的概念。--------------------------------------------------------------------------------
Cortex-M3允許具有較少中斷源時使用較少的寄存器位指定中斷源的優先級,因此STM32把指定中斷優先級的寄存器位減少到4位,這4個寄存器位的分組方式如下: 第0組:所有4位用于指定響應優先級
第1組:最高1位用于指定搶占式優先級,最低3位用于指定響應優先級
第2組:最高2位用于指定搶占式優先級,最低2位用于指定響應優先級
第3組:最高3位用于指定搶占式優先級,最低1位用于指定響應優先級
第4組:所有4位用于指定搶占式優先級可以通過調用STM32的固件庫中的函數NVIC_PriorityGroupConfig()選擇使用哪種優先級分組方式,這個函數的參數有下列5種:NVIC_PriorityGroup_0 => 選擇第0組
NVIC_PriorityGroup_1 => 選擇第1組
NVIC_PriorityGroup_2 => 選擇第2組
NVIC_PriorityGroup_3 => 選擇第3組
NVIC_PriorityGroup_4 => 選擇第4組 接下來就是指定中斷源的優先級,下面以一個簡單的例子說明如何指定中斷源的搶占式優先級和響應優先級:// 選擇使用優先級分組第1組
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);// 使能EXTI0中斷
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定搶占式優先級別1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定響應優先級別0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);// 使能EXTI9_5中斷
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定搶占式優先級別0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定響應優先級別1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);要注意的幾點是:1)如果指定的搶占式優先級別或響應優先級別超出了選定的優先級分組所限定的范圍,將可能得到意想不到的結果;2)搶占式優先級別相同的中斷源之間沒有嵌套關系;3)如果某個中斷源被指定為某個搶占式優先級別,又沒有其它中斷源處于同一個搶占式優先級別,則可以為這個中斷源指定任意有效的響應優先級別。二,開關總中斷:在STM32/Cortex-M3中是通過改變CPU的當前優先級來允許或禁止中斷。
PRIMASK位:只允許NMI和hard fault異常,其他中斷/異常都被屏蔽(當前CPU優先級=0)。
FAULTMASK位:只允許NMI,其他所有中斷/異常都被屏蔽(當前CPU優先級=-1)。在STM32固件庫中(stm32f10x_nvic.c和stm32f10x_nvic.h) 定義了四個函數操作PRIMASK位和FAULTMASK位,改變CPU的當前優先級,從而達到控制所有中斷的目的。下面兩個函數等效于關閉總中斷:
void NVIC_SETPRIMASK(void);
void NVIC_SETFAULTMASK(void);下面兩個函數等效于開放總中斷:
void NVIC_RESETPRIMASK(void);
void NVIC_RESETFAULTMASK(void);上面兩組函數要成對使用,不能交叉使用。例如:第一種方法:
NVIC_SETPRIMASK(); //關閉總中斷
NVIC_RESETPRIMASK();//開放總中斷第二種方法:
NVIC_SETFAULTMASK(); //關閉總中斷
NVIC_RESETFAULTMASK();//開放總中斷常常使用NVIC_SETPRIMASK(); // Disable Interrupts
NVIC_RESETPRIMASK(); // Enable InterruptsSTM32時鐘系統STM32資料 2009-09-23 14:53 閱讀72 評論0
字號: 大大 中中 小小
在STM32中,有五個時鐘源,為HSI、HSE、LSI、LSE、PLL。①、HSI是高速內部時鐘,RC振蕩器,頻率為8MHz。②、HSE是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率范圍為4MHz~16MHz。③、LSI是低速內部時鐘,RC振蕩器,頻率為40kHz。④、LSE是低速外部時鐘,接頻率為32.768kHz的石英晶體。⑤、PLL為鎖相環倍頻輸出,其時鐘輸入源可選擇為HSI/2、HSE或者HSE/2。倍頻可選擇為2~16倍,但是其輸出頻率最大不得超過72MHz。圖1 HSE/LSE時鐘源其中40kHz的LSI供獨立看門狗IWDG使用,另外它還可以被選擇為實時時鐘RTC的時鐘源。另外,實時時鐘RTC的時鐘源還可以選擇LSE,或者是HSE的128分頻。RTC的時鐘源通過RTCSEL[1:0]來選擇。STM32中有一個全速功能的USB模塊,其串行接口引擎需要一個頻率為48MHz的時鐘源。該時鐘源只能從PLL輸出端獲取,可以選擇為1.5分頻或者1分頻,也就是,當需要使用USB模塊時,PLL必須使能,并且時鐘頻率配置為48MHz或72MHz。另外,STM32還可以選擇一個時鐘信號輸出到MCO腳(PA8)上,可以選擇為PLL輸出的2分頻、HSI、HSE、或者系統時鐘。系統時鐘SYSCLK,它是供STM32中絕大部分部件工作的時鐘源。系統時鐘可選擇為PLL輸出、HSI或者HSE。系統時鐘最大頻率為72MHz,它通過AHB分頻器分頻后送給各模塊使用,AHB分頻器可選擇1、2、4、8、16、64、128、256、512分頻。其中AHB分頻器輸出的時鐘送給5大模塊使用:①、送給AHB總線、內核、內存和DMA使用的HCLK時鐘。②、通過8分頻后送給Cortex的系統定時器時鐘。③、直接送給Cortex的空閑運行時鐘FCLK。④、送給APB1分頻器。APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB1外設使用(PCLK1,最大頻率36MHz),另一路送給定時器(Timer)2、3、4倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器2、3、4使用。⑤、送給APB2分頻器。APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB2外設使用(PCLK2,最大頻率72MHz),另一路送給定時器(Timer)1倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器1使用。另外,APB2分頻器還有一路輸出供ADC分頻器使用,分頻后送給ADC模塊使用。ADC分頻器可選擇為2、4、6、8分頻。在以上的時鐘輸出中,有很多是帶使能控制的,例如AHB總線時鐘、內核時鐘、各種APB1外設、APB2外設等等。當需要使用某模塊時,記得一定要先使能對應的時鐘。需要注意的是定時器的倍頻器,當APB的分頻為1時,它的倍頻值為1,否則它的倍頻值就為2。連接在APB1(低速外設)上的設備有:電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看門狗、Timer2、Timer3、Timer4。注意USB模塊雖然需要一個單獨的48MHz時鐘信號,但它應該不是供USB模塊工作的時鐘,而只是提供給串行接口引擎(SIE)使用的時鐘。USB模塊工作的時鐘應該是由APB1提供的。連接在APB2(高速外設)上的設備有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。下圖是STM32用戶手冊中的時鐘系統結構圖,通過該圖可以從總體上掌握STM32的時鐘系統。STM32外部中斷之二STM32資料 2009-09-10 21:18 閱讀243 評論0
字號: 大大 中中 小小
STM32 外部中斷配置1配置中斷1、 分配中斷向量表:/* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);2、 設置中斷優先級:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //設置中斷優先級3、 初始化外部中斷:/*允許EXTI4中斷 */NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //中斷通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;//強占優先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //次優先級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中斷使能NVIC_Init(&NVIC_InitStructure); //初始化中斷注意:如果我們配置的外部針腳為PA4,或PB4,或PC4,PD4等,那么采用的外部中斷也必須是EXTI4,同樣,如果外部中斷針腳是PA1,PB1,PC1,PD1 那么中斷就要用EXTI1,其他類推。2配置GPIO針腳作為外部中斷的觸發事件 1、 選擇IO針腳GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;注意,如果的針腳是端口的4號針腳,配置的中斷一定是EXTI42、 配置針腳為輸入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;3、 初始化針腳GPIO_Init(GPIOD,&GPIO_InitStructure);3配置EXTI線,使中斷線和IO針腳線連接上1、 將EXTI線連接到IO端口上將EXTI線4連接到端口GPIOD的第4個針腳上GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);注意:如果配置的針腳是4號,那么參數必須是GPIO_PinSource4如果配置的針腳是3號,那么參數必須是GPIO_PinSource32、配置中斷邊沿/*配置EXTI線0上出現下降沿,則產生中斷*/EXTI_InitStructure.EXTI_Line = EXTI_Line4;注意:如果配置的4號針腳,那么EXTI_Line4是必須的EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿觸發EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中斷線使能EXTI_Init(&EXTI_InitStructure); //初始化中斷EXTI_GenerateSWInterrupt(EXTI_Line4); //EXTI_Line4中斷允許到此中斷配置完成,可以寫中斷處理函數。舉例:配置函數/************************************************************************** 函數名 NVIC_Configration* 描述 配置各個中斷寄存器* 輸入 無 * 輸出 無* 返回值 無****************************************************************************/void NVIC_Configration(void){NVIC_InitTypeDef NVIC_InitStructure; //#ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //#else /* VECT_TAB_FLASH *//* Set the Vector Table base location at 0x08000000 */ //NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); //#endif NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //設置中斷優先級/*允許EXTI4中斷 */NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); /*允許EXTI9中斷*/NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); /*配置SysTick處理優先級:優先級以及子優先級*/}/************************************************************************* 函數名 :GPIO_Configuration(void)* 描述 :配置TIM2陣腳* 輸入 :無* 輸出 :無* 返回 :無************************************************************************/void GPIO_Configuration(void){/* GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure); */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOC,&GPIO_InitStructure);/*配置GPIOD的第一個管角為浮動輸入*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOD,&GPIO_InitStructure);/*配置GPIOB的第9個管腳為浮動輸入*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOB,&GPIO_InitStructure); }/*************************************************************** 函數 SysTick_Configuration* 描述 設置SysTick* 輸入 無* 輸出 無* 返回值 無***************************************************************/void SysTick_Configuration(void){/*配置 HCLK 時鐘做為SysTick 時鐘源*/SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //系統時鐘8分頻 72MHzNVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 8,2);/*SysTick Interrupt each 1000Hz with HCLK equal to 72MHz*/SysTick_SetReload(9000);//中斷周期1ms/*Enable the SysTick Interrupt */SysTick_ITConfig(ENABLE);//打開中斷 SysTick_CounterCmd(SysTick_Counter_Enable);SysTick_CounterCmd(SysTick_Counter_Clear); }/******************************************************************************* 函數名 EXTI_Configuration* 描述 配置EXTI線* 輸入 無 * 輸出 無* 返回值 無******************************************************************************/void EXTI_Configuration(void){/*將EXTI線0連接到PA0*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource4);/*配置EXTI線0上出現下降沿,則產生中斷*/EXTI_InitStructure.EXTI_Line = EXTI_Line4;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);EXTI_GenerateSWInterrupt(EXTI_Line4);/*將EXTI線9連接到PB9上*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource9);/*將EXTI線9上出現下降沿產生中斷*/EXTI_InitStructure.EXTI_Line = EXTI_Line9;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);EXTI_GenerateSWInterrupt(EXTI_Line9); }中斷函數:void EXTI4_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line4)!= RESET){EXTI_ClearITPendingBit(EXTI_Line4);if(Ledflag == 0){Ledflag = 1;GPIOC->ODR |= 0X00000080;}else{Ledflag = 0; GPIOC->ODR &= 0XFFFFFF7F;}}}注:時鐘設置的時候最好加上這句: RCCRCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能AFIO時鐘STM32中定時器的時鐘源STM32資料 2009-07-24 21:34 閱讀277 評論0
字號: 大大 中中 小小 STM32中有多達8個定時器,其中TIM1和TIM8是能夠產生三對PWM互補輸出的高級定時器,常用于三相電機的驅動,它們的時鐘由APB2的輸出產生。其它6個為普通定時器,時鐘由APB1的輸出產生。下圖是STM32參考手冊上時鐘分配圖中,有關定時器時鐘部分的截圖:從圖中可以看出,定時器的時鐘不是直接來自APB1或APB2,而是來自于輸入為APB1或APB2的一個倍頻器,圖中的藍色部分。下面以定時器2~7的時鐘說明這個倍頻器的作用:當APB1的預分頻系數為1時,這個倍頻器不起作用,定時器的時鐘頻率等于APB1的頻率;當APB1的預分頻系數為其它數值(即預分頻系數為2、4、8或16)時,這個倍頻器起作用,定時器的時鐘頻率等于APB1的頻率兩倍。假定AHB=36MHz,因為APB1允許的最大頻率為36MHz,所以APB1的預分頻系數可以取任意數值;當預分頻系數=1時,APB1=36MHz,TIM2~7的時鐘頻率=36MHz(倍頻器不起作用);當預分頻系數=2時,APB1=18MHz,在倍頻器的作用下,TIM2~7的時鐘頻率=36MHz。有人會問,既然需要TIM2~7的時鐘頻率=36MHz,為什么不直接取APB1的預分頻系數=1?答案是:APB1不但要為TIM2~7提供時鐘,而且還要為其它外設提供時鐘;設置這個倍頻器可以在保證其它外設使用較低時鐘頻率時,TIM2~7仍能得到較高的時鐘頻率。再舉個例子:當AHB=72MHz時,APB1的預分頻系數必須大于2,因為APB1的最大頻率只能為36MHz。如果APB1的預分頻系數=2,則因為這個倍頻器,TIM2~7仍然能夠得到72MHz的時鐘頻率。能夠使用更高的時鐘頻率,無疑提高了定時器的分辨率,這也正是設計這個倍頻器的初衷。STM32筆記之外部中斷GPIOSTM32資料 2009-07-14 13:35 閱讀331 評論0
字號: 大大 中中 小小
b) 初始化函數定義:
void EXTI_Configuration(void); //定義IO中斷初始化函數
c) 初始化函數調用:
EXTI_Configuration();//IO中斷初始化函數調用簡單應用:
d) 初始化函數:
void EXTI_Configuration(void)
{EXTI_InitTypeDef EXTI_InitStructure; //EXTI初始化結構定義EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中斷標志GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管腳選擇GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件選擇EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發模式EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動中斷EXTI_Init(&EXTI_InitStructure);//初始化
}e) RCC初始化函數中開啟I/O時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);GPIO初始化函數中定義輸入I/O管腳。
//IO輸入,GPIOA的4腳輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
f) 在NVIC的初始化函數里面增加以下代碼打開相關中斷:NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動NVIC_Init(&NVIC_InitStructure); //初始化g) 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數,在其中添入執行代碼。一般最少三個步驟:先使用if語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中斷發生來源{ EXTI_ClearITPendingBit(EXTI_Line3); //清除中斷標志USART_SendData(USART1, 0x41); //發送字符“a”GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED發生明暗交替
}
h) 中斷注意事項:
中斷發生后必須清除中斷位,否則會出現死循環不斷發生這個中斷。然后需要對中斷類型進行判斷再執行代碼。
使用EXTI的I/O中斷,在完成RCC與GPIO硬件設置之后需要做三件事:初始化EXTI、NVIC開中斷、編寫中斷執行代碼。 STM32的USARTSTM32資料 2009-07-14 13:33 閱讀489 評論4
字號: 大大 中中 小小
b) 初始化函數定義:
void USART_Configuration(void); //定義串口初始化函數
c) 初始化函數調用:
void UART_Configuration(void); //串口初始化函數調用
初始化代碼:
void USART_Configuration(void) //串口初始化函數
{
//串口參數初始化 USART_InitTypeDef USART_InitStructure; //串口設置恢復默認參數//初始化參數設置USART_InitStructure.USART_BaudRate = 9600; //波特率9600USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長8位USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字節USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打開Rx接收和Tx發送功能USART_Init(USART1, &USART_InitStructure); //初始化USART_Cmd(USART1, ENABLE); //啟動串口
}RCC中打開相應串口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);GPIO里面設定相應串口管腳模式
//串口1的管腳初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管腳9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管腳10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入GPIO_Init(GPIOA, &GPIO_InitStructure); //RX初始化d) 簡單應用:
發送一位字符
USART_SendData(USART1, 數據); //發送一位數據
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送完畢
接收一位字符
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完畢
變量= (USART_ReceiveData(USART1)); //接受一個字節發送一個字符串先定義字符串:char rx_data[250];然后在需要發送的地方添加如下代碼int i; //定義循環變量while(rx_data!='\0') //循環逐字輸出,到結束字'\0'{USART_SendData(USART1, rx_data); //發送字符while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發送完畢i++;} e) USART注意事項:
發動和接受都需要配合標志等待。
只能對一個字節操作,對字符串等大量數據操作需要寫函數使用串口所需設置:RCC初始化里面打開RCC_APB2PeriphClockCmd
(RCC_APB2Periph_USARTx);GPIO里面管腳設定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP); f) printf函數重定義(不必理解,調試通過以備后用)
(1) 需要c標準函數:
#include "stdio.h"
(2) 粘貼函數定義代碼
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) //定義為putchar應用
(3) RCC中打開相應串口
(4) GPIO里面設定相應串口管腳模式
(6) 增加為putchar函數。
int putchar(int c) //putchar函數
{if (c == '\n'){putchar('\r');} //將printf的\n變成\rUSART_SendData(USART1, c); //發送字符while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送結束return c; //返回值
}(8) 通過,試驗成功。printf使用變量輸出:%c字符,%d整數,%f浮點數,%s字符串,/n或/r為換行。注意:只能用于main.c中。3、 NVIC串口中斷的應用
a) 目的:利用前面調通的硬件基礎,和幾個函數的代碼,進行串口的中斷輸入練習。因為在實際應用中,不使用中斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b) 初始化函數定義及函數調用:不用添加和調用初始化函數,在指定調試地址的時候已經調用過,在那個NVIC_Configuration里面添加相應開中斷代碼就行了。
c) 過程:
i. 在串口初始化中USART_Cmd之前加入中斷設置:
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE發送中斷,TC傳輸完成中斷,RXNE接收中斷,PE奇偶錯誤中斷,可以是多個。
ii. RCC、GPIO里面打開串口相應的基本時鐘、管腳設置
iii. NVIC里面加入串口中斷打開代碼:
NVIC_InitTypeDef NVIC_InitStructure;//中斷默認參數NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設置為串口1中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中斷響應優先級0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷
NVIC_Init(&NVIC_InitStructure); //初始化iv. 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數,在其中添入執行代碼。一般最少三個步驟:先使用if語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void) //串口1中斷
{
char RX_dat; //定義字符變量if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判斷發生接收中斷{USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中斷標志GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //開始傳輸RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收數據,整理除去前兩位USART_SendData(USART1, RX_dat); //發送數據while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發送結束}
}d) 中斷注意事項:
可以隨時在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關閉中斷響應。
NVIC_InitTypeDef NVIC_InitStructure定義一定要加在NVIC初始化模塊的第一句。
全局變量與函數的定義:在任意.c文件中定義的變量或函數,在其它.c文件中使用extern+定義代碼再次定義就可以直接調用了。 STM32運行的必要硬件庫STM32資料 2009-07-14 13:31 閱讀163 評論0
字號: 大大 中中 小小
0、 實驗之前的準備
a) 接通串口轉接器
b) 下載IO與串口的原廠程序,編譯通過保證調試所需硬件正常。1、 flash,lib,nvic,rcc和GPIO,基礎程序庫編寫
a) 這幾個庫函數中有一些函數是關于芯片的初始化的,每個程序中必用。為保障程序品質,初學階段要求嚴格遵守官方習慣。注意,官方程序庫例程中有個platform_config.h文件,是專門用來指定同類外設中第幾號外設被使用,就是說在main.c里面所有外設序號用x代替,比如USARTx,程序會到這個頭文件中去查找到底是用那些外設,初學的時候參考例程別被這個所迷惑住。
b) 全部必用代碼取自庫函數所帶例程,并增加逐句注釋。
c) 習慣順序——Lib(debug),RCC(包括Flash優化),NVIC,GPIO
d) 必用模塊初始化函數的定義:
void RCC_Configuration(void); //定義時鐘初始化函數
void GPIO_Configuration(void); //定義管腳初始化函數
void NVIC_Configuration(void); //定義中斷管理初始化函數
void Delay(vu32 nCount); //定義延遲函數
e) Main中的初始化函數調用:
RCC_Configuration(); //時鐘初始化函數調用
NVIC_Configuration(); //中斷初始化函數調用
GPIO_Configuration(); //管腳初始化函數調用
f) Lib注意事項:
屬于Lib的Debug函數的調用,應該放在main函數最開始,不要改變其位置。g) RCC注意事項:
Flash優化處理可以不做,但是兩句也不難也不用改參數……
根據需要開啟設備時鐘可以節省電能
時鐘頻率需要根據實際情況設置參數
h) NVIC注意事項
注意理解占先優先級和響應優先級的分組的概念
i) GPIO注意事項
注意以后的過程中收集不同管腳應用對應的頻率和模式的設置。作為高低電平的I/O,所需設置:RCC初始化里面打開RCC_APB2
PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO里面管腳設定:IO輸出(50MHz,Out_PP);IO輸入(50MHz,IPU);j) GPIO應用
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//讀入IO
k) 簡單Delay函數
void Delay(vu32 nCount)//簡單延時函數
{for(; nCount != 0; nCount--);} 基于STM32的PWM輸出STM32資料 2009-07-14 13:30 閱讀449 評論2
字號: 大大 中中 小小
c) 初始化函數定義:
void TIM_Configuration(void); //定義TIM初始化函數
d) 初始化函數調用:
TIM_Configuration(); //TIM初始化函數調用
e) 初始化函數,不同于前面模塊,TIM的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM初始化函數
{ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時器初始化結構TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結構//TIM3初始化TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFFTIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼//TIM3通道初始化TIM_OCStructInit(& TIM_OCInitStructure); //默認參數TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作狀態TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設定為輸出,需要PWM輸出才需要這行代碼TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長度TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化TIM_Cmd(TIM3, ENABLE); //啟動TIM3
}f) RCC初始化函數中加入TIM時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO里面將輸入和輸出管腳模式進行設置。信號:AF_PP,50MHz。
h) 使用中斷的話在NVIC里添加如下代碼://打開TIM2中斷NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動NVIC_Init(&NVIC_InitStructure); //初始化中斷代碼:
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源{TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標志GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//變換LED色彩IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數值}
}i) 簡單應用:
//改變占空比
TIM_SetCompare4(TIM3, 變量);j) 注意事項:
管腳的IO輸出模式是根據應用來定,比如如果用PWM輸出驅動LED則應該將相應管腳設為AF_PP,否則單片機沒有輸出。 STM32資料一(轉載)STM32資料 2009-06-14 20:15 閱讀766 評論1
字號: 大大 中中 小小 注:下面是一些常用的代碼,網上很多但是大多注釋不全。高手看沒問題,對于我們這些新手就費勁了……所以我把這些代碼集中,進行了逐句注釋,希望對新手們有價值。閱讀flash: 芯片內部存儲器flash操作函數我的理解——對芯片內部flash進行操作的函數,包括讀取,狀態,擦除,寫入等等,可以允許程序去操作flash上的數據。基礎應用1,FLASH時序延遲幾個周期,等待總線同步操作。推薦按照單片機系統運行頻率,0—24MHz時,取Latency=0;24—48MHz時,取Latency=1;48~72MHz時,取Latency=2。所有程序中必須的用法:FLASH_SetLatency(FLASH_Latency_2);位置:RCC初始化子函數里面,時鐘起振之后。基礎應用2,開啟FLASH預讀緩沖功能,加速FLASH的讀取。所有程序中必須的用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);位置:RCC初始化子函數里面,時鐘起振之后。3、 閱讀lib:調試所有外設初始化的函數。我的理解——不理解,也不需要理解。只要知道所有外設在調試的時候,EWRAM需要從這個函數里面獲得調試所需信息的地址或者指針之類的信息。基礎應用1,只有一個函數debug。所有程序中必須的。用法: #ifdef DEBUGdebug();#endif位置:main函數開頭,聲明變量之后。4、 閱讀nvic:系統中斷管理。我的理解——管理系統內部的中斷,負責打開和關閉中斷。基礎應用1,中斷的初始化函數,包括設置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。用法: void NVIC_Configuration(void){NVIC_InitTypeDef NVIC_InitStructure; //中斷管理恢復默認參數#ifdef VECT_TAB_RAM //如果C/C++ Compiler\Preprocessor\Defined symbols中的定義了VECT_TAB_RAM(見程序庫更改內容的表格)NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在RAM調試#else //如果沒有定義VECT_TAB_RAMNVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在Flash里調試#endif //結束判斷語句//以下為中斷的開啟過程,不是所有程序必須的。//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC優先級分組,方式。//注:一共16個優先級,分為搶占式和響應式。兩種優先級所占的數量由此代碼確定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分別代表搶占優先級有1、2、4、8、16個和響應優先級有16、8、4、2、1個。規定兩種優先級的數量后,所有的中斷級別必須在其中選擇,搶占級別高的會打斷其他中斷優先執行,而響應級別高的會在其他中斷執行完優先執行。//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名; //開中斷,中斷名稱見函數庫//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優先級//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應優先級//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動此通道的中斷//NVIC_Init(&NVIC_InitStructure); //中斷初始化}5、 閱讀rcc:單片機時鐘管理。我的理解——管理外部、內部和外設的時鐘,設置、打開和關閉這些時鐘。基礎應用1:時鐘的初始化函數過程——用法:void RCC_Configuration(void) //時鐘初始化函數{ErrorStatus HSEStartUpStatus; //等待時鐘的穩定RCC_DeInit(); //時鐘管理重置RCC_HSEConfig(RCC_HSE_ON); //打開外部晶振HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就緒if (HSEStartUpStatus == SUCCESS){FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//flash讀取緩沖,加速FLASH_SetLatency(FLASH_Latency_2); //flash操作的延時RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB使用系統時鐘RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)為HCLK的一半RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)為HCLK的一半//注:AHB主要負責外部存儲器時鐘。PB2負責AD,I/O,高級TIM,串口1。APB1負責DA,USB,SPI,I2C,CAN,串口2345,普通TIM。RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MHRCC_PLLCmd(ENABLE); //啟動PLLwhile (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} //等待PLL啟動RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //將PLL設置為系統時鐘源while (RCC_GetSYSCLKSource() != 0x08){} //等待系統時鐘源的啟動}//RCC_AHBPeriphClockCmd(ABP2設備1 | ABP2設備2 |, ENABLE); //啟動AHP設備//RCC_APB2PeriphClockCmd(ABP2設備1 | ABP2設備2 |, ENABLE);//啟動ABP2設備//RCC_APB1PeriphClockCmd(ABP2設備1 | ABP2設備2 |, ENABLE); //啟動ABP1設備}6、 閱讀exti:外部設備中斷函數我的理解——外部設備通過引腳給出的硬件中斷,也可以產生軟件中斷,19個上升、下降或都觸發。EXTI0~EXTI15連接到管腳,EXTI線16連接到PVD(VDD監視),EXTI線17連接到RTC(鬧鐘),EXTI線18連接到USB(喚醒)。基礎應用1,設定外部中斷初始化函數。按需求,不是必須代碼。用法: void EXTI_Configuration(void){EXTI_InitTypeDef EXTI_InitStructure; //外部設備中斷恢復默認參數EXTI_InitStructure.EXTI_Line = 通道1|通道2; //設定所需產生外部中斷的通道,一共19個。EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產生中斷EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都觸發 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動中斷的接收 EXTI_Init(&EXTI_InitStructure); //外部設備中斷啟動}7、 閱讀dma:通過總線而越過CPU讀取外設數據我的理解——通過DMA應用可以加速單片機外設、存儲器之間的數據傳輸,并在傳輸期間不影響CPU進行其他事情。這對于入門開發基本功能來說沒有太大必要,這個內容先行跳過。8、 閱讀systic:系統定時器我的理解——可以輸出和利用系統時鐘的計數、狀態。基礎應用1,精確計時的延時子函數。推薦使用的代碼。用法:static vu32 TimingDelay; //全局變量聲明void SysTick_Config(void) //systick初始化函數{SysTick_CounterCmd(SysTick_Counter_Disable); //停止系統定時器SysTick_ITConfig(DISABLE); //停止systick中斷SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick使用HCLK作為時鐘源,頻率值除以8。SysTick_SetReload(9000); //重置時間1毫秒(以72MHz為基礎計算)SysTick_ITConfig(ENABLE); //開啟systic中斷}void Delay (u32 nTime) //延遲一毫秒的函數{SysTick_CounterCmd(SysTick_Counter_Enable); //systic開始計時TimingDelay = nTime; //計時長度賦值給遞減變量while(TimingDelay != 0); //檢測是否計時完成SysTick_CounterCmd(SysTick_Counter_Disable); //關閉計數器SysTick_CounterCmd(SysTick_Counter_Clear); //清除計數值}void TimingDelay_Decrement(void) //遞減變量函數,函數名由“stm32f10x_it.c”中的中斷響應函數定義好了。{if (TimingDelay != 0x00) //檢測計數變量是否達到0{ TimingDelay--; //計數變量遞減}}注:建議熟練后使用,所涉及知識和設備太多,新手出錯的可能性比較大。新手可用簡化的延時函數代替:void Delay(vu32 nCount) //簡單延時函數{for(; nCount != 0; nCount--); //循環變量遞減計數}當延時較長,又不需要精確計時的時候可以使用嵌套循環:void Delay(vu32 nCount) //簡單的長時間延時函數{int i; //聲明內部遞減變量for(; nCount != 0; nCount--) //遞減變量計數{for (i=0; i<0xffff; i++)} //內部循環遞減變量計數}9、 閱讀gpio:I/O設置函數我的理解——所有輸入輸出管腳模式設置,可以是上下拉、浮空、開漏、模擬、推挽模式,頻率特性為2M,10M,50M。也可以向該管腳直接寫入數據和讀取數據。基礎應用1,gpio初始化函數。所有程序必須。用法:void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure; //GPIO狀態恢復默認參數GPIO_InitStructure.GPIO_Pin = GPIO_Pin_標號 | GPIO_Pin_標號 ; //管腳位置定義,標號可以是NONE、ALL、0至15。GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//輸出速度2MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入模式GPIO_Init(GPIOC, &GPIO_InitStructure); //C組GPIO初始化//注:以上四行代碼為一組,每組GPIO屬性必須相同,默認的GPIO參數為:ALL,2MHz,FLATING。如果其中任意一行與前一組相應設置相同,那么那一行可以省略,由此推論如果前面已經將此行參數設定為默認參數(包括使用GPIO_InitTypeDef GPIO_InitStructure代碼),本組應用也是默認參數的話,那么也可以省略。以下重復這個過程直到所有應用的管腳全部被定義完畢。……}基礎應用2,向管腳寫入0或1用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01); //寫入1基礎應用3,從管腳讀入0或1用法:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)STM32筆記之七:讓它跑起來,基本硬件功能的建立0、 實驗之前的準備a) 接通串口轉接器b) 下載IO與串口的原廠程序,編譯通過保證調試所需硬件正常。1、 flash,lib,nvic,rcc和GPIO,基礎程序庫編寫a) 這幾個庫函數中有一些函數是關于芯片的初始化的,每個程序中必用。為保障程序品質,初學階段要求嚴格遵守官方習慣。注意,官方程序庫例程中有個platform_config.h文件,是專門用來指定同類外設中第幾號外設被使用,就是說在main.c里面所有外設序號用x代替,比如USARTx,程序會到這個頭文件中去查找到底是用那些外設,初學的時候參考例程別被這個所迷惑住。b) 全部必用代碼取自庫函數所帶例程,并增加逐句注釋。c) 習慣順序——Lib(debug),RCC(包括Flash優化),NVIC,GPIOd) 必用模塊初始化函數的定義:void RCC_Configuration(void); //定義時鐘初始化函數void GPIO_Configuration(void); //定義管腳初始化函數void NVIC_Configuration(void); //定義中斷管理初始化函數void Delay(vu32 nCount); //定義延遲函數e) Main中的初始化函數調用:RCC_Configuration(); //時鐘初始化函數調用NVIC_Configuration(); //中斷初始化函數調用GPIO_Configuration(); //管腳初始化函數調用f) Lib注意事項:屬于Lib的Debug函數的調用,應該放在main函數最開始,不要改變其位置。g) RCC注意事項:Flash優化處理可以不做,但是兩句也不難也不用改參數……根據需要開啟設備時鐘可以節省電能時鐘頻率需要根據實際情況設置參數h) NVIC注意事項注意理解占先優先級和響應優先級的分組的概念i) GPIO注意事項注意以后的過程中收集不同管腳應用對應的頻率和模式的設置。作為高低電平的I/O,所需設置:RCC初始化里面打開RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO里面管腳設定:IO輸出(50MHz,Out_PP);IO輸入(50MHz,IPU);j) GPIO應用GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//讀入IOk) 簡單Delay函數void Delay(vu32 nCount)//簡單延時函數{for(; nCount != 0; nCount--);}實驗步驟:RCC初始化函數里添加:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);不用其他中斷,NVIC初始化函數不用改GPIO初始化代碼://IO輸入,GPIOB的2、10、11腳輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//管腳號GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //輸入輸出模式GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化簡單的延遲函數:void Delay(vu32 nCount) //簡單延時函數{ for (; nCount != 0; nCount--);} //循環計數延時完成之后再在main.c的while里面寫一段:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1Delay(0xffff);GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0Delay(0xffff);就可以看到連接在PB2腳上的LED閃爍了,單片機就跑起來了。STM32筆記之八:來跟PC打個招呼,基本串口通訊a) 目的:在基礎實驗成功的基礎上,對串口的調試方法進行實踐。硬件代碼順利完成之后,對日后調試需要用到的printf重定義進行調試,固定在自己的庫函數中。b) 初始化函數定義:void USART_Configuration(void); //定義串口初始化函數c) 初始化函數調用:void UART_Configuration(void); //串口初始化函數調用初始化代碼:void USART_Configuration(void) //串口初始化函數{//串口參數初始化 USART_InitTypeDef USART_InitStructure; //串口設置恢復默認參數//初始化參數設置USART_InitStructure.USART_BaudRate = 9600; //波特率9600USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長8位USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字節USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打開Rx接收和Tx發送功能USART_Init(USART1, &USART_InitStructure); //初始化USART_Cmd(USART1, ENABLE); //啟動串口}RCC中打開相應串口RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);GPIO里面設定相應串口管腳模式//串口1的管腳初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管腳9GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管腳10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入GPIO_Init(GPIOA, &GPIO_InitStructure); //RX初始化d) 簡單應用:發送一位字符USART_SendData(USART1, 數據); //發送一位數據while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送完畢接收一位字符while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完畢變量= (USART_ReceiveData(USART1)); //接受一個字節發送一個字符串先定義字符串:char rx_data[250];然后在需要發送的地方添加如下代碼int i; //定義循環變量while(rx_data!='\0') //循環逐字輸出,到結束字'\0'{USART_SendData(USART1, rx_data); //發送字符while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發送完畢i++;} e) USART注意事項:發動和接受都需要配合標志等待。只能對一個字節操作,對字符串等大量數據操作需要寫函數使用串口所需設置:RCC初始化里面打開RCC_APB2PeriphClockCmd(RCC_APB2Periph_USARTx);GPIO里面管腳設定:串口RX(50Hz,IN_FLOATING);串口TX(50Hz,AF_PP); f) printf函數重定義(不必理解,調試通過以備后用)(1) 需要c標準函數:#include "stdio.h"(2) 粘貼函數定義代碼#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) //定義為putchar應用(3) RCC中打開相應串口(4) GPIO里面設定相應串口管腳模式(6) 增加為putchar函數。int putchar(int c) //putchar函數{if (c == '\n'){putchar('\r');} //將printf的\n變成\rUSART_SendData(USART1, c); //發送字符while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送結束return c; //返回值}(8) 通過,試驗成功。printf使用變量輸出:%c字符,%d整數,%f浮點數,%s字符串,/n或/r為換行。注意:只能用于main.c中。3、 NVIC串口中斷的應用a) 目的:利用前面調通的硬件基礎,和幾個函數的代碼,進行串口的中斷輸入練習。因為在實際應用中,不使用中斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。b) 初始化函數定義及函數調用:不用添加和調用初始化函數,在指定調試地址的時候已經調用過,在那個NVIC_Configuration里面添加相應開中斷代碼就行了。c) 過程:i. 在串口初始化中USART_Cmd之前加入中斷設置:USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE發送中斷,TC傳輸完成中斷,RXNE接收中斷,PE奇偶錯誤中斷,可以是多個。ii. RCC、GPIO里面打開串口相應的基本時鐘、管腳設置iii. NVIC里面加入串口中斷打開代碼:NVIC_InitTypeDef NVIC_InitStructure;//中斷默認參數NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設置為串口1中斷NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中斷響應優先級0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷NVIC_Init(&NVIC_InitStructure); //初始化iv. 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數,在其中添入執行代碼。一般最少三個步驟:先使用if語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。void USART1_IRQHandler(void) //串口1中斷{char RX_dat; //定義字符變量if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判斷發生接收中斷{USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中斷標志GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //開始傳輸RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收數據,整理除去前兩位USART_SendData(USART1, RX_dat); //發送數據while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發送結束}}d) 中斷注意事項:可以隨時在程序中使用USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關閉中斷響應。NVIC_InitTypeDef NVIC_InitStructure定義一定要加在NVIC初始化模塊的第一句。全局變量與函數的定義:在任意.c文件中定義的變量或函數,在其它.c文件中使用extern+定義代碼再次定義就可以直接調用了。STM32筆記之九:打斷它來為我辦事,EXIT (外部I/O中斷)應用a) 目的:跟串口輸入類似,不使用中斷進行的IO輸入效率也很低,而且可以通過EXTI插入按鈕事件,本節聯系EXTI中斷。b) 初始化函數定義:void EXTI_Configuration(void); //定義IO中斷初始化函數c) 初始化函數調用:EXTI_Configuration();//IO中斷初始化函數調用簡單應用:d) 初始化函數:void EXTI_Configuration(void){ EXTI_InitTypeDef EXTI_InitStructure; //EXTI初始化結構定義EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中斷標志GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管腳選擇GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件選擇EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發模式EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動中斷EXTI_Init(&EXTI_InitStructure);//初始化}e) RCC初始化函數中開啟I/O時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);GPIO初始化函數中定義輸入I/O管腳。//IO輸入,GPIOA的4腳輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化f) 在NVIC的初始化函數里面增加以下代碼打開相關中斷:NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動NVIC_Init(&NVIC_InitStructure); //初始化g) 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數,在其中添入執行代碼。一般最少三個步驟:先使用if語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中斷發生來源{ EXTI_ClearITPendingBit(EXTI_Line3); //清除中斷標志USART_SendData(USART1, 0x41); //發送字符“a”GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED發生明暗交替}h) 中斷注意事項:中斷發生后必須清除中斷位,否則會出現死循環不斷發生這個中斷。然后需要對中斷類型進行判斷再執行代碼。使用EXTI的I/O中斷,在完成RCC與GPIO硬件設置之后需要做三件事:初始化EXTI、NVIC開中斷、編寫中斷執行代碼。STM32筆記之十:工作工作,PWM輸出a) 目的:基礎PWM輸出,以及中斷配合應用。輸出選用PB1,配置為TIM3_CH4,是目標板的LED6控制腳。b) 對于簡單的PWM輸出應用,暫時無需考慮TIM1的高級功能之區別。c) 初始化函數定義:void TIM_Configuration(void); //定義TIM初始化函數d) 初始化函數調用:TIM_Configuration(); //TIM初始化函數調用e) 初始化函數,不同于前面模塊,TIM的初始化分為兩部分——基本初始化和通道初始化:void TIM_Configuration(void)//TIM初始化函數{ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時器初始化結構TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結構//TIM3初始化TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFFTIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼//TIM3通道初始化TIM_OCStructInit(& TIM_OCInitStructure); //默認參數TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作狀態TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設定為輸出,需要PWM輸出才需要這行代碼TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長度TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化TIM_Cmd(TIM3, ENABLE); //啟動TIM3}f) RCC初始化函數中加入TIM時鐘開啟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);g) GPIO里面將輸入和輸出管腳模式進行設置。信號:AF_PP,50MHz。h) 使用中斷的話在NVIC里添加如下代碼://打開TIM2中斷NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應級NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動NVIC_Init(&NVIC_InitStructure); //初始化中斷代碼:void TIM2_IRQHandler(void){if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源{TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標志GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//變換LED色彩IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數值} }i) 簡單應用://改變占空比TIM_SetCompare4(TIM3, 變量);j) 注意事項:管腳的IO輸出模式是根據應用來定,比如如果用PWM輸出驅動LED則應該將相應管腳設為AF_PP,否則單片機沒有輸出我的測試程序可以發出不斷循環三種波長并捕獲,對比結果如下:捕捉的穩定性很好,也就是說,同樣的方波捕捉到數值相差在一兩個數值。捕捉的精度跟你設置的濾波器長度有關,在這里TIM_ICInitStructure.TIM_ICFilter = 0x4; //濾波設置,經歷幾個周期跳變認定波形穩定0x0~0xF這個越長就會捕捉數值越小,但是偏差幾十個數值,下面是0、4、16個周期濾波的比較,out是輸出的數值,in是捕捉到的。現在有兩個疑問:1、在TIM2的捕捉輸入通道初始化里面這句TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時鐘觸發源按照硬件框圖,4通道應該對應TI4FP4。可是實際使用TI1FP1,TI2FP2都行,其他均編譯錯誤未注冊。這是為什么?2、關閉調試器和IAR程序,直接供電跑出來的結果第一個周期很正常,當輸出脈寬第二次循環變小后捕捉的數值就差的遠了。不知道是為什么STM32筆記之十二:時鐘不息工作不止,systic時鐘應用a) 目的:使用系統時鐘來進行兩項實驗——周期執行代碼與精確定時延遲。b) 初始化函數定義:void SysTick_Configuration(void);c) 初始化函數調用:SysTick_Configuration();d) 初始化函數:void SysTick_Configuration(void){SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時鐘除8SysTick_SetReload(250000); //計數周期長度SysTick_CounterCmd(SysTick_Counter_Enable); //啟動計時器SysTick_ITConfig(ENABLE); //打開中斷}e) 在NVIC的初始化函數里面增加以下代碼打開相關中斷:NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級設置,一般設置的高一些會少受其他影響f) 在stm32f10x_it.c文件中找到void SysTickHandler 函數void SysTickHandler(void){執行代碼}g) 簡單應用:精確延遲函數,因為systic中斷往往被用來執行周期循環代碼,所以一些例程中使用其中斷的啟動和禁止來編寫的精確延時函數實際上不實用,我自己編寫了精確計時函數反而代碼更精簡,思路更簡單。思路是調用后,變量清零,然后使用時鐘來的曾變量,不斷比較變量與延遲的數值,相等則退出函數。代碼和步驟如下:i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計時ii. 在stm32f10x_it.c文件中相應定義:extern u16 Tic_Val;//在本文件引用MAIN.c定義的精確計時變量iii. 定義函數名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數iv. 精確延時函數:void Tic_Delay(u16 Tic_Count) //精確延時函數{ Tic_Val=0; //變量清零while(Tic_Val != Tic_Count){printf("");}//計時}v. 在stm32f10x_it.c文件中void SysTickHandler 函數里面添加Tic_Val++;//變量遞增vi. 調用代碼:Tic_Delay(10); //精確延時vii. 疑問:如果去掉計時行那個沒用的printf("");函數將停止工作,這個現象很奇怪C語言功底問題。是的,那個“注意事項”最后的疑問的原因就是這個Tic_Val應該改為vu16while(Tic_Val != Tic_Count){printf("");}//計時就可以改為:while(Tic_Val != Tic_Count); //檢查變量是否計數到位STM32筆記之十三:惡搞,兩只看門狗a) 目的:了解兩種看門狗(我叫它:系統運行故障探測器和獨立系統故障探測器,新手往往被這個并不形象的象形名稱搞糊涂)之間的區別和基本用法。b) 相同:都是用來探測系統故障,通過編寫代碼定時發送故障清零信號(高手們都管這個代碼叫做“喂狗”),告訴它系統運行正常。一旦系統故障,程序清零代碼(“喂狗”)無法執行,其計數器就會計數不止,直到記到零并發生故障中斷(狗餓了開始叫喚),控制CPU重啟整個系統(不行啦,開始咬人了,快跑……)。c) 區別:獨立看門狗Iwdg——我的理解是獨立于系統之外,因為有獨立時鐘,所以不受系統影響的系統故障探測器。(這條狗是借來的,見誰偷懶它都咬!)主要用于監視硬件錯誤。窗口看門狗wwdg——我的理解是系統內部的故障探測器,時鐘與系統相同。如果系統時鐘不走了,這個狗也就失去作用了。(這條狗是老板娘養的,老板不干活兒他不管!)主要用于監視軟件錯誤。d) 初始化函數定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數栓一起了,用的時候根據情況刪減。void WDG_Configuration(void);e) 初始化函數調用:WDG_Configuration();f) 初始化函數void WDG_Configuration() //看門狗初始化{//軟件看門狗初始化WWDG_SetPrescaler(WWDG_Prescaler_8); //時鐘8分頻4ms// (PCLK1/4096)/8= 244 Hz (~4 ms)WWDG_SetWindowValue(65); //計數器數值WWDG_Enable(127); //啟動計數器,設置喂狗時間// WWDG timeout = ~4 ms * 64 = 262 msWWDG_ClearFlag(); //清除標志位WWDG_EnableIT(); //啟動中斷//獨立看門狗初始化IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//啟動寄存器讀寫IWDG_SetPrescaler(IWDG_Prescaler_32);//40K時鐘32分頻IWDG_SetReload(349); //計數器數值IWDG_ReloadCounter(); //重啟計數器IWDG_Enable(); //啟動看門狗}g) RCC初始化:只有軟件看門狗需要時鐘初始化,獨立看門狗有自己的時鐘不需要但是需要systic工作相關設置。RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);h) 獨立看門狗使用systic的中斷來喂狗,所以添加systic的中斷打開代碼就行了。軟件看門狗需要在NVIC打開中斷添加如下代碼:NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中斷等級NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應中斷優先級NVIC_Init(&NVIC_InitStructure); //打開中斷i) 中斷程序,軟件看門狗在自己的中斷中喂狗,獨立看門狗需要使用systic的定時中斷來喂狗。以下兩個程序都在stm32f10x_it.c文件中。void WWDG_IRQHandler(void){WWDG_SetCounter(0x7F); //更新計數值WWDG_ClearFlag(); //清除標志位}void SysTickHandler(void){ IWDG_ReloadCounter(); //重啟計數器(喂狗)}j) 注意事項:i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!ii. 初始化程序的調用一定要在systic的初始化之后。iii. 獨立看門狗需要systic中斷來喂,但是systic做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以不影響systic的其他應用,其他systic周期代碼也可參考:第一步:在stm32f10x_it.c中定義變量int Tic_IWDG; //喂狗循環程序的頻率判斷變量第二步:將SysTickHandler中喂狗代碼改為下面:Tic_IWDG++; //變量遞增if(Tic_IWDG>=100) //每100個systic周期喂狗{ IWDG_ReloadCounter();//重啟計數器(喂狗)Tic_IWDG=0; //變量清零}
總結
以上是生活随笔為你收集整理的stm32中断优先级分组的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32串口学习总结(经典)
- 下一篇: stm32中#ifndef __LED_