关于CH32V307 串口+DMA 传输

官方给的例程里 串口+DMA 好像只是一个简单的演示,请问有对应的 串口+DMA 传输 中断接收,主动发送的例子吗,在方法里找了挺久,也没找到对应的,新手求助!!

您好,附件为一个串口DMA中断例程,可以参考修改。

icon_rar.gifCH32V307 串口DMA.zip



DMA_BufferSize=100  这个配置 如果接收一次数据的时候,是要等到接收到的数据到达100后 才会标识一次接收完成吗?


您好,是的,后面若有问题,可以通过邮箱沟通(lzs@wch.cn)。


串口发送直接用DMA很简单了,接收就用systick定时间接查询串口空闲,当持续一段时间空闲了就去DMA取数据不就行了?

讲真,不建议中断接收,当115200波特率8个串口中断接收数据那是灾难了。


期待DMA不定长接收例程。


不定长那个    有点难吧 


我发一个 串口+DMA 收发数据的例程

最简单的串口DMA接收检测到空闲,则认为一帧数据接收完成,然后把接收到的数据拷贝到发送缓存用串口DMA发出去。

接收是判断串口空闲标志、发送是判断DMA传输完成标志,全程无中断。毕竟跑RTOS的话,中断太多不好把控啊。

嗯,这是参考隔壁STM32F103的做法。


