本讲主要实现usart RX的实现,主要分几部分的应用
1. USART 1 RX polling的实现
2. USART1 RX DMA的实现
3. USART1 RX DMA中断的实现
4. 配合着TIMER进行RX DMA中断实现实现(用途很大)
本文章不在对寄存器贴图,直接上代码以及运行图,有兴趣的可以去调试下看看寄存器,以下历程都必须调用Init函数,Init函数源码
void USART1_Init()
{
/* 1. ENABLE USART1 GPIOA CLOCK */
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
/* 2. ENABLE USART1 IN APB2 BUS CLOCK */
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
/* 3. CONFIG GPIOA PA9 AF MODE */
GPIOA->CRH &= ~(GPIO_CRH_MODE9 | GPIO_CRH_CNF9);
GPIOA->CRH |= GPIO_CRH_MODE9 | GPIO_CRH_CNF9_1;
GPIOA->CRH &= ~(GPIO_CRH_MODE10 | GPIO_CRH_CNF10);
GPIOA->CRH |= GPIO_CRH_CNF10_1;
/* 4. CONFIG USART1 BAUD RATE 115200 */
USART1->BRR |= 0x271;
/* 5. ENBALE TRANSPORT AND ENABLE USART1 */
USART1->CR1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
}
例1:USART1 RX Polling实现
代码:
void USART1_RX_Polling()
{
int index = 0;
while(1)
{
if((USART1->SR & USART_SR_RXNE) != 0)
{
if(index > 50)
break;
buffer[index++] = USART1->DR;
}
}
printf("receive :%s",buffer);
}
运行效果图,直到收到index >50,会整个打印出来
例2:USART1 RX DMA的实现,源码:
void USART1_RX_DMA()
{
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
USART1->CR3 |= USART_CR3_DMAR;
/* 6. CONFIG DMA */
DMA1_Channel5->CMAR = (uint32_t)buffer;
DMA1_Channel5->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel5->CNDTR = 20;
DMA1_Channel5->CCR |= DMA_CCR5_PL | DMA_CCR5_MINC | DMA_CCR5_EN;
while(DMA1_Channel5->CNDTR != 0);
printf("RX :%s\n",buffer);
}
运行效果图,DMA搬运20个数据,等待搬运完成,就会打印出来
例3:USART1 RX DMA中断的实现
程序源码:
void DMA1_Channel5_IRQHandler(void)
{
TIM2->EGR = TIM_EGR_UG;
TIM2->SR &= ~TIM_SR_UIF;
NVIC_ClearPendingIRQ(TIM2_IRQn);
if (DMA1->ISR & DMA_ISR_HTIF5)
{
DMA1->IFCR = DMA_IFCR_CHTIF5;
printf("HTIF: %d\n", DMA1_Channel5->CNDTR);
}
if (DMA1->ISR & DMA_ISR_TCIF5)
{
DMA1->IFCR = DMA_IFCR_CTCIF5;
printf("TCIF: %d\n", DMA1_Channel5->CNDTR);
}
}
void USART1_RX_DMA_IRPT()
{
NVIC_SetPriorityGrouping(4);
NVIC_SetPriority(DMA1_Channel5_IRQn, 1);
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
USART1->CR3 |= USART_CR3_DMAR;
/* 6. CONFIG DMA */
DMA1_Channel5->CMAR = (uint32_t)buffer;
DMA1_Channel5->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel5->CNDTR = 20;
DMA1_Channel5->CCR |= DMA_CCR5_PL | DMA_CCR5_MINC | DMA_CCR5_EN | DMA_CCR5_HTIE | DMA_CCR5_TCIE;
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
while(1);
}
运行图,从串口发送数据,不光发送多少个,发送10个时候,会触发发送一半中断,发送到20个的时候,会触发发送完成中断
例4:
配合着TIMER进行RX DMA中断实现实现
源码:
void TIM2_IRQHandler(void)
{
TIM2->SR &= ~TIM_SR_UIF;
printf("timeout! CNDTR=%d\n", DMA1_Channel5->CNDTR);
}
void Time2_Enable(int arr,int psc)
{
RCC->APB1ENR = RCC_APB1ENR_TIM2EN; // 72M clock
TIM2->ARR = arr;
TIM2->PSC = psc;
TIM2->EGR = TIM_EGR_UG;
TIM2->CR1 = TIM_CR1_URS;
TIM2->DIER = TIM_DIER_UIE;
TIM2->CR1 |= TIM_CR1_CEN;
NVIC_SetPriority(TIM2_IRQn, 1);
NVIC_EnableIRQ(TIM2_IRQn);
}
void DMA1_Channel5_IRQHandler(void)
{
TIM2->EGR = TIM_EGR_UG;
TIM2->SR &= ~TIM_SR_UIF;
NVIC_ClearPendingIRQ(TIM2_IRQn);
if (DMA1->ISR & DMA_ISR_HTIF5)
{
DMA1->IFCR = DMA_IFCR_CHTIF5;
printf("HTIF: %d\n", DMA1_Channel5->CNDTR);
}
if (DMA1->ISR & DMA_ISR_TCIF5)
{
DMA1->IFCR = DMA_IFCR_CTCIF5;
printf("TCIF: %d\n", DMA1_Channel5->CNDTR);
}
}
void USART1_RX_DMA_IRPT()
{
NVIC_SetPriorityGrouping(4);
NVIC_SetPriority(DMA1_Channel5_IRQn, 1);
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
USART1->CR3 |= USART_CR3_DMAR;
/* 6. CONFIG DMA */
DMA1_Channel5->CMAR = (uint32_t)buffer;
DMA1_Channel5->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel5->CNDTR = 20;
DMA1_Channel5->CCR |= DMA_CCR5_PL | DMA_CCR5_MINC | DMA_CCR5_EN | DMA_CCR5_HTIE | DMA_CCR5_TCIE;
NVIC_EnableIRQ(DMA1_Channel5_IRQn);
while(1);
}
运行效果图,timer每2S触发一次中断,打印DMA还需要传输多少数据才能完成,知道串口发送完20byte数据