搜档网
当前位置:搜档网 › stm32中断源与事件总结20130710

stm32中断源与事件总结20130710

stm32中断源与事件总结20130710
stm32中断源与事件总结20130710

STM32的NVIC 嵌套向量中断控制器

异常

Cortex-M3处理器和NVIC对所有优先级进行划分和处理。所有的异常处理均在Handle 模式下进行。当出现异常时,处理器的状态被自动保存到栈中;在中断服务子程序结束之后,又会自动从栈中恢复处理器的状态。获取中断向量和状态保存是同时进行的,这提高了进入中断处理的效率。Cortex-M3处理器支持尾链技术,即当发生背靠背中断时,无需保存和恢复状态,而是继续执行。Cortex-M3处理器的一下特性,提高了处理异常的效率并降低了时间的延迟。

◆处理器状态的自动保存和恢复;

◆中断向量表读取与处理器状态保存并行处理;

◆支持尾链技术,当处理背靠背的中断时,不需要在2个终端服务子程序之间进行入栈和出栈操作;

◆可动态重设优先级;

◆NVIC和Cortex-M3处理器和紧密耦合,可尽早处理中断,尤其是晚到的高优先级中断;

◆中断的数目可以配置,1~240;

◆为Handle和Thread模式分别提供独立的栈和访问权限等级;

◆可屏蔽优先级以支持临界区。

一、异常的种类

Cortex-M3处理器将复位、不可屏蔽中断、外部中断、故障都统一为异常,异常有多种类型。故障是指指令执行时由于错误的条件所导致的异常。故障可分为同步故障和一般故障,同步故障是指当指令产生错误时就同时报告错误,而异步故障则是指当指令产生错误时无法保证同时报告错误。下表列出了异常的类型、位置和优先级。位置是指中断向量在中断向量表中的位置,是相对于中断限量表开始处字的偏移。优先级的值越小,优先级越高。

二、中断优先级

在CM3 中,优先级对于异常来说很关键的,它会影响一个异常是否能被响应,以及何时可以响应。优先级的数值越小,则优先级越高。CM3 支持中断嵌套,使得高优先级异常会抢占(preempt)低优先级异常。有3 个系统异常:复位,NMI 以及硬fault ,它们有固定的优先级,并且它们的优先级号是负数,从而高于所有其它异常。所有其它异常的优先级则都是可编程的(但不能编程为负数)。

原则上,CM3 支持3 个固定的高优先级和多达256 级的可编程优先级,并且支持128级抢占(128 的来历请见下文分解——译注)。但是,绝大多数CM3 芯片都会精简设计。以致实际上支持的优先级数会更少,如8 级,16级,32级等。它们在设计时会裁掉表达优先级的几个低端有效位,以达到减少优先级数的目的(可见,不管使用多少位,优先级号是以MSB 对齐的——译注)。

举例来说,如果只使用了3 个位来表达优先级,则优先级配置寄存器的结构会如图7.1所

示:

在图中,[4:0] 没有被实现,所以读它们总是返回零,写它们则忽略写入的值。因此,对于3 个位的情况,我们能够使用的8 个优先级为:0x00 (最高),0x20 ,0x40 ,0x60 ,0x80 ,0xA0,0xC0 以及0xE0 。

通过让优先级以MSB 对齐,可以简化程序的跨器件移植。比如,如果一个程序早先在支持4 位优先级的器件上运行,在移植到只支持 3 位优先级的器件后,其功能不受影响。但若是对齐到LSB,则会使MSB 丢失,导致数值大于7 的低优先级一下子升高了,甚至会反转小于等于7 的高优先级。如,8 号优先级因为损失了MSB ,现在反而变成0 号了!

NVIC 中有一个寄存器是“应用程序中断及复位控制寄存器”(内容见表7.5),它里面有一个位段名为“优先级组”。该位段的值对每一个优先级可配置的异常都有影响——把其优先级分为个位段:MSB 所在的位段(左边的)对应抢占优先级,而LSB 所在的位段(右边的)对应亚优先级。

抢占优先级决定了抢占行为:当系统正在响应某异常L 时,如果来了抢占优先级更高的异常H,则H 可以抢占L。亚优先级则处理“内务”:当抢占优先级相同的异常有不止一个悬起时,就优先响应亚优先级最高的异常。

这种优先级分组规定:亚优先级至少是 1 个位。因此抢占优先级最多是7 个位,造成了最多只有128 级抢占的现象。

但是CM3 允许从比特7 处分组,此时所有的位都表达亚优先级,没有任何位表达抢占优先级,因而所有优先级可编程的异常之间就不会发生抢占——相当于在它们之中除能了CM3 的中断嵌套机制。当然还有凌架于法律之上的三位老大:复位,NMI 和硬fault 。它们无论何时出现,都立即无条件抢占所有优先级可编程的“平民异常”。

在计算抢占优先级和亚优先级的有效位数时,必须先求出下列值:

◆芯片实际使用了多少位来表达优先级

◆优先级组是如何划分的。

二、异常的优先级

在处理器处理异常时,优先级决定了处理器何时以及如何进行异常处理。可以给中断设置软件优先级以及对其进行分组。

优先级NVIC支持通过软件设置的优先级。通过写中断优先级寄存器的PRI_N字段可以设置优先级,范围为0~255。硬件优先级随着中断号的增加而减小,优先级0为最高优先级,255为最低优先级。

通过软件设置的优先级权限高于硬件优先级。例如,如果设置IRQ[0]的优先级为1,IRQ[31]的优先级为0,则IRQ[31]的优先级比IRQ[0]的高。但通过软件设置的优先级对复位、不可屏蔽中断和硬件故障没有影响。

当多个中断具有相同的优先级时,拥有最小中断号的挂起中断优先执行。例如,IRQ[0] 和IRQ[1]的优先级都为1,则IRQ[0]优先执行。

优先级分组。为了更好的对大量的中断进行优先级管理和控制,NVIC支持优先级分组。通过设定应用中断和复位中断控制寄存器的PRIGROUP字段,可以将PRI_N字段分成2个

部分:抢占优先级和次要优先级,如表2所列。抢占优先级可以认为是优先级分组,当多个挂起的异常具有相同的抢占优先级时,次要优先级就起作用。优先级分组和次要优先级共同作用确定了异常的优先级,当两个挂起的异常具有完全相同的优先级时,硬件位置编号低的异常优先级被激活。

Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:

第0组:所有4位用于指定响应优先级

第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级

第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级

第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级

