OpenEdv-开源电子网

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

串口一配合DMA接收不定长数据

[复制链接]

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
发表于 2018-6-27 10:45:11 | 显示全部楼层 |阅读模式
5金钱
程序要完成功能是:串口一配合DMA接收不定长数据,并通过串口二发出到电脑上显示
这是我大致写的程序,程序测试可以进入串口一中断,但是串口助手没有接收到数据

void Usart1_Init(u32 bound)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;
    DMA_InitTypeDef   DMA_InitStructure;

    //开时钟总线
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);


    //复位串口一
    USART_DeInit(USART1);
       
    // GPIOÅ配置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //PA9 TX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;              //PA10 RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //串口一配置
    USART_InitStructure.USART_BaudRate = bound;                  
    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);        

    // 配置串口一NVIC
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;        
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         
    NVIC_Init(&NVIC_InitStructure);                        

       
        DMA_DeInit(DMA1_Channel5);     //复位DMA1的通道5,和串口一的Rx对应
        //DMA1通道5的配置
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR);
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_DMA_Rxbuf;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = 128;            
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel5,&DMA_InitStructure);
       
      DMA_ITConfig(DMA1_Channel5,DMA_IT_TE,ENABLE);
      DMA_ITConfig(DMA1_Channel5,DMA_IT_TC,ENABLE);   
        DMA_Cmd(DMA1_Channel5,ENABLE);

        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //开串口空闲中断

        USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);  //串口一DMA接收使能
          
     USART_Cmd(USART1, ENABLE);                               //′®¿ú3ê1Äü       
     USART_ClearFlag(USART1, USART_FLAG_TC);  //清接收完成标志
}

//串口一中断函数
void USART1_IRQHandler(void)
{
    u8 i = 0;
    LED2_OFF;  //关闭LED2
    if(USART_GetITStatus(USART1, USART_IT_IDLE) == SET)
    {
         LED1_OFF;     
         i = USART1->SR;  
        i = USART1->DR;  //清USART_IT_IDLE标志
        //USART_ClearFlag(USART1,USART_IT_IDLE);
        DMA_Cmd(DMA1_Channel5, DISABLE);  //关闭DMA
        i = 128-DMA_GetCurrDataCounter(DMA1_Channel5); //得到真正接收数据个数
         USART1_DMA_Rxbuf[i] = '\0';
         
        Uaer1_Rxflag = 1;        //串口一接收完成标志位置一               
        DMA1_Channel5->CNDTR = 128;    //重新设置接收数据个数
        DMA_Cmd(DMA1_Channel5, ENABLE);//打开DMA
    }
}


//主函数
int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);         
        LED_Init();

        Usart2_init(2400);
        Usart1_Init(9600);

        LED1_ON;LED2_ON;

        while(1)                       
        {               
                if(Uaer1_Rxflag == 1)
                {
                        //LED1_ON;
                        Uaer1_Rxflag = 0;               
                        USART2_Printf(USART1_DMA_Rxbuf);   //串口二发送串口一DMA接收缓存数据
                }
        }
}


请问配置了串口一的DMA接收,串口一有数据过来就会存放到DMA接收缓存数组中吗?不用读USARTx->DR。
还有我程序这样有错误吗?刚学串口DMA,请多多指教

最佳答案

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

你把刚才发的贴http://www.openedv.com/thread-273874-1-1.html 中的while(1)改成下面就可以了,就是串口1收,串口2转发出去 while(1) { if(USART1_RX_STA&0x8000) { USART2_printf("USART1_RX_BUF=%s",USART1_RX_BUF); //printf("USART1_RX_BUF=%s",USART1_RX_BUF);//串口1可用printf 在sys里面设置,但是printf非dma发送 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-27 10:45:12 | 显示全部楼层
本帖最后由 275891381 于 2018-6-27 18:18 编辑
qiuzhicheng 发表于 2018-6-27 14:05
有没有大神帮我看看

你把刚才发的贴http://www.openedv.com/thread-273874-1-1.html
中的while(1)改成下面就可以了,就是串口1收,串口2转发出去
while(1)
{
      if(USART1_RX_STA&0x8000)
      {               
           USART2_printf("USART1_RX_BUF=%s",USART1_RX_BUF);        
           //printf("USART1_RX_BUF=%s",USART1_RX_BUF);//串口1可用printf 在sys里面设置,但是printf非dma发送                                
           USART1_RX_STA=0;
      }
}

