STM32
直播中

张桂兰

7年用户 1245经验值
私信 关注
[问答]

STM32串口DMA通讯接收不到数据的原因?

//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发送

}


回帖(1)

jsqueh

2024-5-9 16:18:19
STM32串口DMA通讯接收不到数据的原因可能有以下几点,请逐一排查:

1. 串口配置问题:请检查串口的波特率、数据位、停止位和奇偶校验位等参数是否与发送端(串口助手)一致。

2. DMA配置问题:请检查DMA的通道、内存地址、外设地址、数据宽度、传输方向等参数是否正确配置。

3. 中断配置问题:请检查是否正确配置了串口接收中断和DMA中断,以及是否在中断服务程序中正确处理了接收到的数据。

4. 硬件连接问题:请检查STM32的串口TX和RX引脚是否正确连接到串口助手的RX和TX引脚。

5. 程序逻辑问题:请检查程序中的逻辑是否正确,例如是否在接收到数据后正确地将数据从DMA缓存区复制到用户定义的缓冲区。

6. LED灯问题:您提到LED0和LED1会常亮,这可能是因为程序中的某个条件判断错误或者中断服务程序中的逻辑错误导致的。

建议您按照以下步骤进行排查:

1. 检查串口配置参数,确保与发送端一致。
2. 检查DMA配置参数,确保正确配置。
3. 检查中断配置,确保串口接收中断和DMA中断已正确配置。
4. 检查硬件连接,确保TX和RX引脚正确连接。
5. 检查程序逻辑,确保接收到的数据能够正确处理。
6. 检查LED灯相关的条件判断和中断服务程序,确保逻辑正确。

希望以上建议能帮助您解决问题。如果问题仍然存在,请提供更详细的代码和硬件连接信息,以便进一步分析。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分