【STM32学习】 串口接收数据 使用串口空闲中断与DMA(一)
一. 串口空闲中断
串口空闲中断,串口空闲时产生中断,也就是RXNE(RXNE位在有数据输入时自动置1)被置1开始检测直到串口空闲后,IDLE位被置为1后进入空闲中断。IDLE位只能通过软件序列来清除,即先读USART_SR,在读USART_DR(xx=USART_SR;xx=USART_DR;),并且IDLE位不能通过USART_ClearFlag()与USART_ClearITPendingBit()来清除。
二. DMA
DMA是一种数据传输方式,DMA即(Direct Memory access )直接存储器访问。外设与内存可以直接进行传输数据,通过DMAC操纵总线来控制数据的传输,这种方式能节省CPU资源。
三. 串口空闲+DMA
串口空闲中断+DMA能够用来接收不定长的数据
GPIO配置:
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitSture;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);时钟使能
GPIO_InitSture.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitSture.GPIO_Pin=GPIO_Pin_9;
GPIO_InitSture.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitSture); //pa9设置为复用推挽输出
GPIO_InitSture.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitSture.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitSture); //pa10设置为浮空输入
}
串口配置:
void USART_Configuration(void)
{
USART_InitTypeDef USART_Initsture;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//时钟使能
USART_Initsture.USART_BaudRate=115200;//波特率为115200
USART_Initsture.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控制
USART_Initsture.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//串口输入输出模式
USART_Initsture.USART_WordLength=USART_WordLength_8b;//字长8
USART_Initsture.USART_Parity=USART_Parity_No;//无奇偶校验
USART_Initsture.USART_StopBits=USART_StopBits_1;//停止位为1位
USART_Init(USART1,&USART_Initsture);//用上面的结构体初始化USART1
USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//串口中断配置,注意这里使能的是USART_IT_IDLE位而不是其他
USART_Cmd(USART1, ENABLE);//使能USART1
}
NVIC配置:
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;//通道为USART1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
DMA配置:
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel5);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//时钟使能AHB
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(ADC1->DR);//DMA的外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)(ADC1_Buffer_RX);//DMA的内存基地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//以外设作为数据源
DMA_InitStructure.DMA_BufferSize=PACKSIZE;缓存区大小为PACKSIZE字节
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//禁止内存地址自加
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//禁止外设地址自加
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//禁止内存到内存的模式
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//正常模式另外一种为循环模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先组为高
DMA_Init(DMA1_Channel5,&DMA_InitStructure);//初始化通道5,因为USART1在通道5上
DMA_Cmd(DMA1_Channel5,ENABLE);使能通道5
}
主函数:
#define PACKSIZE 50
int flag;
u8 USART1_Buffer_RX[PACKSIZE];
int main(void)
{
GPIO_Configuration();
USART_Configuration();
Delay_init();
NVIC_Configuration();
// Buffer_Init();
DMA_Configuration();
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);//USART请求接收输入
printf("hello:\n");
while(1)
{
if(flag==1)
{
printf("%s\n",USART1_Buffer_RX);
flag=0;
}
}
}
中断服务程序:
void USART1_IRQHandler(void)
{
u8 abu;
if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
{
flag=1;
abu=USART1->SR;
abu=USART1->DR; //软件序列清除空闲IDLE位
DMA_Cmd(DMA1_Channel5,DISABLE);//必须关闭通道5才能进行重新设置
abu=128-DMA_GetCurrDataCounter(DMA1_Channel5);//128减去最近接收的数据长度
USART1_Buffer_RX[abu]=0;
DMA1_Channel5->CNDTR=PACKSIZE;
DMA_SetCurrDataCounter(DMA1_Channel5,PACKSIZE);
DMA_Cmd(DMA1_Channel5,ENABLE);//设置数据长度完成重新开启DMA通道5
}
}
整了一天发篇文章记录一下。。。。。。。