STM32F4的串口DMA接收,寄存器版本

2019-07-20 21:09发布

本帖最后由 mack13013 于 2016-7-25 20:37 编辑

谁用STM32F4的串口DMA接收了?
有没有寄存器版本的代码?

我用串口DMA,DMA总是不能触发,每次接收数据都是0。

空闲中断倒是好用,也能实现不定长、非换行数据接收,只是放着DMA这个个东西在那里浪费者总不是个事。

自己的代码贴出来吧,哪位大侠帮忙看看什么问题.

[mw_shl_code=c,true]


int main(void)
{
    Stm32_Clock_Init(336,8,2,7);                        //设置时钟,168Mhz
    delay_init(168);                                                //初始化延时函数

    Board_Init();
    DMA_Config(DMA1_Stream5, 4, (u32)USART2 ->DR, (u32)USART_RX_BUF, USART_BUFF_LEN, 0);
        usart2_init(42,9600);        //串口初始化为9600
   
   
   
   

   
    for(;;)
    {
    }
}
[/mw_shl_code]

[mw_shl_code=c,true]

//串口2中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_BUFF_LEN];    //接收缓冲,最大USART_BUFF_LEN个字节.

u8 USART_TX_BUF[USART_BUFF_LEN];    //发送缓冲,最大USART_BUFF_LEN个字节.

u32 unRcvCnt = 0;
u8 ucRcvLen = 0;

void USART2_IRQHandler(void)
{
    volatile u8 ucRcv;
    u8 ucSndCnt = 0;

   
    if(USART2 ->SR & (1 << 4))//线路空闲
    {
        USART_RX_BUF[ucRcvLen] = USART2->DR; //这里读取一下,防止硬件检测未读取
        ucRcvLen++;
        
        unRcvCnt++;
//        if(DMA1 ->HISR & (1 << 27))
//        {
//            DMA1 ->HIFCR |= (1 << 27);
//        }
        
        
//        unRcvLen = DMA1_Stream5 ->NDTR;
        
//        if(16 == USART_BUFF_LEN - DMA1_Stream5 ->NDTR)//接收到了正常的16字节数据
//        {
//        }
        
//        memcpy(USART_TX_BUF, &unRcvCnt, sizeof(u32));
//        USART_TX_BUF[sizeof(u32)] = 0;
        
        memcpy(USART_TX_BUF, USART_RX_BUF, 16);

        for(ucSndCnt = 0; ucSndCnt < DEFAULT_RCVSND_LEN; ucSndCnt++)
        {
            while((USART2->SR&0X40)==0)
            {
                ;//等待发送空闲
            }
            USART2 ->DR = USART_TX_BUF[ucSndCnt];
        }
        USART2 ->SR &= ~(1 << 4);//清除空闲中断状态
        DMA_Enable(DMA1_Stream5);
        ucRcvLen = 0;
    }
}
//初始化IO 串口2
//pclk2CLK2时钟频率(Mhz)
//bound:波特率
void usart2_init(u32 pclk2, u32 bound)
{
    float temp;
    u16 mantissa;
    u16 fraction;
    temp=(float)(pclk2 * 1000000) / (bound * 16);//得到USARTDIV@OVER8=0
    mantissa = temp;                                 //得到整数部分
    fraction = (temp - mantissa) * 16; //得到小数部分@OVER8=0
    mantissa <<= 4;
    mantissa += fraction;
    //RCC->AHB1ENR |= 1 << 3;           //使能PORTD口时钟
    RCC->APB1ENR |= 1 << 17;          //使能串口2时钟
    GPIO_Set(GPIOD, PIN5 | PIN6, GPIO_MODE_AF, GPIO_OTYPE_PP, GPIO_SPEED_50M, GPIO_PUPD_PU);//PD5、PD6复用功能,推挽上拉输出
    GPIO_AF_Set(GPIOD, 5, 7);     //PD5,AF7
    GPIO_AF_Set(GPIOD, 6, 7);     //PD5,AF7
    //波特率设置
    USART2 ->BRR = mantissa;         //波特率设置
    USART2 ->CR1 &= ~(1 << 15);         //设置OVER8=0
    USART2 ->CR1 |= 1 << 3;          //串口发送使能
    //使能接收中断
    USART2 ->CR1 |= 1 << 2;          //串口接收使能
//   USART2 ->CR1 |= 1 << 5;            //接收缓冲区非空中断使能
    USART2 ->CR1 |= 1 << 4;     //使能空闲中断
    USART2 ->CR3 |= 1 << 6;     //串口2使能DMA接收
    //USART2 ->CR3 |= 1 << 7;     //串口2使能DMA发送

    MY_NVIC_Init(3, 3, USART2_IRQn, 2);//组2,最低优先级

    USART2->CR1 |= 1 << 13;          //串口使能
}









[/mw_shl_code]




[mw_shl_code=c,true]