第4组:所有4位用于指定抢占式优先级

可以通过调用STM32的固件库中的函数NVIC_PriorityGroupConfig()选择使用哪种优先级分组方式,这个函数的参数有下列5种:

NVIC_PriorityGroup_0 => 选择第0组

NVIC_PriorityGroup_1 => 选择第1组

NVIC_PriorityGroup_2 => 选择第2组

NVIC_PriorityGroup_3 => 选择第3组

NVIC_PriorityGroup_4 => 选择第4组

二、NVIC与中断控制

向量中断控制器,简称NVIC ,是Cort ex‐M3不可分离的一部分,它与CM3 内核的逻辑紧密耦合,有一部分甚至水乳交融在一起。NVIC 与CM3 内核同声相应,同气相求,相辅相成,里应外合,共同完成对中断的响应。N VIC 的寄存器以存储器映射的方式来访问,除了包含控制寄存器和中断处理的控制逻辑之外,NVIC 还包含了MPU的控制寄存器、SysT ick 定时器以及调试控制。

NVIC 的访问地址是0xE000 _E000 。

每个外部中断都有一个对应的优先级寄存器,每个寄存器占用8 位,但是允许最少只使用最高3 位。4 个相临的优先级寄存器拼成一个32位寄存器。如前所述,根据优先级组设置,优先级可以被分为高低两个位段,分别是抢占优先级和亚优先级。优先级寄存器都可以按字节访问,当然也可以按半字/ 字来访问。有意义的优先级寄存器数目由芯片厂商实现的中断数目决定,优先级配置寄存器的详细信息在附录D 中给出

STM32中断向量表

地址为偏移量,不是绝对地址。NVIC的绝对地址在e000e000

Core_cm3.h

中断嵌套问题

9.具体优先级的确定和嵌套规则。ARM corte x_m3(STM32)规定

a/ 只能高抢先优先级的中断可以打断低抢先优先级的中断服务,构成中断嵌套。

b/ 当2(n)个相同抢先优先级的中断出现,它们之间不能构成中断嵌套,但STM32 首先响应子优先级高的中断。

c/ 当2(n)个相同抢先优先级和相同子优先级的中断出现,STM32 首先响应中断通道所对应的中断向量地址低的那个中断(见ROM0008,表52)。具体一点:

0 号抢先优先级的中断,可以打断任何中断抢先优先级为非0 号的中断;1 号抢先优先级的中断,可以打断任何中断抢先优先级为2、3、4 号的中断;……;构成中断嵌套。如果两个中断的抢先优先级相同,谁先出现,就先响应谁,不构成嵌套。如果一起出现(或挂在那里等待),就看它们2 个谁的子优先级高了,如果子优先级也相同,就看它们的中断向量位置了。

2.中断(EXTI)

外部中断/事件控制器(EXTI)由19个产生事件/中断要求的边沿检测器组成。每个输入线可以独立地配合输入类型和对应的触发事件。每个输入线都可以被独立地屏蔽,由挂起寄存器保持着状态线的中断要求。

EXTI控制器的结构图如图5-1所示,其主要特性如下:

?每个中断/事件都有独立的触发和屏蔽;

?每个中断线都有专用的状态线;

?支持多达19个中断/事件请求;

?检测脉冲宽度低于APB2时钟宽度的外部信号。

要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置2 个触发寄存器,同时在中断屏蔽寄存器的相应位写’1’允许中断请求。当外部中断线上发生了期待的边沿时,将产生一个中断请求,对应的挂起位也随之被置’1’。在挂起寄存器的对应位写’1’,将清除该中断请求。

如果需要产生事件,必须先配置好并使能事件线。根据需要的边沿检测通过设置 2 个触发寄存器,同时在事件屏蔽寄存器的相应位写’1’允许事件请求。当事件线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被置’1’。

通过在软件中断/ 事件寄存器写’1’,也可以通过软件产生中断/ 事件请求。

硬件中断选择

通过下面的过程来配置20个线路做为中断源:

●配置20个中断线的屏蔽位(EXTI_IMR)

●配置所选中断线的触发选择位(EXTI_RTSR 和EXTI_FTSR) ;

●配置对应到外部中断控制器(EXTI) 的NVIC中断通道的使能和屏蔽位,使得20个中断线中的请求可以被正确地响应。

硬件事件选择

通过下面的过程,可以配置20个线路为事件源

●配置20个事件线的屏蔽位(EXTI_EMR)

●配置事件线的触发选择位(EXTI_RTSR 和EXTI_FTSR)

软件中断/事件的选择

20个线路可以被配置成软件中断/ 事件线。下面是产生软件中断的过程:

●配置20个中断/ 事件线屏蔽位(EXTI_IMR, EXTI_EMR)

●设置软件中断寄存器的请求位(EXTI_SWIER)

另外四个EXTI线的连接方式如下:

●EXTI线16连接到PVD输出

●EXTI线17连接到RTC闹钟事件

●EXTI线18连接到USB唤醒事件

●EXTI线19连接到以太网唤醒事件(只适用于互联型产品)

以TIME2为例,分析整个中断过程

a/ 初始化过程

首先要设置寄存器AIRC 中PRIGROUP 的值,规定系统中的抢先优先级和子优先级的个数(在4 个bits 中占用的位数);

设置TIME2 本身的寄存器,允许相应的中断,如允许UIE(TIME2_DIER 的第[0]位)

设置TIME2 中断通道的抢先优先级和子优先级(IP[28] ,在NVIC 寄存器组中)

设置允许TIME2 中断通道。在NVIC 寄存器组的ISER 寄存器中的一位。

b/ 中断响应过程

当TIME2 的UIE 条件成立(更新,上溢或下溢),硬件将TIME2 本身寄存器中UIE 中断标志置位,然后通过TIME2 中断通道向内核申请中断服务。

此时内核硬件将TIME2 中断通道的Pending 标志置位(相当与中断通道标志置位),表示TIME2 有中断申请。

如果当前有中断在处理,TIME2 的中断级别不够高,那么就保持Pending 标志,当然用户可以在软件中通过写ICPR 寄存器中相应的位把本次中断清除掉。

当内核有空,开始响应TIME2 的中断,进入TIME2 的中断服务。此时硬件将IABR 寄存器中相应的标志位置位,表示TIME2 中断正在被处理。同时硬件清除TIME2 的Pending 标志位。

c/ 执行TIME2 的中断服务程序

