OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 20452|回复: 24

串口接收数据的四种方式

[复制链接]

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
发表于 2016-2-17 17:04:41 | 显示全部楼层 |阅读模式
1金钱

首先需要配置stm32的串口:
1、使能时钟
2、使能串口中断
3、初始化串口
这里想重点说明一下串口数据的接收策略:
不怕麻烦举四个例子说明,如果很了解就跳过,初学者还是有作用的(欢迎拍砖)
实例一:
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++)
USART2_SendByte(Uart2_Buffer[Uart2_Tx_Num]); //发送数据
Uart2_Rx_Num = 0; //初始化
Uart2_Tx_Num = 0;
Uart2_Sta = 0;
}
这是加了数据头和数据尾的接收方式,数据头和尾的个数可增加,此处只用于调试之用。中断函数用于接收数据以及判断数据的头尾,第二个函数在main函数里按照查询方式执行。
优点:较简单,采用缓存区接收,对提高数据的正确行有一定的改善 。
缺点:要是第一次数据接收错误,回不到初始化状态,必须复位操作 。
实例三:
void USART2_IRQHandler()
{
     if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
     {
        USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志.
        Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
        Uart2_Rx++;
        Uart2_Rx &= 0x3F; //判断是否计数到最大
      }
      if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出
      {
          USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR
          USART_ReceiveData(USART2); //读DR
       }
}

if( Uart2_Tx != Uart2_Rx )
{
    USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据
    Uart2_Tx++;
    Uart2_Tx &= 0x3F; //判断是否计数到最大
}  
采用FIFO方式接收数据,由0x3F可知此处最大接收量为64个,可变,中断函数只负责收,另一函数在main函数里执行,FIFO方式发送。
优点:发送和接收都很自由,中断占用时间少,有利于MCU处理其它。
缺点:对数据的正确性没有判断,一概全部接收。
实例四:
void USART2_IRQHandler()
{
     if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生
     {
        USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
        Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);
        Uart2_Rx++;
        Uart2_Rx &= 0xFF;
     }
     if(Uart2_Buffer[Uart2_Rx-1] == 0x5A) //头
        Uart2_Tx = Uart2_Rx-1;
     if((Uart2_Buffer[Uart2_Tx] == 0x5A)&&(Uart2_Buffer[Uart2_Rx-1] == 0xA5)) //   检测到头的情况下检测到尾
     {
            Uart2_Len = Uart2_Rx-1- Uart2_Tx; //长度
            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(tx2=0;tx2 <= Uart2_Len;tx2++,Uart2_Tx++)
                USART2_SendByte(Uart2_Buffer[Uart2_Tx]); //发送数据
        Uart2_Rx = 0; //初始化
        Uart2_Tx = 0;
        Uart2_Sta = 0;
}





对于第三种FIFO方式不是很理解,望大家赐教

最佳答案

