OpenEdv-开源电子网

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

采用串口DMA双缓冲方法,快速更新外部FLASH中文字库。更新原子哥例程的4个字库仅需一分钟左右!

  [复制链接]

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
发表于 2015-12-5 20:20:18 | 显示全部楼层 |阅读模式
    最近在玩一个320*480的液晶,想显示中文字体,后来看了原子哥的例程是用FAT文件系统更新的,觉得工程比较大、较麻烦。所以我又开始想借助强大的串口哥实现字库更新了。哈哈.....
  说做就做,但是串口历来速度比较慢,还要考虑到FLASH的写入速度问题,发现网上很多实现方案大都是采用串口发一个字节存储一个字节的方案,那差不多就只能是115200的波特率来存储了。后来为了提高速度,我决定利用STM32 DMA双缓冲的方法,定义两个4096字节的串口DMA缓冲BUF,存满一个换一个的方法。那么可以利用程序稍微计算一下4096字节写入FLASH的时间是多少?
 定义一个4096字节大小的缓冲区:  u8 TEXT_Buffer[4096]={"Holle ..."};
 设置定时器以1MHZ的频率计数:TIM3_CH3_Cap_Init(0XFFFFFFFF,84-1); 
 先擦除FLASH块在写入,计算写入时间:
  W25QXX_Erase_Sector(0);
  TIM_Cmd(TIM3,ENABLE ); //使能定时器3
   W25QXX_Write(TEXT_Buffer,0,4096);
  TIM_Cmd(TIM3,DISABLE ); //关闭定时器3
  TIM3CH3_Count=TIM_GetCounter(TIM3);//获取当前的捕获值.
  printf("Used time:%d us\r\n",TIM3CH3_Count);
   结果:多次复位看的时间很稳定,都是14ms的样子



 那再来试试先不擦除FLASH块,直接写入看看时间:
 // W25QXX_Erase_Sector(0);
  TIM_Cmd(TIM3,ENABLE ); //使能定时器3
  W25QXX_Write(TEXT_Buffer,0,4096);
  TIM_Cmd(TIM3,DISABLE ); //关闭定时器3
  TIM3CH3_Count=TIM_GetCounter(TIM3);//获取当前的捕获值.
  printf("Used time:%d us\r\n",TIM3CH3_Count);
 结果:多次复位看时间,哎呀,貌似有些慢了。。。63ms的样子
 



行。那再来算一下在先擦除块再写入的情况下(13ms),能够允许的最高波特率是多少;
串口发送一个字节的数据是10个比特(在8N1的情况下),那么发送4096个字节需要发送 4096*10 个比特,那么时间不短于13ms的最高比特率就大概是:   4096*10/0.013 = 3150769 ;貌似很大了,没有概念,估计STM32都没法设置这么高了。

 好吧,那就直接从XCOM里面选个最高的波特率来算好了。XCOM可选的最高波特率是 1382400,发送4096个字节时间是:4096*10*1000/1382400=29.6ms;哈哈,看来按照DMA双缓冲4096个字节的方案貌似扛得住高波特率呀。但是把STM32设置成1382400之后发现通信不正常了,好吧,那就降一格。选个921600试试,发现通信正常。那就暂且把波特率设置为921600了。发送4096个字节的时间为:4096*10*1000/921600 = 44.4ms;
 综合考虑:波特率设置为921600;



程序设计思路:设置串口波特率为921600,定义两个4096字节大小的缓冲区BUF_0,BUF_1,初始化DMA为双缓冲接收模式。上电自检FLASH有无字库,没有则先擦除3.1M空间的FLASH以备更新字库。XCOM显示提示字库更新顺序,以及液晶显示字库更新进度。更新完毕后显示 12*12,16*16,24*24 三行不同字体大小的汉字。

注意:程序中根据DMA中断间隔来判断某一字库是否已经发送完毕,方法是判断两个DMA中断的时间间隔大于正常间隔10ms则认为已发送完毕。