所有TIME2 的中断事件,都是在一个TIME2 中断服务程序中完成的,所以进入中断程序后,中断程序需要首先判断是哪个TIME2 的具体事件的中断,然后转移到相应的服务代码段去。

注意不要忘了把该具体中断事件的中断标志位清除掉,硬件是不会自动清除TIME2 寄存器中具体的中断标志位的。

如果TIME2 本身的中断事件多于 2 个,那么它们服务的先后次序就由用户编写的中断服务决定了。换句话说,对于TIME2 本身的多个中断的优先级,系统是不能设置的。所以用户在编写服务程序时,应该根据实际的情况和要求,通过软件的方式,将重要的中断优先处理掉。

当然你也可以每次中断服务只处理其中的一个,然后再次进入中断,处理下一个。

d/ 中断返回

内核执行完中断服务后,便进入中断返回过程,在这个过程中需要:

硬件将IABR 寄存器中相应的标志位清另,表示该中断处理完成

如果TIME2 本身还有中断标志位置位,表示TIME2 还有中断在申请,则重新将TIME2的Pending 标志置为1,等待再次进入TIME2 的中断服务。

相关寄存器

1、中断屏蔽寄存器(EXTI_IMB)

2、事件屏蔽寄存器(EXTI_EMR)

3、上升沿触发选择寄存器(EXTI_RTSR)

4、下降沿触发选择寄存器(EXTI_FTSR)

5、软件中断事件寄存器(EXTI_SWIER)

6、挂起寄存器(EXTI_PR)

NVIC的库函数

核心代码分析

键盘中断实验

int main(void)

{

unsigned char a=0,b=0,c=0;

RCC_Configuration(); //系统时钟设置及外设时钟使能NVIC_Configuration();

/*对控制3个LED指示灯的IO口进行了初始化,将3个端口配置为推挽上拉输出,

口线速度为50Mhz。将中断线PC5,PC2,PC3配置为输入模式。

在配置某个口线时,首先应对它所在的端口的时钟进行使能。否则无法配置成功,由于用到了端口B和端口D,C,E,

因此要对这4个端口的时钟进行使能,同时由于用到复用IO口功能用于配置外部中断。因此还要使能AFIO(复用功能IO)时钟。*/

GPIO_Configuration();

while (1)

{

numm(); //键盘扫描程序

if(num==1&&a==0){GPIO_ResetBits(GPIOB, GPIO_Pin_5);a=1;} //K1 按下作处理

else if(num==1&&a==1){GPIO_SetBits(GPIOB, GPIO_Pin_5);a=0;}

if(num==2&&b==0){GPIO_ResetBits(GPIOD, GPIO_Pin_6);b=1;} //K2 按下作处理

else if(num==2&&b==1){GPIO_SetBits(GPIOD, GPIO_Pin_6);b=0;}

if(num==3&&c==0){GPIO_ResetBits(GPIOD, GPIO_Pin_3);c=1;} //K3 按下作处理

else if(num==3&&c==1){GPIO_SetBits(GPIOD, GPIO_Pin_3);c=0;}

}

}

void RCC_Configuration(void){

SystemInit(); //配置了系统时钟,标准函数,配置到72MHZ

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 启用APB2 上的AFIO 寄存器,启动的IO复用功能,可能是板子某些端口存在重映射。如果板子上使用AFIO,必须开启这个选项。库函数中

这个函数可以对特定位置进行重映射

这个实例当中,应该不需要这样做。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC| RCC_APB2Periph_GPIOD| RCC_APB2Periph_GPIOE , ENABLE); } //全部IO的RCC使能

注意配置顺序

RCC_Configuration-> SystemInit();->SetSysClock();->#elif defined SYSCLK_FREQ_72MHz SetSysClockTo72();->这个函数内决定了使用外部的8M晶振。

注意

#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* #define SYSCLK_FREQ_HSE HSE_V ALUE */

#define SYSCLK_FREQ_24MHz 24000000

#else

/* #define SYSCLK_FREQ_HSE HSE_V ALUE */

/* #define SYSCLK_FREQ_24MHz 24000000 */

/* #define SYSCLK_FREQ_36MHz 36000000 */

/* #define SYSCLK_FREQ_48MHz 48000000 */

/* #define SYSCLK_FREQ_56MHz 56000000 */

#define SYSCLK_FREQ_72MHz 72000000

如果是低配CPU,那么就定义为24MHZ

如果是高配的,那么可以定义为24,36,48,56,72.默认是72.可以通过注释的方式,变更系统的频率。

如果要更改系统外设的频率,那么需要更改相应的SetSysClockTo72()之类的函数

void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;

/* Configure one bit for preemption priority */

/* 优先级组说明了抢占优先级所用的位数,和子优先级所用的位数在这里是1,7 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

设置为group1,也即是有2级抢占性优先级,每个抢占性中断内有8个子优先级

/* Enable the EXTI9-5 Interrupt */

NVIC_InitStructure.NVIC_IRQChannel =EXTI9_5_IRQn; //外部中断9-5 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //外部中断2 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //外部中断3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级0

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能

NVIC_Init(&NVIC_InitStructure);

外部中断0,1,2,3,4单独一个中断标志,一个口。而中断5-9共享一个,10-15共享一个

//用于配置AFIO外部中断配置寄存器AFIO_EXTICR1,用于选择EXTI2外部中断的输入源是PC5。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5); //外部中断配置AFIO--ETXI9-5

//用于配置AFIO外部中断配置寄存器AFIO_EXTICR1,用于选择EXTI2外部中断的输入

源是PC2。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2); //外部中断配置AFIO--ETXI2

//用于配置AFIO外部中断配置寄存器AFIO_EXTICR1,用于选择EXTI2外部中断的输入源是PC3。

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3); //外部中断配置AFIO--ETXI3

EXTI_InitStructure.EXTI_Line = EXTI_Line5; //PC5 作为键盘K1 检测状态

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

EXTI_InitStructure.EXTI_Line = EXTI_Line2; //PC2 作为键盘K2 检测状态

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

EXTI_InitStructure.EXTI_Line = EXTI_Line3; //PC3 作为键盘K3 检测状态

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

}

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)

{

uint32_t tmp = 0x00;

/* Check the parameters */

assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));

assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));

tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));

AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;

AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));

}

中断与事件的理解

这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚进入,经过编号2的边沿检测电路,通过编号3的或门进入中断挂起请求寄存器,最后经过编号4的与门输出到NVIC中断检测电路,这个边沿检测电路受上升沿或下降沿选择寄存器控制,用户可以使用这两个寄存器控制需要哪一个边沿产生中断,因为选择上升沿或下降沿是分别受2个平行的寄存器控制,所以用户可以同时选择上升沿或下降沿,而如果只有一个寄存器控制,那么只能选择一个边沿了.

