您的位置 首页 开关

STM32运用DMA加串口闲暇中止接纳数据

STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想…

STM32中,需求用串口接纳数据,是运用串口中止来接纳数据。可是用这种办法的话,就要频频进入串口中止,然后处理,功率就比较低。于是就想到用DMA来接纳串口数据,这个STM32也是支撑的。可是要害的一点,怎样知道数据接纳结束了呢?假如接纳的数据长度固定,那就好办,直接设置DMA的接纳数据个数就行了。可是假如长度不固定了,那应该怎样办了?

这个时分,就要用到STM32在串口中供给的另一个好用的东西了,便是串口闲暇中止。在STM32的串口控制器中,设置了有串口闲暇中止,即假如串口闲暇,又舱位了串口闲暇中止的话,就触发串口闲暇中止,然后程序就会跳到串口中止去碑文。有了这个,是不是能够判别什么时分串口数据接纳结束了呢?由于串口数据接纳结束后,串口总线肯定是会闲暇的嘛,那这个中止肯定是会触发的了。

还有一个问题,这串口闲暇中止是只需串口闲暇就会发生吗?其实不是的,串口闲暇中止要触发的话,是要RXNE位被置位后,串口总线闲暇才会触发的。所以咱们不必忧虑,串口数据发送结束后,会不会触发串口闲暇中止了。

下面用代码来阐明。

1、装备串口。包含设置串口的引脚装备,串口的装备,串口中止的装备,串口的接纳DMA的装备

void USART_init(void){   GPIO_InitTypeDef   GPIO_InitStructure;    USART_InitTypeDef  USART_InitStructure;    NVIC_InitTypeDef   NVIC_InitStructure;     //舱位时钟    RCC_APB2PeriphClockCmd(USART_RCC,ENABLE);    //装备TX端口    GPIO_InitStructure.GPIO_Pin = GPIO_USART_TX;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure);    //装备RX端口    GPIO_InitStructure.GPIO_Pin = GPIO_USART_RX;    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure);     //装备串口形式    USART_InitStructure.USART_BaudRate = 115200;    USART_InitStructure.USART_WordLength = USART_WordLength_8b;    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);       //中止装备    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    NVIC_Init(&NVIC_InitStructure);     /* 若总线闲暇,发生中止 */    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);     /*舱位串口DMA接纳*/    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);       USART_Cmd(USART1,ENABLE);}

代码比较简单,一看就理解了,这便是运用库函数开发的优点,代码易懂。这儿,要害的是要舱位总线闲暇中止,而且舱位串口DMA接纳。留意,不要舱位串口接纳中止,否则接纳数据就会一向发生中止了。

2、DMA装备

DMA装备,要先检查串口接纳是运用的哪个DMA的哪个通道,关于USART1_RX运用的是DMA1的5通道。

然后便是代码装备DMA了。

void DMA_init(void){   DMA_InitTypeDef    DMA_Initstructure;//   NVIC_InitTypeDef   NVIC_Initstructure;      /*舱位DMA时钟*/   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);  //   /* Enable the DMA1 Interrupt *///   NVIC_Initstructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;       //通道设置为串口1中止//   NVIC_Initstructure.NVIC_IRQChannelSubPriority = 1;     //中止呼应优先级0//   NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority=1;//   NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;        //翻开中止//   NVIC_Init(&NVIC_Initstructure);    /*DMA装备*/   DMA_Initstructure.DMA_PeripheralBaseAddr =  (u32)(&USART1->DR);;   DMA_Initstructure.DMA_MemoryBaseAddr     = (u32)receive_data;   DMA_Initstructure.DMA_DIR = DMA_DIR_PeripheralSRC;   DMA_Initstructure.DMA_BufferSize = 128;   DMA_Initstructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;   DMA_Initstructure.DMA_MemoryInc =DMA_MemoryInc_Enable;   DMA_Initstructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;   DMA_Initstructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;   DMA_Initstructure.DMA_Mode = DMA_Mode_Normal;   DMA_Initstructure.DMA_Priority = DMA_Priority_High;   DMA_Initstructure.DMA_M2M = DMA_M2M_Disable;   DMA_Init(DMA1_Channel5,&DMA_Initstructure);     //发动DMA   DMA_Cmd(DMA1_Channel5,ENABLE);    //舱位DMA发送发成中止   //DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE); }

由于这儿,不需求用到DMA中止,所以DMA中止就不要使能了。因而DMA中止装备也就不需求了。这儿,要害的是要设置DMA_DIR为DMA_DIR_PeripheralSRC,一共数据是从外设到内存。这儿设定的DMA_Mode是一般形式,即数据传输就只能一次。

3、串口中止程序编写

这个便是要害的当地了。在这儿,需求做什么了。需求对DMA设置下。当进入这个中止的时分,串口接纳的数据,已经在内存的数组中了。经过读取DMA的计数值,就能够知道接纳到了多少个数据。然后再把DMA给diable掉,从头设置接纳数据长度,在舱位DMA,接纳下一次串口数据。为什么要这么做了,由于在STM32手册中有如下阐明:

别的还有一点,串口闲暇中止触发后,硬件会主动将串口闲暇中止标志位给置1,咱们是需求将给标志位给置0的,否则又要进中止了,这个在手册中也有阐明。

代码就如下了:

void USART1_IRQHandler(void){    unsigned char num=0;    if(USART_GetITStatus(USART1,USART_IT_IDLE) == SET)    {       num = USART1->SR;       num = USART1->DR; //清USART_IT_IDLE标志       DMA_Cmd(DMA1_Channel5,DISABLE);    //封闭DMA       num = 128 -  DMA_GetCurrDataCounter(DMA1_Channel5);      //得到真实接纳数据个数         receive_data[num] = \0;       DMA1_Channel5->CNDTR=128;       //从头设置接纳数据个数          DMA_Cmd(DMA1_Channel5,ENABLE);  //舱位DMA       receive_flag = 1;           //接纳数据标志方位1    }}

要害的一点,便是要读取SR,DR,将USART_IT_IDLE标志给清掉,然后DMA设置要留意下。

在主函数中,运用下面代码测验:

int main(){    periph_init();    printf("hello world\n");    while(1)    {       while(receive_flag == 0);       receive_flag = 0;       printf("%s",receive_data);    }}

当串口接纳数据后,中止程序会使receive_flag为1,然后就跳出while循环。打印接纳到的数据。

测验成果:

发送什么,就接纳什么。

还测验了下,在波特率460800下,都仍是能正常的作业的。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/kaiguan/265316.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部