为什么只有在串口空闲中断DMA中断里面打印接收数组才完整?

2019-07-21 04:03发布

使用的串口4空闲接收中断 + DMA,为什么只有在串口4的接收中断中打印输出才是完整,同时在调试watch1内也能看到USART4_RX_BUF数据和Usart4_Rec_Cnt 的接收动态,在外部main函数中调用Get_Picture()函数,用串口3却打印不出来,而且接收计数器Usart4_Rec_Cnt 也都为0(同样使用中断输出加黑标粗的代码)
void Get_Picture(void)
{
        u8 tx = 0, rx = 0;
        u8 senddata[7] = { 0x55, 0x48, 0x01, 0x33, 0x00, 0x02, 0x23};          //发送读数据协议55 48 01 32 00 02 23
        usart4_send(senddata, 7);       //发送7位读数据协议
        u3_printf("CAM_TX: ");
        for(tx = 0; tx < 7; tx ++)
       {
             u3_printf("%02X ",senddata[tx]);       
       }
       u3_printf(" ");
       u3_printf("CAM_RX: ");
      for(rx = 0; rx < Usart4_Rec_Cnt; rx ++)
      {
          u3_printf("%02X ",USART4_RX_BUF[rx]);       
      }
       u3_printf(" ");       
}

void uart4_init(u32 bound)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        DMA_InitTypeDef DMA_UART4_RX;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);       
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);        //使能DMA传输
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);

        USART_DeInit(UART4);  //复位串口4
        //UART4_TX   PC10
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PC.10
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
        GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC10

        //UART4_RX          PC.11
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOC, &GPIO_InitStructure);  //初始化PB11

        //485EN       PB.4
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //内部上拉输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        USART4_SEND = U4SEND_DISABLE;

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

        //USART 初始化设置
        USART_InitStructure.USART_BaudRate = bound; //串口波特率
        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(UART4, &USART_InitStructure); //初始化串口4
               
        USART_ITConfig(UART4, USART_IT_IDLE, ENABLE); //开启空闲中断
        USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE); //使能串口4的DMA接收
        USART_Cmd(UART4, ENABLE); //使能串口

        //DMA_RX相应的DMA配置
        DMA_DeInit(DMA2_Channel3);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5
        DMA_UART4_RX.DMA_PeripheralBaseAddr = (u32)&UART4->DR;  //DMA外设ADC基地址
        DMA_UART4_RX.DMA_MemoryBaseAddr = (u32)USART4_RX_BUF;  //DMA内存基地址
        DMA_UART4_RX.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存
        DMA_UART4_RX.DMA_BufferSize = USART4_REC_LEN;  //DMA通道的DMA缓存的大小
        DMA_UART4_RX.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_UART4_RX.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_UART4_RX.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
        DMA_UART4_RX.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
        DMA_UART4_RX.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
        DMA_UART4_RX.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
        DMA_UART4_RX.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA2_Channel3, &DMA_UART4_RX);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART4_Tx_DMA_Channel所标识的寄存器
               
        DMA_Cmd(DMA2_Channel3, ENABLE);  //正式驱动DMA传输
}