USART.c代码:
[mw_shl_code=c,true]//初始化IO 串口1 //bound:波特率 void uart_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); //使能GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6,ENABLE);//使能USART1时钟 //串口1对应引脚复用映射 GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_USART6); //GPIOA9复用为USART1 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_USART6); //GPIOA10复用为USART1 //USART1端口配置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //GPIOA9与GPIOA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉 GPIO_Init(GPIOC,&GPIO_InitStructure); //初始化PA9,PA10 //USART1 初始化设置 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(USART6, &USART_InitStructure); //初始化串口1 USART_Cmd(USART6, ENABLE); //使能串口1 USART_ClearFlag(USART6, USART_FLAG_TC); USART_ITConfig(USART6, USART_IT_RXNE, ENABLE);//开启相关中断 USART_DMACmd(USART6,USART_DMAReq_Rx,ENABLE); //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART6_IRQn;//串口1中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 //DMA配置 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2 时钟使能 DMA_DeInit(DMA2_Stream1); //恢复默认值 串口1接收是DMA2数据流2通道4 while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待 DMA 可配置 /* 配置 DMA Stream */ DMA_InitStructure.DMA_Channel = DMA_Channel_5; //通道选择 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART6->DR;//DMA 外设地址 DMA_InitStructure.DMA_Memory0BaseAddr = (u32)Usart6_Rece_Buf0;//DMA 存储器 0 地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式 DMA_InitStructure.DMA_BufferSize = Usart6_DMA_Len;//数据传输量 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8 位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8 位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//注意:这里设置为循环模式,不然不能启动第二次传输 DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式禁止 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//FIFO 阈值 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输 DMA_DoubleBufferModeConfig(DMA2_Stream1, (uint32_t)Usart6_Rece_Buf1, DMA_Memory_0); //Usart6_Rece_Buf0 先缓冲 DMA_DoubleBufferModeCmd(DMA2_Stream1, ENABLE); DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化 DMA Stream DMA_Cmd(DMA2_Stream1, ENABLE); //开启 DMA 传输 DMA_ITConfig(DMA2_Stream1,DMA_IT_TC,ENABLE); //使能DMA传输完成中断 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn;//DMA2_Stream1_IRQn中断通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority =2; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、 } //开启一次 DMA 传输 //DMA_StreamxMA 数据流,DMA1_Stream0~7/DMA2_Stream0~7 //ndtr:数据传输量 void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr) { DMA_Cmd(DMA_Streamx, DISABLE); //关闭 DMA 传输 while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保 DMA 可以被设置 DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量 DMA_Cmd(DMA_Streamx, ENABLE); //开启 DMA 传输 } void USART6_IRQHandler(void) //串口1中断服务程序 { if(USART_GetITStatus(USART6, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { USART_ReceiveData(USART6);//(USART1->DR); //读取接收到的数据 } } void DMA2_Stream1_IRQHandler(void) //串口1中断服务程序 { if(DMA_GetFlagStatus(DMA2_Stream1,DMA_FLAG_TCIF1)==SET) { DMA_ClearFlag(DMA2_Stream1,DMA_FLAG_TCIF1); //**********************数据帧处理******************// if(1==DMA_GetCurrentMemoryTarget(DMA2_Stream1)) GBK_BUF_Flag=0; else GBK_BUF_Flag=1; //**************************************************// } } [/mw_shl_code]

