打印
[应用相关]

关于STM32空闲中断

[复制链接]
706|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎么样才能确定接收到了一条完整的数据了,,我们都知道只要打开DMA

那家伙就不停的把接收的数据放到我们指定的地方.
只要接收到一条完整的数据我就该去处理了
关于空闲中断,,,就是说每接收到一条完整的数据就会置位空闲标志位,我们只需要判断空闲标志位是否置一,,就能知道是不是接收到了一条完整的数据
用空闲中断的好处就是,,对于以前我写程序通信都会在数据的后面加上尾,,然后另一个接收的单片机通过判断数据的尾来确定是不是一条完整的数据,,,有了空闲中断就不需要在给数据加上尾了,,,,,



作者:杨奉武
链接:https://www.jianshu.com/p/2aad70a49ef7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

使用特权

评论回复
沙发
monitoring|  楼主 | 2020-5-17 11:34 | 只看该作者
直接程序吧

u8  Usart1_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.
u8  Usart1_RX_BUF[1024]={0};//串口1接收缓冲,最大 1024 个字节.
u16 Usart1_REC_Cnt =0;//串口1接收的数据个数
u16 Usart1_Current_Cnt =0;//串口1当前接收的数据个数
u16 Usart1_Current_cnt =0;//串口1当前接收的数据个数
u8  Usart1_AT_flage =0;//串口1接收完成标志位
u8  Usart2_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.
u8  Usart2_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.
u16 Usart2_REC_Cnt =0;//串口2接收的数据个数
u16 Usart2_Current_Cnt =0;//串口2当前接收的数据个数
u16 Usart2_Current_cnt =0;//串口2当前接收的数据个数
u8  Usart2_AT_flage =0;//串口2接收完成标志位
u8  Usart3_RX_BUF[1024]={0};//串口3接收缓冲,最大 1024 个字节.
u16 Usart3_REC_Cnt =0;//串口3接收的数据个数
u8  Usart3_AT_flage =0;//串口3接收完成标志位
u8 Free_Read_Rst=0;//读DR清除空闲中断

使用特权

评论回复
板凳
monitoring|  楼主 | 2020-5-17 11:34 | 只看该作者
voidUSART123_Init(uint32_t bound_1,uint32_t bound_2,uint32_t bound_3)

{

USART_InitTypeDef USART_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2|RCC_APB1Periph_USART3, ENABLE);//使能USART2,USART3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO , ENABLE);//USART1_TX  PA9GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP;;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure);//USART1_RX  PA10GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_Init(GPIOA,&GPIO_InitStructure);//USART2_TX  GPIOA.2GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;//PA.2GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);//USART2_RX      GPIOA.3初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);//USART3_TX  GPIOB.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PB10GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure);//USART3_RX      GPIOB.11初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate=bound_1;

USART_InitStructure.USART_WordLength=USART_WordLength_8b;

USART_InitStructure.USART_StopBits=USART_StopBits_1;

USART_InitStructure.USART_Parity=USART_Parity_No ;

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode= USART_Mode_Rx |USART_Mode_Tx;

USART_Init(USART1,&USART_InitStructure);

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口1总线空闲中断USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);//开启串口2总线空闲中断USART_InitStructure.USART_BaudRate=bound_2;

USART_Init(USART2,&USART_InitStructure);

USART_InitStructure.USART_BaudRate=bound_3;

USART_Init(USART3,&USART_InitStructure);

USART_Cmd(USART1, ENABLE);

USART_Cmd(USART2, ENABLE);

USART_Cmd(USART3, ENABLE);

}

使用特权

评论回复
地板
monitoring|  楼主 | 2020-5-17 11:35 | 只看该作者
/********************串口 1 中断服务程序**********************/voidUSART1_IRQHandler(void)

{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET) //正常情况下进入这个接收

{

USART_ClearITPendingBit(USART1, USART_FLAG_ORE);

USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中断标志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//读取接收到的数据Usart1_REC_Cnt++;

}elseif(USART_GetITStatus(USART1,USART_IT_IDLE) ==SET)//传输完一条完整的数据就会进入这个

{

Free_Read_Rst= USART1->DR;//清USART_IT_IDLE标志Usart1_AT_flage =1;//接收到一条完整的数据Usart1_Current_Cnt = Usart1_REC_Cnt;//复制接收到的数据个数Usart1_REC_Cnt =0;//清零接收的个数}

}

使用特权

