你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 串口通讯之 DMA

[复制链接]
stm32code 发布时间:2020-7-16 10:02

直接上代码
/********************************************************************************
* 函 数 名: USART_Config()
* 功能描述: 配置USART的GPIO口
* 输入参数: bau 串口波特率
* 输出参数: void
* 注    释: 配置USART串口参数
********************************************************************************/
void USARTx_Config(USART_TypeDef* USARTx,unsigned int bar)
{
    USART_InitTypeDef USART_InitStructure;
    //USART1 初始化设置
    USART_InitStructure.USART_BaudRate = bar;                                                                      //波特率设置
    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(USARTx, &USART_InitStructure);                                                                     //初始化串口1
   
}
/********************************************************************************
* 函 数 名: USARTx_IT_Config()
* 功能描述: 配置USART的GPIO口
* 输入参数:  irq  中断通道号
*           Pre   抢占优先级
*           Sub   子优先级
* 输出参数: void
* 注    释: 配置串口中断
********************************************************************************/
void USARTx_IT_Config(unsigned char irq,unsigned char Pre,unsigned char Sub)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    //Usart1 NVIC 配置
    NVIC_InitStructure.NVIC_IRQChannel = irq;                //串口1中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=Pre;//抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =Sub;         //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化VIC寄存器、   
}
/********************************************************************************
* 函 数 名: USARTx_DMA_Config()
* 功能描述: 配置USART的DMA通道
* 输入参数:  DMAy_Channelx  通道号
*           paddr          外设地址 (串口的DR地址,详情配置见Init代码)
*           Maddr          存储器地址
*           dir            模式     DMA_DIR_PeripheralDST(存储器到外设) DMA_DIR_PeripheralSRC(外设到存储器)
*           size           传输数据量
* 输出参数: void
* 注    释: 配置串口中断
********************************************************************************/
void USARTx_DMA_Config(DMA_Channel_TypeDef* DMAy_Channelx,unsigned int paddr,unsigned int Maddr,unsigned int dir,unsigned int size)
{
    DMA_InitTypeDef  DMA_InitStructure;
   
    DMA_DeInit(DMAy_Channelx);
    /* 配置 DMA 发送通道*/
    DMA_InitStructure.DMA_PeripheralBaseAddr = paddr;                          //DMA外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr = Maddr;                           //DMA 存储器地址
    DMA_InitStructure.DMA_DIR = dir;                                                               //存储器到外设模式
    DMA_InitStructure.DMA_BufferSize = size;                                                    //数据传输量
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;           //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //存储器增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度:8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;         //存储器数据长度:8位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                           //使用普通模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //中等优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                            //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMAy_Channelx, &DMA_InitStructure);                            //初始化DMA
}
/********************************************************************************
* 函 数 名: USART_Init()
* 功能描述: 配置USART
* 输入参数: void
* 输出参数: void
* 注    释: 配置USART串口参数
********************************************************************************/
void USARTx_Init(void)
{
    /*USART1 config*/
    USARTx_Config(USART1,115200);
    USART_Cmd(USART1, ENABLE);  //使能串口1
    USART_ClearFlag(USART1, USART_FLAG_TC);        /*清除发送中断标志*/
    USART_ClearFlag(USART1, USART_IT_IDLE);        /*清除空闲中断标志*/
    USART_ITConfig(USART1, USART_FLAG_TC, ENABLE); /*开启空闲中断*/
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); /*开启空闲中断*/
    USARTx_IT_Config(USART1_IRQn,0,0);
    USARTx_DMA_Config(DMA1_Channel4,(unsigned int)&USART1->DR,(unsigned int)USARTStr.SendBuff,DMA_DIR_PeripheralDST,0);
    USARTx_DMA_Config(DMA1_Channel5,(unsigned int)&USART1->DR,(unsigned int)USARTStr.ReadBuff,DMA_DIR_PeripheralSRC,USART_BUFSIZE);
    USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);  /* 使能DMA串口发送和接受请求 */
    DMA_Cmd(DMA1_Channel5,ENABLE); /*打开接收数据通道*/
    UserMemset((unsigned char *)&USARTStr,0,sizeof(USARTStr));
   
    /*USART2 config*/
    USARTx_Config(USART2,115200);
    USART_Cmd(USART2, ENABLE);  //使能串口1
    USART_ClearFlag(USART2, USART_FLAG_TC);        /*清除发送中断标志*/
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); /*开启空闲中断*/
    USARTx_IT_Config(USART2_IRQn,0,1);
    USARTx_DMA_Config(DMA1_Channel7,(unsigned int)&USART2->DR,(unsigned int)USART2Str.SendBuff,DMA_DIR_PeripheralDST,0);
    USARTx_DMA_Config(DMA1_Channel6,(unsigned int)&USART2->DR,(unsigned int)USART2Str.ReadBuff,DMA_DIR_PeripheralSRC,USART_BUFSIZE);
    USART_DMACmd(USART2, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);  /* 使能DMA串口发送和接受请求 */
    DMA_Cmd(DMA1_Channel6,ENABLE); /*打开接收数据通道*/
    UserMemset((unsigned char *)&USART2Str,0,sizeof(USART2Str));
}
/********************************************************************************
* 函 数 名: USART1SendData
* 功能描述: 串口1DMA发送数组
* 输入参数: buf 发送的数组
*          len  数组长度
* 输出参数: void
* 注    释: 无
********************************************************************************/
void USART1SendData(unsigned char *pData,unsigned short size)
{
    UserCopy(USARTStr.SendBuff,pData,size);
    DMA_Cmd(DMA1_Channel4,DISABLE);
    DMA1_Channel4->CNDTR = size;
    DMA_Cmd(DMA1_Channel4,ENABLE);
}
/********************************************************************************
* 函 数 名: USART1_IRQHandler
* 功能描述: 串口接收中断
* 输入参数: void
* 输出参数: void
* 注    释: 无
********************************************************************************/
void USART1_IRQHandler(void)
{
    unsigned char temp;
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  //空闲中断
    {
        temp = USART1->SR;
        temp = USART1->DR;
        temp = temp;
        USARTStr.Len = USART_BUFSIZE - DMA1_Channel5->CNDTR;
        USARTStr.Flag = 0x80;
        DMA_Cmd(DMA1_Channel5, DISABLE);
        DMA1_Channel5->CNDTR=USART_BUFSIZE;
        DMA_Cmd(DMA1_Channel5, ENABLE);
        USART_ClearITPendingBit(USART1, USART_IT_IDLE);
    }
    if(USART_GetITStatus(USART1, USART_FLAG_TC) != RESET)  //传输完成中断
    {
        USARTStr.Flag = 0;
        UserMemset((unsigned char *)&USARTStr,0,USARTStr.Len);
    }
}


