직렬+DMA+남 은 중단 부정 확 한 데이터 수신 실현

5708 단어 STM32
직렬 dma 의 사용 을 기록 해 보 세 요.dma 의 장점 은 그의 전송 이 CPU 를 거치 지 않 아 도 메모리 와 외부 장치 의 직접 양 방향 통신 을 실현 할 수 있다 는 것 입 니 다.dma 를 합 리 적 으로 사용 하면 프로그램 설 계 를 간단하게 할 수 있다.직렬 3 을 예 로 들 어 직렬 dma 의 설정 과정 을 소개 합 니 다.다른 직렬 포트 도 마찬가지 입 니 다.dma 의 채널 만 수정 하면 됩 니 다.
  우선 직렬 포트 의 설정 과정 은 일반적인 설정 과 기본적으로 일치 하지만,한 가지 설명 은 dma 를 사용 하여 정 해 지지 않 은 데 이 터 를 수신 하면 비교적 자주 사용 하 는 방법 은 빈 공간 을 이용 하여 중단 하 는 것 이다.그 러 니까 설정 할 때 RXNE 를 중단 시 키 지 마 세 요.
  직렬 포트 초기 화 시 중단 되 는 설정
  
//  RXNE   IDLE
	USART_ITConfig(USART3, USART_IT_TC,DISABLE);
	USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
	USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);

 
 
 
직렬 포트 초기 화 완료 후 dma 설정 진행
 
//DMA1      
//           ,             
//    ->    /8     /       
//DMA_CHx:DMA  CHx
//cpar:    
//cmar:     
//cndtr:      
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
	NVIC_InitTypeDef  NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;  
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
	NVIC_Init(&NVIC_InitStructure);  
	
 	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	//  DMA  
	
	DMA_DeInit(DMA_CHx);   // DMA   1         

	DMA1_MEM_LEN=cndtr;
	DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA     
	DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA     
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //      ,          
	DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA   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   x       
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA  x            
	DMA_Init(DMA_CHx, &DMA_InitStructure);  //  DMA_InitStruct         DMA   USART1_Tx_DMA_Channel       

	DMA_Cmd(DMA_CHx,ENABLE);  
}

 
 
수신 부분의 설정 입 니 다.주의해 야 할 멤버 변 수 는 DMA 입 니 다.DIR,전송 방향 설정.외부 데이터 부터 직렬 외부 장치 까지 DMA 사용DIR_PeripheralSRC 는 dma 를 초기 화하 고 직렬 에서 외부 로 전송 하려 면 DMA 를 사용 합 니 다.DIR_PeripheralDST 로 dma 를 초기 화 합 니 다.따라서 두 채널 을 보 내 고 받 을 때 두 개의 함 수 를 사용 할 수 있 으 며 하나의 매개 변수 만 다 릅 니 다.물론 바 텀 드라이브 를 작성 할 때 이 성 어 를 입구 매개 변수 에 넣 을 수도 있 습 니 다.상부 프로그램 이 호출 할 때 방향 설정 을 입력 하면 됩 니 다.
 
다음은 인 터 럽 트 서비스 함수 입 니 다.저 희 는 남 은 인 터 럽 트 를 설정 합 니 다.즉,외부 장치 가 요청 을 한 후에 이 데 이 터 를 받 은 후에 발생 하 는 인 터 럽 트 입 니 다.따라서 RNXE 인 터 럽 트 처럼 하나씩 받 을 때마다 저장 할 필요 가 없 으 며,남 은 인 터 럽 트 가 생 겼 을 때 데 이 터 는 이미 받 아 들 였 습 니 다.데 이 터 는 DMA 와 외부 에 설 치 된 맵 을 설정 할 때의 배열 에 저 장 됩 니 다.그래서 우리 의 중단 임 무 는 이 데 이 터 를 버퍼 로 옮 겨 공급 용 프로그램 으로 사용 하 는 것 입 니 다.동시에 직렬 수신 완료 플래그 를 표시 합 니 다.
 
