OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2084|回复: 0

F103 串口DMA只能收发一次,复位之后才能再次收发为什么啊?

[复制链接]

2

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2023-5-23
在线时间
22 小时
发表于 2023-9-12 10:37:40 | 显示全部楼层 |阅读模式
#include "stm32f10x.h"
#include "mydma.h"

u8 USART2_TX_BUF[USART2_MAX_TX_LEN];         //发送缓冲,最大USART2_MAX_TX_LEN字节
u8 u1rxbuf[USART2_MAX_RX_LEN];                        //发送数据缓冲区1
u8 u2rxbuf[USART2_MAX_RX_LEN];                        //发送数据缓冲区2
u8 witchbuf=0;                                  //标记当前使用的是哪个缓冲区,0:使用u1rxbuf;1:使用u2rxbuf
u8 USART2_TX_FLAG=0;                                        //USART2发送标志,启动发送时置1
u8 USART2_RX_FLAG=0;                                        //USART2接收标志,启动接收时置1

//1.USART2初始化
void Initial_UART2(unsigned long baudrate)
{
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);        //使能USART2,GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOD,&GPIO_InitStructure);

    GPIO_ResetBits(GPIOD,GPIO_Pin_7);
       
        //USART2_TX   GPIOA.2初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                                                                                //PA.2
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                                                        //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                                                //GPIO速率50MHz
        GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                                        //初始化GPIOA.2
       
        //USART2_RX          GPIOA.3初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                                                                                //PA.3
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                                                        //浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);                                                                                        //初始化GPIOA.3
         
        //USART 初始化设置
        USART_InitStructure.USART_BaudRate = baudrate;                                                                        //串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;                                                //字长为8位数据格式
        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(USART2, &USART_InitStructure);                                                                                 //初始化串口2
       
        //中断开启设置
        USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);                                                                        //开启检测串口空闲状态中断
        USART_ClearFlag(USART2,USART_FLAG_TC);                                                                                        //清除USART2标志位
       
        USART_Cmd(USART2, ENABLE);                                                                                                                //使能串口2
       
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;                                                                //NVIC通道设置
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;                                                //抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                                                                //响应优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                                                                        //根据指定的参数初始化NVIC寄存器
       
        DMA1_USART2_Init();                                                                                                                                //DMA1_USART2初始化
}

//2.DMA初始化
void DMA1_USART2_Init(void)
{
        DMA_InitTypeDef DMA1_Init;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);                                                //使能DMA1时钟

        //DMA_USART2_RX  USART2->RAM的数据传输
        DMA_DeInit(DMA1_Channel6);                                                                                                //将DMA的通道6寄存器重设为缺省值
        DMA1_Init.DMA_PeripheralBaseAddr = (u32)(&USART2->DR);                                        //启动传输前装入实际RAM地址
        DMA1_Init.DMA_MemoryBaseAddr = (u32)u1rxbuf;                                            //设置接收缓冲区首地址
        DMA1_Init.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                //数据传输方向,从外设读取到内存
        DMA1_Init.DMA_BufferSize = USART2_MAX_RX_LEN;                                                        //DMA通道的DMA缓存的大小
        DMA1_Init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                //外设地址寄存器不变
        DMA1_Init.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //内存地址寄存器递增
        DMA1_Init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;                        //数据宽度为8位
        DMA1_Init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                                        //数据宽度为8位
        DMA1_Init.DMA_Mode = DMA_Mode_Normal;                                                                        //工作在正常模式
        DMA1_Init.DMA_Priority = DMA_Priority_High;                                                         //DMA通道 x拥有高优先级
        DMA1_Init.DMA_M2M = DMA_M2M_Disable;                                                                        //DMA通道x没有设置为内存到内存传输
         
        DMA_Init(DMA1_Channel6,&DMA1_Init);                                                                         //对DMA通道6进行初始化
       
        //DMA_USART2_TX  RAM->USART2的数据传输
        DMA_DeInit(DMA1_Channel7);                                                                                                //将DMA的通道7寄存器重设为缺省值
        DMA1_Init.DMA_PeripheralBaseAddr = (u32)(&USART2->DR);                                        //启动传输前装入实际RAM地址
        DMA1_Init.DMA_MemoryBaseAddr = (u32)USART2_TX_BUF;                              //设置发送缓冲区首地址
        DMA1_Init.DMA_DIR = DMA_DIR_PeripheralDST;                                                                 //数据传输方向,从内存发送到外设
        DMA1_Init.DMA_BufferSize = USART2_MAX_TX_LEN;                                                        //DMA通道的DMA缓存的大小
        DMA1_Init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                //外设地址寄存器不变
        DMA1_Init.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                        //内存地址寄存器递增
        DMA1_Init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;                        //数据宽度为8位
        DMA1_Init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                                        //数据宽度为8位
        DMA1_Init.DMA_Mode = DMA_Mode_Normal;                                                                        //工作在正常模式
        DMA1_Init.DMA_Priority = DMA_Priority_High;                                                         //DMA通道 x拥有高优先级
        DMA1_Init.DMA_M2M = DMA_M2M_Disable;                                                                        //DMA通道x没有设置为内存到内存传输

        DMA_Init(DMA1_Channel7,&DMA1_Init);                                                                         //对DMA通道7进行初始化
       
        //DMA1通道6 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;                                //NVIC通道设置
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;                                //抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                                                //子优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                                                        //根据指定的参数初始化NVIC寄存器

        //DMA1通道7 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;                                //NVIC通道设置
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;                                //抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                                                //子优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                                                        //根据指定的参数初始化NVIC寄存器

        DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);                                                        //开USART2 Rx DMA中断
        DMA_ITConfig(DMA1_Channel7,DMA_IT_TC,ENABLE);                                                        //开USART2 Tx DMA中断

        DMA_Cmd(DMA1_Channel6,ENABLE);                                                                           //使DMA通道6停止工作
        DMA_Cmd(DMA1_Channel7,DISABLE);                                                                           //使DMA通道7停止工作
         
        USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);                                                //开启串口DMA发送
        USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);                                                //开启串口DMA接收
}