下面是变量的声明


#define USART_BUFSIZE       1024                /*最大接收串口数据的值*/

/****************************************************************************
* Local Types
****************************************************************************/

typedef struct TagUSARTStruct{          /*声明结构体来接收串口的数据*/
   
    unsigned short      Len;
    unsigned char       Flag;
    unsigned char       SendBuff[USART_BUFSIZE];   /* 发送数据 */
    unsigned char       ReadBuff[USART_BUFSIZE];   /* 接收数据 */

}T_USARTStruct;

extern T_USARTStruct USARTStr;          /*外部调用声明*/
extern T_USARTStruct USART2Str;

串口的gpio配置是好搞的我就补贴上代码了
千万记住打开相关的时钟配置

/* open DMA1 clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

以上的配置代码是测试完全通过的,在DMA中所说的外设到内存其实是配置了串口的DR数据地址映射到全局变量中,所说的外设是STM32在M3内核上添加的功能,例如:串口,IIC,SPI,ADC,DAC等这些外设,配置DMA时候把这些地址给到DMA外设地址配置上去,DMA内存是把代码中的全局变量的地址。STM32DMA有三种模式:内存到内存和外设到内存、内存到外设。使用接收PC端或者其他设备发送过来的数据在配置DMA时候必须提前打开,否则接收不到数据。例如串口1接收数据在配置DMA1通道5时候,在配置时要事先使能打开。通道4是用于发送数据出去可以填写好发送内容再打开,填数据前必须先关闭通道,中断可以根据需求去配置,但是配置了中断记得及时的清除标志位。否则发生整个程序在不断的执行中断代码,主程序代码无法执行,包括DMA的中断配置可根据手册查询配置,同样配置了,也要及时的清除中断标志。使用C自带微型库会增加代码大小,使用不多其实建议自己写,下面贴出代码。

/********************************************************************************
* 函 数 名: UserCopy
* 功能描述: 拷贝数据
* 输入参数: pdata 拷贝到的数组
*          data   要拷贝的数组
*          len    拷贝的长度
* 输出参数: void
* 注    释: 无
********************************************************************************/
void UserCopy(unsigned char *pdata,unsigned char *data,int len)
{
    int i;
    for(i=0;i<len;i++)
    {
        pdata = data;
    }
}

/********************************************************************************
* 函 数 名: UserMemset
* 功能描述: 清除数据
* 输入参数: pdata  要清楚的数组
*          t      填充的数据
*          len    数组长度
* 输出参数: void
* 注    释: 无
********************************************************************************/
void UserMemset(unsigned char *pdata,char t,int len)
{
    int i;
    for(i=0;i<len;i++)
    {
        pdata = t;
    }
}
/**************************************************************
* 函 数 名:HexToAscii
* 功能描述:十六进制转字符串
* 输入参数:pHex    十六进制
*          pAscii  字符串
*          nLen    长度
* 输出参数: void
* 注    释: 无
***************************************************************/
void HexToAscii(unsigned char *pHex, unsigned char *pAscii, int nLen)
{
    unsigned char Nibble[2];
    unsigned int i,j;
    for (i = 0; i < nLen; i++)
    {
        Nibble[0] = (pHex & 0xF0) >> 4;
        Nibble[1] = pHex & 0x0F;
        for (j = 0; j < 2; j++)
        {
            if(Nibble[j] < 10)
            {
                Nibble[j] += 0x30;
            }
            else
            {
                if(Nibble[j] < 16)    Nibble[j] = Nibble[j] - 10 + 'A';
            }
            *pAscii++ = Nibble[j];
        }
    }
    *pAscii++ = '\0';
}





收藏 3 评论4 发布时间:2020-7-16 10:02

举报

4个回答
ts2000 回答时间:2020-7-17 14:31:19
谢谢分享!!!
stm32code 回答时间:2020-7-18 08:56:33
ts2000 发表于 2020-7-17 14:31
谢谢分享!!!

不客气
pic2008 回答时间:2020-7-21 09:43:45
谢谢分享!!!  十分有用的
dinasind 回答时间:2020-9-4 17:36:45
谢谢分享,学习了
tian07 回答时间:2020-9-7 16:59:07
谢谢分享,新人学习
tian07 回答时间:2020-9-7 16:59:46
谢谢分享,新人学习

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版