评论回复
5
monitoring|  楼主 | 2020-5-17 11:35 | 只看该作者
主函数循环里只需要......

使用特权

评论回复
6
monitoring|  楼主 | 2020-5-17 11:36 | 只看该作者
先说一点:单片机的串口可以接收任意波特率的数据,你所写的9600意思是以这个波特率发送....

其实昨天才发现这家伙真的太准确了,,准确到如果碰见通信中速率如果不是设置的波特率,就是说通信的速率慢了不是(我上面设置的波特率是9600)1/9600(S)发过来一位数据了,低于了这个值假设是2400吧!接受到一位数据后如果1/9600(s)后没有接收到数据,那么这家伙也会进空闲中断.......因为你是设置的9600,,,,那么在1/9600(s)后理应接收到下一位数据....而其实是在1/2400(S)后才会接收到另一位数据.....如果能把空闲中断的检测时间降到满足的要求就好了....

使用特权

评论回复
7
monitoring|  楼主 | 2020-5-17 11:37 | 只看该作者
所以嘛,,,,,自己写个别这么苛刻的,昨天写好了,不过呢今天主要是把自己遇到的问题说一下

其实思路都知道

串口接收的时候打开一个定时器,并且只要接收到数据就清零一个变量,这个变量是在定时器里面执行自加一操作,,

如果串口一段时间(空闲中断的检测时间)不接收数据了这个变量就能自加到我们设置的数,然后关掉定时器,置位接收完成标志位,...

使用特权

评论回复
8
monitoring|  楼主 | 2020-5-17 11:38 | 只看该作者
直接上程序

/********************串口 1 中断服务程序**********************/voidUSART1_IRQHandler(void)

{if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET)

{

USART_ClearITPendingBit(USART1, USART_FLAG_ORE);

USART_ClearITPendingBit(USART1,USART_IT_ORE);//清除中断标志Usart1_RX_BUF[Usart1_REC_Cnt] =USART_ReceiveData(USART1);//读取接收到的数据Usart1_REC_Cnt++;

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );//打开定时器开始计时Time2_cnt =0;//清零计数}

}

使用特权

评论回复
9
monitoring|  楼主 | 2020-5-17 11:39 | 只看该作者
voidtimer_config(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/*Resets the TIM2*/
TIM_DeInit(TIM2);//设置了时钟分割。
TIM_TimeBaseStructure.TIM_ClockDivision =0;//选择了计数器模式。
TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值
TIM_TimeBaseStructure.TIM_Period =10;//定时时间1ms进一次//设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01M
TIM_TimeBaseStructure.TIM_Prescaler =7199;//
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);/*Enables the TIM2 counter*/
TIM_Cmd(TIM2, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );

}

使用特权

评论回复
10
monitoring|  楼主 | 2020-5-17 11:40 | 只看该作者
voidTIM2_IRQHandler(void)

{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) ==SET)

{

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if(Time2_cnt<100)//防止累加循环过去

{

Time2_cnt++;

}
if(Time2_cnt>3)//空闲时间大于约3毫秒

{

TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE );//关闭定时器---注意千万不要放到主函数里面关,,,,大家可以试一试会出现什么问题.....
Usart1_AT_flage =1;//接收完成标志位置一

Usart1_Current_Cnt=Usart1_REC_Cnt;//赋值接收的数据个数

Usart1_REC_Cnt=0;//清零接收的数据个数     
}

}

使用特权

评论回复
11
monitoring|  楼主 | 2020-5-17 11:41 | 只看该作者
然后昨天又写了一个两个串口的,因为用了两个串口做数据转换(用的串口1和串口3),,,,其实其中一个也可以用空闲中断,,但是担心数据传输过程中万一速率有所变化,,,,,,,,完蛋啦

使用特权