字库更新部分代码:
[mw_shl_code=c,true]//字库区域占用的总扇区数大小(3个字库+unigbk表+字库信息=3238700字节,约占791个W25QXX扇区) #define FONTSECSIZE 791 //字库存放起始地址 #define FONTINFOADDR 1024*1024*0 //字库存放首地址 //定义各个字库的大小 #define UNIGBK 171*1024 //171KB #define GBK12_FONSIZE 562*1024 //562KB #define GBK16_FONSIZE 749*1024 //749KB #define GBK24_FONSIZE 1684*1024 //1684KB //显示当前字体更新进度 //x,y:坐标 //size:字体大小 //fsize:整个文件大小 //pos:当前文件指针位置 u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos) { float prog; u8 t=0XFF; prog=(float)pos/fsize; prog*=100; if(t!=prog) { LCD_ShowString(x+3*size/2,y,240,320,size,"%"); t=prog; if(t>100)t=100; LCD_ShowNum(x,y,t,3,size);//显示数值 } return 0; } //更新某一个 //x,y:坐标 //size:字体大小 //fx:更新的内容 0,ungbk;1,gbk12;2,gbk16;3,gbk24; //返回值:0,成功;其他,失败. u8 updata_fontx(u16 x,u16 y,u8 size,u8 fx) { u32 flashaddr=0; u8 res; u32 offx=0; u32 fsize=0; switch(fx) { case 0: //更新UNIGBK.BIN ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo); //信息头之后,紧跟UNIGBK转换码表 fsize=ftinfo.ugbksize=UNIGBK; //UNIGBK大小 flashaddr=ftinfo.ugbkaddr; printf("Please send UNIGBK.bin\r\n"); break; case 1: ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize; //UNIGBK之后,紧跟GBK12字库 fsize=ftinfo.gbk12size=GBK12_FONSIZE; //GBK12字库大小 flashaddr=ftinfo.f12addr; //GBK12的起始地址 printf("Please send GBK12.FON\r\n"); break; case 2: ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size; //GBK12之后,紧跟GBK16字库 fsize=ftinfo.gbk16size=GBK16_FONSIZE; //GBK16字库大小 flashaddr=ftinfo.f16addr; //GBK16的起始地址 printf("Please send GBK16.FON\r\n"); break; case 3: ftinfo.f24addr=ftinfo.f16addr+ftinfo.gbk16size; //GBK16之后,紧跟GBK24字库 fsize=ftinfo.gkb24size=GBK24_FONSIZE; //GBK24字库大小 flashaddr=ftinfo.f24addr; //GBK24的起始地址 printf("Please send GBK24.FON\r\n"); break; } fupd_prog(x,y,size,fsize,offx); //进度显示 while(1)//死循环执行 { if(GBK_OVER_Flag) GBK_OVER_Flag++; if(GBK_BUF_Flag!=2) { GBK_OVER_Flag=1; if(GBK_BUF_Flag==0) W25QXX_Write(Usart6_Rece_Buf0,offx+flashaddr,Usart6_DMA_Len); //开始写入Usart6_DMA_Len个数据 else if(GBK_BUF_Flag==1) W25QXX_Write(Usart6_Rece_Buf1,offx+flashaddr,Usart6_DMA_Len); //开始写入Usart6_DMA_Len个数据 offx+=Usart6_DMA_Len; GBK_BUF_Flag=2; fupd_prog(x,y,size,fsize,offx); //进度显示 } delay_us(100); if(GBK_OVER_Flag>(WATE_TIME+10)*10) //超过正常时间10ms则说明此字库发送完毕 break; } if(DMA_GetCurrentMemoryTarget(DMA2_Stream1)==1) W25QXX_Write(Usart6_Rece_Buf1,offx+flashaddr,Usart6_DMA_Len-DMA_GetCurrDataCounter(DMA2_Stream1));//将DMA最后的一帧数据写入FLASH else W25QXX_Write(Usart6_Rece_Buf0,offx+flashaddr,Usart6_DMA_Len-DMA_GetCurrDataCounter(DMA2_Stream1));//将DMA最后的一帧数据写入FLASH printf("This Font updated successfull!\r\n"); uart_init(BAUD_RATE); //重新初始化串口及DMA GBK_OVER_Flag=0; return res; } //更新字体文件,UNIGBK,GBK12,GBK16,GBK24一起更新 //x,y:提示信息的显示地址 //size:字体大小 //提示信息字体大小 //返回值:0,更新成功; // 其他,错误代码. u8 update_font(u16 x,u16 y,u8 size) { u16 i,j; LCD_ShowString(x,y,240,320,size,(u8*)"Erasing sectors... ");//提示正在擦除扇区 for(i=0;i<FONTSECSIZE;i++) //先擦除字库区域,提高写入速度 { fupd_prog(x+20*size/2,y,size,FONTSECSIZE,i);//进度显示 W25QXX_Read((u8*)Usart6_Rece_Buf1,((FONTINFOADDR/4096)+i)*4096,4096);//读出整个扇区的内容(借用一下DMA缓冲区) for(j=0;j<4096;j++)//校验数据 { if(Usart6_Rece_Buf1[j]!=0XFF)break;//需要擦除 } if(j!=4096)W25QXX_Erase_Sector((FONTINFOADDR/4096)+i); //需要擦除的扇区 } delay_ms(100); LCD_ShowString(x,y,240,320,size,(u8*)"Updating UNIGBK.BIN "); updata_fontx(x+20*size/2,y,size,0); //更新GBK12.FON LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK12.FON "); updata_fontx(x+20*size/2,y,size,1); //更新GBK12.FON LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK16.FON "); updata_fontx(x+20*size/2,y,size,2); //更新GBK16.FON LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK24.FON "); updata_fontx(x+20*size/2,y,size,3); //更新GBK16.FON //全部更新好了 ftinfo.fontok=0XAA; W25QXX_Write((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo)); //保存字库信息 printf("All Font file updated successfull!!!\r\n"); LCD_Clear(WHITE); return 0; }[/mw_shl_code]
图片:




工程见附件。

测试视屏:http://v.youku.com/v_show/id_XMTQwNDk3NDU1Ng==.html





 









液晶中文显示(串口更新字库).zip

555.97 KB, 下载次数: 3047

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

15

主题

786

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3223
金钱
3223
注册时间
2015-7-26
在线时间
811 小时
发表于 2015-12-5 21:10:41 | 显示全部楼层
我的博客:http://blog.csdn.net/itdo_just
回复 支持 反对

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2015-12-5 21:41:07 | 显示全部楼层
很不错啊 LZ
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-5 21:46:10 | 显示全部楼层
回复【3楼】ricefat:
---------------------------------
嘿嘿,相比老师来说,水平一般般。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-5 21:46:22 | 显示全部楼层
回复【2楼】229382777@qq.com:
---------------------------------
谢谢
回复 支持 反对

使用道具 举报

33

主题

481

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
5075
金钱
5075
注册时间
2013-10-4
在线时间
654 小时
发表于 2015-12-5 22:01:33 | 显示全部楼层
做的不错,谢谢分享
回复 支持 反对

使用道具 举报

88

主题

7377

帖子

5

精华

资深版主

Rank: 8Rank: 8

积分
14980
金钱
14980
注册时间
2013-11-13
在线时间
1823 小时
发表于 2015-12-5 22:34:49 | 显示全部楼层
不错,厉害啊!多谢分享
开往春天的手扶拖拉机
回复 支持 反对

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
发表于 2015-12-5 22:58:34 | 显示全部楼层
很好,谢谢分享.....
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2015-12-5 23:37:08 | 显示全部楼层
这个必须cool啊
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

13

主题

314

帖子

0

精华

高级会员

Rank: 4

积分
713
金钱
713
注册时间
2012-7-20
在线时间
102 小时
发表于 2015-12-6 00:33:44 | 显示全部楼层
cool........
互联网,智能设备爱好者,欢迎讨论任何有意思的想法。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-6 09:45:43 | 显示全部楼层
回复【9楼】正点原子:
------------------------------
嘿嘿,谢谢原子哥。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-6 09:46:06 | 显示全部楼层
回复【10楼】shibusha:
---------------------------------
谢谢。多多交流。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-6 09:48:32 | 显示全部楼层
回复【7楼】zuozhongkai:
---------------------------------
谢谢版主。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2015-12-6 10:05:15 | 显示全部楼层
很好,很牛逼,谢谢分享!!!
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

18

主题