/*
??串口2接收后一帧(当接收空闲则认为一帧数据,有空再尝试ModbusRTU的3.5T间隔空闲帧)返回
?UART1??TX-->PA9???RX-->PA10?|??UART2??TX-->PA2???RX-->PA3?|??UART3??TX-->PB10??????RX-->PB11
?UART4??TX-->PC10??RX-->PC11?|??UART5??TX-->PC12??RX-->PD2?|??UART6??TX-->PC0/PE10??RX-->PC1/PE11
?UART7??TX-->PC2???RX-->PC3??|??UART8??TX-->PC4???RX-->PC5
?UART1??TX-->DMA1_Channel4???RX-->DMA1_Channel5?|??UART2??TX-->DMA1_Channel7???RX-->DMA1_Channel6?|??UART3??TX-->DMA1_Channel2???RX-->DMA1_Channel3
?UART4??TX-->DMA2_Channel5???RX-->DMA2_Channel3?|??UART5??TX-->DMA2_Channel4???RX-->DMA2_Channel2?|??UART6??TX-->DMA2_Channel6???RX-->DMA2_Channel7
?UART7??TX-->DMA2_Channel8???RX-->DMA2_Channel9?|??UART8??TX-->DMA2_Channel10??RX-->DMA2_Channel11
*/
#include?"debug.h"
#define?USART_MAX_LEN?256
//定义要用到的全局变量
uint8_t?USART2_RxBuf[USART_MAX_LEN]={0};???//接收缓存
uint8_t?USART2_TxBuf[USART_MAX_LEN]={0};???//发送缓存
//串口2初始化、中断、DMA配置
void?USART2_Init(u32?bound){
????RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);????????//使能GPIOA时钟
????RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);???????//使能USART2时钟
????//GPIO端口设置??USART2端口配置
????/*?USART2?TX-->A.2???RX-->A.3?*/
????GPIO_InitTypeDef?GPIO_InitStructure;
????GPIO_StructInit(&GPIO_InitStructure);???????????????????//初始化结构体
????GPIO_InitStructure.GPIO_Pin?=?GPIO_Pin_2;???????????????//?串口2的Tx是Pin2
????GPIO_InitStructure.GPIO_Speed?=?GPIO_Speed_50MHz;???????//?IO速度?50MHz?视具体情况增减速度
????GPIO_InitStructure.GPIO_Mode?=?GPIO_Mode_AF_PP;?????????//?复用推挽输出
????GPIO_Init(GPIOA,?&GPIO_InitStructure);??????????????????//?配置到?GPIOA
????GPIO_StructInit(&GPIO_InitStructure);???????????????????//初始化结构体
????GPIO_InitStructure.GPIO_Pin?=?GPIO_Pin_3;???????????????//?串口2的Rx是Pin3
????GPIO_InitStructure.GPIO_Mode?=?GPIO_Mode_IN_FLOATING;???//?浮空输入
????GPIO_Init(GPIOA,?&GPIO_InitStructure);??????????????????//?配置到GPIOA
????//USART2?初始化设置
????USART_DeInit(USART2);???????????????????????????????????????????????????????????????//初始化串口2
????USART_InitTypeDef?USART_InitStructure;
????USART_StructInit(&USART_InitStructure);?????????????????????????????????????????????//初始化结构体
????USART_InitStructure.USART_BaudRate?=?bound;?????????????????????????????????????????//?波特率
????USART_InitStructure.USART_WordLength?=?USART_WordLength_8b;?????????????????????????//?8位数据
????USART_InitStructure.USART_StopBits?=?USART_StopBits_1;??????????????????????????????//?1位停止
????USART_InitStructure.USART_Parity?=?USART_Parity_No;?????????????????????????????????//?无校验
????USART_InitStructure.USART_HardwareFlowControl?=?USART_HardwareFlowControl_None;?????//?无硬件流控制
????USART_InitStructure.USART_Mode?=?USART_Mode_Tx?|?USART_Mode_Rx;?????????????????????//?允许发送?允许接收
????USART_Init(USART2,?&USART_InitStructure);???????????????????????????????????????????//?配置到串口2
????RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,?ENABLE);??????????????????????//使能开启DMA时钟
????/*?配置DMA1_Channel7,USART2发送?*/
????DMA_InitTypeDef?DMA_InitStructure;
????DMA_DeInit(DMA1_Channel7);??????????????????????????????????????????????//初始化DMA1_Channel7
????DMA_StructInit(&DMA_InitStructure);??????????????????????????????????????//初始化结构体
????DMA_InitStructure.DMA_PeripheralBaseAddr?=?(u32)&USART2->DATAR;?????????//DMA外设地址
????DMA_InitStructure.DMA_MemoryBaseAddr?????=?(u32)USART2_TxBuf;???????????//DMA?存储器0地址
????DMA_InitStructure.DMA_DIR????????????????=?DMA_DIR_PeripheralDST;???????//存储器到外设模式
????DMA_InitStructure.DMA_BufferSize?????????=?USART_MAX_LEN;???????????????//数据传输量
????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_Init(DMA1_Channel7,?&DMA_InitStructure);????????????????????????????//配置到DMA1_Channel7
????/*?配置DMA1_Channel6,串口2接收*/
????DMA_DeInit(DMA1_Channel6);??????????????????????????????????????????????//?初始化DMA1_Channel6
????DMA_StructInit(&DMA_InitStructure);?????????????????????????????????????//?初始化结构体
????DMA_InitStructure.DMA_PeripheralBaseAddr?=?(uint32_t)&USART2->DATAR;????//?DMA外设地址
????DMA_InitStructure.DMA_MemoryBaseAddr?????=?(uint32_t)USART2_RxBuf;??????//?DMA?存储器0地址
????DMA_InitStructure.DMA_DIR????????????????=?DMA_DIR_PeripheralSRC;???????//?存储器到外设模式
????DMA_InitStructure.DMA_BufferSize?????????=?USART_MAX_LEN;???????????????//?数据传输量
????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_VeryHigh;???????//?高等优先级
????DMA_InitStructure.DMA_M2M????????????????=?DMA_M2M_Disable;?????????????//?禁止内存到内存的传输
????DMA_Init(DMA1_Channel6,?&DMA_InitStructure);????????????????????????????//?配置到DMA1_Channel6
????DMA_Cmd(DMA1_Channel7,?DISABLE);????????????????????????????????????????//先关闭DMA1_Channel7不允许发送数据
????DMA_Cmd(DMA1_Channel6,?ENABLE);?????????????????????????????????????????//使能DMA1_Channel6通道,开始接收数据
????USART_DMACmd(USART2,?USART_DMAReq_Rx,?ENABLE);??????????????????????????//开启串口DMA接收
????USART_DMACmd(USART2,?USART_DMAReq_Tx,?ENABLE);??????????????????????????//开启串口DMA发送
????USART_Cmd(USART2,?ENABLE);??????????????????????????????????????????????//打开串口2?开始干活
}
//查询方式串口2收发数据
void?USART2_Server(void){
????if(USART_GetFlagStatus(USART2,?USART_FLAG_IDLE)?!=?RESET?){?????????//-串口2空闲
????????USART_ClearFlag(USART2,?USART_FLAG_IDLE);
????????uint16_t?i,len;
????????len?=?USART_MAX_LEN?-?DMA_GetCurrDataCounter(DMA1_Channel6);????//?获取接收到的数据长度?单位为字节
????????USART_ReceiveData(USART2);??????????????????????????????????????//?清除空闲中断标志位(接收函数有清标志位的作用)
????????DMA_Cmd(DMA1_Channel6,?DISABLE);????????????????????????????????//?关闭DMA1_Channel6不再接收数据
????????DMA_ClearFlag(DMA1_FLAG_TC6);???????????????????????????????????//?清DMA1_Channel6接收完成标志位
????????DMA_SetCurrDataCounter(DMA1_Channel6,USART_MAX_LEN);????????????//?重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
????????for?(i?=?0;?i?<?len;?++i)?{?????????????????????????????????????//?把接收到的数据转移到发送数组
????????????USART2_TxBuf[i]?=?USART2_RxBuf[i];
????????}
????????DMA_SetCurrDataCounter(DMA1_Channel7,len);??????????????????????//?设置数据发送长度
????????DMA_Cmd(DMA1_Channel7,ENABLE);??????????????????????????????????//?打开DMA1_Channel7开始发送数据流
????}else?if(DMA_GetFlagStatus(DMA1_FLAG_TC7)){?????????????????????????//-DMA发送完成
????????DMA_ClearFlag(DMA1_FLAG_TC7);???????????????????????????????????//?清除DMA1_IT_TC7传输完成标志
????????DMA_Cmd(DMA1_Channel7,DISABLE);?????????????????????????????????//?关闭DMA1_Channel7不再发送数据
????????DMA_Cmd(DMA1_Channel6,?DISABLE);????????????????????????????????//?先关闭DMA1_Channel6才能配置
????????DMA_ClearFlag(DMA1_FLAG_TC6);???????????????????????????????????//?清DMA1_Channel6接收完成标志位
????????DMA_SetCurrDataCounter(DMA1_Channel6,USART_MAX_LEN);????????????//?重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
????????DMA_Cmd(DMA1_Channel6,?ENABLE);?????????????????????????????????//?重新打开DMA1_Channel6开始接收数据
????}
}
int?main(void){
????NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
????Delay_Init();
????USART_Printf_Init(115200);
????printf("SystemClk:%d\r\n",?SystemCoreClock);
????printf("USART?DMA?TEST\r\n");
????USART2_Init(115200);
????while(1){
????????USART2_Server();
????????Delay_Ms(20);
????}
}



