打印
[STM32F0]

STM32F051串口的DMA方式发送总是失败

[复制链接]
7643|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
我的串口配置和DMA 都没有使用中断。串口不用DMA方式可以正常发送。这是什么原因呢
沙发
missing01|  楼主 | 2014-3-23 13:33 | 只看该作者
本帖最后由 missing01 于 2014-3-23 17:36 编辑

//#include <stm32f0xx_lib.h>
#include <stdint.h>
#include <system_stm32f0xx.h>
#include <stm32f0xx_gpio.h>
#include <Main.h>
#include "systick.h"
#include "LCD32.h"
#include "dma.h"


//#define ADC1_DR_Address   0x40013800
#define USART1_TDR_Address  0x40013828

const uint8_t TEXT_TO_SEND[]={"ALIENTEK MiniSTM32 DMA ????"};
uint8_t SendBuff[16]="nihaoshijie";

void LedInit()
{
       
        GPIO_InitTypeDef gpiostudy;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA ,ENABLE);//使能AHB外设GPIOA时钟
        gpiostudy.GPIO_Pin=GPIO_Pin_11;
        gpiostudy.GPIO_Mode=GPIO_Mode_OUT;
        gpiostudy.GPIO_Speed=GPIO_Speed_50MHz;
        gpiostudy.GPIO_PuPd=GPIO_PuPd_NOPULL;
        gpiostudy.GPIO_OType = GPIO_OType_PP;
        GPIO_Init(GPIOA,&gpiostudy);
}

void usart_init()
{
       
                GPIO_InitTypeDef gpiostudy;
        USART_InitTypeDef USART_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);//使能AHB外设GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  //使能串口时钟;

        //PA.9  TX
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
        gpiostudy.GPIO_Pin=GPIO_Pin_9;
        gpiostudy.GPIO_Mode=GPIO_Mode_AF;
         gpiostudy.GPIO_OType=GPIO_OType_PP;
         gpiostudy.GPIO_PuPd=GPIO_PuPd_UP;
        gpiostudy.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&gpiostudy);
         // PA.10  RX
        gpiostudy.GPIO_Pin=GPIO_Pin_10;
        gpiostudy.GPIO_Mode=GPIO_Mode_OUT;
        gpiostudy.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&gpiostudy);
        USART_InitStructure.USART_BaudRate = 9600;//一般设置为9600;
        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_Tx;

    USART_Init(USART1, &USART_InitStructure);

        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);//使能串口1 的 DMA发送
   // USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断

   // USART_Cmd(USART1, ENABLE);                    //使能串口
       
       
}


void delay(int i)
{
        int j,k;
        for(j=0;j<15000;j++)
        {
                for(k=0;k<i;k++);
        }
}

void  MYDMA_Init()
{
        DMA_InitTypeDef   DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//使能DMA 总线时钟
        DMA_DeInit(DMA1_Channel4);
//        DMA1_MEM_LEN=cndtr;
        DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)USART1_TDR_Address;  //DMA外设基地址
        DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)SendBuff;     //DMA内存基地址
        DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST; //外设作为DMA传输的目的地址
        DMA_InitStructure.DMA_BufferSize=16;                                                        //        DMA通道的DMA缓存大小
        DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设寄存器地址不变
        DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//DMA 内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;//数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
        DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;//DMA工作在正常缓存模式
        DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道拥有中等优先级
        DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//DMA通道X没有设置内存到内存的操作
        DMA_Init(DMA1_Channel4, &DMA_InitStructure);  //按照以上参数初始化DMA
}
int main()
{

       
        float pro=0;//进度
        GPIO_SetBits(GPIOA,GPIO_Pin_11);       
        LedInit();
        SystemInit();
        Systick_NVICInit();       
  //         MYDMA_Config(DMA1_Channel4,(uint32_t)USART1_TDR_Address,(uint32_t)SendBuff,16);//DMA1??4,?????1,????SendBuff,??5200
        usart_init();
                       
//        MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!
        MYDMA_Init();
        DMA_Cmd(DMA1_Channel4, ENABLE);  //使能USART1 TX DMA1 ??????

        while(1)
         {       
         
         
                 if(DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET)//等待通道4传输完成
                {
                                DMA_ClearFlag(DMA1_FLAG_TC4);  //清除发送完成标志
                                break;
                }
                pro = DMA_GetCurrDataCounter(DMA1_Channel4);    //得到当前还剩余多少个数据                  
                GPIO_ResetBits(GPIOA,GPIO_Pin_11);
                 delay(1000);  //1s

                 GPIO_SetBits(GPIOA,GPIO_Pin_11);
                 delay(2000);  //1s
                 
         }
         

}
以上是主函数中的代码