void RX3_IT_Handler(void)
{
	uint16_t temp = 0;  
    uint16_t i = 0;  
#ifdef OS_TICKS_PER_SEC	 	//          ,     ucosII .
OSIntEnter( );
#endif
    //            
    if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)  
    {  
        temp = USART_ReceiveData( USART3 );//    
        DMA_Cmd(DMA1_Channel3,DISABLE); //  DMA   
		//    
		temp = RX3_Recv_Len - DMA_GetCurrDataCounter(DMA1_Channel3);  
		for (i = 0;i < temp;i++)  
        {  
            RX3_Buff[i] = RX3_Temp[i];  
        } 
		RX3_Point=temp;
		RX3_Point|=0x80;
		//  DMA  
		DMA_SetCurrDataCounter(DMA1_Channel3,RX3_Recv_Len);  
		//  DMA
        DMA_Cmd(DMA1_Channel3,ENABLE);    
    }
	__nop();
		
#ifdef OS_TICKS_PER_SEC	 	//          ,     ucosII .
		OSIntExit( );  											 
#endif  
}

 
 
 
dma 전송 을 한 번 시작 합 니 다(주로 직렬 로 데 이 터 를 보 냅 니 다.직렬 dma 전송 채널 을 정확하게 설정 한 후에 호출 합 니 다)
 
 
 
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{ 
	DMA_Cmd(DMA_CHx, DISABLE );  //  USART1 TX DMA1             
 	DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA   DMA     
 	DMA_Cmd(DMA_CHx, ENABLE);  //  USART1 TX DMA1        
}

직렬 dma 수신 을 열 고 직렬 초기 화 완료 후 호출 하면 dma 수신 이 완 료 됩 니 다.
 
 
void u3_dma_init(void)
{
	//  RXNE   IDLE
	USART_ITConfig(USART3, USART_IT_TC,DISABLE);
	USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
	USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);

	MYDMA_Config(DMA1_Channel3,(u32)&USART3->DR,(u32)RX3_Temp,RX3_Recv_Len);//RX
	//  DMA  
	USART_DMACmd(USART3,USART_DMAReq_Rx,ENABLE);
}

 
 
응용 인터페이스 함수:직렬 dma 에서 보 냅 니 다.만약 에 부정 확 한 데 이 터 를 보 내 면 데이터 의 끝 에 끝 표 지 를 추가 할 수 있 습 니 다.그러면 dma 는 해당 하 는 길이 의 데이터 만 보 낼 수 있 습 니 다.
void u3_dma_sendData(u8 *buff)
{
		u8 i=0;
		unsigned char* p_str;
		p_str=buff;
		//       
		//          
		while(*p_str != TXEND_SYMBOL || *( p_str + 1 ) != TXEND_SYMBOL){
			p_str++;
			if(i++>70){
				MyPrintf("error, not found txend_symbol\r\
"); return ; } } usart_dma_init(DMA1_Channel2,(u32)&USART3->DR,(u32)buff,i);//TX USART_DMACmd(USART3,USART_DMAReq_Tx,ENABLE); MYDMA_Enable(DMA1_Channel2); while(1){ if(DMA_GetFlagStatus(DMA1_FLAG_TC2)!=RESET) // 4 { DMA_ClearFlag(DMA1_FLAG_TC2);// 4 break; } DMA_GetCurrDataCounter(DMA1_Channel2);// } // MyPrintf("send done!\r
"); }

그 중 usartdma_init 함수 와 MYDMAConfig 는 방향 이라는 성어 변수 만 다 릅 니 다.여 기 는 더 이상 열거 하지 않 습 니 다.
직렬 수신 에 대해 서 는 상부 에 스 캔 함 수 를 쓸 수 있 고 수신 이 완 료 된 표지 위 치 를 계속 검사 할 수 있 습 니 다.
이로써 직렬 dma 의 송 수신 이 완료 되 었 습 니 다.
 

좋은 웹페이지 즐겨찾기