OpenEdv-开源电子网

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

stm32串口发送数据丢失

[复制链接]

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
发表于 2016-7-18 11:05:50 | 显示全部楼层 |阅读模式
1金钱
想用串口发送数据写入W25Q64,数据比较多,可是在串口调试助手显示发送和接收的数据差太多,好多数据丢失了,求解决办法?
这是串口中断函数
串口中断函数.PNG

串口调试助手显示是这样
串口接收.PNG

实际接收的数据少了好多






最佳答案

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

你边接收边处理数据,那肯定处理不过来啊!!处理数据不能放中断里面,中断只做接收,不然得话,当你来了一大堆数据,你FLASH还是写完,剩下的数据全部因为没法进入中断,全丢失了,送你个串口1的封装好的程序,写个usart1.c和usart.h 然后直接调用接口,你可以参考下,usart1.c文件如下 [mw_shl_code=c,true]/* Includes ------------------------------------------------------------------*/ #include #include "usart1.h" ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

14

主题

219

帖子

0

精华

高级会员

Rank: 4

积分
598
金钱
598
注册时间
2014-4-14
在线时间
76 小时
发表于 2016-7-18 11:05:51 | 显示全部楼层
你边接收边处理数据,那肯定处理不过来啊!!处理数据不能放中断里面,中断只做接收,不然得话,当你来了一大堆数据,你FLASH还是写完,剩下的数据全部因为没法进入中断,全丢失了,送你个串口1的封装好的程序,写个usart1.c和usart.h 然后直接调用接口,你可以参考下,usart1.c文件如下
[mw_shl_code=c,true]/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "usart1.h"
#include "delay.h"

/* 最大缓存 */
#define MAXRECV USART1_BUFF
static char RX_BUFF[MAXRECV]={0};  //接收缓冲
static int RX_SIZ=0;               //接收到的数据长度  

#if (USART1_485_EN == 1)
#define RS485_TX_EN PAout(8)    //485模式控制.0,接收;1,发送.
#endif

/*********************************************************
  * @function  usart1_Configuration
  * @role      USART1串口初始化
  * @input     bound:波特率
  * @output    None
  * @return    None
  ********************************************************/
void usart1_Configuration(int bound)
{   
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

#if (USART1_MAP_EN == 0)
    /* config USART1 clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //PA9 TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);   
     
    //PA10 RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
     
#else
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//开启端口B和复用功能时钟
    GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);//使能端口重映射
    //uart 的GPIO重映射管脚初始化
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//悬空输入
    GPIO_Init(GPIOB,&GPIO_InitStructure);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
#endif
     
#if (USART1_485_EN == 1)
    //RE PA.8
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;        //输入输出控制IO     
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);  
#endif

    /* USART1 mode config */
    USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
    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); //初始化串口
   
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级3级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
    NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
     
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART1, ENABLE);                    //使能串口
    USART_ClearFlag(USART1, USART_FLAG_TC);       // 清标志
    RX_SIZ = 0;

#if (USART1_485_EN == 1)
    RS485_TX_EN=0;          //默认为接收模式
#endif
}

/*********************************************************
  * @function  USART1_IRQHandler
  * @role      串口接收中断
  * @input     None
  * @output    None
  * @return    None
  ********************************************************/
void USART1_IRQHandler(void)
{
    char buff = 0;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
    {        
        if(RX_SIZ < MAXRECV){
            buff = USART_ReceiveData(USART1);//记录接收到的值
            if(buff || RX_SIZ){
                RX_BUFF[RX_SIZ++]  = buff;
            }
        }
        USART_ClearITPendingBit(USART1,USART_IT_RXNE);    //清除中断标志.
    }

    if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)==SET)//溢出
    {
        USART_ClearFlag(USART1,USART_FLAG_ORE);//读SR
        USART_ReceiveData(USART1);//读DR
    }
}

/*********************************************************
  * @function  usart1_Send
  * @role      发送len个字节.
  * @input     要发送的数据与长度,
               (为了和本代码的接收匹配,这里建议不要超过 MAXRECV 个字节)
  * @output    None
  * @return    None
  ********************************************************/
