您现在的位置: 主页 > 嵌入式软件 > C/C++ > keilc > 串口通信深度剖析三
本文所属标签:
为本文创立个标签吧:

串口通信深度剖析三

来源:网络整理 网络用户发布,如有版权联系网管删除 2018-07-11 

串口通信深度剖析三



在STM32中,我们经常需要用串口接收数据,除了串口用于代码调试printf基础功能之外,我们更多需要使用串口中断来接收数据,但是如此的话频繁进入串口中断,然后处理,效率还是太低,老板(CPU)也不高兴,于是召集各片内外设召开了技术讨论会


DMA:可以使用我来接收串口数据,比如使用USART1的话利用DMA2就可以


老板:比较关键的一点就是不知道何时数据接收完毕,因为将DMA接收数据长度不固定了,那应该怎么办呢?


正在大家冥思苦想的时候,STM32的串口站起来了,生气的说到:

看来你们对我的认识还是不够啊,我还支持串口空闲中断呢,你们只需要对我进行简单的串口空闲中断配置,那么当接受到数据以后,首次进入空闲,我就会产生空闲中断,然后程序就会跳到串口中断服务函数中去




大伙一听,好像是这么个理儿,老板也很高兴了,确定这种方案之后吩咐大家开始进行STM32串口空闲中断不定长数据接收配置,结果如下:

nvic.h:

 1#ifndef__NVIC_H
2#define__NVIC_H
3
4#include"stm32f4xx.h"
5
6voidNVIC_Priority_Init(void);//为所有用到的中断配置抢占优先级和响应优先级
7
8#endif
9
10/**
11*@}
12*/

13
14/**
15*@}
16*/

17
18/************************(H)madmanazo*****ENDOFFILE****/

nvic.c:

 1/******************************************************************************
2*@Filename-->nvic.c
3*@Author-->By@madmanazo
4*@E-mail-->madmanazo@gmail.com
5*@Version-->V1.0
6*@Date-->03-8-2018
7*@Brief-->MCU系统所有中断控制汇总文件
8*
9
*@Copyright(C)20**
10*@Allrightsreserved
11*******************************************************************************
12*Update
13*
14******************************************************************************/

15
16/*Includes------------------------------------------------------------------*/
17#include"nvic.h"
18
19/******************************Codearea************************************/
20
21//为所有用到的中断配置抢占优先级和响应优先级
22voidNVIC_Priority_Init(void)
23{
24/***************************stm32优先级配置************************************
25
26******************************************************************************/

27
28//SysTick_IRQn由于在有一些中断函数中会用到,所以他的中断优先级需要配置为最高的
29NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority(NVIC_PriorityGroup_2,0,0));//SysTick_IRQn中断
30NVIC_SetPriority(USART1_IRQn,NVIC_EncodePriority(NVIC_PriorityGroup_2,1,0));//USART1_IRQn中断
31}
32
33/**
34*@}
35*/

36
37/**
38*@}
39*/

