OpenEdv-开源电子网

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

stm32F407USART DMA发送长度不够数据不对

[复制链接]

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2012-6-3
在线时间
21 小时
发表于 2016-2-28 14:52:14 | 显示全部楼层 |阅读模式
1金钱
使用stm32F407的USART1 做DMA发送,发现发送的长度和设置的长度会出现差异,比如我设置发送40个字节,总会出现少于40个字节的现象,并且发现一般在第四个字节之后数据就不对了,找了好几天找不到问题,希望大侠帮忙看看,使用USCOSIII和不使用操作系统都试过了,都不行
/*********************************************************************
*       初始化串口
**********************************************************************/
void Init_USART1(u32 BaudRate)
{
  //GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitTypeDef NVIC_JnitStructure_DMA;
DMA_InitTypeDef  DMA_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟

//串口1对应引脚复用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1

//USART1端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
   //USART1 初始化设置
USART_InitStructure.USART_BaudRate = BaudRate;//波特率设置
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); //初始化串口1

USART_Cmd(USART1, ENABLE);  //使能串口1

//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;  //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;   //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
  
//串口发DMA配置  
//启动DMA时钟
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
//DMA发送中断设置
NVIC_JnitStructure_DMA.NVIC_IRQChannel = DMA2_Stream7_IRQn;
NVIC_JnitStructure_DMA.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_JnitStructure_DMA.NVIC_IRQChannelSubPriority = 0;
NVIC_JnitStructure_DMA.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_JnitStructure_DMA);

//DMA通道配置
DMA_DeInit(DMA2_Stream7);
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE){}//等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
//外设地址
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_ADDRESS;//(uint32_t)(&USART1->DR);
//内存地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)tx;
//dma传输方向
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
//设置DMA在传输时缓冲区的长度
DMA_InitStructure.DMA_BufferSize = 8;
//设置DMA的外设递增模式,一个外设
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//设置DMA的内存递增模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据字长
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//内存数据字长
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//设置DMA的传输模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//设置DMA的优先级别
DMA_InitStructure.DMA_Priority = DMA_Priority_High;

//指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式  
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;   
//指定了FIFO阈值水平
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;        
//指定的Burst转移配置内存传输
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;      
//指定的Burst转移配置外围转移 */  
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
//配置DMA2的通道         
DMA_Init(DMA2_Stream7, &DMA_InitStructure);  
//使能中断
DMA_ITConfig(DMA2_Stream7,DMA_IT_TC,ENABLE);
DMA_Cmd(DMA2_Stream7,DISABLE);
//串口收DMA配置  
//启动DMA时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
//DMA通道配置
DMA_DeInit(DMA2_Stream2);
   while (DMA_GetCmdStatus(DMA2_Stream2) != DISABLE){}//等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
//外设地址
DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_ADDRESS;//(uint32_t)(&USART1->DR);
//内存地址
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)tx;
//dma传输方向
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
//设置DMA在传输时缓冲区的长度
DMA_InitStructure.DMA_BufferSize = 8;
//设置DMA的外设递增模式,一个外设
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//设置DMA的内存递增模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//外设数据字长
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
//内存数据字长
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
//设置DMA的传输模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
//设置DMA的优先级别
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

//指定如果FIFO模式或直接模式将用于指定的流 : 不使能FIFO模式  
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;   
//指定了FIFO阈值水平
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;        
//指定的Burst转移配置内存传输
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;      
//指定的Burst转移配置外围转移 */  
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

//配置DMA1的通道         
DMA_Init(DMA2_Stream2, &DMA_InitStructure);  
//使能通道
DMA_Cmd(DMA2_Stream2,ENABLE);

        
//采用DMA方式发送
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
//采用DMA方式接收
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
//中断配置
USART_ITConfig(USART1,USART_IT_TC,DISABLE);
USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
USART_ITConfig(USART1,USART_IT_TXE,DISABLE);
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);  
    //启动串口  
    USART_Cmd(USART1, ENABLE);   
}

