没写博客的感悟:昨天没有写博客,今天就倒霉了,得写两篇,果然不能偷懒,当天没有做的事,无论如何你都得要做,为了改掉这个拖延的小毛病,给自己定了一条规则,无论多晚,哪怕没有网没有电也得写完每天更新的博客,以此勉励。
今天主要总结和复习三个知识点,NVIC中断优先级管理、串口通信、及串口通信的简单配置实例:
第一部分:
NVIC中断优先级管理:
首先是中断分组,我们知道所用的CM3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。然而STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。STM32有84个中断,包括16个内核中断和68个可屏蔽中断,具有16级可编程的中断优先级。而我所用的STM32F103系列上面,又只有60个可屏蔽中断(在107系列才有68个),而STM系列把中断分为5个组,如下图一所示
图一
这么多大概60个中断如何管理,这是我一开始想到的问题,当然是用寄存器进行管理,有七组寄存器对所有的中断进行管理,中断寄存器分别如下,引用MDK对寄存器组的分类:
typedef struct
{
__IO uint32_t ISER[8]; //中断使能寄存器组:设置为:8个32位寄存器来控制256个中断,由于我用的只有60个故只需设置ISER[0]-ISER[2]即可
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; //中断除能寄存器组:设置和中断使能一样
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; //中断挂起寄存器组:设置和中断使能一样,通过置一把正在执行的中断挂起从而执行同级别或更高级别的中断,写0无效
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; //中断解挂控制寄存器组:设置和中断使能一样作用和挂起寄存器组相反
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; // 中断激活标志位寄存器组:这是一个只读寄存器,如果置一可以知道该位所对应的正在运行的中断,运行完毕由硬件自动清零
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; // 中断优先级控制寄存器组:这是非常重要的一个寄存器,总共有240个8位的寄存器组成,每8位代表一个中断,而每八位只用了其高八位,我所用的103系列只用了0-//67即可,详细的会在下面给出
uint32_t RESERVED5[644];
__O uint32_t STIR; // 软件触发中断寄存器组
} NVIC_Type;
中断优先级控制寄存器组,说这个之前得明白一个概念,优先级概念,STM系列的中断优先级分为两级,抢占优先级和响应优先级。而又得知道两者的区别,其中区别如下:
voidNVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);/
整个系统执行过程中,只设置一次中断分组。
②针对每个中断,设置对应的抢占优先级和响应优先级:
voidNVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
③ 如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
第二部分:串口通信基本原理voidUSART_Init();//串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
voidUSART_Cmd();//使能串口
voidUSART_ITConfig();//使能相关中断
voidUSART_SendData();//发送数据到串口,DR
uint16_tUSART_ReceiveData();//接受数据,从DR读取接受到的数据
FlagStatusUSART_GetFlagStatus();//获取状态标志位
voidUSART_ClearFlag();//清除状态标志位
ITStatusUSART_GetITStatus();//获取中断状态标志位
voidUSART_ClearITPendingBit();//清除中断状态标志位
其中提出一点波特率的计算方式如图5所示:NVIC_Init();
USART_ITConfig();
⑥使能串口:USART_Cmd();
⑦编写中断处理函数:USARTx_IRQHandler();
⑧串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取:
FlagStatusUSART_GetFlagStatus(USART_TypeDef* USARTx,uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
编写得主函数代码如下:
#include "stm32f10x.h"
//串口通信实验1
void my_usart_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructA;
USART_InitTypeDef USART_InitStructA;
NVIC_InitTypeDef NVIC_InitStructA;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//enable GPIOA和USART1 的时钟
//初始化GPIOA,查表可知串口1发送模式下是全双工,GPIO口设置为推挽复用模式
GPIO_InitStructA.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructA.GPIO_Pin=GPIO_Pin_9;
GPIO_InitStructA.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructA);
//初始化GPIOA,查表可知串口1接受模式下是全双工,GPIO口设置为浮空输入模式
GPIO_InitStructA.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructA.GPIO_Pin=GPIO_Pin_10;
GPIO_InitStructA.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructA);
//初始化串口参数
USART_InitStructA.USART_BaudRate=115200;
USART_InitStructA.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructA.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_InitStructA.USART_Parity=USART_Parity_No;
USART_InitStructA.USART_StopBits=USART_StopBits_1;
USART_InitStructA.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1,&USART_InitStructA);
//开启接受中断且初始化NVIC
NVIC_InitStructA.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructA.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructA.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructA.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructA);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//设置串口状态
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void)
{
u8 res;
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE))//由于有可能开启了很多中断故需要判断是否是我们所要的中断函数
{
res=USART_ReceiveData(USART1);//接受来自串口一的数据
USART_SendData(USART1,res);//
}
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
my_usart_Init();
while(1);
//运行以后就一直在主函数等待,当电脑给单片机发送数据时就跳到中断
}
由于我没有JLINK在线调试,故用USB直接下载到单片机进行调试,最后用串口助手可以得到所设想达到的输出:结果如图六
图六
其中白色的发送是先经过PC先发送给单片机,如然后单片机又发送给PC由串口助手在打印得出;