STM32F072B-DISCO 是我认为性价比最高的一款CPU的demo系统,以前一直在用PIC的CPU但最近几年ST异军突起,几次课题查找芯片无一例外都是ST,像USB,CAN,ZIGBEE等,ST都做的很出色,特别是芯片太便宜了,几乎都是几块人民币,STM32F072B-DISCO 提供了大量例题,我通过对例题的分析做出简单扼要的笔记,以加深自己的理解。
第一篇:中断系统
我认为理解和掌握中断系统是会使CPU的唯一标准。
int main(void)
{
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f0xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f0xx.c file
*/
所有例题开始都有这么一段注释,在进入main之前CPU已经完成了一系列初始化工作,startup_stm32f0xx.s在后面必须认真分析
/* Initialize LEDs mounted on STM32F072B-DISCO board */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
STM_EVAL_LEDInit(LED5);
STM_EVAL_LEDInit(LED6);
/* Configure PA0 in interrupt mode */
EXTI0_1_Config(); // 外部中断 0 1 配置
配置中断子程序
static void EXTI0_1_Config(void)
{
/* Enable GPIOA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure PA0 pin as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Enable SYSCFG clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* Connect EXTI0 Line to PA0 pin */
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
/* Configure EXTI0 line */
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set EXTI0 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); 开中断并设定优先级
}
打开stm32f0xx_misc.c
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02]; The corresponding IPR number, M, is given by M = N DIV 4
tmppriority &= (uint32_t)(~(((uint32_t)0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8)));
tmppriority |= (uint32_t)((((uint32_t)NVIC_InitStruct->NVIC_IRQChannelPriority << 6) & 0xFF) << ((NVIC_InitStruct->NVIC_IRQChannel & 0x03) * 8));
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel >> 0x02] = tmppriority; 设定优先级
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F); 开启中断
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[0] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
上面的NVIC_Init 看上去有点复杂通过查看
STM32F0xxx Cortex-M0 programming manual.pdf
的73页,大概明白了计算过程
Doc ID 022979 Rev 1 73/91
4.2.6 Interrupt priority register (IPR0-IPR7)
Address offset: 0x0300
Reset value: 0x0000 0000
Table 27. IPR bit assignments
Bits Name Function
[31:24] Priority, byte offset 3 Each priority field holds a priority value, 0-192. The lower the value,
the greater the priority of the corresponding interrupt. The processor
implements only bits[7:6] of each field, bits[5:0] read as zero and //这里是说数值越低优先越高,因为只有4个优先级所以每字节只是7和6位有效。
ignore writes. This means writing 255 to a priority register saves
value 192 to the register.
The IPR registers provide an 8-bit priority field for each interrupt. These registers are only
word-accessible. Each register holds four priority fields, as shown in Figure 14.
Figure 14. IPR register mapping
See Interrupt set-enable register (ISER) on page 71 Accessing the Cortex-M0 NVIC
registers using CMSIS on page 70 for more information about the interrupt priority array, that
provides the software view of the interrupt priorities.
Find the IPR number and byte offset for interrupt N as follows:
● The corresponding IPR number, M, is given by M = N DIV 4
● The byte offset of the required Priority field in this register is N MOD 4, where:
– byte offset 0 refers to register bits[7:0]
– byte offset 1 refers to register bits[15:8] //计算方法
– byte offset 2 refers to register bits[23:16]
– byte offset 3 refers to register bits[31:24].
打开startup_stm32f0xx.s 详细分析
PUBLIC __vector_table
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_VDDIO2_IRQHandler ; PVD and VDDIO2 through EXTI Line detect
DCD RTC_IRQHandler ; RTC through EXTI Line
DCD FLASH_IRQHandler ; FLASH
DCD RCC_CRS_IRQHandler ; RCC and CRS
DCD EXTI0_1_IRQHandler ; EXTI Line 0 and 1 //向量表中外部中断 0 1,标号EXTI0_1_IRQHandler
DCD EXTI2_3_IRQHandler ; EXTI Line 2 and 3
DCD EXTI4_15_IRQHandler ; EXTI Line 4 to 15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Default interrupt handlers.
;;
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:NOROOT:REORDER(2) //SECTION .text:CODE:REORDER(2) modify bu hxc 2014.11.9
Reset_Handler
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
PUBWEAK NMI_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
NMI_Handler
B NMI_Handler
PUBWEAK HardFault_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
HardFault_Handler
B HardFault_Handler
PUBWEAK SVC_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
SVC_Handler
B SVC_Handler
PUBWEAK PendSV_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
PendSV_Handler
B PendSV_Handler
PUBWEAK SysTick_Handler
SECTION .text:CODE:NOROOT:REORDER(1)
SysTick_Handler
B SysTick_Handler
PUBWEAK WWDG_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
WWDG_IRQHandler
B WWDG_IRQHandler
PUBWEAK PVD_VDDIO2_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
PVD_VDDIO2_IRQHandler
B PVD_VDDIO2_IRQHandler
PUBWEAK RTC_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
RTC_IRQHandler
B RTC_IRQHandler
PUBWEAK FLASH_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
FLASH_IRQHandler
B FLASH_IRQHandler
PUBWEAK RCC_CRS_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
RCC_CRS_IRQHandler
B RCC_CRS_IRQHandler
PUBWEAK EXTI0_1_IRQHandler
SECTION .text:CODE:NOROOT:REORDER(1)
EXTI0_1_IRQHandler
B EXTI0_1_IRQHandler //外部中断 0 1 跳转地址
打开stm32f0xx_it.c
/******************************************************************************/
/* STM32F0xx Peripherals Interrupt Handlers */
/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */
/* available peripheral interrupt handler's name please refer to the startup */
/* file (startup_stm32f0xx.s). */
/******************************************************************************/
/**
* @brief This function handles External line 0 to 1 interrupt request.
* @param None
* @retval None
*/
void EXTI0_1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET)
{
/* Toggle LED4 */ //中断处理内容
STM_EVAL_LEDToggle(LED4);
/* Clear the EXTI line 0 pending bit */
EXTI_ClearITPendingBit(EXTI_Line0); //退出前清除中断标志,以便接收下次中断
}
}
打开stm32f0xx.h
WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */
PVD_VDDIO2_IRQn = 1, /*!< PVD and VDDIO2 supply comparator through EXTI Line detect Interrupt */
RTC_IRQn = 2, /*!< RTC through EXTI Line Interrupt */
FLASH_IRQn = 3, /*!< FLASH Interrupt */
RCC_CRS_IRQn = 4, /*!< RCC and CRS Interrupts */
EXTI0_1_IRQn = 5, /*!< EXTI Line 0 and 1 Interrupts */ 在这IRQ号=5
EXTI2_3_IRQn = 6, /*!< EXTI Line 2 and 3 Interrupts