按下来是编号3的或门,这个或门的另一个输入是软件中断/事件寄存器,从这里可以看出,软件可以优先于外部信号请求一个中断或事件,即当软件中断/事件寄存器的对应位为"1"时,不管外部信号如何,编号3的或门都会输出有效信号.

一个中断或事件请求信号经过编号3的或门后,进入挂起请求寄存器,到此之前,中断和事件的信号传输通路都是一致的,也就是说,挂起请求寄存器中记录了外部信号的电平变化.

外部请求信号最后经过编号4的与门,向NVIC中断控制器发出一个中断请求,如果中断屏蔽寄存器的对应位为"0",则该请求信号不能传输到与门的另一端,实现了中断的屏蔽.

明白了外部中断的请求机制,就很容易理解事件的请求机制了.图中红色虚线箭头,标出了外部事件信号的传输路径,外部请求信号经过编号3的或门后,进入编号5的与门,这个与门的作用与编号4的与门类似,用于引入事件屏蔽寄存器的控制;最后脉冲发生器的一个跳变的信号转变为一个单脉冲,输出到芯片中的其它功能模块.从这张图上我们也可以知道,从外部激励信号来看,中断和事件的产生源都可以是一样的.之所以分成2个部分,由于中断是需要CPU参与的,需要软件的中断服务函数才能完成中断后产生的结果;但是事件,是靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,比如引起DMA操作,AD转换等;

简单举例:外部I/O触发AD转换,来测量外部物品的重量;如果使用传统的中断通道,需要I/O触发产生外部中断,外部中断服务程序启动AD转换,AD转换完成中断服务程序提交最后结果;要是使用事件通道,I/O触发产生事件,然后联动触发AD转换,AD转换完成中断服务程序提交最后结果;相比之下,后者不要软件参与AD触发,并且响应速度也更块;要是使用事

件触发DMA操作,就完全不用软件参与就可以完成某些联动任务了。

总结:

可以这样简单的认为,事件机制提供了一个完全有硬件自动完成的触发到产生结果的通道,不要软件的参与,降低了CPU的负荷,节省了中断资源,提高了响应速度(硬件总快于软件),是利用硬件来提升CPU芯片处理事件能力的一个有效方法;

关于STM32串口空闲中断IDEL的问题

关于STM32串口空闲中断IDEL的问题 1.空闲中断是接受数据后出现一个byte 的高电平(空闲)状态,就会触发空闲 中断.并不是空闲就会一直中断,准确的说应该是上升沿(停止位)后一个 byte,如果一直是低电平是不会触发空闲中断的(会触发break 中断)。 2.关于第二点有要铺垫的三个情况,datasheet 中”当一空闲帧被检测到时,其处 理步骤和接收到普通数据帧一样,但如果IDLEIE 位被设置将产生一个中断”“空 闲符号被视为完全由'1'组成的一个完整的数据帧,后面跟着包含了数 据的下一帧的开始位'1'的位数也包括了停止位的位数”空闲符号的 配图后面跟这一个低电平.有人理解为只有收到下一个数据的起始位才会触发中 断,这样理解是不对的,应该是数据后有空闲了一帧就会触发. 3.清中断的方式感觉奇怪,使用函数USART_ClearITPendingBit( USART1, USART_IT_IDLE )清除不了中断的.我用的是3.5 的库,查看函数说明,里面的 @param 参数并没有IDLE,后面的@note 中,这样说:”PE(Parity error),FE(Framing error),NE(Noise error),ORE(OverRun error) and IDLE(Idle line detected) pending bits are cleared by software sequence: a read operation to USART_SR register (USART_GetITStatus()) followed by a read operation to USART_DR register (USART_ReceiveData()).”我是通过语句”USART1->DR;”来清除IDLE 中断的. 现在有很多数据处理都要用到不定长数据,而单片机串口的RXNE 中断一次 只能接收一个字节的数据,没有缓冲区,无法接收一帧多个数据,现提供两种 利用串口IDLE 空闲中断的方式接收一帧数据,方法如下: 方法1:实现思路:采用STM32F103 的串口1,并配置成空闲中断IDLE 模 式且使能DMA 接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成 之后,当外部给单片机发送数据的时候,假设这帧数据长度是200 个字节,那

TMS320F28335外部中断总结

TMS320F28335外部中断总结 作者:Free 文章来源:Free 点击数:93 更新时间:2010-8-26 在这里我们要十分清楚DSP的中断系统。C28XX一共有16个中断源,其中有2个不可屏蔽的中断RESET和NMI、定时器1和定时器2分别使用中断13 和14。这样还有12个中断都直接连接到外设中断扩展模块PIE上。说的简单一点就是PIE 通过12根线与28335核的12个中断线相连。而PIE的另外 一侧有12*8根线分别连接到外设,如AD、SPI、EXINT等等。这样PIE共管理12*8=96个外部中断。这12组大中断由28335核的中断寄存器IER来控 制,即IER确定每个中断到底属于哪一组大中断(如IER |= M_INT12;说明我们要用第12组的中断,但是第12组里面的什么中断CPU并不知道需 要再由PIEIER确定)。接下来再由PIE模块中的寄存器PIEIER中的低8确定该中断是这一组的第几个中断,这些配置都要告诉CPU(我们不难想 象到PIEIER共有12总即从PIEIER1-PIEIER12)。另外,PIE模块还有中断标志寄存器PIEIFR,同样它的低8位是来自外部中断的8个标志位,同 样CPU的IFR寄存器是中断组的标志寄存器。由此看来,CPU的所有中断寄存器控制12组的中断,PIE的所有中断寄存器控制每组内8个的中断。 除此之外,我们用到哪一个外部中断,相应的还有外部中断的寄存器,需要注意的就是外部中断的标志要自己通过软件来清零。而PIE和CPU的 中断标志寄存器由硬件来清零。 EALLOW; // This is needed to write to EALLOW protected registers PieVectTable.XINT2 = &ISRExint; //告诉中断入口地址 EDIS; // This is needed to disable write to EALLOW protected registers PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block使能PIE PieCtrlRegs.PIEIER1.bit.INTx5= 1; //使能第一组中的中断5 IER |= M_INT1; // Enable CPU 第一组中断

最新stm32学习之串口usart复习进程