回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-27 11:37:34 | 显示全部楼层
不定长怎么触发DMA中断啊??如果配置了,串口DMA,只要接收到字节,自动转入DMA对应的数组或者说是内存区。不需要你做任何处理。你除了DMA中断根本不知道,通信什么时间结束的。所以最好还是定长触发中断。
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-27 11:40:00 | 显示全部楼层
jinfeihan57 发表于 2018-6-27 11:37
不定长怎么触发DMA中断啊??如果配置了,串口DMA,只要接收到字节,自动转入DMA对应的数组或者说是内存区 ...

可以的,收到就触发接收,空闲中断关了读出来就好了
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-27 11:45:41 | 显示全部楼层
jinfeihan57 发表于 2018-6-27 11:37
不定长怎么触发DMA中断啊??如果配置了,串口DMA,只要接收到字节,自动转入DMA对应的数组或者说是内存区 ...

接收不定长数据用的是串口空闲中断,就是接收完一帧数据后,接收停顿超过一字节时间(这里我不明白什么意思,可能是接收一字节所用的时间吧),才会进入串口中断函数。
我没有配置DMA中断
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-27 11:47:10 | 显示全部楼层
275891381 发表于 2018-6-27 11:40
可以的,收到就触发接收,空闲中断关了读出来就好了

那你用的是串口的中断??那DMA的优势就没体现出来。你要是这样就没必要用DMA啊!你直接在你的串口中断里把接收到的数据赋值给一个数组就行了啊!!
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-27 11:47:21 | 显示全部楼层
275891381 发表于 2018-6-27 11:40
可以的,收到就触发接收,空闲中断关了读出来就好了

那你用的是串口的中断??那DMA的优势就没体现出来。你要是这样就没必要用DMA啊!你直接在你的串口中断里把接收到的数据赋值给一个数组就行了啊!!
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-27 11:48:39 | 显示全部楼层
275891381 发表于 2018-6-27 11:40
可以的,收到就触发接收,空闲中断关了读出来就好了

为什么我进了串口中断,发不出数据来呢
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-27 11:57:02 | 显示全部楼层
jinfeihan57 发表于 2018-6-27 11:47
那你用的是串口的中断??那DMA的优势就没体现出来。你要是这样就没必要用DMA啊!你直接在你的串口中断里 ...

使用串口空闲中断和DMA,就不用串口接收到一字节数据就进入串口中断处理。可以等待一帧数据接收完成,再进入中断函数处理。这样也是减少了cpu的占用
我要接收未知的数据(长度和结束符未知),如果采用接收中断的话,接收到一字节就存放到数组里面,就不知道什么时候结束了,因为串口一会一直接收数据
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-27 12:18:10 | 显示全部楼层
jinfeihan57 发表于 2018-6-27 11:47
那你用的是串口的中断??那DMA的优势就没体现出来。你要是这样就没必要用DMA啊!你直接在你的串口中断里 ...

接收发送的短的话效果的确不明显,很多发送都是查询标志量防冲突的,还是需要死等,有系统跑接收又长还是明显的
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-27 14:05:55 | 显示全部楼层
有没有大神帮我看看
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-27 17:52:27 | 显示全部楼层
qiuzhicheng 发表于 2018-6-27 14:05
有没有大神帮我看看

晚上发个帖子给你发一个,你试试
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 09:01:00 | 显示全部楼层
275891381 发表于 2018-6-27 18:14
你把刚才发的贴http://www.openedv.com/thread-273874-1-1.html
中的while(1)改成下面就可以了,就是 ...

非常感谢你的帮助
我用的是stm32f103Vet6
我把你启动文件.md换成.hd,C/C++宏定义STM32F10X_MD换成STM32F10X_HD
芯片选择stm32f103Vet6,晶振改成8.0,后面选择大容量芯片
编译出现中断函数名重定义
Error: L6200E: Symbol UART5_IRQHandler multiply defined (by startup_stm32f10x_hd_1.o and startup_stm32f10x_hd.o).
可是并没有startup_stm32f10x_hd_1.o这个文件啊
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-28 09:20:25 | 显示全部楼层
没搞懂你的做法,能解释一下你要做什么和你现在做了什么吗?
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 09:29:04 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 09:01
非常感谢你的帮助
我用的是stm32f103Vet6
我把你启动文件.md换成.hd,C/C++宏定义STM32F10 ...

我上传的例子直接按你的操作改,没问题的,你估计哪里改多了
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 09:33:35 | 显示全部楼层
jinfeihan57 发表于 2018-6-28 09:20
没搞懂你的做法,能解释一下你要做什么和你现在做了什么吗?

就是用串口一接收不定长度数据,然后通过串口二发出在电脑上显示出来
使用串口空闲中断+DMA
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 10:02:26 | 显示全部楼层
275891381 发表于 2018-6-28 09:29
我上传的例子直接按你的操作改,没问题的,你估计哪里改多了

