 |
1樓
巨大八爪鱼
2016-12-19 19:26
#include <stm32f10x.h> #define _BV(n) (1 << (n)) uint8_t num = 0; uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; void delay(void) { uint32_t i; for (i = 0; i < 2000; i++); } // 數碼管顯示部分 void SerIn(uint8_t data) { uint8_t i; for (i = 0; i < 8; i++) { GPIOC->BRR = _BV(15); if (data & 0x80) GPIOC->BSRR = _BV(13); else GPIOC->BRR = _BV(13); GPIOC->BSRR = _BV(15); data <<= 1; } } void ParOut(void) { GPIOC->BRR = _BV(14); GPIOC->BSRR = _BV(14); } int main(void) { RCC->APB2ENR = 0x19; // 開啟PB和PC以及AFIO的時鐘 GPIOB->CRL = 0x00280000; // PB4設為帶上下拉的輸入, PB5設為2MHz推輓輸出 GPIOB->ODR = 0x10; // PB4選擇上拉模式, PB5輸出0 GPIOC->CRH = 0x33300000; // PC13~15設為50MHz推輓輸出 // External interrupt/event controller EXTI->IMR = _BV(4); // 開啟PX4中斷 (Interrupt mask register) EXTI->FTSR = _BV(4); // PX4在下降沿觸發中斷 (Falling trigger selection register) AFIO->EXTICR[1] = 0x01; // 指定PX4中的PX為PB SerIn(seg8[num]); // 段選 SerIn(_BV(0)); // 位選 ParOut(); while (1) { if (EXTI->PR & _BV(4)) // 檢測中斷標誌位 (Pending register) { num++; if (num > 9) num = 0; SerIn(seg8[num]); SerIn(_BV(0)); ParOut(); // 等待按鍵PB4釋放 while ((GPIOB->IDR & _BV(4)) == 0) delay(); EXTI->PR |= _BV(4); // 通過寫1來清除中斷標誌位 } } }
|
 |
2樓
巨大八爪鱼
2016-12-19 19:29
【步驟】 1.開啟AFIO的時鐘,也就是將RCC->APB2ENR寄存器的最低位設為1 2.把相應端口設為輸入 3.通過EXTI->IMR寄存器開中斷 4.通過EXTI->FTSR寄存器設置中斷觸發方式 5.通過AFIO->EXTICR[n]寄存器決定PX中X的值。PX0~3在該[0]號寄存器中設置,PX4~7在[1]號寄存器中設置,以此類推
|
 |
3樓
巨大八爪鱼
2016-12-19 19:33
對於第4步,EXTI_RTSR寄存器設置的觸發方式為上升沿觸發,EXTI_FTSR為下降沿觸發
|
 |
4樓
巨大八爪鱼
2016-12-19 20:19
1樓的程序是通過查詢的方式來處理中斷。下面的程序則是通過中斷服務函數來處理: #include <stm32f10x.h> #define _BV(n) (1 << (n)) uint8_t num = 0; uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; void delay(void) { uint32_t i; for (i = 0; i < 2000; i++); } // 數碼管顯示部分 void SerIn(uint8_t data) { uint8_t i; for (i = 0; i < 8; i++) { GPIOC->BRR = _BV(15); if (data & 0x80) GPIOC->BSRR = _BV(13); else GPIOC->BRR = _BV(13); GPIOC->BSRR = _BV(15); data <<= 1; } } void ParOut(void) { GPIOC->BRR = _BV(14); GPIOC->BSRR = _BV(14); } // 中斷服務函數 void EXTI4_IRQHandler(void) { num++; if (num > 9) num = 0; SerIn(seg8[num]); SerIn(_BV(0)); ParOut(); // 等待按鍵PB4釋放 while ((GPIOB->IDR & _BV(4)) == 0) delay(); // 清除中斷標誌 //NVIC->ICPR[0] = _BV(10); // 無效, 因為該中斷正在執行 EXTI->PR |= _BV(4); // 只能通過這種方式清除中斷 } int main(void) { RCC->APB2ENR = 0x19; // 開啟PB和PC以及AFIO的時鐘 GPIOB->CRL = 0x00280000; // PB4設為帶上下拉的輸入, PB5設為2MHz推輓輸出 GPIOB->ODR = 0x10; // PB4選擇上拉模式, PB5輸出0 GPIOC->CRH = 0x33300000; // PC13~15設為50MHz推輓輸出 // External interrupt/event controller EXTI->IMR = _BV(4); // 開啟PX4中斷 (Interrupt mask register) EXTI->FTSR = _BV(4); // PX4在下降沿觸發中斷 (Falling trigger selection register) AFIO->EXTICR[1] = 0x01; // 指定PX4中的PX為PB NVIC->ISER[0] = _BV(10); // 允許執行中斷函數 SerIn(seg8[num]); // 段選 SerIn(_BV(0)); // 位選 ParOut(); while (1); }
|
 |
5樓
巨大八爪鱼
2016-12-19 20:21
首先,對於PX4中斷,所使用的線路是EXTI4,也就是EXTI Line4 interrupt。該線路的位置(Position)是10。這在用戶手冊中是可以查到的: 
|
 |
6樓
巨大八爪鱼
2016-12-19 20:29
要想中斷函數得到執行,就必須配置NVIC->ISER[n]寄存器(Interrupt set-enable registers)。 表中的Position的值的範圍是0~59,而每個ISER寄存器只有32位,所以分了好幾個寄存器來設置:  [0]號寄存器專門設置0~31號中斷 [1]號寄存器專門設置32~63號中斷 因此配置第10號中斷的代碼就是: NVIC->ISER[0] = _BV(10); 寫1是開啟,寫0無效。要想關閉只有對NVIC->ICER[n]寄存器(Interrupt clear-enable registers)寫1才行。 中斷服務函數的名稱必須為EXTI4_IRQHandler,不能自行修改。在該函數中必須通過對EXTI->PR寄存器(Pending register)寫1來清除中斷標誌,防止該函數反覆執行。
|
 |
7樓
巨大八爪鱼
2016-12-19 20:35
IRQHandler的全稱是Interrupt Request Handler,也就是中斷請求處理器。
|