硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1050|回复: 0
收起左侧

[有问必答] 基于RTX操作系统阻塞实现串口DMA数据收发

[复制链接]

7

主题

15

回帖

36

积分

新手上路

积分
36
发表于 2021-11-6 13:24:52 | 显示全部楼层 |阅读模式
1、基于RTX系统阻塞,实现串口DMA收发数据。采用当前时间片与上一时间片串口接收DMA流传输数据量相同来判断串口数据是否接收完毕。     串口DMA发送中断服务函数中开启串口发送完成中断,
__align(32) static u8 ucHmiTxBuf[MBBUFSIZE];
__align(32) static u8 ucHmiRxBuf[MBBUFSIZE];

static u16 USART2_DMAR(u8 *rbuf, u16 rlen, u16 timeout)
{
        u16 c;
        c = USART2->SR;
        c = USART2->DR;
        DMA1_Stream5->CR &= ~DMA_SxCR_EN;           //禁止DMA
        DMA1_Stream5->NDTR = rlen;
        DMA1_Stream5->PAR = (u32)(&USART2->DR);
        DMA1_Stream5->M0AR = (u32)rbuf;

        DMA1_Stream5->CR = 0;
        DMA1_Stream5->CR |= 4<<25 | 1<<17 | 0<<13 | 0<<11 | 1<<10 | 0<<6;

        USART2->CR3 |= USART_CR3_DMAR;               //使能TXDMA功能
        DMA1->HIFCR = (0x000F << 8) | (0x0001 << 6);//清标志
        DMA1_Stream5->CR |= DMA_SxCR_EN;              //使能DMA
        /*-----------------------------------------------------------
        等数据进来
        -------------------------------------------------------------*/
        do
        {
                os_dly_wait(5);
                if (--timeout == 0) break;
        }
        while (DMA1_Stream5->NDTR == rlen);
        if (timeout == 0)
        {
                USART2->CR3 &= ~USART_CR3_DMAR;
                DMA1_Stream5->CR &= ~DMA_SxCR_EN;     //禁止DMA
                return 0;                         //接收超时
        }
        /*-----------------------------------------------------------
        等待串口数据接收完毕,返回接收数据长度
        -------------------------------------------------------------*/
        do
        {
                c = DMA1_Stream5->NDTR;
                os_dly_wait(5);
        }
        while (c != DMA1_Stream5->NDTR);
        USART2->CR3 &= ~USART_CR3_DMAR;
        DMA1_Stream5->CR &= ~DMA_SxCR_EN;                  
        return(rlen - DMA1_Stream5->NDTR);
}

static u8 USART2_DMAT(u8 *sbuf, u16 slen)
{
        DMA1_Stream6->CR &= ~DMA_SxCR_EN;                 
        DMA1_Stream6->NDTR = slen;                  
        DMA1_Stream6->PAR  = (u32)(&USART2->DR);         
        DMA1_Stream6->M0AR = (u32)sbuf;   

        DMA1_Stream6->CR = 4<<25 | 1<<17 | 0<<13 | 0<<11 | 1<<10 | 1<<6 | 1<<4;
        USART2->CR3 |= USART_CR3_DMAT;                  
        DMA1->HIFCR |= (0x000F << 18) | (0x0001 << 16);   
        MY_NVIC_Init(7,0,DMA1_Stream6_IRQn,4);       
        DMA1_Stream6->CR |= DMA_SxCR_EN;                 
        return 1;
}

void USART2_IRQHandler(void)
{
        if(USART2->SR & USART_SR_TC)
        {
                USART2->CR3 &= ~USART_CR3_DMAT;
                USART2->SR &= ~USART_SR_TC;
                USART2->CR1 &= ~USART_CR1_TCIE;
                HMI485RCV();
        }
}

void DMA1_Stream6_IRQHandler(void)
{
        if(DMA1->HISR & DMA_HISR_TCIF6)
        {
                DMA1_Stream6->CR &= ~DMA_SxCR_EN;
                DMA1->HIFCR |= DMA_HIFCR_CTCIF6;
                USART2->CR1 |= USART_CR1_TCIE;
        }
}




int initUsart2(u32 pclk1,u32 bound,u16 stopbits,u16 parity)
{
        float temp;
        u16 mantissa;
        u16 fraction;
        if(pclk1 > 42)
                pclk1 = 42;
        temp=(float)(pclk1*1000000)/(bound*16);//得到USARTDIV@OVER8=0
        mantissa=temp;                                 //得到整数部分
        fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0
        mantissa<<=4;
        mantissa+=fraction;
       
        RCC->APB1RSTR |= RCC_APB1RSTR_USART2RST;
        RCC->APB1RSTR &= ~RCC_APB1RSTR_USART2RST;
        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
        RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
        RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
        GPIO_Set(GPIOA,PIN2|PIN3,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU);
        GPIO_AF_Set(GPIOA,2,7);
        GPIO_AF_Set(GPIOA,3,7);       
        GPIO_Set(GPIOA,PIN4,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_NONE);
       
        USART2->BRR = mantissa;
        USART2->CR1 = 0;
        USART2->CR1 |= (0<<15);            //16倍过采样
        if(parity == 2)               
        {
                USART2->CR1 |= 2<<9;   //使能奇偶校验,偶校验方式
                USART2->CR1 |= (1<<12);  //1个起始位,9个数据位
        }
        else if(parity == 1)
        {
                USART2->CR1 |= 3<<9;                //使能奇偶校验,奇校验方式
                USART2->CR1 |= (1<<12);  //1个起始位,9个数据位
        }
        else
        {
                USART2->CR1 &= ~(1<<10);
                USART2->CR1 |= (0<<12);  //1个起始位,8个数据位
        }
       
        if(stopbits == 0)
                USART2->CR2 |= (0 << 12);  //停止位设置
        else if(stopbits == 1)
                USART2->CR2 |= (2 << 12);  //停止位设置
        else
                USART2->CR2 |= (0 << 12);  //停止位设置
        USART2->CR1 |= (1<<2)|(1<<3);     //串口收发使能
        USART2->SR &= ~(1<<6);                                                //清串口发送完成中断标志位
        MY_NVIC_Init(7,0,USART2_IRQn,4);  
        USART2->CR3 &= ~( (1<<6) | (1<<7) );   //关闭串口DMA收发  
        USART2->CR1 |= (1<<13);                                                                 //使能串口
        return 0;
}


__task void hmiusart_task(void)
{
        initUsart2(42,19200,0,0);
        HMI485RCV();
        while(1)
        {
                usRcvLength = USART2_DMAR(ucHmiRxBuf,MBBUFSIZE,100);
                if(usRcvLength > 0)
                {  
                    //代表接收到数据,进行数据解包处理
                   HMI485SEND();
                   USART2_DMAT(ucHmiTxBuf,usHmiTxDATALen);

                }
        }
}
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-6-17 19:50 , Processed in 0.180203 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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