评论回复
12
monitoring|  楼主 | 2020-5-17 11:42 | 只看该作者
uint8_t  Usart1_TimeFlage =0;//串口1空闲变量允许累加标志
uint16_t Usart1_IdealTime =0;//串口1空闲累加变量
uint8_t  Usart3_TimeFlage =0;//串口3空闲变量允许累加标志
uint16_t Usart3_IdealTime =0;//串口3空闲累加变量
u8  Usart1_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.
u8  Usart1_RX_BUF[1024]={0};//串口1接收缓冲,最大 1024 个字节.
u16 Usart1_REC_Cnt =0;//串口1接收的数据个数
u16 Usart1_Current_Cnt =0;//串口2当前接收的数据个数
u16 Usart1_Current_cnt =0;//串口2当前接收的数据个数
u8  Usart1_AT_flage =0;//串口1接收完成标志位
u8  Usart2_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.
u8  Usart2_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.
u16 Usart2_REC_Cnt =0;//串口2接收的数据个数
u16 Usart2_Current_Cnt =0;//串口2当前接收的数据个数
u16 Usart2_Current_cnt =0;//串口2当前接收的数据个数
u8  Usart2_AT_flage =0;//串口2接收完成标志位
u8  Usart3_RX_Cop[1024]={0};//串口2备用接收缓冲,最大 1024 个字节.
u8  Usart3_RX_BUF[1024]={0};//串口2接收缓冲,最大 1024 个字节.
u16 Usart3_REC_Cnt =0;//串口2接收的数据个数
u16 Usart3_Current_Cnt =0;//串口2当前接收的数据个数
u16 Usart3_Current_cnt =0;//串口2当前接收的数据个数
u8  Usart3_AT_flage =0;//串口2接收完成标志位

使用特权

评论回复
13
monitoring|  楼主 | 2020-5-17 11:43 | 只看该作者


使用特权

评论回复
14
monitoring|  楼主 | 2020-5-17 11:44 | 只看该作者
voidtimer3_config(void)

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);/*Resets the TIM2*/
TIM_DeInit(TIM3);//设置了时钟分割。
TIM_TimeBaseStructure.TIM_ClockDivision =0;//选择了计数器模式。
TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//初值
TIM_TimeBaseStructure.TIM_Period =10;//定时时间1Ms进一次//设置了用来作为 TIMx 时钟频率除数的预分频值。72M / 7099+1 = 0.01M
TIM_TimeBaseStructure.TIM_Prescaler =7199;//
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);/*Enables the TIM2 counter*/
TIM_Cmd(TIM3, ENABLE);/*Enables the TIM2 Capture Compare channel 1 Interrupt source*/
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );

}

使用特权

评论回复
15
monitoring|  楼主 | 2020-5-17 11:46 | 只看该作者
voidTIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update) ==SET)
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
if(Usart1_TimeFlage ==1)//开始累加空闲变量
{
if(Usart1_IdealTime<400)//防止累加过去,造成循环
{
Usart1_IdealTime++;//空闲变量累加
}
}
if(Usart1_IdealTime>=100)//调节这个值以适应不同的接收速率
{
Usart1_TimeFlage=0;//停止空闲变量累加
Usart1_IdealTime =0;//清零空闲累加变量
Usart1_AT_flage =1;//接收标志位置一
Usart1_Current_Cnt = Usart1_REC_Cnt;//拷贝接收的数据个数
Usart1_REC_Cnt =0;//清零接收的数据个数
}
if(Usart3_TimeFlage ==1)//开始累加空闲变量
{
if(Usart3_IdealTime<400)//防止累加过去,造成循环
{
Usart3_IdealTime++;//空闲变量累加
}
}
if(Usart3_IdealTime>=100)//调节这个值以适应不停的接收速率
{
Usart3_TimeFlage=0;//停止空闲变量累加
Usart3_IdealTime =0;//清零空闲累加变量
Usart3_AT_flage =1;//接收标志位置一
Usart3_Current_Cnt = Usart3_REC_Cnt;//拷贝接收的数据个数
Usart3_REC_Cnt =0;//清零接收的数据个数
}
}
}

使用特权

评论回复
16
monitoring|  楼主 | 2020-5-17 11:47 | 只看该作者

那么主循环里---具体的处理函数,改为自己的就行

使用特权

评论回复
17
monitoring|  楼主 | 2020-5-17 11:47 | 只看该作者
源码,,这个是用的板子的空闲中断,,,,板子的其余文件删掉便可,,,,

链接:http://pan.baidu.com/s/1c228q6c密码:pl3k

使用特权

评论回复
18
monitoring|  楼主 | 2020-5-17 11:48 | 只看该作者

作者:杨奉武
链接:https://www.jianshu.com/p/2aad70a49ef7
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

使用特权

评论回复
19
caoenq| | 2020-5-17 20:41 | 只看该作者
monitoring 发表于 2020-5-17 11:48
作者:杨奉武
链接:https://www.jianshu.com/p/2aad70a49ef7
来源:简书

假如发送方发送的数据帧不是连续的怎么解决?

使用特权

评论回复
20
磨砂| | 2020-6-5 16:44 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

14

主题

192

帖子

1

粉丝