OpenEdv-开源电子网

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

STM32F103串口DMA传输问题

[复制链接]

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
发表于 2016-7-25 09:41:50 | 显示全部楼层 |阅读模式
1金钱
请教各位大侠一个问题:
          我现在使用STM32F103的串口2,DMA通道6进行接收固定长度的数据帧,帧长度为13个,但是每次接收的数据都有错位。例如,我通过上位机固定200ms发送一帧数据:为01 02 03 04 05 06 07 08 09 0a 0b 0c 0d,但是软件仿真的时候看DMA接收缓存里面的数据就不对了,接收到的数据有错位的现象,实际收到的为 06 07 08 09 0a 0b 0c 0d 01 02 03 04 05,数据信息还是发送的信息,就是顺序乱了,整了两天了,还是没解决,请教各位大侠是什么原因,如下是我的DMA相关代码:
void Uart2_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
        /* Configure USART2 Tx  as alternate function push-pull */
          GPIO_InitStructure.GPIO_Pin = RS485_1_TX_PIN;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
          GPIO_Init(RS485_1_PORT, &GPIO_InitStructure);          
          /* Configure USART2 Rx   as input floating */
          GPIO_InitStructure.GPIO_Pin = RS485_1_RX_PIN;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
          GPIO_Init(RS485_1_PORT, &GPIO_InitStructure);
          GPIO_InitStructure.GPIO_Pin = RS485_1_EN_PIN;  // 控制485的收发
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式
          GPIO_Init(RS485_1_PORT, &GPIO_InitStructure);
          USART_InitStructure.USART_BaudRate            = RS485_1_COM_BAUD;
        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(USART2, &USART_InitStructure);
        USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
        DMA_Cmd(DMA1_Channel6, DISABLE);
          DMA_DeInit(DMA1_Channel6);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART2->DR);// 设置串口发送数据寄存器
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)Rs485RxBuf1;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize = RF_DATA_PACKLEN;
        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_Circular;          // 循环传输模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  // 关闭内存到内存的DMA模式
        DMA_Init(DMA1_Channel6, &DMA_InitStructure);
        DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
        USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
        DMA_ClearFlag(DMA1_FLAG_GL6);  
        DMA_Cmd(DMA1_Channel6, ENABLE);
        USART_Cmd(USART2, ENABLE);
        RS485_1_RX_ENABLE;
}


void DMA1_Channel6_IRQHandler(void)
{
        if(DMA_GetITStatus(DMA1_IT_TC6))
        {
                DMA_ClearITPendingBit(DMA1_IT_GL6);
                Write_DataFifo(&Rs485Fifo1, &Rs485RxBuf1);
        }
}

仿真的时候实时观测Rs485RxBuf1这个buf,里面的内容就是错位的数据。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11544
金钱
11544
注册时间
2014-4-1
在线时间
1315 小时
发表于 2016-7-25 09:58:06 | 显示全部楼层

PC第一次发送的数据,接收对吗?


回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
 楼主| 发表于 2016-7-25 09:58:40 | 显示全部楼层
第一次是对的
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
 楼主| 发表于 2016-7-25 09:59:27 | 显示全部楼层
xuande 发表于 2016-7-25 09:58
PC第一次发送的数据,接收对吗?

第一次是对的,到了第二次就开始乱了,但是数据信息没有问题,都是那13个数据
回复

使用道具 举报

3

主题

177

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1604
金钱
1604
注册时间
2016-1-28
在线时间
265 小时
发表于 2016-7-25 10:00:51 | 显示全部楼层
帮顶!
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11544
金钱
11544
注册时间
2014-4-1
在线时间
1315 小时
发表于 2016-7-25 10:05:13 | 显示全部楼层

收完第一帧,重新初始化一下。

回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
 楼主| 发表于 2016-7-25 10:07:41 | 显示全部楼层
xuande 发表于 2016-7-25 10:05
收完第一帧,重新初始化一下。

好的,我试一下
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
 楼主| 发表于 2016-7-25 10:20:15 | 显示全部楼层
xuande 发表于 2016-7-25 10:05
收完第一帧,重新初始化一下。

我在中断里面重新初始化了DMA,跟我之前的效果一样,我现在把发送延时到5ms一次,好像又不出错了,昨天测试是PC一直循环发送,就不行,难道是帧与帧之间需要个小的延时?等待DMA释放总线?
回复

使用道具 举报

0

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
295
金钱
295
注册时间
2016-6-17
在线时间
60 小时
发表于 2016-7-25 10:20:51 | 显示全部楼层
把接收缓存设大一些,每次读取DMA当前的指针位置
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2016-7-22
在线时间
1 小时
 楼主| 发表于 2016-7-25 10:27:01 | 显示全部楼层
zzx499 发表于 2016-7-25 10:20
把接收缓存设大一些,每次读取DMA当前的指针位置

我的处理机制是DMA收完一帧数据之后,立马写进我的数据fifo,数据fifo的单位是13,你的意思设大DMA缓冲区,减少进终端的频率,可能效果会更好是吗?
回复

使用道具 举报

0

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
295
金钱
295
注册时间
2016-6-17
在线时间
60 小时
发表于 2016-7-25 10:42:54 | 显示全部楼层
liudingming 发表于 2016-7-25 10:27
我的处理机制是DMA收完一帧数据之后,立马写进我的数据fifo,数据fifo的单位是13,你的意思设大DMA缓冲区 ...

你先设大DMA缓冲,多发几次看看两次数据之间是否连续,就知道你到底是发的问题,还是收的问题。
如果每次接收到数据不必立即处理,可以设大缓冲区,关闭DMA中断,用定时器控制读取频率,每次读取的DMA指针位置,读取的数据长度可控,从哪个字符读取也可控,很灵巧。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-9 04:18

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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