void usart1_Send(char *buf,int len)
{
    int t;
#if (USART1_485_EN == 1)
    RS485_TX_EN=1;
#endif
    for(t=0;t<len;t++)       //循环发送数据
    {
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);   
        USART_SendData(USART1,buf[t]);
    }   
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)==RESET){//发送一个字符完成产生中断
        USART_ClearITPendingBit(USART1 ,USART_IT_TXE);//清发送中断
    }
#if (USART1_485_EN == 1)
    RS485_TX_EN=0;
#endif
}

/*********************************************************
  * @function  usart1_Receive
  * @role      RS232查询接收到的数据
  * @input     buf:接收缓存首地址,与缓存长度
  * @output    None
  * @return    接收的数据长度
  ********************************************************/
int usart1_Receive(char *buf, int buflen)
{
    int rxlen=RX_SIZ;
    int i=0;
    int ret = 0;        //默认为0      
    delay_ms(10);       //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
    if(rxlen==RX_SIZ && rxlen)//接收到了数据,且接收完成了
    {
        for(i=0;(i < rxlen) && (i < (buflen - 1));i++)
        {
            buf=RX_BUFF;
            RX_BUFF = 0;         
        }      
        buf='\0';
        ret=i;  //记录本次数据长度
        RX_SIZ=0;       //清零
    }
    return ret;
}

/*********************************************************
  * @function  usart1_FreeBuff
  * @role      清空缓存中的数据
  * @input     None
  * @output    None
  * @return    None
  ********************************************************/
void usart1_FreeBuff(void)
{
    int rxlen=RX_SIZ;
    int i=0;
    delay_ms(10);       //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
    while(rxlen)
    {
        if(rxlen==RX_SIZ && rxlen)//接收到了数据,且接收完成了
        {
            for(i=0;(i<rxlen) && (i < (MAXRECV-1)) ;i++){
                RX_BUFF = 0;
            }   
            RX_SIZ=0;       //清零
        }
        delay_ms(10);       //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
        rxlen=RX_SIZ;
    }
}[/mw_shl_code]
usart.h文件如下
[mw_shl_code=c,true]#ifndef __USART1_H_
#define __USART1_H_
#include "sys.h"

#define USART1_BUFF     200  //接收数据缓存
#define USART1_485_EN   0    //1 开启485功能,0 关闭485功能
#define USART1_MAP_EN   0   //1 开启重定向功能,0关闭重定向功能

void usart1_Configuration(int bound);
void usart1_Send(char *buf,int len);
int  usart1_Receive(char *buf, int buflen);
void usart1_FreeBuff(void);

#endif[/mw_shl_code]

然后是sys.h文件
[mw_shl_code=c,true]#ifndef __SYS_H
#define __SYS_H

#include "stm32f10x.h"

//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_UCOS     1       //定义系统文件夹是否支持UCOS
                                                                        
      
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C   
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C   

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08
  
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

typedef enum {FALSE = 0, TRUE = !FALSE} bool;

#endif[/mw_shl_code]
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2016-7-18 12:35:30 | 显示全部楼层
你是边接收边写入flash么???
回复

使用道具 举报

9

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2016-7-4
在线时间
47 小时
发表于 2016-7-18 14:26:50 | 显示全部楼层
中断里面操作flash写,不出错才奇怪
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 16:41:00 | 显示全部楼层
八度空间 发表于 2016-7-18 12:35
你是边接收边写入flash么???

嗯嗯,所以出错了
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 16:41:23 | 显示全部楼层
GS1101923161 发表于 2016-7-18 13:12
你边接收边处理数据,那肯定处理不过来啊!!处理数据不能放中断里面,中断只做接收,不然得话,当你来了一 ...

谢啦,先学学
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 16:43:26 | 显示全部楼层
Randy.zhang 发表于 2016-7-18 14:26
中断里面操作flash写,不出错才奇怪

那写flash放在哪里写呢
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 17:00:56 | 显示全部楼层

我把写函数去了,可还是只接受了部分数据,为什么啊 发了20多万个,只接受了1000多
发送.PNG
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-7-18 17:06:10 | 显示全部楼层
马小跳 发表于 2016-7-18 17:00
我把写函数去了,可还是只接受了部分数据,为什么啊 发了20多万个,只接受了1000多