40
41/************************(C)madmanazo*****ENDOFFILE****/
42
43/***********************************************************************************
44这里对所有使用的中断进行优先级配置
45
46需要注意的是:
471.当需要中断嵌套时,优先级高的可以打断优先级低的中断,实现中断嵌套
482.在优先级设置中,以preemption为主,数值越小,优先级越高,但是当preemption数值一样时,
49Subpriority数值越小,优先级越高;只有在Preemption和Subpriority都一样时,才是同一级的中
50断,不会发生中断嵌套。
513.Cortex-M3内核中对中断优先级的定义
52既然每个中断源都需要被指定这两种优先级,就需要有相应的寄存器位记录每个中断的优先级;在Cortex-M3中定义了8个比特位用于设置中断源的优先级,这8个比特位可以有8种分配方式,如下:
53优先级分组抢占优先级域子优先级域
547所有8位用于指定响应优先级0
556最高1位用于指定抢占式优先级最低7位用于指定响应优先级
565最高2位用于指定抢占式优先级最低6位用于指定响应优先级
574最高3位用于指定抢占式优先级最低5位用于指定响应优先级
583最高4位用于指定抢占式优先级最低4位用于指定响应优先级
592最高5位用于指定抢占式优先级最低3位用于指定响应优先级
601最高6位用于指定抢占式优先级最低2位用于指定响应优先级
610(default)最高7位用于指定抢占式优先级最低1位用于指定响应优先级
62这就是优先级分组的概念。
634.stm32中对中断优先级的定义
64Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位,这4个寄存器位的分组方式如下:
65第0组:所有4位用于指定响应优先级
66第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
67第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
68第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
69第4组:所有4位用于指定抢占式优先级,0
705.相关分组定义:(STM32指定中断优先级的寄存器有效位为4位)
71============================================================================================================================
72NVIC_PriorityGroup|NVIC_IRQChannelPreemptionPriority|NVIC_IRQChannelSubPriority|Description
73============================================================================================================================
74NVIC_PriorityGroup_0|0|0-15|0bitsforpre-emptionpriority
75|||4bitsforsubpriority
76----------------------------------------------------------------------------------------------------------------------------
77NVIC_PriorityGroup_1|0-1|0-7|1bitsforpre-emptionpriority
78|||3bitsforsubpriority
79----------------------------------------------------------------------------------------------------------------------------
80NVIC_PriorityGroup_2|0-3|0-3|2bitsforpre-emptionpriority
81|||2bitsforsubpriority
82----------------------------------------------------------------------------------------------------------------------------
83NVIC_PriorityGroup_3|0-7|0-1|3bitsforpre-emptionpriority
84|||1bitsforsubpriority
85----------------------------------------------------------------------------------------------------------------------------
86NVIC_PriorityGroup_4|0-15|0|4bitsforpre-emptionpriority
87|||0bitsforsubpriority
88============================================================================================================================
896.相关内核提供函数释义:
90voidNVIC_SetPriorityGrouping(uint32_tPriorityGroup)//设置优先级分组数值
91uint32_tNVIC_GetPriorityGrouping(void)//获取优先级分组数值
92uint32_tNVIC_EncodePriority(uint32_tPriorityGroup,uint32_tPreemptPriority,uint32_tSubPriority)//基于优先级分组、组优先级、子优先级生成优先级数值,ThereturnedpriorityvaluecanbeusedforNVIC_SetPriority(...)function
93voidNVIC_DecodePriority(uint32_tPriority,uint32_tPriorityGroup,uint32_t*pPreemptPriority,uint32_t*pSubPriority)//提取组优先级和子优先级
947.相关使用注意事项:
95要注意的几点是:
961).如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
972).抢占式优先级别相同的中断源之间没有嵌套关系;
983).如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
99*************************************************************************************/

100
101/**
102*@}
103*/

104
105/**
106*@}
107*/

108
109/************************(C)madmanazo*****ENDOFFILE****/

usart.h:

 1#ifndef__USART_H
2#define__USART_H
3
4#include"stm32f4xx.h"
5#include"stdio.h"
6
7#defineUSART1_REC_LEN100
8
9externu8USART_RX_BUF[USART1_REC_LEN];
10externu8USART1_REC_CNT;
11externu8USART1_RX_FLAG;
12
13voidUSART1_Init(u32bound);
14
15#endif
16
17/**
18*@}
19*/

20
21/**
22*@}
23*/

24
25/***************(H)madmanazo*****ENDOFFILE****/

usart.c:

 1/******************************************************************************
2*@Filename-->usart.c
3*@Author-->By@madmanazo
4*@E-mail-->madmanazo@gmail.com
5*@Version-->V1.0
6*@Date-->6-20-2018
7*@Brief-->MCU串口空闲中断不定长数据接收配置
8*
9
*@Copyright(C)20**
10*@Allrightsreserved
11*******************************************************************************
12*Update
13*
14******************************************************************************/

15
16/*Includes------------------------------------------------------------------*/
17#include"usart.h"
18
19/******************************Codearea************************************/
20
21u8USART_RX_BUF[USART1_REC_LEN];
22u8USART1_REC_CNT=0;
23u8USART1_RX_FLAG=0;
24
25/*******************************************************************************
26*@Name:USART1_Init
27*@brief:USART1初始化配置
28*@Input:bound:串口波特率
29*@Output:None
30*@retval:None
31*******************************************************************************/

