標(biāo)題: (菜鳥(niǎo)筆記)類(lèi)比STC51單片機(jī)的STM32串口中斷純寄存器操作 [打印本頁(yè)]
作者: spraut 時(shí)間: 2021-2-3 15:01
標(biāo)題: (菜鳥(niǎo)筆記)類(lèi)比STC51單片機(jī)的STM32串口中斷純寄存器操作
本菜文以STM32的USART1中斷為例,類(lèi)比STC系列的51單片機(jī)相對(duì)應(yīng)的操作,粗淺地分析一下STM32串口中斷各項(xiàng)配置的含義。本著知其所以然的理念,例程采用了直接訪(fǎng)問(wèn)寄存器的方式,未使用任何庫(kù)函數(shù)。
盡管STM32和STC相差很大,但它們的串口操作流程還是比較相近的,都包括引腳配置、通訊參數(shù)配置、中斷配置和中斷服務(wù)程序等步驟。為了節(jié)約時(shí)間,前兩項(xiàng)內(nèi)容就不多說(shuō)了。
例程的運(yùn)行條件如下:
1.USART1_RX在PA10上,配置成上拉/下拉輸入模式,USART1_TX在PA9上,配置成2MHz的復(fù)用推挽模式;
2.9600bps,8N1數(shù)據(jù)格式;
3.PB0接了一只LED。
下面進(jìn)入串口中斷配置主題。
先通過(guò)下圖回顧一下STC單片機(jī)串口1中斷邏輯,以及流程中涉及到的概念。
圖1.jpg (40.71 KB, 下載次數(shù): 85)
下載附件
2021-2-3 14:26 上傳
寄存器SCON的位1(TI發(fā)送中斷請(qǐng)求)和位0(RI接收中斷請(qǐng)求)是兩個(gè)中斷源,也就是說(shuō),在串口發(fā)送或接收數(shù)據(jù)時(shí),硬件會(huì)使SCON.1或SCON.0置位,從而產(chǎn)生TI發(fā)送中斷請(qǐng)求或接收中斷請(qǐng)求,但這兩個(gè)請(qǐng)求能不能被程序響應(yīng),還得過(guò)ES和EA兩關(guān),如果IE.4(ES串口中斷使能)和IE.7(EA中斷總開(kāi)關(guān))都為1,TI或RI的請(qǐng)求才能進(jìn)入中斷優(yōu)先級(jí)評(píng)估模塊。在這個(gè)模塊里,TI或RI中斷會(huì)根據(jù)寄存器IPH和IP相應(yīng)位的值分為4個(gè)優(yōu)先級(jí)。
不管TI或RI中斷是什么優(yōu)先級(jí),只要中斷被CPU響應(yīng)了,那就會(huì)把串口1中斷向量賦值給程序計(jì)數(shù)器PC,也就是把程序存儲(chǔ)器0023H和0024H兩個(gè)單元的值賦給PC,從而進(jìn)入串口的中斷服務(wù)程序,直至執(zhí)行到RETI指令為止才退出。
這個(gè)過(guò)程至少涉及五個(gè)主要概念:中斷源、中斷使能、中斷優(yōu)先級(jí)、中斷向量、中斷服務(wù)程序。同樣,STM32的串口1中斷也有這五個(gè)概念。
下圖是STM32F1xx串口1中斷邏輯:
圖3.jpg (45.49 KB, 下載次數(shù): 65)
下載附件
2021-2-3 14:45 上傳
現(xiàn)在開(kāi)始直接面向寄存器操作。
1、中斷源使能配置
目標(biāo)寄存器:USART1_CR1串口1控制寄存器1
寄存器地址:0x4001380c
賦值:0x202c
本例僅開(kāi)放了接收中斷,所以只用到了USART1_CR1寄存器。UE(USART1_CR1.13)、RXNEIE(USART1_CR1.5)、TE(USART1_CR1.3)和RE(USART1_CR1.2)同時(shí)置位,這就產(chǎn)生了0x202c的賦值。
圖2.jpg (110.17 KB, 下載次數(shù): 84)
下載附件
2021-2-3 14:45 上傳
這是USART1中斷源及相應(yīng)使能位的邏輯圖,圖中標(biāo)紅線(xiàn)路是可以產(chǎn)生中斷的信號(hào),綠色信號(hào)代表各個(gè)中斷線(xiàn)路的使能信號(hào)。咱得承認(rèn),人家STM32F1xx的中斷源還真是挺多的,而且都能單獨(dú)使能,比STC靈活多了。
2、串口中斷開(kāi)放
USART1沒(méi)有像STC那樣的中斷總開(kāi)關(guān)EA,但它有和ES類(lèi)似的串口中斷使能,所有的中斷都有自己的使能開(kāi)關(guān),它們集合在一個(gè)寄存器族NVIC_ISER0~NVIC_ISER7里,每個(gè)中斷各占其中的一個(gè)位。
Cortex-M3在這方面的做法很有意思,它通過(guò)中斷向量表為每個(gè)中斷分配了一個(gè)向量號(hào),然后再以這個(gè)向量號(hào)為索引,找到并操作NVIC寄存器組中相關(guān)的寄存器或位,包括后面要說(shuō)的中斷優(yōu)先級(jí)設(shè)置也是如此,所以咱們先來(lái)看看STM32中斷向量表:
圖4.jpg (175.24 KB, 下載次數(shù): 58)
下載附件
2021-2-3 14:38 上傳
USART1的向量號(hào)是37,請(qǐng)記住這個(gè)‘門(mén)牌號(hào)’。
開(kāi)放中斷需要操作NVIC_ISERx寄存器:
圖5.jpg (43.65 KB, 下載次數(shù): 64)
下載附件
2021-2-3 14:45 上傳
NVIC_ISER共8個(gè)寄存器,即NVIC_ISER0---NVIC_ISER7,而STM32F1xx只排了60多個(gè)中斷號(hào)(不同型號(hào)可用的中斷數(shù)量不同),所以實(shí)際上只使用了NVIC_ISER0~NVIC_ISER2,其中在NVIC_ISER0占座的是0號(hào)窗口看門(mén)狗WWDG中斷---31號(hào)I2C1事件中斷,USART1中斷在NVIC_ISER1的bit5上。所以,USART1中斷使能的操作如下:
目標(biāo)寄存器:NVIC_ISER1中斷設(shè)置使能寄存器1
寄存器地址:0xe000e104
賦值:bit5置位
3、中斷優(yōu)先級(jí)分組設(shè)置
STM32的中斷優(yōu)先級(jí)設(shè)置比STC復(fù)雜一些,它需要先設(shè)置所有中斷的優(yōu)先級(jí)分組,也就是通過(guò)SCB_AIRCR寄存器將中斷優(yōu)先級(jí)分為搶占級(jí)和響應(yīng)級(jí),這是兩個(gè)與STC不太一樣的優(yōu)先級(jí)概念。
首先需要明確的是,SCB_AIRCR設(shè)置的不是某個(gè)具體中斷的搶占級(jí)和響應(yīng)級(jí),而是針對(duì)所有中斷。
目標(biāo)寄存器:SCB_AIRCR系統(tǒng)控制模塊應(yīng)用程序中斷和復(fù)位控制寄存器
寄存器地址:0xe000ed0c
賦值:0x05fa0400
圖6.jpg (44.94 KB, 下載次數(shù): 70)
下載附件
2021-2-3 14:45 上傳
書(shū)上說(shuō)了,每次操作這個(gè)寄存器都必須在VECTKEY段上寫(xiě)0x05fa,否則它不認(rèn)賬,會(huì)忽略寫(xiě)入操作。SCB_AIRCR的復(fù)位值很‘聰明’,恰好是密鑰0x05fa的反碼。
在寫(xiě)入密鑰的同時(shí)對(duì)PRIGROUP[2:0]賦值才是核心目的,在英文手冊(cè)上它的全稱(chēng)是interrupt priority grouping,字面意思是中斷優(yōu)先級(jí)分組,而按照它的功能來(lái)說(shuō),俺覺(jué)得叫‘中斷優(yōu)先級(jí)分隔位標(biāo)志’比較貼切,因?yàn)樗甘境隽藫屨技?jí)和響應(yīng)級(jí)的分隔位置。
STM32F1xx用1個(gè)叫IP[x]的字節(jié)來(lái)定義優(yōu)先級(jí),但只用了它的高4位,并且按照PRIGROUP[2:的值把這4位分成搶占和響應(yīng)兩組,以本例中PRIGROUP[2:0]=100(也就是4)為例,IP[x]從位4分隔開(kāi)來(lái),位7~位5成為搶占組,可形成23(8級(jí))搶占級(jí)別,又因?yàn)槲?~位0沒(méi)有啟用,所以只剩下位4作為響應(yīng)組,也就只有0、1兩個(gè)響應(yīng)級(jí)別。
在后序的步驟當(dāng)中,這個(gè)IP[x]字節(jié)將在具體中斷優(yōu)先級(jí)配置當(dāng)中賦不同的數(shù)值,從而確定相應(yīng)中斷的優(yōu)先級(jí)。
回過(guò)頭來(lái)簡(jiǎn)單說(shuō)一說(shuō)什么是搶占級(jí)(Group priority)和響應(yīng)級(jí)(Sub priority)。
搶占級(jí)的數(shù)值越低,優(yōu)先級(jí)就越高,可以嵌入低級(jí)別中斷;響應(yīng)沒(méi)有搶先嵌套權(quán),但響應(yīng)級(jí)別高的可以?xún)?yōu)先執(zhí)行。假設(shè)正在執(zhí)行一個(gè)搶占級(jí)為1/響應(yīng)級(jí)為1的A中斷,簡(jiǎn)稱(chēng)為A(g1s1),又來(lái)了3個(gè)中斷,分別是B(g0s1)、C(g2s1)、D(g2s0),那么B就會(huì)打斷A嵌套進(jìn)去被執(zhí)行,沒(méi)辦法,誰(shuí)讓B的搶占級(jí)別高呢。等B執(zhí)行完了,A就會(huì)繼續(xù)執(zhí)行,C和D也只能在外面等著,因?yàn)樗鼈兊膿屨技?jí)別都比A低。等A執(zhí)行完了就會(huì)優(yōu)先執(zhí)行D,因?yàn)楸M管C和D的搶占級(jí)是一樣的,但D的響應(yīng)優(yōu)先級(jí)高于C,C只好眼巴巴了。
3、結(jié)合PRIGROUP[2:的具體中斷優(yōu)先級(jí)設(shè)定
具體到USART1中斷,剛才說(shuō)的PRIGROUP[2:0]和優(yōu)先級(jí)字節(jié)IP[x]該怎樣落地呢?
目標(biāo)寄存器:NVIC_IPR9中斷優(yōu)先級(jí)設(shè)置寄存器
寄存器地址:0xe000e409
賦值:對(duì)應(yīng)IP[37]的字節(jié)賦值0x30
STM32設(shè)置了一個(gè)叫做NVIC_IPRx的寄存器陣列,每個(gè)寄存器可以存放4個(gè)中斷的優(yōu)先級(jí)8位(1個(gè)字節(jié))配置數(shù)據(jù),這個(gè)陣列與NVIC_ISERx的布局方式類(lèi)似,只不過(guò)NVIC_ISERx是位布局,而NVIC_IPRx則是字節(jié)布局:
IP[37]就是USART1中斷優(yōu)先級(jí)配置的字節(jié),
PRIGROUP[2:0]=4已經(jīng)確定了搶占級(jí)用3個(gè)位、響應(yīng)級(jí)用1個(gè)位,那么IP[37]=0x30的意思就是配置USART1中斷的搶占級(jí)為1,響應(yīng)級(jí)也為1。
4、例程
//串口1中斷測(cè)試程序
//GPIOA/GPIOB相關(guān)寄存器定義
#define GPIOA_Base 0x40010800
#define GPIOB_Base 0x40010C00
#define GPIO_ConfigurationRegisterLow 0x00
#define GPIO_ConfigurationRegisterHigh 0x04
#define GPIO_OutputDataRegister 0x0c
#define GPIOA_CRH (*(volatile unsigned int*)(GPIOA_Base + GPIO_ConfigurationRegisterHigh))
#define GPIOB_CRL (*(volatile unsigned int*)(GPIOB_Base + GPIO_ConfigurationRegisterLow))
#define LED1 *(volatile unsigned int *)0x42218180
//RCC相關(guān)寄存器定義
#define RCC_APB2ENR (*(volatile unsigned int*)0x40021018)
//USART1相關(guān)寄存器定義
#define USART1_Base 0x40013800
#define USART_DataRegister 0x04
#define USART_BaudRateRegister 0x08
#define USART_ControlRegister1 0x0c
#define USART_ControlRegister2 0x10
#define USART1_DR (*(volatile unsigned int*)(USART1_Base + USART_DataRegister))
#define USART1_BRR (*(volatile unsigned int*)(USART1_Base + USART_BaudRateRegister))
#define USART1_CR1 (*(volatile unsigned int*)(USART1_Base + USART_ControlRegister1))
#define USART1_CR2 (*(volatile unsigned int*)(USART1_Base + USART_ControlRegister2))
#define ResetUSART1 *(volatile unsigned int*)0x424201b8
#define USART1_RXNE *(volatile unsigned int*)0x42270014
//NVIC相關(guān)寄存器定義
#define SCB_AIRCR *(volatile unsigned int*)0xe000ed0c
#define NVIC_ISER1 *(volatile unsigned int*)0xe000e104
#define NVIC_IPR9 *(volatile unsigned int*)0xe000e409
//---------------------------------------
void Delay_ms(unsigned short int MsCount)
{
unsigned int i = 0;
while(MsCount--)
{
i=8030;
while(i--);
}
}
void U1BaudRate(unsigned int PCLK2,unsigned int BaudRate)
//波特率設(shè)置
{
float UsartDiv;
unsigned short int Mantissa;//波特率換算參數(shù)整數(shù)部分
unsigned short int Fraction;//波特率換算參數(shù)小數(shù)部分
UsartDiv = (float)(PCLK2*1000000)/(BaudRate*16);
Mantissa = UsartDiv;//得到整數(shù)部分
Fraction = (UsartDiv-Mantissa)*16;//得到小數(shù)部分
Mantissa <<= 4;
Mantissa = Mantissa + Fraction;
USART1_BRR = Mantissa;
}
int main(void)
{
/*為節(jié)約篇幅,就不把時(shí)鐘初始化程序列出來(lái)了,PCLK2為72MHz.*/
//開(kāi)啟USART1和GPIOA/GPIOB時(shí)鐘
RCC_APB2ENR |=0x0000400c;
//配置USART1_RX(PA10)和USART1_TX(PA9)
GPIOA_CRH = (GPIOA_CRH & 0xfffff00f) | 0x000008a0;
//配置LED1(接在了PB0上)引腳狀態(tài)
GPIOB_CRL = (GPIOB_CRL & 0xfffffff0) | 0xee000006;
//復(fù)位USART1
ResetUSART1=1;
ResetUSART1=0;
//配置波特率為9600,數(shù)據(jù)格式為8N1
U1BaudRate(72,9600);
//使能USART1模塊,使能發(fā)送和接收,開(kāi)啟接收中斷
USART1_CR1 |=0x202c;
//寫(xiě)入VECTKEY,PRIGROUP賦值為4
SCB_AIRCR &=0x05faf8ff;
SCB_AIRCR |=0x05fa0400;
//使能USART1中斷
NVIC_ISER1 |=1<<5;
//配置USART1的搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)
NVIC_IPR9 &=0xffff00ff;
NVIC_IPR9 |=0x3000;
while(1)
{
LED1 = 0;
Delay_ms(1000);
LED1 = 1;
Delay_ms(1000);
}
}
void USART1_IRQHandler(void)
//串口1中斷服務(wù)程序
{
unsigned char tmp;
if(USART1_RXNE ==1)
{
USART1_RXNE=0;
tmp=USART1_DR;
USART1_DR=tmp;
}
}
歡迎光臨 (http://www.torrancerestoration.com/bbs/) |
Powered by Discuz! X3.1 |