STM32串口通讯收不到数据求助

2019-07-14 15:57发布

//STM32串口DMA通讯接收不到数据
//请各位大神帮忙看看,下面的DMA配置问题出在哪里
//程序编写思路是:用串口助手发数据给STM32的串口2,收到数据后返回收到的数据给串口助手;
//现在遇到的问题:用串口助手发数据给它,但不能返回数据,LED0和LED1会常亮;

//小弟初学,这个问题弄了一个星期还没有解决,望大家高抬贵手帮帮我;
//谢谢




u8 rcv_num_temp=0;  //接收到的数据长度临时缓存
u8 rcv_num=0;  //接收到的数据长度缓存

u8 rcv_bufferfer_temp[128];  //接收数据临时缓存,最大64个字节
u8 rcv_buffer[128];  //接收缓存,最大64个字节

u8 rcv_complete_temp=0;  //一帧接收完成临时缓存(1为完成)
u8 rcv_complete=0;     //接收完成标志   1为完成

u8 send_complete=0;    //发送完成标志   1为完成




//USART2参数配置函数
void USART2_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART2_InitStructure;
      
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);  //使能GPIOD时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);  //使能USART2时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //开启DMA1时钟
      
USART_DeInit(USART2);

//发送接收控制模式      
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;  //PD7
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure);

//USART2-TX      
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;  //PA2
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;  //复用推挽
GPIO_Init(GPIOA,&GPIO_InitStructure);

//USART2-RX      
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;  //PA3
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure);

RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE);//复位串口2
RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE);//停止复位

//USART2通讯协议
USART2_InitStructure.USART_BaudRate=115200;  //波特率115200
USART2_InitStructure.USART_WordLength=USART_WordLength_8b;  //数据位8位
USART2_InitStructure.USART_StopBits=USART_StopBits_1;  //停止位1位
USART2_InitStructure.USART_Parity=USART_Parity_No ;  //无校验
USART2_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;  //无硬件流
USART2_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;  //发送/接收使能
USART_Init(USART2,&USART2_InitStructure);  //初始化USART2成员变量

USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);  //开启串口空闲IDEL中断
USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);  //开启串口DMA接收
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);  //开启串口DMA发送

RS485_TX_EN=0;                        //默认为接收模式
USART_Cmd(USART2,ENABLE);  //串口使能
}      



//USART2中断配置函数
void USART2_NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
      
  NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;  //USART2全局中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;  //抢占优先级为2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;  //子优先级为0
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;  //通道使能
  NVIC_Init(&NVIC_InitStructure);  //初始化中断成员变量
}



//USART2初始化函数
void USART2_Init(void)
{
  USART2_Configuration( );
  USART2_NVIC_Configuration( );
}





//DMA1_USART2_RX参数配置函数
void DMA1_USART2_RX_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //开启DMA1时钟
      
DMA_Cmd(DMA1_Channel6, DISABLE);  //关DMA1通道6
DMA_DeInit(DMA1_Channel6);  //恢复为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART2->DR;  //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = rcv_bufferfer_temp[0];  //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //设置外设为数据源
DMA_InitStructure.DMA_BufferSize = 128;  //DMA缓存大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //外设数据宽度8位,一个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  //内存数据宽度8位,一个字节
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //单次传输模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  //优先级设置
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //关闭内存到内存的DMA模式
DMA_Init(DMA1_Channel6, &DMA_InitStructure);   //初始化DMA成员变量
DMA_ClearFlag(DMA1_FLAG_GL6);  //清除DMA1所有标志
      
// DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);   //开启DMA1通道6传输完成中断
      
DMA_Cmd(DMA1_Channel6, ENABLE);  //开启DMA1通道6,等待接收数据
}


/**************************************************************************************************
//当使用总线空闲检测一帧数据是否发完时,DMA1_USART2_RX_NVIC_Configuration( )就不需要
//DMA1_USART2_RX中断配置函数
void DMA1_USART2_RX_NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;  //DMA1_USART2接收中断通道6  
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //抢占优先级为2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //子优先级为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //通道使能
  NVIC_Init(&NVIC_InitStructure);  //初始化成员变量
}
**************************************************************************************************/


//DMA1_USART2_RX初始化函数
void DMA1_USART2_RX_Init(void)
{
  DMA1_USART2_RX_Configuration( );
//        DMA1_USART2_RX_NVIC_Configuration( );
}





//DMA1_USART2_TX参数配置函数
void DMA1_USART2_TX_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //开启DMA1时钟  

DMA_Cmd(DMA1_Channel7, DISABLE);  //关DMA1通道7
DMA_DeInit(DMA1_Channel7);  //恢复为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART2->DR;  //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = rcv_bufferfer_temp[0];  //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //设置外设为目标
DMA_InitStructure.DMA_BufferSize = rcv_num_temp;   //需要发送的字节数
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //外设数据宽度8位,一个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  //内存数据宽度8位,一个字节
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //单次传输模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  //优先级设置
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //关闭内存到内存的DMA模式
DMA_Init(DMA1_Channel7, &DMA_InitStructure);   //初始化DMA成员变量
DMA_ClearFlag(DMA1_FLAG_GL7);  //清除DMA所有标志      
      
DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);   //开启DMA1通道7传输完成中断
      
DMA_Cmd(DMA1_Channel7, ENABLE);  //开启DMA1通道7,等待发送数据
}



//DMA1_USART2_TX中断配置函数
void DMA1_USART2_TX_NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;  //DMA1_USART2接收中断通道7
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //抢占优先级为2
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //子优先级为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  //通道使能
  NVIC_Init(&NVIC_InitStructure);  //初始化成员变量
}



//DMA1_USART2_TX初始化函数
void DMA1_USART2_TX_Init(void)
{
  DMA1_USART2_TX_Configuration( );
  DMA1_USART2_TX_NVIC_Configuration( );
}



//DMA1_USART2初始化函数
void DMA1_USART2_Init(void)
{
  DMA1_USART2_RX_Init( );  //DMA1_USART2_RX初始化函数
  DMA1_USART2_TX_Init( );  //DMA1_USART2_TX初始化函数

}




//RS485_USART2初始化函数
void RS485_USART2_Init(void)
{
  USART2_Init( );  //USART2初始化函数
  DMA1_USART2_Init( );  //DMA1_USART2初始化函数
}





//USART2数据接收中断函数
void USART2_IRQHandler(void)
{
  u8 Clear=Clear;

  LED0=0;
      
  if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)  //空闲中断
  {                       
     Clear=USART2->SR;  //读SR寄存器
     Clear=USART2->DR;  //读DR寄存器(先读SR再读DR,就是为了清除IDLE中断)               
               
     DMA_Cmd( DMA1_Channel6, DISABLE );  //关DMA1通道6
                  
     rcv_complete_temp= 1;          //一帧接收完成临时缓存               
  }
}





//USART2_DMA1数据发送中断函数
void DMA1_Channel7_IRQHandler(void)
{
  if(DMA_GetITStatus(DMA1_FLAG_TC7))  //如果DMA1通道7发送完成
  {
     LED1=1;
               
     DMA_Cmd( DMA1_Channel7, DISABLE );   // 关闭DMA通道7
     DMA_ClearITPendingBit( DMA1_FLAG_GL7 );  // 清除标志
                              
     send_complete=1;  //发送完成
  }
}






//USART2_DMA1数据接收函数
void USART2_DMA1_Rx_Data(void)
{      
  if( rcv_complete_temp== 0 )  //如果未接收到一帧数据
        {
           DMA_Cmd( DMA1_Channel6, DISABLE );  //关DMA1通道6
           DMA_ClearFlag( DMA1_FLAG_GL6 );  //清除DMA1所有标志
           DMA1_Channel6->CNDTR = 128;  //重新赋值计数值(DMA缓存大小)
           DMA_Cmd(DMA1_Channel6, ENABLE);  //开启DMA1通道6,等待接收数据
        }

  if( rcv_complete_temp== 1 )  //如果接收到一帧数据
  {
               
    DMA_Cmd( DMA1_Channel6, DISABLE );  //关DMA1通道6
    DMA_ClearFlag( DMA1_FLAG_GL6 );  //清除DMA1所有标志
    rcv_num_temp= 128- DMA_GetCurrDataCounter( DMA1_Channel6 );  //获取接收到的字节数

    LED0=1;

               
//  if( rcv_bufferfer_temp[0]>0 )  LED0=0;
               
               
    rcv_complete=1;  //接收完成  
  }
}





//USART2_DMA1数据发送函数
void USART2_DMA1_Tx_Data(void)
{      

  LED1=0;
      
  rcv_complete_temp= 0;
  DMA_Cmd( DMA1_Channel7, DISABLE );   // 关闭DMA通道
  DMA_ClearFlag(DMA1_FLAG_GL7);  //清除DMA所有标志      
  DMA1_Channel7->CNDTR = rcv_num_temp;  // 设置要发送的字节数      
  DMA_Cmd( DMA1_Channel7, ENABLE );  //开始DMA发送
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
13条回答
陈囝囝100
1楼-- · 2019-07-14 19:57
:)
请叫我杰西卡
2楼-- · 2019-07-14 22:27
hfjydz2013 发表于 2018-11-19 09:27
不要DMA 直接中断 开启接收非空中断允许  那样接收到一个 就send一个

我之前就是用接收非空做的,很稳定但是很慢,所有现在做成DMA形式的,也参考了许多网上的资料,现在找不到问题出在哪里
kdsnvjsnjk
3楼-- · 2019-07-15 02:20
DMA发送要主动触发的,485发送和接受的控制信号是相反的,串口接收中断一般是检测RXNE标志,不是IDLE。。。建议你看看原子哥的例程。。。
请叫我杰西卡
4楼-- · 2019-07-15 07:19
 精彩回答 2  元偷偷看……
kdsnvjsnjk
5楼-- · 2019-07-15 08:42
请叫我杰西卡 发表于 2018-11-19 10:29
//USART2½ÓÊÕÖжϺ¯Êý
void USART2_IRQHandler(void)  //Êý¾Ý½ÓÊÕÖжϠ      
{       

115200的波特率不会慢的。。。还是建议你看看开发板例程,如:正点原子,野火。。。
AHTLTC
6楼-- · 2019-07-15 10:38
好多。。看不下去了。。。

一周热门 更多>