32voidUSART1_Init(u32bound)
33{
34GPIO_InitTypeDefGPIO_InitStructure;
35USART_InitTypeDefUSART_InitStructure;
36DMA_InitTypeDefDMA_InitStructure;
37
38RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_DMA2,ENABLE);//使能GPIOA时钟&DMA2时钟
39RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟
40
41GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//PA9复用为USART1
42GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//PA10复用为USART1
43
44GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//复用功能
45GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽复用输出
46GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;//选择USART1对应的管脚:PA9->USART1_TX,PA10->USART1_RX
47GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
48GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//端口速度100MHz
49GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIO端口初始化
50
51USART_InitStructure.USART_BaudRate=bound;//设置串口波特率:115200
52USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//设置有无硬件流控制:无
53USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//设置模式:接收&发送
54USART_InitStructure.USART_Parity=USART_Parity_No;//设置有无奇偶校验:无
55USART_InitStructure.USART_StopBits=USART_StopBits_1;//设置停止位:1位
56USART_InitStructure.USART_WordLength=USART_WordLength_8b;//设置数据位:8位
57USART_Init(USART1,&USART_InitStructure);//USART1初始化
58
59DMA_DeInit(DMA2_Stream2);//将DMA2_Stream2寄存器取消初始化为其默认复位值
60while(DMA_GetCmdStatus(DMA2_Stream2)!=DISABLE);//等待DMA可配置
61DMA_InitStructure.DMA_BufferSize=USART1_REC_LEN;//设置DMA数据传输量
62DMA_InitStructure.DMA_Channel=DMA_Channel_4;//设置DMA数据传输通道
63DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//设置数据传输方向
64DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//设置是否开启FIFO模式
65DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;//设置FIFO阈值,可以为FIFO的1/4、1/2、3/4、1倍,没有开启FIFO时可不关心
66DMA_InitStructure.DMA_Memory0BaseAddr=(u32)USART_RX_BUF;//设置存放DMA传输数据的内存基地址
67DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;//设置存储器突发传输配置,可设置单次突发传输、4个节拍增量、8个节拍增量、16个节拍增量突发传输模式
68DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;//设置内存的数据长度是为字节存储、半字存储还是字存储
69DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//设置传输数据时内存地址是否递增
70DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//设置DMA模式,可设置普通模式或循环模式,循环模式会让DMA接收一帧数据之后再回到初址
71DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)(&(USART1->DR));//设置DMA传输的外设基地址
72DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;//设置外设突发传输配置,可设置单次突发传输、4个节拍增量、8个节拍增量、16个节拍增量突发传输模式
73DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//设置外设的数据长度是为字节传输、半字传输还是字传输
74DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//设置传输数据的时候外设的地址是不变还是递增
75DMA_InitStructure.DMA_Priority=DMA_Priority_High;//设置DMA通道的优先级,有低、中、高、超高四种优先级可选
76DMA_Init(DMA2_Stream2,&DMA_InitStructure);//DMA2forUSART1_RX初始化
77
78DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA传输
79NVIC_EnableIRQ(USART1_IRQn);//使能USART1中断通道
80USART_Cmd(USART1,ENABLE);//USART1使能
81USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//若总线空闲,产生中断
82USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//USART1'sDMA接收&发送使能
83USART_ClearFlag(USART1,USART_FLAG_TC);//清除发送完成标志
84}
85
86/*******************************************************************************
87*@Name:USART1_IRQHandler
88*@brief:USART1中断服务函数
89*@Input:None
90*@Output:None
91*@retval:None
92*******************************************************************************/

93voidUSART1_IRQHandler(void)
94{
95u8i;
96
97if(USART_GetITStatus(USART1,USART_IT_IDLE)!=RESET)//接收中断(接收到的数据必须是0x0D0x0A结尾)
98{
99i=USART1->SR;//软件序列清零(读入USART_SR寄存器,然后读入USART_DR寄存器)
100i=USART1->DR;
101//USART_ReceiveData(USART1);//ClearIDLEinterruptflagbit(注释掉上面i相关代码换成此句效果一样)
102//(X)USART_ClearITPendingBit(USART1,USART_IT_IDLE);//清除发送完成标志(可查看参考手册712页或者USART_ClearITPendingBit函数说明(stm32f4xx_usart.c源文件1437~1441行))
103
104USART1_REC_CNT=USART1_REC_LEN-DMA_GetCurrDataCounter(DMA2_Stream2);//算出接本帧数据长度
105
106/***********帧数据长度返回***************/
107printf("TheLength:%drn",USART1_REC_CNT);
108/*************************************/
109
110USART1_RX_FLAG=1;//接收数据标志置位
111
112DMA_Cmd(DMA2_Stream2,DISABLE);//失能DMA传输
113while(DMA_GetCmdStatus(DMA2_Stream2)!=DISABLE);//等待DMA可配置
114DMA_SetCurrDataCounter(DMA2_Stream2,USART1_REC_LEN);//重新设置接收数据的个数
115DMA_Cmd(DMA2_Stream2,ENABLE);//使能DMA传输
116USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//若总线空闲,产生中断
117}
118}
119
120/*******************************************************************************
121*@Name:fputc
122*@brief:内部调用函数,注意要勾选OPTIONS中的USEMicroLIB选项
123*由于printf执行是调用fputc函数,所以相当于重新定义printf函数
124*,支持printf()发送数据。
125*@Input:None
126*@Output:None
127*@retval:None
128*******************************************************************************/