/*********************************************************************
*       接口函数MA发送中断处理函数
**********************************************************************/
void DMA2_Stream7_IRQHandler(void)
{
#if SYSTEM_SUPPORT_OS  //使用UCOS操作系统
OSIntEnter();   
  #endif
if(DMA_GetITStatus(DMA2_Stream7,DMA_IT_TCIF7) != RESET)
{
  //清除标志位
  DMA_ClearFlag(DMA2_Stream7,DMA_FLAG_TCIF7);
  //关闭DMA
  DMA_Cmd(DMA2_Stream7,DISABLE);
  //打开发送完成中断,发送最后两个字节
//  USART_ITConfig(USART1,USART_IT_TC,ENABLE);
}
  #if SYSTEM_SUPPORT_OS  
OSIntExit();     //退出中断
   #endif
//
}
/*********************************************************************
*参数:data:发送数据存放地址
*   size:发送数据字节数
**********************************************************************/
void USART1_TX(u16 size)
{
//等待空闲
// while (Flag_Tx_Gsm_Busy);
// Flag_Tx_Gsm_Busy = 1;
// //复制数据
DMA_Cmd(DMA2_Stream7,DISABLE);
//memcpy(USART1_TX_Buffer,data,size);
while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE){}//等待DMA可配置
//设置传输数据长度
DMA_SetCurrDataCounter(DMA2_Stream7,size);
//打开DMA,开始发送
  DMA_Cmd(DMA2_Stream7,ENABLE);
}
/*********************************************************************
*       处理发送完成中断
*返回:0:未产生,1:已经产生
**********************************************************************/
uint8_t USART1_TXend(void)
{
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
    {
  //关闭发送完成中断
  USART_ITConfig(USART2,USART_IT_TC,DISABLE);
  //发送完成
        USART1_Tx_STA = 0;
  
  return 1;
    }

return 0;
}
/*********************************************************************
*       处理接收完成中断
*参数:buf:接收的数据
*     len:接收的数据长度
*返回:0:未产生,其他:已经产生,此值为接收的数据长度
**********************************************************************/
u8 USART1_DMA_Rx(u8 *buf)
{
uint16_t len = 0;

//接收完成中断
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {
     USART1->SR;
     USART1->DR; //清USART_IT_IDLE标志
  //关闭DMA
     DMA_Cmd(DMA2_Stream2,DISABLE);
  //清除标志位
  DMA_ClearFlag(DMA2_Stream2,DMA_FLAG_TCIF2);
  
  //获得接收帧帧长
  len = USART1_Rx_Len - DMA_GetCurrDataCounter(DMA2_Stream2);
//  memcpy(buf,USART_RX_BUF,len);
  
  //设置传输数据长度
  DMA_SetCurrDataCounter(DMA2_Stream2,USART1_Rx_Len);
     //打开DMA
  DMA_Cmd(DMA2_Stream2,ENABLE);
  return len;
    }

return 0;
}

void USART1_IRQHandler(void)                 //串口1中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS  //使用UCOS操作系统
OSIntEnter();   
#endif
Res = USART1_DMA_Rx(USART_RX_BUF);
USART1_TXend();
// if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
// {
//  Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
//  USART_RX_BUF[0]=Res;
  
//  if((USART_RX_STA&0x8000)==0)//接收未完成
//  {
//   if(USART_RX_STA&0x4000)//接收到了0x0d
//   {
//    if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
//    else USART_RX_STA|=0x8000; //接收完成了
//   }
//   else //还没收到0X0D
//   {
//    if(Res==0x0d)USART_RX_STA|=0x4000;
//    else
//    {
//     USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
//     USART_RX_STA++;
//     if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收   
//    }   
//   }
//  }      
//  }
   //读SR后读DR清除Idle
  USART2->SR;
  USART2->DR;
   USART_ClearITPendingBit(USART1, USART_IT_TC);
  // USART_ClearITPendingBit(USART1, USART_IT_IDLE);
#if SYSTEM_SUPPORT_OS  
OSIntExit();     //退出中断
#endif
}
#endif





u8 tx[254];
int main(void)
{
int i;
delay_init(168);        //延时初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断分组配置
Init_USART1(115200);
  USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);  //使能串口1的DMA发送   
LED_Init();      //LED初始化
  for(i=0;i<254;i++)
   tx=i;
while(1)
{
USART1_TX(40);
//  for(i=0;i<40;i++)
//  {USART_SendData(USART1,tx);
//   delay_us(100);
//  }
delay_ms(1000);
  LED0= !LED0;
}
}

缓冲区的数据也都没问题啊

收到长度对,数据也不对,中间数据也不一样,但是数组是我写死的


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

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2012-6-3
在线时间
21 小时
 楼主| 发表于 2016-2-28 15:16:20 | 显示全部楼层
本帖最后由 dxhuo 于 2016-2-28 15:39 编辑

我先自己回复一个,我发现发送字符串没问题呢,自己试了一下,这么长的字符串都没问题

回复

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2012-6-3
在线时间
21 小时
 楼主| 发表于 2016-2-28 15:39:49 | 显示全部楼层
图片怎么进不来
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-21 04:05

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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