虽然现在工作中主要使用的是51系列单片,看到STM32发展如此快,就买了一个板子开始学习,没有自己想的那么简单,只能下班回来学习,有时一个问题自己得琢磨好几晚上才解决,今晚猛然想,何不在一个论坛把自己遇到的问题写出来,看了一下几个论坛,最终绝地写在这个论坛上,学习STM32已经快半个月了,期间遇到好多问题,今晚就先写一下今晚碰到的问题,想到什么就写什么。
1 对NVIC的理解
CM3支持硬件中断嵌套,分为抢占式优先级和亚优先级,使用规则主要有,抢占优先级高级别的可以打断低级别的,同一级别的抢占优先级同时发生时,亚当优先级高的先发生中断,若是相同,则按硬件排列顺序发生。若是有一个亚优先级正在执行中断,同一级别的其它亚优先级发生时,则先挂起,等此中断执行完再执行!
从库函数中找到优先级分组模式:
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /* 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /* 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /* 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /* 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /* 4 bits for pre-emption priority
0 bits for subpriority */
从中可以看出第一组只有一个级别,16个亚优先级,我可以这样理解,若是分配成这个组里,不能发生嵌套中断,同时发生中断时,亚优先级高的先发生,若有中断执行时,必须等中断执行完才能执行下一个中断。最后一组正好相反,有15个级别,若是执行一个中断,可以最多嵌套15个中断执行一个中断。看下面的例子:
NVIC_InitTypeDef NVIC_InitStructure; //定义中断初始化类型结构体变量
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //配置优先级分组1 2个两个抢占优先级 8个亚优先级
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //开口外部中断0
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//配置0号抢占式优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//亚优先级配置为0号
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
NVIC_Init(&NVIC_InitStructure); //对外部中断0进行初始化配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //开口外部中断5到9
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//配置1号抢占式优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//亚优先级配置为1号
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
NVIC_Init(&NVIC_InitStructure); //对外部中断0进行初始化配置
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn; //ADC1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//配置1号抢占式优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//亚优先级配置为1号
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
NVIC_Init(&NVIC_InitStructure); //对外部中断0进行初始化配置
从上面的配置来看,外部中断0的优先级最高,可以打断ADC和外部5到9的中断,也就说可以嵌套发生,当ADC中断和外部5到9中断同时发生时,它们的抢占优先级别相同,亚优先级别也相同,因为ADC1硬件排在更靠前,则先发生ADC中断,若是两者任何一个中断正在执行,则等此中断执行完,再去执行另一个中断。
今天晚上就先理解到这里,明天晚上继续。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
3 SysTick仔细探究
首先看STM官方芯片资料,上面真正涉及到得很少,其中在系统时钟树有个简单的说明如下:
手册如下说明: RCC通过AHB时钟(HCLK)8分频后作为Cortex系统定时器(SysTick)的外部时钟。通过对SysTick控制与状态寄存器的设置,可选择上述时钟或Cortex(HCLK)时钟作为SysTick时钟。通过这句话,可以看出SysTick时钟的来源,从图上也可以详细的看出SysTick是经过8分频得来的,这样好理解了,我们在手册上再仔细找,很能找到一句话:系统嘀嗒校准值固定为9000,当系统嘀嗒时钟设定为9MHz(HCLK/8的最大值),产生1ms时间基准。简单的说,我们把SysTick设置为9000时,就能产生1ms时间基准,说的明白点就是一个中断信号。计算一下:
系统的晶振是8MHZ,PLL9倍频以后为8MHZ*9=72MHz,然后经过8分频为9MHZ,即给systick分配的时钟9MHz,接下来我们再计算,一个计数周期的时间为1/9000000S, 这样写更容易明白点,我要计时1ms的话,即1/1000s的时间,(1/1000)/(1/9000000)=9000,可以看出我们要计时1ms的话设置为9000是这样得来的。其实上面的公式自己可以推导一下,设系统的时钟频率为SystemFrequency,我们要给滴答定时器设置的值为SystemFrequency / (1/时间基准)。例如1ms的设置72000000 / (1/0.001S)=9000.通过这里我们可以很容易的分配时间。注意设置的时候不要超过24位的最大值0xffffff.
其中在库中有专门的配置函数如下:
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SYSTICK_MAXCOUNT) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SYSTICK_MAXCOUNT) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL = (0x00); /* Load the SysTick Counter Value */
SysTick->CTRL = (1 << SYSTICK_CLKSOURCE) | (1<<SYSTICK_ENABLE) | (1<<SYSTICK_TICKINT); /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
} 看这个函数就很好理解,配置好要基准的时间,就等中断发生吧。
void SysTick_Handler(void)
{
}在中断函数,我们可以划分时间片,不要使CPU空等待.也就是到达你想要的那个时间就执行你想做的动作,主要不超出时间片得时间就行。今晚就先总结到这里,简单的知识写出来容易理解一些,反复来回进度有点慢了。
一周热门 更多>