串口中斷函數詳解
ARM cortex_m3 內核支持 256 個中斷(16 個內核+240 外部)和可編程 256 級中斷優先級的設置。
STM32支持的中斷共為84個(16個內核+68個外部),和16級可編程中斷優先級的設置。
AIRCR是NIVC配置中一個關鍵的寄存器,由於STM32有很多中斷,要處理這些中斷的時候總是需要先后順序的,所以采用AIRCR寄存器給中斷優先級進行分組。
優先組別總用有5組, 0-4,分為搶占優先級和響應優先級(也稱為子優先級),使用低字節的高四位來設置中斷優先級分組。
例如:當AIRCR寄存器的第八位到第十位都為1時,寄存器的第四位到第七位都是在設置響應優先級,最高可以有0個搶占優先級和16級響應優先級。具體分配如下表:
| 組 | AIRCR[10: 8] | bit[7: 4] | 結果 |
|---|---|---|---|
| 0 | 111 | 0:4 | 0 位搶占優先級, 4 位響應優先級 |
| 1 | 110 | 1:3 | 1 位搶占優先級, 3 位響應優先級 |
| 2 | 101 | 2:2 | 2 位搶占優先級, 2 位響應優先級 |
| 3 | 100 | 3:1 | 3 位搶占優先級, 1 位響應優先級 |
| 4 | 011 | 4:0 | 4 位搶占優先級, 0 位響應優先級 |
在使用NVIC初始化以前需要使用NVIC_PriorityGroupConfig( )函數設置中斷優先級分組。分組后再在中斷初始化函數中使用NVIC_IRQChannelPreemptionPriority設置具體的中斷優先級。
下面為串口初始化函數以及中斷函數:
void uart_init (){
//GPIO端口設置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能 USART1,GPIOA時鍾
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
//
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器
//USART 初始化設置
USART_InitStructure.USART_BaudRate = 115200;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式
USART_InitStructure.USART_StopBits = USART_StopBits_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; //收發模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler (void) //串口1中斷服務程序
{
u8 Res;
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ //接收中斷(接收到的數據必須是 0x0d 0x0a結尾)。USART_GetITStatus函數如果接收寄存器存在數據就返回SET
Res =USART_ReceiveData(USART1); //讀取接收到的數據,一次發送一個字節
if ((USART_RX_STA&0x8000)==0){ //接收未完成
if (USART_RX_STA&0x4000){ //接收到了0x0d 0x0D(asc碼是13) 指的是“回車”
if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else {//還沒收到0X0D
if (Res==0x0d)USART_RX_STA|=0x4000;
else {
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if (USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重 新開始接收
}
}
}
}
}
這里詳細介紹稍難理解一點的語句
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
-
第一個參數為使用串口1
-
第二個參數為中斷標志,串口有很多種中斷,這里是使用USART_IT_RXNE中斷
-
第三個參數為使能
下面為中斷處理函數:
if((USART_RX_STA&0x8000)==0)
USART_RX_STA是狀態標記變量,bit0~13接收有效字節數目,bit14接收0x0d,bit15接收完成標志。當接收完成時,bit15置為1。
該變量從0開始,串口中斷接收到一個數據(一個字節)就自增1。當數據讀取全部OK時候(回車和換行符號來的時候),那么 USART_RX_STA的最高位置1,表示串口數據接收全部完畢了,然后main函數里面可以處理數據了。
當接收到從電腦發過來的數據,把接收到的數據保存在USART_RX_BUF 中,同時在接收狀態寄存器(USART_RX_STA)中計數接收到的有效數據個數,當收到回車(0X0D,0X0A)的第一個字節0X0D 時,計數器將不再增加,等待0X0A 的到來,而如果0X0A 沒有來到,則認為這次接收失敗,重新開始下一次接收。如果順利接收到0X0A,則標記USART_RX_STA的第16位,這樣完成一次接收,並等待該位被其他程序清除,從而開始下一次的接收,而如果遲遲沒有收到0X0D,那么在接收數據超過設定值個數后,會丟棄前面的數據,重新接收。
0x4000,即二進制0100 0000 0000 0000,與變量USART_RX_STA,按位與(&),作用是判斷USART_RX_STA數值第15位是否為0。
0x8000,即二進制1000 0000 0000 0000,與變量USART_RX_STA,按位與(&),作用是判斷USART_RX_STA數值第16位是否為0。
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
為了去除最高兩位的影響,將最高兩位置0。
if (USART_RX_STA>200) USART_RX_STA=0
200為自己設定的值,如果接收到的函數大於這個值,就清除掉整個字符串重新輸入。