//3.接收不定长数据
//串口2中断函数
void USART2_IRQHandler(void)                       
{
        u8 *p;
        u8 USART2_RX_LEN = 0;                                                                                        //接收数据长度
        if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)                        //串口2空闲中断
        {
                USART_ReceiveData(USART2);                                                                         //清除串口2空闲中断IDLE标志位
                USART_ClearFlag(USART2,USART_FLAG_TC);                                                //清除USART2标志位
                DMA_Cmd(DMA1_Channel6, DISABLE );                                                   //关闭USART2 TX DMA1 所指示的通道
                USART2_RX_LEN = USART2_MAX_RX_LEN - DMA1_Channel6->CNDTR;        //获得接收到的字节数
                if(witchbuf)                                                                        //之前用的u2rxbuf,切换为u1rxbuf
                {
                        p=u2rxbuf;                                                                                                //先保存前一次数据地址再切换缓冲区
                        DMA1_Channel6->CMAR=(u32)u1rxbuf;                                                //切换为u1rxbuf缓冲区地址
                        witchbuf=0;                                                                     //下一次切换为u2rxbuf
                }else                                                                               //之前用的u1rxbuf,切换为u2rxbuf
                {
                        p=u1rxbuf;                                                                                                //先保存前一次数据地址再切换缓冲区
                        DMA1_Channel6->CMAR=(u32)u2rxbuf;                                                //切换为u2rxbuf缓冲区地址
                        witchbuf=1;                                                                     //下一次切换为u1rxbuf
                }
                DMA1_Channel6->CNDTR = USART2_MAX_RX_LEN;                                        //DMA通道的DMA缓存的大小
                DMA_Cmd(DMA1_Channel6, ENABLE);                                                     //使能USART2 TX DMA1 所指示的通道
                       
                DMA_USART2_Tx_Data(p,USART2_RX_LEN);
        GPIO_SetBits(GPIOD,GPIO_Pin_7);
  }
}



//4.数据发送
//DMA 发送应用源码
void DMA_USART2_Tx_Data(u8 *buffer, u32 size)
{
        while(USART2_TX_FLAG);                                                //等待上一次发送完成(USART2_TX_FLAG为1即还在发送数据)
        USART2_TX_FLAG=1;                                                        //USART2发送标志(启动发送)
        DMA1_Channel7->CMAR  = (uint32_t)buffer;        //设置要发送的数据地址
        DMA1_Channel7->CNDTR = size;                            //设置要发送的字节数目
        DMA_Cmd(DMA1_Channel7, ENABLE);                                //开始DMA发送
}
//DMA1通道7中断
void DMA1_Channel7_IRQHandler(void)
{
        if(DMA_GetITStatus(DMA1_IT_TC7)!= RESET)        //DMA接收完成标志
        {
                DMA_ClearITPendingBit(DMA1_IT_TC7);         //清除中断标志
                USART_ClearFlag(USART2,USART_FLAG_TC);        //清除串口2的标志位
                DMA_Cmd(DMA1_Channel7, DISABLE );           //关闭USART2 TX DMA1 所指示的通道
                USART2_TX_FLAG=0;                                                //USART2发送标志(关闭)
        }
}


DMA.zip

6.02 MB, 下载次数: 6

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-24 15:22

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表