STM32学习之串口USART STM32 的串口是相当丰富的。最多可提供5路串口,有分数波特率发生器、支持单线光通信和半双工单线通讯、支持LIN、智能卡协议和IrDA SIR ENDEC 规范(仅串口3 支持)、具有DMA 等。串口最基本的设置,就是波特率的设置。STM32 的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应IO口的模式,然后配置一下波特率,数据位长度,奇偶校验位等信息,就可以使用了。 1、串口时钟使能。串口作为STM32 的一个外设,其时钟由外设始终使能寄存器控制,这里我们使用的串口1是在APB2ENR 寄存器的第14 位。除了串口1 的时钟使能在APB2ENR寄存器,其他串口的时钟使能位都在APB1ENR。 1、串口的作用:用在STM32板子和PC机通信的。我们调试的时候,无法知道是否正确,就可以用STM32的cpu,给串口输出一些信息给PC,我们通过屏幕(实际上是终端串口软件),可以看到这些信息,从而知道当前程序的错误可能出现的位置。当然,也可以在PC的键盘敲打命令,让串口帮传递给STM32板子,来执行这些命令。 2、串口的工作模式一般有两种方式:查询和中断 (1)查询:串口程序不断地循环查询,看看当前有没有数据要它传,如果有,就帮助传送(可以从PC到STM32板子,也可以从STM32 板子到PC)。 (2)中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着要它帮助传输数据——它就马上进行数据的传送。同样,可以从PC到STM32板子,也可以从STM32板子到PC 。 步骤一从硬件开始学习。大家先打开芯达STM32开发板附带的原理图。找到串口部分。笔者把它截图如下。我们发现,串口模块的电路是这样的:STM32的CPU引脚,通过两个PA端口的引脚PA10和PA9(此两个引脚复用USART),连接到一个SP3232芯片,或者MAX232芯片。然后再连接到DB9串口座上。由于232芯片可以允许走两路信号,因此,我们扩展了一个串口COM2,请注意,如无特别说明,我们都将使用COM1。

STM32串口中断接收方式详细比较

本例程通过PC机的串口调试助手将数据发送至STM32,接收数据后将所接收的数据又发送至PC机,具体下面详谈。。。 实例一: void USART1_IRQHandler(u8 GetData) { u8 BackData; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志. GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR; USART1_SendByte(GetData); //发送数据 GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED闪烁,接收成功发送完成 delay(1000); GPIO_ResetBits(GPIOE, GPIO_Pin_8 ); } } 这是最基本的,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main函数里无其他要处理的。 优点:简单,适合很少量数据传输。 缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失。 实例二: void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2); Uart2_Rx_Num++; } if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) //判断最后接收的数据是否为设定值,确定数据正确性 Uart2_Sta=1; if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出 { USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR USART_ReceiveData(USART2); //读DR } } if( Uart2_Sta ) { for(Uart2_Tx_Num=0;Uart2_Tx_Num < Uart2_Rx_Num;Uart2_Tx_Num++)

STM32 无中断串口代码

STM32 无中断串口代码2010-05-14 16:09 串口,是我们日常使用最多的一部分,刚开始做电子工程师的,基本都是从这个开始的,下面的代码是我使用STM32库编写的串口输出和读取的代码。 1、串口初始化函数:void USART_Ini(USART_TypeDef* USARTx,u16 buad) 2、串口中断开启和关闭:USART_IT(USART_TypeDef* USARTx,FunctionalState NewState) 3、串口接收:u16 Getch(USART_TypeDef* USARTx) 4、串口单个字符输出:void Putch(USART_TypeDef* USARTx,u16 ch) 5、串口输出字符串:void PutStr(USART_TypeDef* USARTx,u16 *SendBuf,u16 Length) #include "stm32f10x_lib.h" u16 RecDateBuffer[100]; u16 RecLen; u8 SendDateBuffer[100]; /************************************************************* ****************** * Function Name : Uart_Ini * Description : 串口初始化 * Input : * Output : None * Return : ************************************************************** *****************/ void USART_Ini(USART_TypeDef* USARTx,u16 buad) { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockIni; GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

stm32 串口中断总结

本文以USART1为例,叙述串口中断的编程过程。 1、先来讲述一下在应用串口中断时涉及到的一些库文件。 首先对于STM32外设库文件的应用编程,misc.c和stm32f10x_rcc.c是肯定要添加到。 接下来就是我们要用到的相关外设了。毫无疑问,串口文件stm32f10x_usart.c是必须的。串口通信是对通用GPIO端口引脚的功能复用,所以还需要stm32f10x_gpio.c文件。另外,因为有中断的产生,所以中断文件stm32f10x_it.c也是必要的,当然这个文件一般和main.c 放在一个文件夹下(一般习惯为User文件夹),因为我们的中断响应函数是要在里面自己编写的。 当然还有其他的基本必须文件如系统配置文件等在这地方就不说了,这个是创建一个工程应该知道的。 2、初始化 对于串口通信的初始化,不仅仅只是对串口的初始化(这个地方是比较烦人的,不像别的芯片那样简洁明了)。 ●?首先时钟使能配置。STM32内部的时钟有很多,感兴趣的自己看看参考手册。此处 以USART1为例说明。有USART1时钟、GPIOA时钟、GPIO复用(AFIO)时钟。由于 此处USART1和GPIOA、AFIO均在APB2上,所以可以一次配置完成。如下: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB 2Periph_USART1 ,ENABLE); ●?其次中断配置。主要有优先级组设定、USART1中断使能、该中断的优先级,中断初 始化。程序如下: void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//选择分组方式0 /* 使能 USART1中断 */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } ●?然后GPIO复用功能配置。一般情况下我们使用原始的外设和GPIO端口引脚的映射 关系,如果要改变其映射的话,请另外查看参考手册上关于GPIO重映射部分。对 于GPIO的复用,其引脚的输入与输出模式都有要求,在参考手册上有详细说明。 void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 配置 USART1 Rx 作为浮空输入 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USARTy_GPIO, &GPIO_InitStructure); /* 配置 USART1 Tx 作为推挽输出 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

STM32个人总结