还是同样的问题,中断里不要处理数据
你先把数据全部接收,然后一次性写进flash或者一次性显示出来
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 17:24:11 | 显示全部楼层
不吃鱼的老鼠 发表于 2016-7-18 17:06
还是同样的问题,中断里不要处理数据
你先把数据全部接收,然后一次性写进flash或者一次性显示出来

我已经把处理的函数去了,把接收的数据存放在很长的数组里,可是接收的数据还是少了很多 中断.PNG
接收.PNG
回复

使用道具 举报

62

主题

903

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3566
金钱
3566
注册时间
2016-1-8
在线时间
544 小时
发表于 2016-7-18 17:25:44 | 显示全部楼层
现在论坛好多新手,明显串口接收中断没有清除,你觉得能收到下一个数据吗?肯定会丢包
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-18 17:43:42 | 显示全部楼层
Sun_Fly 发表于 2016-7-18 17:25
现在论坛好多新手,明显串口接收中断没有清除,你觉得能收到下一个数据吗?肯定会丢包

写了清除中断函数了,只不过是写在if里面的,现在我把它放到if后面,确实好了很多。但我想问,发送的text里面有10万多个数据,总不至于定义一个这么长的数组吧,有什么好的解决方法来存放接收的数据吗,,,我是想把接收的数据写入W25Q64里面
回复

使用道具 举报

0

主题

23

帖子

0

精华

初级会员

Rank: 2

积分
188
金钱
188
注册时间
2016-4-14
在线时间
148 小时
发表于 2016-7-18 17:51:03 | 显示全部楼层
加串口通信协议吧,比如Ymode
人机界面设计
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-7-19 08:34:50 | 显示全部楼层
马小跳 发表于 2016-7-18 17:24
我已经把处理的函数去了,把接收的数据存放在很长的数组里,可是接收的数据还是少了很多

但是你放了一句USART1_Putc(SendBuff[t]);打印,一样的道理,还是会丢数据
要不就改发送端,你的发送端怎么处理的,相对于你现在写的接收来说发送太快了
回复

使用道具 举报

0

主题

183

帖子

0

精华

高级会员

Rank: 4

积分
684
金钱
684
注册时间
2016-1-27
在线时间
184 小时
发表于 2016-7-19 08:36:58 | 显示全部楼层
马小跳 发表于 2016-7-18 17:43
写了清除中断函数了,只不过是写在if里面的,现在我把它放到if后面,确实好了很多。但我想问,发送的text ...

加协议,将数据打包成帧发送
回复

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2016-7-18
在线时间
5 小时
发表于 2016-7-19 08:50:39 | 显示全部楼层
项起!!
回复

使用道具 举报

9

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2016-7-4
在线时间
47 小时
发表于 2016-7-19 10:21:54 | 显示全部楼层
马小跳 发表于 2016-7-18 16:43
那写flash放在哪里写呢

把数据全部收完后,再去操作flash
可以先把中断接收的数据存到一个buff中,也可以使用消息队列来处理
回复

使用道具 举报

30

主题

1170

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1993
金钱
1993
注册时间
2016-2-16
在线时间
527 小时
发表于 2016-7-19 10:32:19 | 显示全部楼层
USART1_putc这个函数原型呢。我感觉你把发送放中断还等待TC标记位了
回复

使用道具 举报

8

主题

39

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2016-7-18
在线时间
27 小时
 楼主| 发表于 2016-7-19 11:03:22 | 显示全部楼层
Randy.zhang 发表于 2016-7-19 10:21
把数据全部收完后,再去操作flash
可以先把中断接收的数据存到一个buff中,也可以使用消息队列来处理

中断接手的数据太多,一个数组是存不下的,队列消息是在哪里设置的呀?
回复

使用道具 举报

9

主题

103

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
228
金钱
228
注册时间
2016-7-4
在线时间
47 小时
发表于 2016-7-19 11:34:22 | 显示全部楼层
马小跳 发表于 2016-7-19 11:03
中断接手的数据太多,一个数组是存不下的,队列消息是在哪里设置的呀?

消息队列得自己写啊
数组存不下?不可能吧
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-10 03:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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