238

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1823
金钱
1823
注册时间
2014-8-5
在线时间
211 小时
发表于 2015-12-6 17:45:19 | 显示全部楼层
谢谢楼主分享,刚好准备搞下双缓存,谢谢,呵呵
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-6 18:35:49 | 显示全部楼层
回复【14楼】八度空间:
---------------------------------
大牛也来了,多多交流。。
回复 支持 反对

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-12-6 21:27:25 | 显示全部楼层
【串口+双缓存+DMA】相比【串口+双缓存】的优势在哪?
回复 支持 反对

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2015-12-6 22:58:02 | 显示全部楼层
回复【17楼】hello_galaxy:
---------------------------------
DMA的优势是什么
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-7 08:59:31 | 显示全部楼层
回复【17楼】hello_galaxy:
---------------------------------
回复【18楼】ricefat:
---------------------------------
DMA的优势就是不需要CPU干预了,像我上面的程序,电脑可以通过921600的波特率一次性发送一个2M字节的文件给单片机,单片机通过DMA自动的把数据循环缓冲到两个4096字节的BUF里面,每次缓冲满一个BUF会自动调到另一个BUF缓冲区,同时产生一个中断告诉CPU已收到一次4096字节数据,然后处理。  那么单片机就是间隔 4096*10*1000/921600=44.4ms 处理一下数据就可以实现串口发过来的大文件了。如果不这么用,单片机每次接收到一个字节都要中断一次,那情况就不同了,这就是DMA和双缓冲的好处了。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-7 09:01:48 | 显示全部楼层
回复【17楼】hello_galaxy:
---------------------------------
如果不使用DMA的话,那么需要每个字节都产生一个串口中断干扰CPU,按照921600波特率的速度发送文件,单片机就受不了了。
回复 支持 反对

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-12-7 11:23:27 | 显示全部楼层
回复【20楼】1201yuge:
---------------------------------
哦,好的,谢谢指教!!!
回复 支持 反对

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-12-18 15:17:18 | 显示全部楼层
回复【20楼】1201yuge:
---------------------------------
void USART6_IRQHandler(void)                 //串口1中断服务程序
{
if(USART_GetITStatus(USART6, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
    USART_ReceiveData(USART6);//(USART1->DR); //读取接收到的数据   
  } 
}
这段程序不是每接收成功就中断一次???
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-19 15:42:15 | 显示全部楼层
回复【22楼】hello_galaxy:
---------------------------------
不会的,你仿真试一下就知道了
回复 支持 反对

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-12-19 16:30:43 | 显示全部楼层
回复【23楼】1201yuge:
---------------------------------
这倒是没有想到,我试一下,我看网上有人设置为串口空闲中断,只要接受完成后就会中断,而这种方法的好处在与可以接受不同长度的数据!!
回复 支持 反对

使用道具 举报

9

主题

93

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
426
金钱
426
注册时间
2011-7-11
在线时间
49 小时
发表于 2015-12-19 21:27:20 | 显示全部楼层
大神使用f4做的?那f103能做到这么高波特率吗
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-20 18:14:05 | 显示全部楼层
回复【25楼】chenyh85:
---------------------------------
只要串口通信没问题,应该就可以实现这么快,同样的思想。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-20 18:14:16 | 显示全部楼层
回复【25楼】chenyh85:
---------------------------------
只要串口通信没问题,应该就可以实现这么快,同样的思想。
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2015-12-20 18:16:24 | 显示全部楼层
回复【24楼】hello_galaxy:
---------------------------------
这是连续发的,空闲中断hold不住的,没有那么大的缓冲区。DMA接收不定长数据的话看我发的另外一个帖子
回复 支持 反对

使用道具 举报

16

主题

173

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2441
金钱
2441
注册时间
2014-11-5
在线时间
348 小时
发表于 2015-12-21 10:36:12 | 显示全部楼层
回复【28楼】1201yuge:
---------------------------------
恩,是的!!!
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
29
金钱
29
注册时间
2015-12-12
在线时间
2 小时
发表于 2016-1-19 18:29:06 | 显示全部楼层
不错,正需要
回复 支持 反对

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
18 小时
发表于 2016-4-10 15:54:00 | 显示全部楼层
很牛逼的代码 ,但是还是几个不懂  程序相当于一直在调用update_font这个函数。update_font又是不停的在擦区域。但是不懂的是。程序没有等待xcom发生数据。再点击发送文件前,应该是没有数据的,调用写时候但是写入了什么数据?。再点击发送数据时。DMA之前好像没有调用SPI写使能。数据什么时候写入的
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2016-4-11 12:05:55 | 显示全部楼层
wuboaini 发表于 2016-4-10 15:54
很牛逼的代码 ,但是还是几个不懂  程序相当于一直在调用update_font这个函数。update_font又是不停的在擦 ...

在DMA中断里面
回复 支持 反对

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
18 小时
发表于 2016-4-13 12:22:24 | 显示全部楼层

我用在DMA中断函数里面响LCD打印调试信息,发现好像进不了DMA中断。怎么都进去不了。因为我是用的3.5寸的屏幕,代码里面我是把您工程里面的lcd.c改了,换成历程里面的lcd。这会有影响吗?
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2016-4-13 13:21:22 | 显示全部楼层
wuboaini 发表于 2016-4-13 12:22
我用在DMA中断函数里面响LCD打印调试信息,发现好像进不了DMA中断。怎么都进去不了。因为我是用的3.5寸的 ...

你检查一下串口是不是一致的,换掉LCD的函数对串口DMA没有影响的,还有我的这个是用STM32F407单片机写的
回复 支持 反对

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
18 小时
发表于 2016-4-13 13:34:21 来自手机 | 显示全部楼层
wuboaini 发表于 2016-4-13 12:22
我用在DMA中断函数里面响LCD打印调试信息,发现好像进不了DMA中断。怎么都进去不了。因为我是用的3.5寸的 ...

我发现下载的文件中有几个明显的问题。能传个完整的代码给我吗,非常感谢wuboaini1123@sina.com
回复 支持 反对

使用道具 举报

8

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2016-4-10
在线时间
18 小时
发表于 2016-4-13 13:43:47 来自手机 | 显示全部楼层
1201yuge 发表于 2016-4-13 13:21
你检查一下串口是不是一致的,换掉LCD的函数对串口DMA没有影响的,还有我的这个是用STM32F407单片机写的

我是用的xcom传输,也是407的板子,探索者。。开发版自带的usb那串口线。是不是要用纯串口线?或者是要插板子上的串口,而不是那个usb的串口。还有个问题不清楚的就是,为什么板子接上电源后,程序进去了检验是否有字库,察写的地方。但是我一打开串口后。又会进去察写的地方,但是串口一直开着,再打开电源就不会有这个问题。问了这么多问题都回答了,真是感谢。
回复 支持 反对

使用道具 举报

4

主题

63

帖子

0

精华

高级会员

Rank: 4

积分
577
金钱
577
注册时间
2016-2-24
在线时间
94 小时
发表于 2016-4-13 14:01:43 | 显示全部楼层
厉害!
回复 支持 反对

使用道具 举报

13

主题

276

帖子

0

精华

高级会员

Rank: 4

积分
697
金钱
697
注册时间
2014-6-20
在线时间
146 小时
发表于 2016-4-13 14:52:43 | 显示全部楼层
不错的方法,我打算直接用SD卡来弄,因为应用本来就有SD卡
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2016-4-13 15:43:02 | 显示全部楼层
wuboaini 发表于 2016-4-13 13:34
我发现下载的文件中有几个明显的问题。能传个完整的代码给我吗,非常感谢wuboaini1123@sina.com

嗯?这个工程就是我视频上面的工程呀
回复 支持 反对

使用道具 举报

20

主题

468

帖子

3

精华

金牌会员

Rank: 6Rank: 6

积分
1681
金钱
1681
注册时间
2014-2-25
在线时间
229 小时
 楼主| 发表于 2016-4-13 15:43:49 | 显示全部楼层
wuboaini 发表于 2016-4-13 13:43
我是用的xcom传输,也是407的板子,探索者。。开发版自带的usb那串口线。是不是要用纯串口线?或者是要插 ...

仿真一步步查看一下,这是上学期弄的了,一些细节忘记了
回复 支持 反对

使用道具 举报

2

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
55
金钱
55
注册时间
2016-3-22
在线时间
8 小时
发表于 2016-4-13 19:05:15 | 显示全部楼层
谢谢分享,大神
回复 支持 反对

使用道具 举报

4

主题

16

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
470
金钱
470
注册时间
2015-10-29
在线时间
41 小时
发表于 2016-6-25 21:11:10 | 显示全部楼层
好东西  谢谢楼主分享
回复 支持 反对

使用道具 举报

4

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2013-9-7
在线时间
17 小时
发表于 2016-8-27 20:08:28 | 显示全部楼层
这是f4的还是F1的啊?
回复 支持 反对

使用道具 举报

1

主题

43

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
232
金钱
232
注册时间
2016-8-9
在线时间
29 小时
发表于 2016-9-2 16:44:51 | 显示全部楼层
mark!谢谢分享!!
回复 支持 反对

使用道具 举报

39

主题

212

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
303
金钱
303
注册时间
2016-4-21
在线时间
129 小时
发表于 2016-10-29 21:42:57 | 显示全部楼层
楼主,好像你都串口中断里完成接收后没清除标志啊,,,,不会出事吗
本人交流群:136045527,欢迎各位大佬和萌新
回复 支持 反对

使用道具 举报

39

主题

212

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
303
金钱
303
注册时间
2016-4-21
在线时间
129 小时
发表于 2016-10-31 16:06:17 | 显示全部楼层
楼主,F1里面并没有双缓冲,怎么办呢?我想了个办法,也是定义了两个缓存区,dma把缓存区1填满后,产生中断,然后中断里把DMA的接收地址改为缓存区2,(更改DMA的设置得先关闭DMA才能更改)。我的想法就是DMA不停的在缓存区1和缓存区2之间来回填充,但是这样就有个问题,在中断里关闭DMA时,有数据发过来,就会漏掉了....尴尬。不知道是不是因为这个问题又产生一个现象,就是当发送的文件已经发送完成100%时,我的TFT屏幕这里显示接收才接收了40%............波特率我已经改到能达到的最高了,怎么解决这些问题呢....求交流
本人交流群:136045527,欢迎各位大佬和萌新
回复 支持 反对

使用道具 举报

16

主题

189

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1296
金钱
1296
注册时间
2013-8-27
在线时间
503 小时
发表于 2016-11-2 14:37:20 | 显示全部楼层
好!我正用到这个功能
回复 支持 反对

使用道具 举报

2

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
61
金钱
61
注册时间
2016-11-2
在线时间
42 小时
发表于 2016-11-21 22:20:39 | 显示全部楼层
一只风筝 发表于 2016-10-31 16:06
楼主,F1里面并没有双缓冲,怎么办呢?我想了个办法,也是定义了两个缓存区,dma把缓存区1填满后,产生中断 ...

你好,我是个菜鸟,你这个F1 dma双缓冲的搞定了没,最后怎么做的呢?能否分享一下?十分感谢!!!
回复 支持 反对

使用道具 举报

39

主题

212

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
303
金钱
303
注册时间
2016-4-21
在线时间
129 小时
发表于 2016-11-29 19:41:58 | 显示全部楼层
tainan 发表于 2016-11-21 22:20
你好,我是个菜鸟,你这个F1 dma双缓冲的搞定了没,最后怎么做的呢?能否分享一下?十分感谢!!!

F1没双缓冲.....最后我用串口一个一个接收字库的
本人交流群:136045527,欢迎各位大佬和萌新
回复 支持 反对

使用道具 举报

3

主题

36

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
432
金钱
432
注册时间
2014-7-1
在线时间
76 小时
发表于 2016-12-7 16:38:38 | 显示全部楼层
如果重点是快:就串口来说,使用DMA与不使用DMA 区别不大,SPI会提高不少。
DMA主要是解决了占用cpu 的问题
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-22 16:26

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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