//DMAx的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//chxMA通道选择,范围:0~7
//par:外设地址
//mar:存储器地址
//ndtr:数据传输量  
//, u8 ucStreamTo:数据传输方向  0:外设到存储器   1: 存储器到外设  2:存储器到存储器
void DMA_Config(DMA_Stream_TypeDef *DMA_Streamx, u8 chx, u32 par, u32 mar, u16 ndtr, u8 ucStreamTo)
{
        DMA_TypeDef *DMAx;
        u8 streamx;
        if((u32)DMA_Streamx > (u32)DMA2)//得到当前stream是属于DMA2还是DMA1
        {
                DMAx = DMA2;
                RCC ->AHB1ENR |= 1 << 22;//DMA2时钟使能
        }
    else
        {
                DMAx = DMA1;
                 RCC->AHB1ENR |= 1 << 21;//DMA1时钟使能
        }
   
        while(DMA_Streamx ->CR & 0X01)
    {
        ;//等待DMA可配置
    }
   
        streamx = (((u32)DMA_Streamx-(u32)DMAx) - 0X10) / 0X18;                //得到stream通道号
   
         if(streamx>=6)
    {
        DMAx ->HIFCR|=0X3D << (6*(streamx-6)+16);        //清空之前该stream上的所有中断标志
    }
        else if(streamx >= 4)
    {
        DMAx ->HIFCR|=0X3D << (6*(streamx-4));    //清空之前该stream上的所有中断标志
    }
        else if(streamx >= 2)
    {
        DMAx ->LIFCR|=0X3D << (6*(streamx-2)+16);//清空之前该stream上的所有中断标志
    }
        else
    {
        DMAx ->LIFCR |= 0X3D << (6*streamx);                                                //清空之前该stream上的所有中断标志
    }
        
        DMA_Streamx ->AR = par;                //DMA外设地址
        DMA_Streamx ->M0AR = mar;                //DMA 存储器0地址
        DMA_Streamx ->NDTR = ndtr;                //长度
        DMA_Streamx ->CR = 0;                        //先全部复位CR寄存器值

    DMA_Streamx ->CR |= (ucStreamTo & 3) << 6;                //传输方向

        DMA_Streamx ->CR |= 0 << 8;                    //非循环模式(即使用普通模式)
        DMA_Streamx ->CR |= 0 << 9;                    //外设非增量模式
        DMA_Streamx ->CR |= 1 << 10;                //存储器增量模式
        DMA_Streamx ->CR |= 0 << 11;                //外设数据长度:8位
        DMA_Streamx ->CR |= 0 << 13;                //存储器数据长度:8位
        DMA_Streamx ->CR |= 1 << 16;                //中等优先级
   
        DMA_Streamx ->CR |= 0 << 21;                //外设突发单次传输
        DMA_Streamx ->CR |= 0 << 23;                //存储器突发单次传输
        DMA_Streamx ->CR |= (u32)chx << 25; //通道选择
        //DMA_Streamx ->FCR=0X21;        //FIFO控制寄存器
   
    DMA_Enable(DMA1_Stream5);
}
//开启一次DMA传输
//DMA_StreamxMA数据流,DMA1_Stream0~7/DMA2_Stream0~7
//ndtr:数据传输量  
void DMA_Enable(DMA_Stream_TypeDef *DMA_Streamx)
{
        DMA_Streamx ->CR &= ~(1<<0);         //关闭DMA传输
        while(DMA_Streamx ->CR & 0X1)
    {
        ;        //确保DMA可以被设置  
    }
        DMA_Streamx ->NDTR = DEFAULT_RCVSND_LEN;                //DMA 数据长度
        DMA_Streamx ->CR |= 1 << 0;                //开启DMA传输
}         




[/mw_shl_code]











友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
mack13013
1楼-- · 2019-07-21 02:28
 精彩回答 2  元偷偷看……
mack13013
2楼-- · 2019-07-21 03:23
使用F4寄存器版,DMA接收串口数据,获取数据长度失败,原因是DMA的NDTR在接收到正常数据之后,会恢复到初始值,
仅在第一次接收之后能获取正常的长度,之后的获取都是初始值。

跟踪库函数版本,也是获取NDTR数据。不知道是不是可用。

不知道是不是需要volatile修饰才行。
mack13013
3楼-- · 2019-07-21 08:31
mack13013 发表于 2016-7-25 21:50
使用F4寄存器版,DMA接收串口数据,获取数据长度失败,原因是DMA的NDTR在接收到正常数据之后,会恢复到初始 ...

看了一下定义,NDTR是加了__IO修饰符的。  这下无解了,看样子确实是硬件设置初始值的。

看下CR或者SR哪里还能设置吧
mack13013
4楼-- · 2019-07-21 12:29
mack13013 发表于 2016-7-25 21:52
看了一下定义,NDTR是加了__IO修饰符的。  这下无解了,看样子确实是硬件设置初始值的。

看下CR或者SR ...

使能TCIE、HTIE中断,失败。

难不成STM32F407有缺陷?  参考手册上也说是会复位,如果复位的话,如何判断接收数据长度??

看来串口接收只能抛弃DMA了

一周热门 更多>