129intfputc(intch,FILE*f)
130{
131USART_SendData(USART1,(u8)ch);
132while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//获取串口状态
133returnch;
134}
135
136/*******************************************************************************
137*@Name:fgetc
138*@brief:内部调用函数,注意要勾选OPTIONS中的USEMicroLIB选项
139*由于scanf执行是调用fgetc函数,所以相当于重新定义scanf函数
140*,支持printf()发送数据。
141*@Input:None
142*@Output:None
143*@retval:None
144*******************************************************************************/

145intfgetc(FILE*f)
146{
147while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);//获取串口状态
148return(USART_ReceiveData(USART1));
149}
150
151/**
152*@}
153*/

154
155/**
156*@}
157*/

158
159/************************(C)madmanazo*****ENDOFFILE****/

main.c:

 1/******************************************************************************
2*@Filename-->main.c
3*@Author-->By@madmanazo
4*@E-mail-->madmanazo@gmail.com
5*@Version-->V1.0
6*@Date-->06-20-2018
7*@Brief-->STM32串口通信交互简单测试
8*
9
*@Copyright(C)20**
10*@Allrightsreserved
11*******************************************************************************
12*Update
13*
14******************************************************************************/

15
16/*Includes------------------------------------------------------------------*/
17#include
18#include"delay.h"
19#include"nvic.h"
20#include"usart.h"
21#include"led.h"
22
23intmain(void)
24{
25u8i;
26
27delay_init();
28NVIC_Priority_Init();
29USART1_Init(115200);
30LED_Init();
31
32while(1)
33{
34if(USART1_RX_FLAG)
35{
36for(i=0;i2;i++)
37printf("%c",USART_RX_BUF[i]);
38printf("n");
39
40for(i=0;i41USART_RX_BUF[i]=0;//指定数据填充
42
43USART1_RX_FLAG=0;//清除标志位
44
45LED1=!LED1;
46}
47delay_ms(300);
48LED2=!LED2;
49}
50}
51
52/**
53*@}
54*/

55
56/**
57*@}
58*/

59
60/************************(C)madmanazo*****ENDOFFILE****/


下载之后效果如下:


使用SSCOM串口调试器和Keil Debug测试:

点击Keil调试器Run(F5)之后发送数据结果如下:


上面结果只是简单测试,提交给老板之后,新的问题来了:如果我们发送数据的频率过快,在下一帧数据到来之前本帧数据未来得及处理怎么办呢?请看《串口通信深度剖析四》


相关资源下载

Keil等软件:

公号菜单栏->下载专区->软件工具内

SSCOM串口/网络数据调试器:

http://www.daxia.com/




以上资料仅供学习使用,更多信息请关注微信公众号:

热爱科技 享受生活

作者:若者

长按二维码关注


往期文章推荐:

STM32学习教程分享

串口通信深度剖析一(和小马哥聊天记录)

串口通信深度剖析二

Qt开发入门-开发环境搭建

Qt开发入门-Helloworld

Qt开发入门-字符串类

Qt开发入门-布局控件

Qt开发入门-按钮控件

Qt开发入门-输入部件

Qt开发入门-其他控件





如需帮助,请在下方留言或微信公众号内回复消息






              查看评论 回复



嵌入式交流网主页 > 嵌入式软件 > C/C++ > keilc > 串口通信深度剖析三
 中断 指定 优先级

"串口通信深度剖析三"的相关文章

网站地图

围观()