我发一个 串口+DMA 收发数据的例程

最简单的串口DMA接收检测到空闲,则认为一帧数据接收完成,然后把接收到的数据拷贝到发送缓存用串口DMA发出去。

接收是判断串口空闲标志、发送是判断DMA传输完成标志,全程无中断。毕竟跑RTOS的话,中断太多不好把控啊。

嗯,这是参考隔壁STM32F103的做法。


/*
  串口2接收后一帧(当接收空闲则认为一帧数据,有空再尝试ModbusRTU的3.5T间隔空闲帧)返回
 UART1  TX-->PA9   RX-->PA10 |  UART2  TX-->PA2   RX-->PA3 |  UART3  TX-->PB10      RX-->PB11
 UART4  TX-->PC10  RX-->PC11 |  UART5  TX-->PC12  RX-->PD2 |  UART6  TX-->PC0/PE10  RX-->PC1/PE11
 UART7  TX-->PC2   RX-->PC3  |  UART8  TX-->PC4   RX-->PC5
 UART1  TX-->DMA1_Channel4   RX-->DMA1_Channel5 |  UART2  TX-->DMA1_Channel7   RX-->DMA1_Channel6 |  UART3  TX-->DMA1_Channel2   RX-->DMA1_Channel3
 UART4  TX-->DMA2_Channel5   RX-->DMA2_Channel3 |  UART5  TX-->DMA2_Channel4   RX-->DMA2_Channel2 |  UART6  TX-->DMA2_Channel6   RX-->DMA2_Channel7
 UART7  TX-->DMA2_Channel8   RX-->DMA2_Channel9 |  UART8  TX-->DMA2_Channel10  RX-->DMA2_Channel11
*/
#include "debug.h"
#define USART_MAX_LEN 256
//定义要用到的全局变量
uint8_t USART2_RxBuf[USART_MAX_LEN]={0};   //接收缓存
uint8_t USART2_TxBuf[USART_MAX_LEN]={0};   //发送缓存
//串口2初始化、中断、DMA配置
void USART2_Init(u32 bound){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能GPIOA时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);       //使能USART2时钟
    //GPIO端口设置  USART2端口配置
    /* USART2 TX-->A.2   RX-->A.3 */
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);                   //初始化结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;               // 串口2的Tx是Pin2
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // IO速度 50MHz 视具体情况增减速度
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  // 配置到 GPIOA
    GPIO_StructInit(&GPIO_InitStructure);                   //初始化结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;               // 串口2的Rx是Pin3
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                  // 配置到GPIOA
    //USART2 初始化设置
    USART_DeInit(USART2);                                                               //初始化串口2
    USART_InitTypeDef USART_InitStructure;
    USART_StructInit(&USART_InitStructure);                                             //初始化结构体
    USART_InitStructure.USART_BaudRate = bound;                                         // 波特率
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;                         // 8位数据
    USART_InitStructure.USART_StopBits = USART_StopBits_1;                              // 1位停止
    USART_InitStructure.USART_Parity = USART_Parity_No;                                 // 无校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;     // 无硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;                     // 允许发送 允许接收
    USART_Init(USART2, &USART_InitStructure);                                           // 配置到串口2
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                      //使能开启DMA时钟
    /* 配置DMA1_Channel7,USART2发送 */
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(DMA1_Channel7);                                              //初始化DMA1_Channel7
    DMA_StructInit(&DMA_InitStructure);                                      //初始化结构体
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART2->DATAR;         //DMA外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)USART2_TxBuf;           //DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;       //存储器到外设模式
    DMA_InitStructure.DMA_BufferSize         = USART_MAX_LEN;               //数据传输量
    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_Init(DMA1_Channel7, &DMA_InitStructure);                            //配置到DMA1_Channel7
    /* 配置DMA1_Channel6,串口2接收*/
    DMA_DeInit(DMA1_Channel6);                                              // 初始化DMA1_Channel6
    DMA_StructInit(&DMA_InitStructure);                                     // 初始化结构体
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DATAR;    // DMA外设地址
    DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)USART2_RxBuf;      // DMA 存储器0地址
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;       // 存储器到外设模式
    DMA_InitStructure.DMA_BufferSize         = USART_MAX_LEN;               // 数据传输量
    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_VeryHigh;       // 高等优先级
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;             // 禁止内存到内存的传输
    DMA_Init(DMA1_Channel6, &DMA_InitStructure);                            // 配置到DMA1_Channel6
    DMA_Cmd(DMA1_Channel7, DISABLE);                                        //先关闭DMA1_Channel7不允许发送数据
    DMA_Cmd(DMA1_Channel6, ENABLE);                                         //使能DMA1_Channel6通道,开始接收数据
    USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);                          //开启串口DMA接收
    USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);                          //开启串口DMA发送
    USART_Cmd(USART2, ENABLE);                                              //打开串口2 开始干活
}
//查询方式串口2收发数据
void USART2_Server(void){
    if(USART_GetFlagStatus(USART2, USART_FLAG_IDLE) != RESET ){         //-串口2空闲
        USART_ClearFlag(USART2, USART_FLAG_IDLE);
        uint16_t i,len;
        len = USART_MAX_LEN - DMA_GetCurrDataCounter(DMA1_Channel6);    // 获取接收到的数据长度 单位为字节
        USART_ReceiveData(USART2);                                      // 清除空闲中断标志位(接收函数有清标志位的作用)
        DMA_Cmd(DMA1_Channel6, DISABLE);                                // 关闭DMA1_Channel6不再接收数据
        DMA_ClearFlag(DMA1_FLAG_TC6);                                   // 清DMA1_Channel6接收完成标志位
        DMA_SetCurrDataCounter(DMA1_Channel6,USART_MAX_LEN);            // 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
        for (i = 0; i < len; ++i) {                                     // 把接收到的数据转移到发送数组
            USART2_TxBuf[i] = USART2_RxBuf[i];
        }
        DMA_SetCurrDataCounter(DMA1_Channel7,len);                      // 设置数据发送长度
        DMA_Cmd(DMA1_Channel7,ENABLE);                                  // 打开DMA1_Channel7开始发送数据流
    }else if(DMA_GetFlagStatus(DMA1_FLAG_TC7)){                         //-DMA发送完成
        DMA_ClearFlag(DMA1_FLAG_TC7);                                   // 清除DMA1_IT_TC7传输完成标志
        DMA_Cmd(DMA1_Channel7,DISABLE);                                 // 关闭DMA1_Channel7不再发送数据
        DMA_Cmd(DMA1_Channel6, DISABLE);                                // 先关闭DMA1_Channel6才能配置
        DMA_ClearFlag(DMA1_FLAG_TC6);                                   // 清DMA1_Channel6接收完成标志位
        DMA_SetCurrDataCounter(DMA1_Channel6,USART_MAX_LEN);            // 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
        DMA_Cmd(DMA1_Channel6, ENABLE);                                 // 重新打开DMA1_Channel6开始接收数据
    }
}
int main(void){
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    USART_Printf_Init(115200);
    printf("SystemClk:%d\r\n", SystemCoreClock);
    printf("USART DMA TEST\r\n");
    USART2_Init(115200);
    while(1){
        USART2_Server();
        Delay_Ms(20);
    }
}



只有登录才能回复,可以选择微信账号登录