使用特权

评论回复
板凳
missing01|  楼主 | 2014-3-23 13:33 | 只看该作者
以上是主函数中的代码   

使用特权

评论回复
地板
missing01|  楼主 | 2014-3-23 13:33 | 只看该作者
本帖最后由 missing01 于 2014-3-23 17:37 编辑

看了很多例子  基本上也就是这么用的,不晓得哪个地方疏忽了

使用特权

评论回复
5
mmuuss586| | 2014-3-23 21:31 | 只看该作者

不知道什么地方问题,帮顶。

使用特权

评论回复
6
明月小厨| | 2014-3-24 11:29 | 只看该作者
void MX_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct;

  /** USART1 GPIO Configuration  
  PA9   ------> USART1_TX
  PA10   ------> USART1_RX
  */

  /*Enable or disable the AHB peripheral clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  /*Configure GPIO pin : PA */
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin alternate function */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);

  /*Configure GPIO pin alternate function */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
}

使用特权

评论回复
7
香水城| | 2014-3-24 14:03 | 只看该作者
如何失败?是数据根本发不出,还是发出的数据是错的?

串口的发送引脚上示波器看了么?

使用特权

评论回复
8
missing01|  楼主 | 2014-3-24 17:41 | 只看该作者
香水城 发表于 2014-3-24 14:03
如何失败?是数据根本发不出,还是发出的数据是错的?

串口的发送引脚上示波器看了么? ...

根本发不出来,用串口助手是什么也接收不到。用函数看一下DMA剩余数据量是16   一直没有减少。而串口用非DMA模式的话  能够正常发送数据

使用特权

评论回复
9
missing01|  楼主 | 2014-3-24 17:45 | 只看该作者
明月小厨 发表于 2014-3-24 11:29
void MX_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct;

要使用串口的DMA  必须这么配置么?  我的串口不用DMA模式是可以正常发出数据的哈

使用特权

评论回复
10
香水城| | 2014-3-25 12:11 | 只看该作者
F0的标准外设固件库里有USART通过DMA进行数据传输的例子,LZ参考过么?

STM32F0xx standard peripherals library

使用特权

评论回复
11
missing01|  楼主 | 2014-3-25 15:38 | 只看该作者
香水城 发表于 2014-3-25 12:11
F0的标准外设固件库里有USART通过DMA进行数据传输的例子,LZ参考过么?

STM32F0xx standard peripherals l ...

发现了我这个有个错误了 。串口DMA默认映射到 通道2上。只有重映射才会到4上。但是改了这个地方,试了一下  还是不行。

使用特权

评论回复
评论
明月小厨 2014-3-26 10:12 回复TA
我等下一查查看,串口对应的DMA通道是第几个; 
12
明月小厨| | 2014-3-26 10:11 | 只看该作者
我想起来一个问题,是不是要手动先写一个数据到串口中,然后串口和DMA间才会有动作?我是说发送;

使用特权

评论回复
13
明月小厨| | 2014-3-26 10:20 | 只看该作者

使用特权

评论回复
14
missing01|  楼主 | 2014-3-26 10:25 | 只看该作者
明月小厨 发表于 2014-3-26 10:20

这块我注意到了。但还是不行

使用特权

评论回复
15
missing01|  楼主 | 2014-3-26 10:26 | 只看该作者
明月小厨 发表于 2014-3-26 10:11
我想起来一个问题,是不是要手动先写一个数据到串口中,然后串口和DMA间才会有动作?我是说发送; ...

