使用DMA+串口IDLE中断,可以实现,DMA不定长接收数据
串口配置初始化:
void usart1_config( u32 Baud, u8 IT_Rx )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1, ENABLE ); //配置串口1时钟
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE); //配置GPIO时钟
/*串口1引脚设置*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //配置A9为Tx
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置输出频率为50MHz
GPIO_Init( GPIOA, &GPIO_InitStructure ); //写入寄存器
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //配置A10为Rx
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //设置为浮空输入
GPIO_Init( GPIOA, &GPIO_InitStructure ); //写入寄存器
/*串口1模式设置*/
USART_InitStructure.USART_BaudRate = Baud; //设置波特率
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 ); //向寄存器写入配置参数
if( IT_Rx ) //如果为1则设置为串口1接收中断
{
usart1_NVIC_configuration(); //串口1中断模式配置
// USART_ITConfig( USART1, USART_IT_RXNE,ENABLE ); //使能串口1接收中断 配置串口DMA接收,就不要再使用串口中断接收,会导致数据接收错误
USART_ITConfig( USART1,USART_IT_IDLE, ENABLE); //使能串口1空闲中断
}
USART_Cmd( USART1, ENABLE ); //使能串口1
}
/***************************************************************************
*函数名:USART1_NVIC_Configuration
*描述:配置USART1接收中断
*输入:无
*输出:无
*调用:内部调用
***************************************************************************/
void usart1_NVIC_configuration( void )
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); //设置中断组别为4组,如果设置过了,就不要再设置,一个程序,只能设置一次
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6; //主优先级6
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init( &NVIC_InitStructure ); //写入寄存器
}串口中断函数:

void USART1_IRQHandler(void){
u8 clearflag = 0;
if( USART_GetITStatus( USART1, USART_IT_IDLE) != RESET ){ //总线空闲,表示数据接收完成
// USART_ClearFlag( USART1, USART_FLAG_IDLE ); //清除标志,这个清除无法使用,如果使用这个方法,是清除不掉标志位的(如果开启串口接收中断,然后用这个则可以清除标志位)
// USART_ClearITPendingBit(USART1,USART_FLAG_IDLE);
clearflag = USART1 ->SR; //只能通过读取标志位的方式将数据清零
clearflag = USART1 ->DR;
//
printf("接收完成");
flag_send = 1;
//重新初始化DMA,等待下一次接收数据,也就是接着从0开始接收
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA_Cmd( DMA1_Channel5, DISABLE );
DMA_SetCurrDataCounter( DMA1_Channel5,5 ); //这个长度最好是和数组的长度一样,这个代表着接收到5个数据后又回从0开始(覆盖),也就是一次传输多少个数据
DMA_Cmd( DMA1_Channel5, ENABLE );
}
}注意事项:需要注意的就是在中断函数中,需要注意清除标志位的方法,以及每一次DMA接收完都需要重新开启DMA接收
DMA初始化
void DMA_Config(){
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE ); //启动DMA时钟
DMA_DeInit( DMA1_Channel5 ); //将通道设置为缺省
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR; //外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Data; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //将外设地址设置为源地址,也就是数据由外设到内存
DMA_InitStructure.DMA_BufferSize = 0; //设置DMA缓冲区大小为128个 字节/半字/字
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设的数据宽度为字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存的数据宽度为字节
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址,不增加
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址,增加,一次加1
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //不是内存到内存
DMA_InitStructure.DMA_Mode =DMA_Mode_Circular; //正常传输,也就是传输一次完成后,不在重复传输
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //设置优先级为中等
DMA_Init( DMA1_Channel5, &DMA_InitStructure );
}启动DMA,开始接收数据
///启动DMA
void DMA_Start(){
// USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
DMA_Cmd( DMA1_Channel5, DISABLE );
DMA_SetCurrDataCounter( DMA1_Channel5,5 ); //这个长度最好是和数组的长度一样,这个代表着接收到5个数据后又回从0开始(覆盖),也就是一次传输多少个数据
DMA_Cmd( DMA1_Channel5, ENABLE );
while( 1 ){
// if( DMA_GetFlagStatus( DMA1_IT_TC5 ) == SET ){ //这个标志位和DMA_SetDataCurrenter中的数据长度有关,这里的完成是指:如果设置为10,那么传输10个就表示完成了,就置位了
// printf("传输完成\r\n");
// printf( "%s \r\n", Data);
// DMA_ClearFlag( DMA1_IT_TC5 );
// }
// if( DMA_GetFlagStatus( DMA1_IT_HT5 ) == SET ){
// printf("传输一半\r\n");
// printf( "%s \r\n", Data);
// DMA_ClearFlag( DMA1_IT_HT5 );
// }
//////如果串口空闲,就代表传输完成,可以继续下一次接受了
if( SReceive_OK == 1 ){
SReceive_OK = 0;
printf("%s",Data);
// ///重新初始化DMA
// USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
// DMA_Cmd( DMA1_Channel5, DISABLE );
// DMA_SetCurrDataCounter( DMA1_Channel5,5 ); //这个长度最好是和数组的长度一样,这个代表着接收到5个数据后又回从0开始(覆盖),也就是一次传输多少个数据
// DMA_Cmd( DMA1_Channel5, ENABLE );
}
// printf("当前传输进度:%0.2f %c", ( 1 - DMA_GetCurrDataCounter( DMA1_Channel5 )/ 10.0) * 100 , bfh );
// printf( "%s \r\n", Data);
//memset(USART_RX_BUF,,); //清空数组
}
}#好好学习!