基础入门编 1.搭建开发环境 详情看光盘资料,主要是软件安装和设置。 2.新建工程 可以直接用模板,了解每个文件的含义,会使用chm帮助。 3.STM32库 库的含义。 4.GPIO流水灯 认识RCC,GPIO的各种模式,寄存器的种类和作用。 5.POLLING按键 主要介绍了各种模式,实验通过不断读取GPIO的状态以达到判断按键的目的。 6.EXTI按键 使用了GPIO的EXTI中断来判断按键,记住EXTI要开AFIO(重映射也要开),另外SYSTICK不归NVIC管。注意NVIC_IRQChannelSubPriority(),最多可以判断16种优先级,即16种中断,同一个中断入口的引脚引发的中断也算是同一种中断,同种种中断不能相互嵌套。(响应优先级是在抢占优先级相同时,同时发生才有用,其中一个发生后无用)。 7.SYSTICK 关键是SYSTICK的初始化函数,了解那几个寄存器的作用和特殊的宏定义(就是选择自己想选择的位),根据配置可以延时不同的时间,详情看代码。 8.串口通信 开启相应RCC,做好Iint,配置好中断(可选,主要用于接收),然后弄好fputc(),可以直接用printf()直接输出。 9.DMA 不经CPU处理直接相互传输,开启相应的DMA,配置好from..to..,字节大小等,用cmd 命令后可以开启传输。 10.ADC(DMA) 主要就是初始化好ADC,什么通道模式之类的,详情看代码,由于使用了DMA模式,要配置好DMA,有ADC_DMACmd()开始传输。 11..FSMC显示英文 用FSMC直接写入液晶的控制芯片的显存,注意使用的是16位的颜色,线的接法要注意(RGB为5:6:5)。 由于用的是模拟的方法,输入数据时用的都是宏,该地址线用来作为C/D,16位是往前移了一位的,因此要乘以2. 值得注意的是开窗的显示手法,在显示字符前先“开”一个窗,当一行数据写完时,自动换到下一行继续写。 在写数据的函数那里可以更换字的背景色,也可以修改该函数的.h的BACKGROUND 的宏定义。 FSMC的初始化暂时不清楚,应该是关于NOR FLASH的。控制代码是配好的,具体的设置看参考文档(有关定位坐标和扫描方式都与此有关)。 (NOR-FLASH 有4个bank,NE[3:0],区分不同的bank,实验用NE1;DataAddress_Mux 数据域地址线复用;8位地址线25:0->24:0 16位地址线25:1->24:0,宏定义是16位的地址线,对应的机内地址*2左移1位) 12.IIC-EEPROM

STM32 Uart串口中断响应、发送接收详细程序

程序实现功能:可以直接接收USART1的数据,并通过串口调试输出显示 #include"stm32f10x_lib.h" void NVIC_Configuration(void); void RCC_Configuration(void); void GPIO_Configuration(void); ErrorStatus HSEStartUpStatus; USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; int main() { #ifdef DEBUG debug #endif RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); /*串口传输速率的大小必须与RCC所设定的时钟相对应起来*/ USART_https://www.sodocs.net/doc/3c9724057.html,ART_BaudRate = 9600; //设置USART的传输速率/*设定数据的接收发送模式*/ USART_https://www.sodocs.net/doc/3c9724057.html,ART_WordLength = USART_WordLength_8b;//在一帧中传输或接受8位数据位 USART_https://www.sodocs.net/doc/3c9724057.html,ART_StopBits = USART_StopBits_1; //定义在帧的结尾传输一个停止位 USART_https://www.sodocs.net/doc/3c9724057.html,ART_Parity = USART_Parity_No; //奇偶失能 USART_https://www.sodocs.net/doc/3c9724057.html,ART_HardwareFlowControl = USART_HardwareFlowControl_None; //指定硬件流控制模式RTS和CTS使能 USART_https://www.sodocs.net/doc/3c9724057.html,ART_Mode = USART_Mode_Rx | USART_Mode_Tx; //指定使能或失能发送和接受模式Tx发送使能和Rx接收使能 USART_Clock https://www.sodocs.net/doc/3c9724057.html,ART_Clock = USART_Clock_Disable; //提升USART时钟时使能还是失能,钟低电平活动 USART_https://www.sodocs.net/doc/3c9724057.html,ART_CPOL = USART_CPOL_Low; //指定SLCK引脚上时钟的极性 USART_https://www.sodocs.net/doc/3c9724057.html,ART_CPHA = USART_CPHA_2Edge; //时钟第二个边缘进行数据捕获 USART_https://www.sodocs.net/doc/3c9724057.html,ART_LastBit = USART_LastBit_Disable; //在SCLK引脚上输出最后发送的那个数据字的脉冲不从SCLK输出 USART_ClockInit(USART1, &USART_ClockInitStructure); USART_Init(USART1, &USART_InitStructure); /*输入输出的中断使能*/ // USART_ITConfig(USART1, USART_IT_TXE, ENABLE); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

STM32串口中断接收方式详细比较