void UART4_RX_DMA_Enable(void)       
{
        DMA_Cmd(DMA2_Channel3, DISABLE ); //先停止DMA
        DMA_SetCurrDataCounter(DMA2_Channel3, USART4_REC_LEN); //DMA通道的DMA缓存的大小
        DMA_Cmd(DMA2_Channel3, ENABLE); //使能USART4 TX DMA2 所指示的通道
}
void UART4_IRQHandler(void)                        //串口4中断服务程序
{
#ifdef OS_TICKS_PER_SEC                 //如果时钟节拍数定义了,说明要使用ucosII了.
        OSIntEnter();   
#endif       
        //串口4空闲中断
        if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  
        {         
                /* 1.清除标志 */
                USART_ClearITPendingBit(UART4, USART_IT_IDLE); //清除中断标志
               
                /* 2.读取DMA */
                USART_ReceiveData(UART4); //读取数据
                Usart4_Rec_Cnt = USART4_REC_LEN - DMA_GetCurrDataCounter(DMA2_Channel3); //接收个数等于接收缓冲区总大小减已经接收的个数
       
                /* 3.开启新的一次DMA接收 */
                UART4_RX_DMA_Enable(); //重新使能DMA,等待下一次的接收

                u3_printf("CAM_RX: ");
                for(rx = 0; rx < Usart4_Rec_Cnt; rx ++)
                {
                        u3_printf("%02X ",USART4_RX_BUF[rx]);               
                }
                u3_printf(" ");
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
13条回答
edmund1234
1楼-- · 2019-07-21 18:41
本帖最后由 edmund1234 于 2019-3-14 18:46 编辑
leozzd 发表于 2019-3-14 18:08
用DMA的接收中断标志位DMA2_Flag_TC3作为判断条件是否可行?查了下资料串口4的DMA接收是第三通道,这个标 ...
看错了, 还以为你使用了DMA中断, 使用DMA完成中断, 必须是DMA已经接收了USART4_REC_LEN个字节, 如果说你确定数据包的长度应该是可以的
但另一个问题是, 你在IDLE中断里重新使能了DMA, 这当中会不会有什么冲突, 要测试才知道。

倒不如, 定义另一全局标志位, 用作标记接收完成吧
leozzd
2楼-- · 2019-07-21 21:43
edmund1234 发表于 2019-3-14 18:33
看错了, 还以为你使用了DMA中断, 使用DMA完成中断, 必须是DMA已经接收了USART4_REC_LEN个字节, 如果说 ...

//串口4空闲中断
if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  
{         
     /* 1.清除标志 */
     USART_ClearITPendingBit(UART4, USART_IT_IDLE); //清除中断标志
     /* 2.读取DMA */
     USART_ReceiveData(UART4); //读取数据
     Usart4_Rec_Cnt = USART4_REC_LEN - DMA_GetCurrDataCounter(DMA2_Channel3)       /* 3.开启新的一次DMA接收 */
      UART4_RX_DMA_Enable(); //重新使能DMA,等待下一次的接收         
}
在这段空闲中断的条件中,加入一个中断完成的全局标志位U4_Rec_Fin传递到外面和Usart4_Rec_Cnt不都一样的效果么。
edmund1234
3楼-- · 2019-07-22 00:06
leozzd 发表于 2019-3-14 22:00
//串口4空闲中断
if(USART_GetITStatus(UART4, USART_IT_IDLE) != RESET)  
{         

哦, 是的, 可以用它
记得用完清零
leozzd
4楼-- · 2019-07-22 05:10
edmund1234 发表于 2019-3-14 22:03
哦, 是的, 可以用它
记得用完清零

你的意思是在这里等待标志位成立条件?
void Get_Picture(void)
{
        ……
        usart4_send(senddata, 7);       //发送7位读数据协议
……
       u3_printf("CAM_RX: ");
      for(rx = 0; rx < Usart4_Rec_Cnt; rx ++)
      {
          u3_printf("%02X ",USART4_RX_BUF[rx]);        
      }
       u3_printf(" ");        
}
leozzd
5楼-- · 2019-07-22 10:31
 精彩回答 2  元偷偷看……
edmund1234
6楼-- · 2019-07-22 13:41
leozzd 发表于 2019-3-14 22:12
你的意思是是在这里等待标志位成立条件?
void Get_Picture(void)
{

void Get_Picture(void)
{
        ……
        usart4_send(senddata, 7);       //发送7位读数据协议
        ……
        while(Usart4_Rec_Cnt)
        {                  Usart4_Rec_Cnt = 0;
                 //USartx print Recbuffer
        }   
        while(Usart4_Rec_Cnt)
        {                  Usart4_Rec_Cnt = 0;
                 //USartx print Recbuffer
        }   
}
这样改, 如何?

一周热门 更多>