OpenEdv-开源电子网

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

战舰DMA实验 printf("\r\nDMA DATA:\r\n");

[复制链接]

5

主题

19

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2018-4-24
在线时间
12 小时
发表于 2018-6-1 16:32:58 | 显示全部楼层 |阅读模式
5金钱
战舰ZET6 DMA实验  寄存器版本
main函数里面有一句 printf("\r\nDMA DATA:\r\n");是把这句话打印到串口去,在打印“DMA DATA:”前后都有换行操作。可是不知道为什么我把程序下载进去以后只有第一次按KEY0键“DMA DATA:前后会都换行,之后按KEY0键只有前面会换行,而后面不会(从串口调试助手里面看)。
主程序如下

#include "sys.h"
#include "delay.h"
#include "usart.h"

#include "led.h"                           
#include "lcd.h"
#include "key.h"
#include "dma.h"          
//ALIENTEK战舰STM32开发板 实验22
//DMA 实验
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司  

#define SEND_BUF_SIZE 8200        //发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE];        //发送数据缓冲区
const u8 TEXT_TO_SEND[]={"ALIENTEK WarShip STM32F1 DMA 串口实验"};        //本实验要传送的就是这句话

int main(void)
{       
        u16 i;
        u8 t=0;
        u8 j,mask=0;
        float pro=0;                        //进度
       
       
        Stm32_Clock_Init(9);        //系统时钟设置
        uart_init(72,115200);        //串口初始化为115200
        delay_init(72);                            //延时初始化
       
        LED_Init();                                  //初始化与LED连接的硬件接口
        LCD_Init();                                   //初始化LCD        
        KEY_Init();                                //按键初始化                        
        MYDMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)SendBuff,SEND_BUF_SIZE);//DMA1通道4,外设为串口1,存储器为SendBuff,长度SEND_BUF_SIZE.
       
        POINT_COLOR=RED;//设置字体为红色
        LCD_ShowString(30,50,200,16,16,"WarShip STM32");       
        LCD_ShowString(30,70,200,16,16,"DMA TEST");       
        LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
        LCD_ShowString(30,110,200,16,16,"2018/6/1");       
        LCD_ShowString(30,130,200,16,16,"KEY0:Start");//显示提示信息       
       
       
       
        j=sizeof(TEXT_TO_SEND);           //j为"ALIENTEK WarShip STM32F1 DMA 串口实验"这句话的字节个数
        for(i=0;i<SEND_BUF_SIZE;i++)//填充数据到SendBuff  SEND_BUF_SIZE为8200
    {
                if(t>=j)//加入换行符
                {
                        if(mask)
                        {
                                SendBuff=0x0a;
                                t=0;
                        }
                        else
                        {
                                SendBuff=0x0d;
                                mask++;
                        }       
                } //如果"ALIENTEK WarShip STM32F1 DMA 串口实验"存放完了,即需要换行,则在SendBuff后面两个依次加上0X0D和0X0A  ,分别表示回车(光标跑到首位置)和换行的意思,
                //换行后继续存"ALIENTEK WarShip STM32F1 DMA 串口实验",因为在存放换行的时候t赋值为0,因此继续存放,所以最上面写的发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.,那个2就是代表0X0D和0X0A的意思
               
                else        //复制TEXT_TO_SEND语句,即"ALIENTEK WarShip STM32F1 DMA 串口实验"这句话,每次复制一个字节
                {
                        mask=0;
                        SendBuff=TEXT_TO_SEND[t];
                        t++;
                }              
    }       




       
        POINT_COLOR=BLUE;//设置字体为蓝色          
        i=0;
        while(1)
        {
                t=KEY_Scan(0);
                if(t==KEY0_PRES)//KEY0按下
                {
                        LCD_ShowString(30,150,200,16,16,"Start Transimit....");
                        LCD_ShowString(30,170,200,16,16,"   %");//显示百分号
                        printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行
                       
                    USART1->CR3=1<<7;           //使能串口1的DMA发送      
                        MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!          
                    //等待DMA传输完成,此时我们来做另外一些事,点灯
                    //实际应用中,传输数据期间,可以执行另外的任务
                    while(1)
                    {
                                if(DMA1->ISR&(1<<13))//等待通道4传输完成
                                {
                                        DMA1->IFCR|=1<<13;//清除通道4传输完成标志
                                        break;
                        }
                               
                                pro=DMA1_Channel4->CNDTR;//得到当前还剩余多少个数据
                                pro=1-pro/SEND_BUF_SIZE;//得到百分比(已经传输了的数据量占总量的百分比)          
                                pro*=100;      //扩大100倍
                                LCD_ShowNum(30,170,pro,3,16);          
                    }                            
                        LCD_ShowNum(30,170,100,3,16);//显示100%          
                        LCD_ShowString(30,150,200,16,16,"Transimit Finished!");//提示传送完成
                }
                i++;
                delay_ms(10);
                if(i==20)
                {
                        LED0=!LED0;//提示系统正在运行       
                        i=0;
                }                  
        }
}



除了第一次按KEY0之外,其他情况

除了第一次按KEY0之外,其他情况

第一次按KEY0

第一次按KEY0

最佳答案

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

在 printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行 后面加一个delay试试
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2018-6-1 16:32:59 | 显示全部楼层
在  printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行
后面加一个delay试试
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