嗯,谢了,建了个新工程,没问题了,我看看行不行
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 10:32:46 | 显示全部楼层
275891381 发表于 2018-6-27 10:45
你把刚才发的贴http://www.openedv.com/thread-273874-1-1.html
中的while(1)改成下面就可以了,就是 ...

串口助手一直显示“USART1_RX_BUF=”,USART1_RX_BUF里面没有数据
这是怎么回事
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 10:39:28 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 10:32
串口助手一直显示“USART1_RX_BUF=”,USART1_RX_BUF里面没有数据
这是怎么回事

代码没改就是这问题,不可能呀,我刚下载了上传的试了下没问题的,你改哪里了吧
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 11:02:52 | 显示全部楼层
275891381 发表于 2018-6-28 10:39
代码没改就是这问题,不可能呀,我刚下载了上传的试了下没问题的,你改哪里了吧

没有啊,我新建工程的文件全部用的是你的,只不过我把#if USART1_DMA==0后面的删了,然后把串口3注释了
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 11:13:06 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 11:02
没有啊,我新建工程的文件全部用的是你的,只不过我把#if USART1_DMA==0后面的删了,然后把串口3注释了

删多了吧你,删到#endif    先试试能用再慢慢删,一口吞胖子,谁知道哪里的问题
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 11:56:58 | 显示全部楼层
275891381 发表于 2018-6-28 11:13
删多了吧你,删到#endif    先试试能用再慢慢删,一口吞胖子,谁知道哪里的问题

换成你的没改的,也是一样的
能打印至少说明串口一是有接收到数据的吧
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 12:07:09 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 11:56
换成你的没改的,也是一样的
能打印至少说明串口一是有接收到数据的吧

你不是用串口助手发的吧,估计发的不是assic吗,第一个就是0,打印字符串直接结束了
你还是串口助手发试试
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 13:36:27 | 显示全部楼层
275891381 发表于 2018-6-28 12:07
你不是用串口助手发的吧,估计发的不是assic吗,第一个就是0,打印字符串直接结束了
你还是串口助手发试 ...

不是用串口助手发的,是接收另外一块板子发来的数据,我也不知道它发的是什么,我要做的是接收然后显示出来
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 14:07:40 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 13:36
不是用串口助手发的,是接收另外一块板子发来的数据,我也不知道它发的是什么,我要做的是接收然后显示出 ...

那我就哈哈了,你还是多学习下吧,你差的太多了
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 14:20:43 | 显示全部楼层
275891381 发表于 2018-6-28 14:07
那我就哈哈了,你还是多学习下吧,你差的太多了

我确实要多学习...
可是串口助手发和板子串口发数据不是一样吗,接收的方式也一样吧
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 14:55:37 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 14:20
我确实要多学习...
可是串口助手发和板子串口发数据不是一样吗,接收的方式也一样吧

接收一样打印不一样,不同的数据格式打印到串口的方式不一样,
回复

使用道具 举报

39

主题

535

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1065
金钱
1065
注册时间
2018-3-27
在线时间
378 小时
 楼主| 发表于 2018-6-28 15:15:00 | 显示全部楼层
275891381 发表于 2018-6-28 14:55
接收一样打印不一样,不同的数据格式打印到串口的方式不一样,

那能不能教教我,或者给我点资料也行,感激不尽
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-28 17:45:55 | 显示全部楼层
qiuzhicheng 发表于 2018-6-28 09:33
就是用串口一接收不定长度数据,然后通过串口二发出在电脑上显示出来
使用串口空闲中断+DMA

一个疑问,怎么判断串口二工作的时间,因为你不知道一是否接受完成了。
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 19:07:52 | 显示全部楼层
jinfeihan57 发表于 2018-6-28 17:45
一个疑问,怎么判断串口二工作的时间,因为你不知道一是否接受完成了。

进入空闲中断就是接收完成了
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-28 19:50:41 | 显示全部楼层
275891381 发表于 2018-6-28 19:07
进入空闲中断就是接收完成了

是这样的吗??
回复

使用道具 举报

31

主题

265

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
413
金钱
413
注册时间
2018-1-9
在线时间
65 小时
发表于 2018-6-28 19:51:52 | 显示全部楼层

两个接受中断之间就是空闲中断吗?
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-6-28 20:15:46 | 显示全部楼层
jinfeihan57 发表于 2018-6-28 19:51
两个接受中断之间就是空闲中断吗?

不是你说的,大约是接收到数据后有一个字节没数据就会进空闲中断,清除后除了再满足条件就不会进了,具体你百度下吧
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-28 02:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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