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

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
谢谢分享,新人学习
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版