5

主题

19

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2018-4-24
在线时间
12 小时
 楼主| 发表于 2018-6-2 15:03:05 | 显示全部楼层
本帖最后由 huiye丶666 于 2018-6-2 19:12 编辑

原子哥按你说的操作真的不会出现前后不一致的说法了,请问这是什么原因造成的,为什么加了delay就不会出现了。
                    printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行
                    delay_ms(100);
                    USART1->CR3=1<<7;           //使能串口1的DMA发送      
                    MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!   这一段话明明是先执行   printf("\r\nDMA DATA:\r\n");      后执行开启DMA传送。  难道说printf还没有执行完就执行了开启DMA传送?
回复

使用道具 举报

5

主题

19

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2018-4-24
在线时间
12 小时
 楼主| 发表于 2018-6-2 19:12:24 | 显示全部楼层
正点原子 发表于 2018-6-2 02:03
在  printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行
后面加一个delay试试

原子哥按你说的操作真的不会出现前后不一致的说法了,请问这是什么原因造成的,为什么加了delay就不会出现了。
                    printf("\r\nDMA DATA:\r\n"); //\r代表回车,\n代表换行
                    delay_ms(100);
                    USART1->CR3=1<<7;           //使能串口1的DMA发送      
                    MYDMA_Enable(DMA1_Channel4);//开始一次DMA传输!   这一段话明明是先执行   printf("\r\nDMA DATA:\r\n");      后执行开启DMA传送。  难道说printf还没有执行完就执行了开启DMA传送?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2018-6-3 00:57:44 | 显示全部楼层
huiye丶666 发表于 2018-6-2 19:12
原子哥按你说的操作真的不会出现前后不一致的说法了,请问这是什么原因造成的,为什么加了delay就不会出 ...

因为printf发送的最后一个字符可能还没完成,然后你就开始DMA发送下一个数据了。
导致之前的数据丢失/出错。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
66
金钱
66
注册时间
2019-6-11
在线时间
17 小时
发表于 2019-10-20 22:33:55 | 显示全部楼层
我在mini开发板上的例程 “ALIENTEK MINISTM32 实验18 DMA实验”,也遇到了类似的情况,主要表现为在printf发送与DMA发送的衔接过程中。经过调试,发现的原因是,开启串口DMA发送请求后“USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);”,只要串口的发送buff为空(TXE==1),这个请求就会一直有效,只是说DMA发送完后,不响应这个请求而已。但是中间插入printf发送时,在最后一个字节写入发送buff(USART1->DR)后,就离开printf函数(注意,此时发送buff的数据需要一点时间才会移入的移位寄存器进行发送,初略的测试一下约为1个波特率的时间,如果使用9600波特率,那么就是约为100us),若程序马上开启DMA,由于此时“串口DMA发送请求”有效,DMA就传输数据到发送buff,覆盖了原来的数据,所以导致printf最后一个字节没有发送。解决方法有如下几个:
1、在printf的重映射中,加入TEX的判断,确保串口发送buff的数据已经进入了移位寄存器。
int fputc(int ch, FILE *f)
{      
        while((USART1->SR&0X40)==0);
        USART1->DR = (u8) ch;
        while((USART1->SR&0X80)==0); //新增 代码,判断TEX已经为1,确保数据进入发送移位寄存器
        return ch;
}
2、在printf发送完后,延迟一段时间,至少为一个波特率,然后在开始DMA发送,这样的目的也是使发送buff的数据进入发送移位寄存器,以免被DMA发送来的数据覆盖。
3、在进行DMA发送前,先关闭串口DMA发送请求,使之前一直有效的串口DMA发送请求先关闭,然后重新开启串口DMA发送请求,部分代码如下:
        while(1)
        {
                t=KEY_Scan(0);
                if(t==KEY0_PRES)//KEY0°′&#207;&#194;
                {
                        LCD_ShowString(60,150,200,16,16,"Start Transimit....");
                        LCD_ShowString(60,170,200,16,16,"   %");
                        printf("\r\nDMA DATA:\r\n ");             
                        USART_DMACmd(USART1,USART_DMAReq_Tx,DISABLE);    //新增代码
                        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);      
                        MYDMA_Enable(DMA1_Channel4);  
                    while(1)
                    {
                                if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)
                                {
                                        DMA_ClearFlag(DMA1_FLAG_TC4);
                                        break;
                        }

或者在DMA发送完毕后,关闭串口DMA发送请求,在下次DMA发送时,再开启串口DMA发送请求,部分代码如下:
        while(1)
        {
                t=KEY_Scan(0);
                if(t==KEY0_PRES)//KEY0°′&#207;&#194;
                {
                        LCD_ShowString(60,150,200,16,16,"Start Transimit....");
                        LCD_ShowString(60,170,200,16,16,"   %");
                        printf("\r\nDMA DATA:\r\n ");             
                        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);      
                        MYDMA_Enable(DMA1_Channel4);  
                    while(1)
                    {
                                if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)
                                {
                                        DMA_ClearFlag(DMA1_FLAG_TC4);
                                        USART_DMACmd(USART1,USART_DMAReq_Tx,DISABLE);    //新增代码
                                        break;
                        }
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-6 18:40

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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