串口中断接收方式详细比较 串口调试,以前也调过,只是没这么深入的琢磨过,最近又在弄,感觉串口很基本,也很有学问,要是出现BUG可能导致系统奔溃。。。现在贴出来,欢迎拍砖指正!!! 本例程通过PC机的串口调试助手将数据发送至STM32,STM32通过SP3232芯片采用中断接收方式完成,然后接收数据后将所接收的数据又发送至PC机,具体下面详谈。。。 实例一: void USART1_IRQHandler(u8 GetData) { u8 BackData; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志. GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR; USART1_SendByte(GetData); //发送数据 GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED闪烁,接收成功发送完成 delay(1000); GPIO_ResetBits(GPIOE, GPIO_Pin_8 ); } } 这是最基本的,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main 函数里无其他要处理的。 优点:简单,适合很少量数据传输。 缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失。 实例二: void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2); Uart2_Rx_Num++; } if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) //判断最后接收的数据是否为设定值,确定数据正确性 Uart2_Sta=1; if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出

stm32学习总结

学习总结 单片机学习经历总结 自从大二寒假接受了一次初始培训开始,我便开始了单片机的学习,一开始借了一块 MSP430G2553的板子,于是便从MSP开始学习单片机。一开始的我对于单片机一窍不通,只能对照着数据手册学习,逐渐开始了解什么是IO口,中断,定时器,AD转换等。开学来了以后接受了四次培训,期间又重新认识这些模块并在学长指导下开始写了一些程序作为练习。后续的学习中我在串口通讯这里遇到了很大阻碍,不太能理解其中的含义,网上的解释又不太看得懂,便找了一些STM32的视频来学习串口,期间发现51和MSP已经不是主流的板子了,现在的厂商更多的是用STM32这样的板子,于是后来的学习重心开始放到了STM32上,因为有了前面的基础,这次从头的学习就更加容易理解STM32的原理与使用了。 MSP430G2553一些模块的总结 (一).IO口模块, 1.我们实用的MSP430G2553有两组IO口,是P1和P 2. 2.IO口的寄存器有:方向选择寄存器PxDIR,输出寄存器PxOUT,输入寄存器PxIN,IO口内部上拉或下拉电阻使能寄存器PxREN, IO口功能选择寄存器PxSEL和PxSEL2,IO口中断使能寄存器PxIE,中断沿选择寄存器PxIES,IO口中断标志寄存器PxIFG。 3.所有的IO都带有中断,其中所有的P1口公用一个中断向量,所有的P2口公用一个中断向量。所以在使用中断时,当进入中断后,还要判断到底是哪一个IO口产生的中断,判断方法可以是判断各个IO口的电平。 4.中断标志PxIFG需要软件清除,也可以用软件置位,从而用软件触发一个中断。 5.PxOUT:如果引脚选择了内部的上拉或下拉电阻使能,则PxOUT设定电阻是上拉还是下拉,0:下拉,1:上拉 (二).时钟系统 1.MSP430的时钟源有: (1).外接低频晶振LFXT1CLK:低频模式32768Hz,高频模式450KHz~8MHz (2).外接高速晶振XT2CLK:8MHz; (3).内部数字控制振荡器DCO: (4).超低功耗低频振荡器VLO: 2.时钟模块:430的时钟模块有MCLK SMCLK ACLK : (1).主系统时钟MCLK:提供给MSP430的CPU时钟。可以来自LFXT1CLK XT2CLK DCO VLO 可选,默认为DCO。

STM32串口典型配置

usart.h : 头文件 /*------------------------------------------------------------------------------------------------------------------*/ #ifndef __USART_H #define __USART_H /* Include -------------------------------------------------------------------*/ #include "stm32f10x.h" #include #include //#include /* Define & Typedef ----------------------------------------------------------*/ /* Macro Switch ---------------------------------------------*/ /*注:以下宏供移植时选择和修改*/ #define USE_RS485 2 //使用RS485 #define USE_USART1 //使用串口1 #define USE_USART2 //使用串口2 #define USE_USART3 //使用串口3 //#define USE_UART4 //使用串口4 //#define USE_UART5 //使用串口5 #define MAX_LEN 256 //打印函数字符串输入最大字节数 #define PUTX fputc //fputc重定向函数 #ifdef USE_RS485 #define RS485 0 #define RS232 1 #define RS24_CONFIG RS24_Configration //RS485-232选择控制端口配置函数 #define RSCHOOSEFLAG SeM.Bit.RSChooseFlag //RS485-232选择标志 #define RS485_T GPIO_SetBits(GPIOA,GPIO_Pin_1) //RS485进入发送状态 #define RS485_R GPIO_ResetBits(GPIOA,GPIO_Pin_1) //RS485进入接收状态

STM32 串口简介

串口作为MCU的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。STM32的串口资源相当丰富的,功能也相当强劲。ALIENTEK战舰STM32开发板所使用的STM32F103ZET6最多可提供5路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持LIN、支持调制解调器操作、智能卡协议和IrDASIRENDEC规范、具有DMA等。用过单片机的人肯定都接触过串口,设置串口无非就是设置波特率、数据位、停止位、奇偶校验位。发送接收也就三种基本方式,轮询、中断和DMA。STM32F10x 的USART 模块也不过如此。所以我重点讲讲我在调试代码时犯得各种错误,那些很容易得到的代码就不详细的讲解了。 串口设置的一般步骤可以总结为如下几个步骤: 1)串口时钟使能,GPIO时钟使能 2)串口复位 3)GPIO端口模式设置 4)串口参数初始化 5)开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤) 6)使能串口 7)编写中断处理函数 与串口基本配置直接相关的几个固件库函数。这些函数和定义主要分布在 stm32f10x_usart.h和stm32f10x_usart.c文件中。 1.串口时钟使能。串口是挂载在APB2下面的外设,所以使能函数为: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1); 2.串口复位。当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是在函数USART_DeInit()中完成: void USART_DeInit(USART_TypeDef*USARTx);//串口复位 比如我们要复位串口1,方法为: USART_DeInit(USART1);//复位串口1 3:GPIO端口设置,首先要是能gpio时钟,然后将用到的串口占用的io口设置一下属性。 4.串口参数初始化。串口初始化是通过USART_Init()函数实现的, void USART_Init(USART_TypeDef*USARTx,USART_InitTypeDef*USART_InitStruct); 这个函数的第一个入口参数是指定初始化的串口标号,这里选择USART1。

STM32串口1中断实验

串口1中断实验 一、实验要求 开发板加电后,先向串口输出一串测试数据,然后在PC端的串口助手类软件上输入结束符为0x0d 0x0a的一串数据,发送到开发板,开发板接收到该字符串后将该字串回传给PC端串口助手软件,传送和接收过程中LED灯闪烁。 二、硬件电路设计 如下图所示,只需要将开发板配套的RS232串口线连接开发板9针串口到PC的串口上,如果电脑上没有串口,可以用USB转串口设备取代标准串口。 三、软件设计思路 根据任务要求,程序内容主要包括: 1. 初始化串口1,使能串口接收中断,通过串口输出相关信息到PC 2. 通过串口中断服务程序检测串口输入信息 3. 将收到的字符发送回PC,然后回到步骤2继续等待 四、程序分析 1.工程结构: 整个工程包含4类源文件,把它们安排在4个组当中:

1)RVMDK组: 仅包含一个启动用汇编源文件startup_stm32f10x_hd.s 。由于奋斗板采用STM32F103大存储器芯片(512k片上FLASH),因此采用STM32标准库中自带的大存储器芯片启动代码.这个文件已经配置好了初始状态,以及中断向量表,可以直接在工程里使用。 如果你在以后的应用中采用了中存储器或者小存储器的STM32芯片,可以将启动代码替换为startup_stm32f10x_md.s (中容量)或者 startup_stm32f10x_ld.s(小容量)。 2)StdPeriph_Driver组: stm32f10x_gpio.c:ST公司的标准库,包含了关于对通用IO口设置的函数。 stm32f10x_rcc.c :ST公司的标准库,包含了关于对系统时钟设置的函数。 stm32f10x_USART.c:ST公司的标准库,包含了关于对USART设置的函数。 Misc.c:ST公司的标准库,包含了关于中断设置的函数。 3)CMSYS组: 是关于整个Cortex-M3平台的系统函数及定义,由ARM公司给出。 4)USER组: main.c:例程的主函数。 stm32f10x_it.c:中断服务函数,此程序只需要增加串口1中断的代码。 2.编译与链接: 编译工程,完成后会提示如下:

STM32使用DMA加串口空闲中断接收数据

STM32使用DMA加串口空闲中断接收数据 STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道数据接收完毕了呢?如果接收的数据长度固定,那就好办,直接设置DMA的接收数据个数就行了。但是如果长度不固定了,那应该怎么办了? 这个时候,就要用到STM32在串口中提供的另一个好用的东西了,就是串口空闲中断。在STM32的串口控制器中,设置了有串口空闲中断,即如果串口空闲,又开启了串口空闲中断的话,就触发串口空闲中断,然后程序就会跳到串口中断去执行。有了这个,是不是可以判断什么时候串口数据接收完毕了呢?因为串口数据接收完毕后,串口总线肯定是会空闲的嘛,那这个中断肯定是会触发的了。 还有一个问题,这串口空闲中断是只要串口空闲就会产生吗?其实不是的,串口空闲中断要触发的话,是要RXNE位被置位后,串口总线空闲才会触发的。所以我们不用担心,串口数据发送完毕后,会不会触发串口空闲中断了。

下面用代码来说明。 1、配置串口。包括设置串口的引脚配置,串口的配置,串口中断的配置,串口的 接收DMA的配置 void USART_init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //开启时钟 RCC_APB2PeriphClockCmd(USART_RCC,ENABLE); //配置TX端口 GPIO_InitStructure.GPIO_Pin = GPIO_USART_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure); //配置RX端口

stm32串口接收字符串经验

stm32串口接收字符串经验 https://www.sodocs.net/doc/3c9724057.html,/jishu_578041_1_1.html2016 分享一个stm32的串口就收字符串以十六进制数解析的程序。好多朋友在用stm32写串口接收的时候说用串口发送数据的时候有丢失的现象,或者发送的数据与接收的数据不一样,比如发送01 串口接收到的是40。还有好多好多的不明现象。今天就和大家讨论一下这些问题是怎么出现的。 在调试串口通信的时候首先要确定硬件是好用的,大家应该都用的是开发板所以硬件部分应该是没问题的。如果是最小系统的话要缺定外接串口模块是不是好的也就是rs3232,如果串口不好使,程序在对也是没用的,再有就是关于电平的问题,在这里说几个芯片就是rs3232芯片和ch340芯片这两个芯片大家都很熟悉了专业性的知识咱就不复i述了,为什么要说这两个芯片呢。因为有的童鞋的板子上没有板载 rs3232的芯片,所以直接将九针串口线的的2、3、5引脚直接接到单片机上了,所以出现可上述发送01收到的是40的情况,这种接是错误的要将串口线接到rs3232的串口上才能开始调试。硬件部分就这些,注意一下就行,下面说说软件部分的在写串口程序是首先要配置串口的初始化 我直接贴出程序再说,#include "pbdata.h"uint8_t TxBuffer1[] = "USART Interrupt Example: This isUSART1 DEMO";

uint8_t RxBuffer1[],rec_f,tx_flag;volatile uint8_t TxCounter1 = 0x00;volatile uint8_t RxCounter1 = 0x00; uint32_t Rec_Len;int main(void){ u8 a=0; RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); USART_Config(USART1); while(1) { if(rec_f==1) { rec_f=0; USART_OUT(USART1,&TxBuffer1[0]); if(a==0){GPIO_SetBits(GPIOA, GPIO_Pin_2); a=1;} else{GPIO_ResetBits(GPIOA, GPIO_Pin_2);a=0; } } }}这是主函数部分,在主函数中只有几个函数的初始化,还有就是定义的数组和标志位。在一般的串口历程中大家会看到的就是定义一个缓冲区,将接收到的串口数据通过串口中断存放到缓冲区中然后在发送到串口中,但是在接收字符串的时候就要用到逐位发送,新手自己有些不了程序,所以只能一直处于蒙着的状态。其实个人感觉整点原子的程序写的真的挺好的,建议新手开始学习的时候看他的程序,有的人就是不喜欢他写程序的风格,这个因人而异,在这里只是建议一下。原子的串口就给出了字符串就收的历程,但是用

STM32的串口中断配置

STM32的串口中断配置,也是很简单的. 首先是配置UART的GPIO口 /****************************************************************************** * * Name : UART1_GPIO_Configuration * Deion : Configures the uart1 GPIO ports. * Input : None * Output : None * Return : None ******************************************************************************* / void UART1_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; // Configure USART1_Tx as alternate push-pull GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure USART1_Rx as input floating GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); } 然后是配置串口参数 /****************************************************************************** * * Name : UART1_Configuration * Deion : Configures the uart1 * Input : None * Output : None * Return : None ******************************************************************************* / void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; Uart1_GPIO_Configuration(); USART_https://www.sodocs.net/doc/3c9724057.html,ART_Clock = USART_Clock_Disable; USART_https://www.sodocs.net/doc/3c9724057.html,ART_CPOL = USART_CPOL_Low; USART_https://www.sodocs.net/doc/3c9724057.html,ART_CPHA = USART_CPHA_2Edge;

STM32串口初始化

#include"stm32f10x.h" void USART_Config(void) { USART_InitTypeDef USART_InitStructure; USART_https://www.sodocs.net/doc/3c9724057.html,ART_BaudRate = 9600; //波特率为9600Hz USART_https://www.sodocs.net/doc/3c9724057.html,ART_WordLength = USART_WordLength_8b; //8位数据 USART_https://www.sodocs.net/doc/3c9724057.html,ART_StopBits = USART_StopBits_1; //在帧结尾传输1 个停止位 USART_https://www.sodocs.net/doc/3c9724057.html,ART_Parity = USART_Parity_No; //奇偶失能 USART_https://www.sodocs.net/doc/3c9724057.html,ART_HardwareFlowControl =USART_HardwareFlowControl_None; //硬件流控制失能 USART_https://www.sodocs.net/doc/3c9724057.html,ART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送使能,接收使能 USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //USART_ITConfig:使能或者失能指定的USART中断USART_IT_RXNE, ENABLE:接收中断 USART_Cmd(USART1, ENABLE); //使能USART 外设 USART_ClearFlag(USART1,USART_FLAG_TC); //清除USARTx 的待处理标志位USART_FLAG_TC:发送完成标志位 }

相关主题