OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3908|回复: 2

stm32f103使用DMA,usart发送和接收不定长数据

[复制链接]

1

主题

1

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2018-2-27
在线时间
32 小时
发表于 2018-2-27 19:11:44 | 显示全部楼层 |阅读模式
5金钱
#include "stm32f10x.h"

#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_dma.h"

#include "misc.h"
#include <stdlib.h>
#include <stdio.h>

#include "string.h"

#define DMA_Rec_Len 200
u8  DMA_Rece_Buf[DMA_Rec_Len];         
u16  Usart1_Rec_Cnt=0;           

#if 1
#pragma import(__use_no_semihosting)            

struct __FILE
{
        int handle;

};

FILE __stdout;      

_sys_exit(int x)
{
        x = x;
}
//&#214;&#216;&#182;¨ò&#229;fputcoˉêy
int fputc(int ch, FILE *f)
{      
        while((USART1->SR&0X40)==0);
    USART1->DR = (u8) ch;      
        return ch;
}
#endif


void RCC_Config()
{
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE) ;
       
       
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);                          

}
void GPIO_Config()         
{
        GPIO_InitTypeDef GPIO_InitStructure;                  
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;               
        GPIO_Init(GPIOA,&GPIO_InitStructure);                  
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;           
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;       
        GPIO_Init(GPIOA,&GPIO_InitStructure);                  

void USART1_Config()            
{
       
        USART_InitTypeDef USART_InitStructure;                              
                     
        USART_InitStructure.USART_BaudRate = 115200;                 
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;      
        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(USART1, &USART_InitStructure);                        

  USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);  
  USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   
        USART_Cmd(USART1, ENABLE);

}

void NVIC_Config()  
{
         NVIC_InitTypeDef NVIC_InitStructure;
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
       
         NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel5_IRQn;
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
         NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
       
         NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_Init(&NVIC_InitStructure);
}

void DMA_Config()
{       
        DMA_InitTypeDef DMA_InitStructure;
  DMA_DeInit(DMA1_Channel5);                     
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);  
       
  DMA_Cmd(DMA1_Channel5, ENABLE);
       

}

void MYDMA_Enable(DMA_Channel_TypeDef* DMA_CHx)
{
        DMA_Cmd(DMA_CHx, DISABLE );  
        DMA_SetCurrDataCounter(DMA_CHx,DMA_Rec_Len);
        DMA_Cmd(DMA_CHx, ENABLE);
}       

void Usart1_Send(u8 *buf,u8 len)
{
        u8 t;
          for(t=0;t<len;t++)               
        {                  
                while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);          
                USART_SendData(USART1,buf[t]);
               
        }         
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);               
}

void USART1_IRQHandler(void)               
{
  int i;
        u16 x;
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  
                {
            USART_ReceiveData(USART1);                        

                  Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5);       

                        Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);       
            
                        USART_ClearITPendingBit(USART1, USART_IT_IDLE);      
                        MYDMA_Enable(DMA1_Channel5);                 
     }


}



int main(void)
{       
       
   int i;
  for( i=10000000;i>0;i--)
         ;
   RCC_Config();
         GPIO_Config();
         USART1_Config()  ;
         NVIC_Config();
         DMA_Config();

         while(1)
         {
                 USART1_IRQHandler() ;
           for( i=1000000;i>0;i--)
         ;
                 
         }
}

这个程序是学习原子哥的程序编写的,在stm32f103已经调试成功,程序功能是从电脑的串口调试助手上发送一个不定长数据到单片上,然后单片机再将该数据返回发送给电脑。运行结果如下图 1519729069(1).jpg

问题:我查看了很多利用IDLE串口空闲中断和DMA来发送和接收数据时,都写了“当单片机接收不定长数据时,DMA默默的将串口上的数据转移到缓冲区”,我想知道的是:
        1、当多个字节发送给USART1时,USART1_DR只能接收1个字节,DMA依靠什么来判断要转移这个字节,毕竟我只打开了IDLE中断并没有打开RNXE和TC中断
        2、请问一下,该程序运行时数据的转移过程及各个中断的变化情况

最佳答案

查看完整内容[请看2#楼]

没有看你写的大段东西 按照我自己用的DMA空闲中断接收和DMA发送给你大概解释一下 初始状态空闲中断不会触发,当你收到数据 比如0x01,0x02,0x0d,0x0a这一帧数据,按一定波特率发过来,当你收到0x01的时候空闲中断也不会触发,直到你收到0x0a的时候,空闲中断触发,这个时候DMA已经把串口上收到的4个字节搬到你的数据缓冲区了,你只需要在空闲中断触发当中把DMA重新设置好接收长度和目标地址,并置位一个标志告诉你的主程序有一帧数据已经 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

85

帖子

0

精华

高级会员

Rank: 4

积分
586
金钱
586
注册时间
2016-5-13
在线时间
106 小时
发表于 2018-2-27 19:11:45 | 显示全部楼层
没有看你写的大段东西
按照我自己用的DMA空闲中断接收和DMA发送给你大概解释一下
初始状态空闲中断不会触发,当你收到数据 比如0x01,0x02,0x0d,0x0a这一帧数据,按一定波特率发过来,当你收到0x01的时候空闲中断也不会触发,直到你收到0x0a的时候,空闲中断触发,这个时候DMA已经把串口上收到的4个字节搬到你的数据缓冲区了,你只需要在空闲中断触发当中把DMA重新设置好接收长度和目标地址,并置位一个标志告诉你的主程序有一帧数据已经接收好了,你可以处理了,然后清除空闲中断标志,开始等待下一帧数据.
空闲中断的触发是数据接收超时1个字节之后开始触发的(不同波特率都是这样)
DMA的串口发送就不详解了,就是设定个发送地址和长度,打开DMA就可以了
回复

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-2-27 19:43:15 | 显示全部楼层
你这个好像只是用dma接收吧,你可以参考下,接收发送都用dma的
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 21:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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