文章目錄
- 一、 理論部分
- 1.中斷系統
- 2.中斷執行流程
- 3.NVIC的基本結構
- 4.EXTI介紹
- 5.AFIO復用IO口
- 二、實驗目的:學習stm32中斷原理和開發編程方法。使用標準完成以下任務:
- (一)實驗一 開關控制LED的亮滅
- 1.代碼部分
- 2.運行結果
- (二)實驗二 接收單個字符控制發送數據
- 1.代碼部分
- 2.運行結果
- (三)實驗三 接收字符串控制發送數據
- 1.代碼部分
- 2.運行結果
- 三、總結
一、 理論部分
1.中斷系統
2.中斷執行流程
3.NVIC的基本結構
4.EXTI介紹
5.AFIO復用IO口
二、實驗目的:學習stm32中斷原理和開發編程方法。使用標準完成以下任務:
用stm32F103核心板的GPIOA端一管腳接一個LED,GPIOB端口一引腳接一個開關(用杜邦線模擬代替)。采用中斷模式編程,當開關接高電平時,LED亮燈;接低電平時,LED滅燈。
可參考教材課件上的6.4.3示例
采用串口中斷方式重做上周的串口通信作業,分別實現:1)當stm32接收到字符“s”時,停止持續發送“hello windows!”; 當接收到字符“t”時,持續發送“hello windows!”(提示:采用一個全局標量做信號燈);2)當stm32接收到字符“stop stm32!”時,停止持續發送“hello windows!”; 當接收到字符“go stm32!”時,持續發送“hello windows!”(提示:要將接收到的連續字符保存到一個字符數組里,進行判別匹配。寫一個接收字符串的函數。
(一)實驗一 開關控制LED的亮滅
1.代碼部分
//exti_key.c文件
#include "exti_key.h"
#include "misc.h"void EXTI_Key_Init()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE); //打開GPIOA和復用輸入輸出口的時鐘//配置GPIO口GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Pin_3; GPIO_InitStructure.GPIO_Pin = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//配置NVIC(Nested Vectored Interrupt Controller:嵌套向量中斷控制器)NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_Init(&NVIC_InitStructure);//配置EXTI(External Interrupt/Event Controller:外部中斷/事件控制器)EXTI_InitTypeDef EXTI_InitStructure;EXTI_ClearITPendingBit(EXTI_Line3);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3);EXTI_InitStructure.EXTI_Line = EXTI_Line3;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_Init(&EXTI_InitStructure);}
#include "stm32f10x.h"
#include "exti_key.h"
#include "LED.h"uint8_t led = 1;
int main()
{GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET); //默認為熄滅EXTI_Key_Init();while(1){}
}void EXTI3_IRQHandler()
{if(EXTI_GetITStatus(EXTI_Line3) != RESET ){led = ~led;if(led == 1){GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);}else{GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);} EXTI_ClearITPendingBit(EXTI_Line3);}}
2.運行結果
20240519_002
(二)實驗二 接收單個字符控制發送數據
采用串口中斷方式,當stm32接收到1個字符“s”時,停止持續發送“hello windows!”; 當接收到1個字符“t”時,持續發送“hello windows!”(提示:采用一個全局標量做信號燈);
1.代碼部分
#include "stm32f10x.h" // Device header
#include "Delay.h"int status = 0;//設置是否發送數據的標志位
int main()
{ //開啟GPIOA和USART1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//實例化控制器的對象GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;//先配置GPIO控制器//1.設置PA9為復用推挽輸出模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //設置為復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;GPIO_Init(GPIOA,&GPIO_InitStructure); //老子草了沒寫這一句,以為只GPIO_Init()一次就可以了,結果忘了這些參數會覆蓋的。//2.設置PA10為浮空輸入模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //設置為浮空輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//再配置USART控制器USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制:選擇無流控制USART_InitStructure.USART_Mode = USART_Mode_Tx |USART_Mode_Rx; //模式選擇發送和接收USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_ClearFlag(USART1, USART_FLAG_TC);USART_Init(USART1,&USART_InitStructure); //初始化串口1//配置中斷源USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//當USART串口接收到數據的時候,就觸發USART中斷// 4.給這個中斷源配置相應的搶占優先級和執行優先級NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //設置搶占(主)優先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; // 設置子優先級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(USART1,ENABLE); //使能串口1char transmitArray[18]={"hello windows! \r\n "}; //windows系統串口發送時,用回車換行組合 (\r\n) 來實現換行while(1){ if(status == 1) //標志位status = 1 發送{for(int i=0;i<=17;i++){USART_SendData(USART1,transmitArray[i]);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)== RESET); //RESET就是0,表示不符合,TXE的E是empty,表示發送寄存器不符合為空,即里面有東西,還在發送。 }Delay_s(1);}}}void USART1_IRQHandler(void)
{while(USART_GetITStatus(USART1,USART_IT_RXNE) == RESET ) //這里不再是USART_GetFlagStatus、USART_FLAG_RXNE,而是USART_GetITStatus、SART_IT_RXNE,要換成中斷{}; uint8_t RData=USART_ReceiveData(USART1);if(RData == 's'){status = 0;}else if (RData == 't'){status = 1;}}
2.運行結果
(三)實驗三 接收字符串控制發送數據
1.代碼部分
#include "stm32f10x.h" // Device header
#include "Delay.h"void InitRDataArray();int status = 0;//設置是否發送數據的標志位char RDataArray[20];//接收指令的字符數組int main()
{ //開啟GPIOA和USART1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//實例化控制器的對象GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;//先配置GPIO控制器//1.設置PA9為復用推挽輸出模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //設置為復用推挽輸出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;GPIO_Init(GPIOA,&GPIO_InitStructure); //老子草了沒寫這一句,以為只GPIO_Init()一次就可以了,結果忘了這些參數會覆蓋的。//2.設置PA10為浮空輸入模式GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //設置為浮空輸入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);//再配置USART控制器USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制:選擇無流控制USART_InitStructure.USART_Mode = USART_Mode_Tx |USART_Mode_Rx; //模式選擇發送和接收USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_ClearFlag(USART1, USART_FLAG_TC);USART_Init(USART1,&USART_InitStructure); //初始化串口1//配置中斷源USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//當USART串口接收到數據的時候,就觸發USART中斷// 4.給這個中斷源配置相應的搶占優先級和執行優先級NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //設置搶占(主)優先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; // 設置子優先級 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_Cmd(USART1,ENABLE); //使能串口1char transmitArray[18]={"hello windows! \r\n "}; //windows系統串口發送時,用回車換行組合 (\r\n) 來實現換行InitRDataArray(); //初始化用來接收指令的字符數組while(1){ if(status == 1) //標志位status = 1 發送{for(int i=0;i<=17;i++){USART_SendData(USART1,transmitArray[i]);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)== RESET); //RESET就是0,表示不符合,TXE的E是empty,表示發送寄存器不符合為空,即里面有東西,還在發送。 }Delay_s(1);}}}//初始化字符數組
void InitRDataArray()
{for(int i=0;i<20;i++){RDataArray[i]=0;}
}void USART1_IRQHandler(void)
{int i=0;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//判斷中斷是接收數據中斷{RDataArray[i]= USART_ReceiveData(USART1); //接收字符i++;} if (strcmp(RDataArray,"stop stm32!")==0){status = 0;//結束發送InitRDataArray(); //初始化用來接收指令的字符數組}
else if (strcmp(RDataArray,"go stm32!")==0){status = 1;//發送數據InitRDataArray(); //初始化用來接收指令的字符數組}
}
2.運行結果
三、總結
我剛把串口通信學得差不多,現在又來了這個中斷,中斷我感覺比之前學的東西都要難。我也說不出為什么,就是覺得它很抽象。