查看完整内容[请看2#楼]

1.通过串口接收中断一个字节一个字节接收数据,同时用定时器来计算接收到数据的时间间隔,如果超过一定时间没有接收到数据则判断为一帧数据接受完,然后再对数据进行解析 2,通过DMA接收,加串口空闲中断方式,只在接收完一帧数据后才会产生中断,然后对数据进行解析 用这两种方法不是更好么??
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

7

主题

185

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2729
金钱
2729
注册时间
2015-12-27
在线时间
469 小时
发表于 2016-2-17 17:04:42 | 显示全部楼层
1.通过串口接收中断一个字节一个字节接收数据,同时用定时器来计算接收到数据的时间间隔,如果超过一定时间没有接收到数据则判断为一帧数据接受完,然后再对数据进行解析
2,通过DMA接收,加串口空闲中断方式,只在接收完一帧数据后才会产生中断,然后对数据进行解析
用这两种方法不是更好么??
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-17 18:06:42 | 显示全部楼层
自己顶一顶
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-17 18:07:03 | 显示全部楼层
自己顶一顶
回复

使用道具 举报

0

主题

45

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
380
金钱
380
注册时间
2014-12-13
在线时间
89 小时
发表于 2016-2-17 18:36:53 | 显示全部楼层
好,谢谢分享
回复

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1684
金钱
1684
注册时间
2014-2-25
在线时间
230 小时
发表于 2016-2-17 23:31:35 | 显示全部楼层
谢谢分享
回复

使用道具 举报

33

主题

197

帖子

0

精华

高级会员

Rank: 4

积分
587
金钱
587
注册时间
2015-1-9
在线时间
80 小时
发表于 2016-2-18 09:40:06 | 显示全部楼层
谢谢分享
回复

使用道具 举报

35

主题

193

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
476
金钱
476
注册时间
2015-12-27
在线时间
116 小时
发表于 2016-2-18 10:36:57 来自手机 | 显示全部楼层
中断服务函数最好不要带入口参数吧?
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-2-18 13:31:04 | 显示全部楼层
第3种不对,你是哪里不理解你说明白啊。Uart2_Rx &= 0x3F; //判断是否计数到最大    Uart2_Tx &= 0x3F; //判断是否计数到最大            这两句不对,改成if(Uart2_Rx&0xc0)rx_flag=1;   这样才对
我有故事,你有酒吗
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-2-18 13:32:11 | 显示全部楼层
来俩不甜的 发表于 2016-2-18 13:31
第3种不对,你是哪里不理解你说明白啊。Uart2_Rx &= 0x3F; //判断是否计数到最大    Uart2_Tx &= 0x3F; // ...

下边那个if是把接收到的数据又发送出去
我有故事,你有酒吗
回复

使用道具 举报

19

主题

702

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3339
金钱
3339
注册时间
2013-7-30
在线时间
708 小时
发表于 2016-2-18 13:33:48 | 显示全部楼层
一般采用队列加超时的接收方法
思想很重要,无论做人还是编程!
我的技术公众号【微联智控工作室】
回复

使用道具 举报

3

主题

92

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
275
金钱
275
注册时间
2012-6-19
在线时间
37 小时
发表于 2016-2-18 16:04:50 | 显示全部楼层
第一种不行,中断里面要延时不好吧。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2016-2-18 19:54:46 | 显示全部楼层
楼上的方法不错.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-19 10:59:59 | 显示全部楼层
钩月黄昏 发表于 2016-2-18 16:28
1.通过串口接收中断一个字节一个字节接收数据,同时用定时器来计算接收到数据的时间间隔,如果超过一定时间 ...

这个方法不错啊。
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-19 11:00:35 | 显示全部楼层
bxl131 发表于 2016-2-18 16:04
第一种不行,中断里面要延时不好吧。

从网上找的。中断里用延时的确不好
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-19 11:02:21 | 显示全部楼层
q546163199 发表于 2016-2-18 10:36
中断服务函数最好不要带入口参数吧?

这个不是很理解,带了会有什么影响吗
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-19 11:02:57 | 显示全部楼层
来俩不甜的 发表于 2016-2-18 13:31
第3种不对,你是哪里不理解你说明白啊。Uart2_Rx &= 0x3F; //判断是否计数到最大    Uart2_Tx &= 0x3F; // ...

主要是没有理解是怎么用的fifo方式,怎么体现出来的啊
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-2-19 11:04:39 | 显示全部楼层
来俩不甜的 发表于 2016-2-18 13:32
下边那个if是把接收到的数据又发送出去

是这样的
回复

使用道具 举报

69

主题

978

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3772
金钱
3772
注册时间
2015-4-26
在线时间
765 小时
发表于 2016-2-19 15:40:25 | 显示全部楼层
fangzhe1992 发表于 2016-2-19 11:02
主要是没有理解是怎么用的fifo方式,怎么体现出来的啊

接收的时候数据从数组的第0个元素开始存入,发送的时候从数组的 第0位开始发送 ,这不就是fifo吗,其实就是给自己脸上贴金,搞的高大上罢了
我有故事,你有酒吗
回复

使用道具 举报

6

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
293
金钱
293
注册时间
2016-1-7
在线时间
54 小时
发表于 2016-2-21 21:06:31 | 显示全部楼层
回复

使用道具 举报

5

主题

28

帖子

0

精华

初级会员

Rank: 2

积分
117
金钱
117
注册时间
2013-7-31
在线时间
23 小时
 楼主| 发表于 2016-4-20 10:57:43 | 显示全部楼层
落尘浅羽 发表于 2016-2-21 21:06
http://no001.blog.51cto.com/1142339/902155/

回复

使用道具 举报

34

主题

178

帖子

0

精华

初级会员

Rank: 2

积分
142
金钱
142
注册时间
2013-11-1
在线时间
183 小时
发表于 2016-9-28 22:58:31 | 显示全部楼层
不错不错
回复

使用道具 举报

菜鸟程序猿 该用户已被删除
发表于 2017-5-2 14:56:10 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2017-6-28
在线时间
0 小时
发表于 2017-6-28 10:07:45 | 显示全部楼层
Uart2_Rx &= 0x3F;感觉这一句应该理解为超过64个数据强制转换为64个
回复

使用道具 举报

0

主题

13

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2019-4-19
在线时间
11 小时
发表于 2019-6-13 23:32:57 | 显示全部楼层
谢谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-26 17:50

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表