这么神奇? 你指的是写个数据到 发送寄存器  TDR中???

使用特权

评论回复
16
明月小厨| | 2014-3-26 10:35 | 只看该作者
USART 可以利用DMA 连续通信。Rx 缓冲器和Tx 缓冲器的DMA 请求是分别产生的。
注: 请参见章节24.4: USART 具体功能配备,以确定是否支持DMA 模式。 如果所用产品无DMA 功能,
应按24.5.2 节或24.5.3 节里所描述的方法使用USART。在USART2_SR 寄存器里, 可以清零TXE/RXNE
标志来实现连续通信。

《利用DMA 发送》:
使用DMA 进行发送,可以通过设置USART_CR3 寄存器上的DMAT 位激活。 在设置TXE 位
之前,数据被预先放到DMA 外设所设定的SRAM 区域(参见章节10:直接内存访问控制器)
设置一个DMA 通道给USART 发送,要使用下列步骤(x 指通道号):
1. 在DMA 控制寄存器上将USART_TDR 寄存器地址配置成DMA 传输的目的地址。 在每个
TXE 事件后,数据将被传送到这个地址。
2. 在DMA 控制寄存器上将内存地址配置成DMA 传输的源地址。 在每个TXE 事件后,将从
此存储器区读出数据并传送到USART_TDR 寄存器。
3. 在DMA 控制寄存器中配置要传输的总的字节数。
4. 在DMA 寄存器上配置通道优先级。
5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA 中断。
6. 将USART_ICR 寄存器的TCCF 位置1 以清除USART_ISR 寄存器的TC 标志。(★★★这一步做了吗?)
7. 在DMA 寄存器上激活该通道。
当传输完成DMA 控制器指定的数据量时,DMA 控制器在该DMA 通道的中断向量上产生一中
断。
在发送模式下,当DMA 传输完所有要发送的数据时,DMA 控制器设置DMA_ISR 寄存器的
TCIF 标志;监视USART_SR 寄存器的TC 标志可以确认USART 通信是否结束。 这样可以在
关闭USART 或进入停机模式之前避免破坏最后一次传输的数据。 软件必须等待TC 被置1。
TC 标志在全部数据发送期间会是零,并且在最后一帧数据发送出去之后会由硬件置1。

使用特权

评论回复
17
明月小厨| | 2014-3-26 10:55 | 只看该作者
(USART_CR1):
位 3 TE: 发送器使能
这个位打开发送器。 由软件置1 和清零。
0: 发送器关闭
1: 发送器打开
注: 1: 在发送期间,TE 位上的一个'0' 脉冲('0' 后面跟一个'1') 会引起当前字发送完后跟着再发送一个线路空闲信息出去。但在智能卡模式中则没有这个功能。 要产生一个空闲字符,TE 位不可以立即被写1。 为了确保所需的持续时间,软件可以等一下USART_ ISR 寄存器中的TEACK 位。
2: 当TE 被置为1 后,和发送开始之间有1 个位的延迟时间。

使用特权

评论回复
18
明月小厨| | 2014-3-26 11:01 | 只看该作者
我查看F1XX的相关说明;最后一步操作是 DMA_CRRx的D0位,置1:即开启DMAx通道

使用特权

评论回复
19
missing01|  楼主 | 2014-3-26 15:41 | 只看该作者
明月小厨 发表于 2014-3-26 10:35
USART 可以利用DMA 连续通信。Rx 缓冲器和Tx 缓冲器的DMA 请求是分别产生的。
注: 请参见章节24.4: USART ...

谢谢你发这么多。刚才我在初始化里加上了       
USART1->ICR|=(1<<6); //清除USART->ICR  TCCF 写1  清除USART->ISR寄存器中的TC标志。
  可是还是没有发送出来

使用特权

评论回复
20
香水城| | 2014-3-26 16:31 | 只看该作者
哎,LZ,不是用正确的例程么?

你比较一下不同,即使用到不同DMA通道,或不同的USART模块,比较传输开始前配置的各个寄存器有和不同就可以找到区别了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

115

帖子

2

粉丝