搜索
bottom↓
回复: 181

【原创】STM32 UART DMA实现未知数据长度接收

  [复制链接]

出0入0汤圆

发表于 2011-11-9 12:33:02 | 显示全部楼层 |阅读模式
串口通信是经常使用到的功能,在STM32中UART具有DMA功能,并且收发都可以使用DMA,使用DMA发送基本上大家不会遇到什么问题,因为发送的时候会告知DMA发送的数据长度,DMA按照发送的长度直接发送就OK了,但是使用DMA接收时候就不同了,因为有时候数据接收并不是每一次都是定长的,但是DMA只在接收数据长度和设定数据长度相同的时候才可以触发中断,告诉MCU数据接收完毕,针对这个问题,解决方法如下,有一点复杂,但是很管用。
1、        首先了解串口通信的协议

(原文件名:1.jpg)

从上图可知,UART在传输一个字节的时候,首先拉低,传输起始位,然后在是LSB –MSB,最后是停止位,停止位是高电平
2、        超时时间
搞过串口通信的都知道,如果串口有协议,一般都是有个超时时间的,超时时间是定义两个帧之间的间隔的,如果串口接收到一个字节后,在规定的超时时间内没有接收到其他数据,我们则认为前面接收的数据位一帧。

(原文件名:2.jpg)
3、        定时器复位复位模式
STM32定时器功能比较强大,其中有一种模式为复位模式,

(原文件名:3.jpg)
上图STM32 用户手册中的举例,注意红色箭头指向的位置,TI1的输入上升沿会复位定时器的计数器,具体请查阅STM32用户手册关于这部分的描述。
整体的思路是这样的,一开始设置好DMA接收,可以把缓冲区长度设置为帧最大长度,我们可以把RX连接到定时器的管脚输入端,并且一开始设置输入并且使能引脚下降沿中断,当帧的第一个字节发送时,因为起始位为低电平,空闲时UART为高电平,满足条件,进入中断,禁止中断,并且在中断中开启定时器,该定时器工作在复位模式,上升沿复位,并且设置好定时器输出比较值为超时时间,比如20ms,这样,在传输后面字节时,肯定会有高低电平出现,即便是传输的是0x00,0xFF,虽然UART数据区不变,但是都为1,或都为0,但是因为起始位为低电平,停止位是高电平,所以肯定会有上升沿,定时器会一直复位,输出定时器的计数器一直到达不了输出比较值,当一帧传输结束后,定时在最后一个字节复位后,由于没有数据继续到达,无法复位,则计数器就能计到输出比较值,这时发出中断,在定时器中断中可以计算出接收数据的长度,并且通知外部数据已经接收完毕。
4、        功能实现
实现的步骤:
1、硬件连接:UART的RX线在连接外部的同时,还需要连接到一个定时器的输入端TIMx_CHx,定时器可以为任意定时器,但是CHx,只能为CH1或CH2,具体的需要看STM32的定时器逻辑图,以STM32F101CB为例,我们暂定把UART1的RX在连接RS232的同时,还连接到TIM4_CH2。
2、软件设置
a) IO、中断设置:在把UART功能口设置好后,还需要设置TIM4_CH2为输入上拉,并且使能该引脚外部中断

/**
  * @brief  Configures the different GPIO ports.
  * @param  None
  * @retval : None
  */
void GPIO_Configuration(void)
{
/* Configure USART1_Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
   
/* Configure USART1_Tx as alternate push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOB.7 Configuration: TIM4 Channel2 as input floatinng */
GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**
  * @brief  Configures the system EXIT.
  * @param  None
  * @retval None
  */
void EXTI_Configuration(void)
{
    EXTI_InitTypeDef   EXTI_InitStructure;
    /* Connect EXTI8 Line to PB.07 pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);
   
    /* Configure EXTI8 line */
    EXTI_InitStructure.EXTI_Line = EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
   
    /* Clears  EXTI line pending bits. */
    EXTI_ClearITPendingBit(EXTI_Line7);
}

/**
  * @brief  Configures NVIC and Vector Table base location.
  * @param  None
  * @retval : None
  */
void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* Configure the NVIC Preemption Priority Bits*/  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    /* Set the Vector Table base location at 0x08000000 */
    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
  
   
    /* Enable the DMA1_Channel_Rx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Configure DMA1_Channel_Tx interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Configure TIM1 update interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    /* Enable and set EXTI9_5 Interrupt to the lowest priority */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 6;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}
把DMA接收的数据缓冲区设置为你认为最大的帧长度,(如果最长不能确定,也可以随便指定一个长度,后面再讲怎么实现)。
b) 定时器设置
因为使用的是TIM4_CH2,所以需要配置TIM4,并且配置为复位模式,把超时时间定为20ms,为了方便TIM4时钟定输入为1KHZ
/*
* This function is called by timer_init() to perform the non-generic portion
* of the initialization of the timer module.
*/
void timer_init_non_generic(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;
    TIM_ICInitTypeDef  TIM_ICInitStructure;
   
    /* TIM4 configuration ----------------------------------------------------*/
    TIM_TimeBaseStructure.TIM_Period = 65535;
    TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/1000000 * 1000 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
   
    /* Output Compare  Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_Pulse = 20;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC1Init(TIM4, &TIM_OCInitStructure);
   
    /* TIM4 Channel 2 Input Capture Configuration */
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0;
    TIM_ICInit(TIM4, &TIM_ICInitStructure);
   
    /* TIM4 Input trigger configuration: External Trigger connected to TI2 */
    TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
   
    /* TIM4 configuration in slave reset mode  where the timer counter is
    re-initialied in response to rising edges on an input capture (TI2) */
    TIM_SelectSlaveMode(TIM4,  TIM_SlaveMode_Reset);
   
    /* TIM4 IT CC1 enable */
    TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);
   
}
c)工作过程如下
在串口传输起始位的时候,首先产生外部中断,在外部中断中开启定时器,禁止外部中断,只要串口上一直有数据,定时器肯定会不停的复位,到达不了定时时间,当串口上没有数据的时候,到超时时间后,定时器产生中断,此时可以读出接收的数据长度,然后开启外部中断,进入下一个周期。

(原文件名:4.jpg)


总结:本方法的缺点是程序开始的初始化麻烦些,但是优点是非常明显的,彻底解放了CPU,这样在计算串口超时的时候,就不需要定时器不停的中断,并且串口接收数据使用DMA方式,也不需要CPU参与,只是在接收结束的时候通知CPU取数据,CPU的利用率会更高。

出0入0汤圆

发表于 2011-11-9 13:17:26 | 显示全部楼层
思路不错,用在Modbus中不错

出0入0汤圆

发表于 2011-11-9 13:31:38 | 显示全部楼层
mark!,好方法

出0入0汤圆

发表于 2011-11-9 13:48:44 | 显示全部楼层
很不错

出0入0汤圆

发表于 2011-11-9 13:58:02 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-9 15:17:08 | 显示全部楼层
good idea

出0入0汤圆

发表于 2011-11-9 15:21:33 | 显示全部楼层
不错

出0入0汤圆

发表于 2011-11-9 15:29:30 | 显示全部楼层
思路很完美,在单帧数据比较多的时候优势更大。
建议在定时器中断时把当前帧收到的所有数据拷到缓冲区,立即初始化DMA准备下一次接收。

出0入0汤圆

发表于 2011-11-9 15:48:02 | 显示全部楼层
不错,充分利用了STM32的各种功能

出0入0汤圆

发表于 2011-11-9 17:00:59 | 显示全部楼层

出0入8汤圆

发表于 2011-11-9 17:16:22 | 显示全部楼层
这也行!!!

出0入0汤圆

发表于 2011-11-9 17:25:41 | 显示全部楼层
研究一下

出0入0汤圆

发表于 2011-11-9 17:29:33 | 显示全部楼层
mark!

出0入0汤圆

发表于 2011-11-9 17:37:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-9 18:08:23 | 显示全部楼层
马瑞卡  我的做法是帧开始几个字节表示长度 收到后再调整DMA

出0入0汤圆

发表于 2011-11-10 07:44:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-10 08:37:30 | 显示全部楼层
思路很好,软硬结合!厉害!

出0入0汤圆

发表于 2011-11-10 08:50:57 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-11-10 15:07:11 | 显示全部楼层
谢谢大家捧场

出0入0汤圆

 楼主| 发表于 2011-11-10 15:15:34 | 显示全部楼层
思路很完美,在单帧数据比较多的时候优势更大。
建议在定时器中断时把当前帧收到的所有数据拷到缓冲区,立即初始化DMA准备下一次接收。

回复【7楼】lisn3188  龙南
-----------------------------------------------------------------------
其实只要DMA还没有接收满,也就是还没有产生DMA接收中断,就不需要管它,即便数据传输的非常大,超过了你的DMA数据缓冲区,只要还没有产生定时器中断,可以直接把数据拷贝走,然后初始化DMA,继续接收,一直到接收结束超时。

出0入0汤圆

 楼主| 发表于 2011-11-10 15:18:32 | 显示全部楼层
马瑞卡  我的做法是帧开始几个字节表示长度 收到后再调整DMA

回复【14楼】xivisi  LiYong
-----------------------------------------------------------------------
首先 马瑞卡 不知道什么意思

其次你的做法我不太认同,如果数据通信都是你的设备,或者数据通信都是你可控的,你可以这么办,如果系统中还是用其他的设备,并不是你能控制的,那你这种方法就不适用了。

出0入0汤圆

 楼主| 发表于 2011-11-10 15:25:16 | 显示全部楼层
思路很好,软硬结合!厉害!

回复【16楼】xukai871105  
-----------------------------------------------------------------------
非常感谢,我觉的好的方法思路就要和大家共享,技术是个死的,与别人分享,别人才能与你分享,我一直是这么告诉我的工程师的。

出0入0汤圆

发表于 2011-11-10 15:39:51 | 显示全部楼层
回复【20楼】weif40423p  
马瑞卡  我的做法是帧开始几个字节表示长度 收到后再调整dma
回复【14楼】xivisi  liyong
-----------------------------------------------------------------------
首先 马瑞卡 不知道什么意思
其次你的做法我不太认同,如果数据通信都是你的设备,或者数据通信都是你可控的,你可以这么办,如果系统中还是用其他的设备,并不是你能控制的,那你这种方法就不适用了。

-----------------------------------------------------------------------

搜狗  马瑞卡=mark

出0入0汤圆

 楼主| 发表于 2011-11-10 15:55:55 | 显示全部楼层
搜狗  马瑞卡=mark

回复【22楼】xivisi  LiYong
-----------------------------------------------------------------------

搜狗 是个神奇的输入法         

出0入0汤圆

发表于 2011-11-10 17:01:02 | 显示全部楼层
很好很强大!

出0入0汤圆

发表于 2011-11-11 00:37:49 | 显示全部楼层
DMA 适用大数据传输 这方法我觉得没必要 我一般开个 512B的BUF之后DMA 在MDA完成中断内会对 定时器清除下,若200MS定时器溢出后再读出DMA的已完成传输计数便可知道有多少可用数据了。。。。。。。。。。。但楼主的做法好创新。

出0入0汤圆

发表于 2011-11-11 06:55:24 | 显示全部楼层
不错!

出0入4汤圆

发表于 2011-11-11 07:38:10 | 显示全部楼层
嗯,不错,改天试一下3M速度的PROFIBUS,11微秒的中断

出0入0汤圆

 楼主| 发表于 2011-11-11 08:50:44 | 显示全部楼层
回复【25楼】cxjava  
dma 适用大数据传输 这方法我觉得没必要 我一般开个 512b的buf之后dma 在mda完成中断内会对 定时器清除下,若200ms定时器溢出后再读出dma的已完成传输计数便可知道有多少可用数据了。。。。。。。。。。。但楼主的做法好创新。
----------------------------------------------------------------------

有个问题 你什么时候开定时器,还有定时器溢出的时候数据还没有传输结束怎么办,这样不就丢数据了吗?
即便你数据能在200ms内传输完毕,但是超时时间是不是太长了点,如果只传了一个字节,要等200ms后才知道,是不是效率也太低了点。

出0入0汤圆

发表于 2011-11-11 09:23:49 | 显示全部楼层
思路确实不错,可以借签。

出0入0汤圆

发表于 2011-11-11 09:47:36 | 显示全部楼层
不错

出0入0汤圆

发表于 2011-11-11 14:09:35 | 显示全部楼层
感觉还是25楼的方法好一点,毕竟只用软件处理,易于实现,第一个定时中断后可以再开一次较短的定时中断,如接收数不变再读接收数据。

出0入0汤圆

发表于 2011-11-11 14:14:58 | 显示全部楼层
AT91SAM7S64这类ARM7系列有串口PDC接收和超时中断功能,很方便。STM32没有有点遗憾。

出0入0汤圆

 楼主| 发表于 2011-11-12 13:47:12 | 显示全部楼层
自己在顶顶       

出0入0汤圆

发表于 2011-11-12 15:18:30 | 显示全部楼层
我记得stm32有空闲检测的。不需要额外的硬件
这个问题我问过,见http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4660811&bbs_page_no=56&bbs_id=9999

出0入0汤圆

发表于 2011-11-12 16:08:38 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-11-12 17:00:55 | 显示全部楼层
回复【34楼】hemjidn  捱多年
我记得stm32有空闲检测的。不需要额外的硬件
这个问题我问过,见http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4660811&bbs_page_no=56&bbs_id=9999
-----------------------------------------------------------------------

没有看太明白,如果hemjidn  有更好的方法,不妨把方法说的仔细一些,大家都学习一下。

出0入0汤圆

发表于 2011-11-12 17:23:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-12 20:22:49 | 显示全部楼层
回复【36楼】weif40423p  
-----------------------------------------------------------------------

打开usart中断,在中断内判断sr的idle标志位,如果置位则清空闲标志并做DMA处理
就这样完了。我简单测试过能正确识别。
我没使用库函数,贴个程序出来也不通用。

出0入0汤圆

发表于 2011-11-12 21:47:26 | 显示全部楼层
关注。

出0入0汤圆

发表于 2011-11-12 22:18:21 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-11-13 15:21:48 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-11-14 09:37:07 | 显示全部楼层
学习了

出0入0汤圆

 楼主| 发表于 2011-11-14 13:36:58 | 显示全部楼层

出0入0汤圆

发表于 2011-11-14 17:19:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-14 17:37:21 | 显示全部楼层
思路不错

出0入0汤圆

发表于 2011-11-14 22:05:19 | 显示全部楼层
MARK.

出0入0汤圆

 楼主| 发表于 2011-11-15 10:31:26 | 显示全部楼层

出0入0汤圆

发表于 2011-11-15 10:48:49 | 显示全部楼层
思路真新颖!

出0入0汤圆

发表于 2011-11-15 11:17:46 | 显示全部楼层
好,正需要

出0入0汤圆

发表于 2011-11-15 11:19:29 | 显示全部楼层
中断,加环形缓冲区,如果通讯不频繁的话,应该也是很好的方法吧。这个感觉有点复杂。

出0入0汤圆

 楼主| 发表于 2011-11-15 14:34:56 | 显示全部楼层

出0入0汤圆

发表于 2011-11-15 15:34:46 | 显示全部楼层
weif40423p :看了你的程序,我觉得我的思路和你的思路几乎有点相同。只不过我使用的是串口Rx开外部中断,使用TIM2 update中断定时超时,但是我总是接收不到想要的数据长度,总是有数据丢失的情况,在这个帖子总有详细说明,恳请你帮看看,先谢过!http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5201217&bbs_page_no=1&bbs_id=3020

出0入0汤圆

发表于 2011-11-15 15:40:47 | 显示全部楼层
参考了21IC上的,思路是:配置外部中断,将接收引脚(RX)的外部中断打开,当接收第一个数据的起始位时产生外部中断,在外部中断处理程序中,关闭外部中断功能,同时使能定时器,在定时器中断中,计数器加一,当计数器达到延时计数值时,表明DMA接收完数据。此时停止定时器,计算已经接收数据的长度,设置接收结束标志,并对数据进行处理,对接收的数据进行处理后,重新初始化DMA,并打开接收引脚(RX)的外部中断功能。 DMA的接收缓冲区比最长数据还长。

出0入0汤圆

发表于 2011-11-15 17:23:32 | 显示全部楼层
不错,标记一下!

出0入0汤圆

发表于 2011-11-15 19:26:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-16 01:16:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-16 08:15:27 | 显示全部楼层
mark

出0入9汤圆

发表于 2011-11-16 08:25:56 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-16 11:02:08 | 显示全部楼层
mark

出0入0汤圆

 楼主| 发表于 2011-11-17 12:32:28 | 显示全部楼层

出0入0汤圆

发表于 2011-11-17 23:59:38 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-19 23:25:52 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-11-25 18:34:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-25 22:36:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-25 23:30:32 | 显示全部楼层
mark

出0入17汤圆

发表于 2011-11-28 10:50:57 | 显示全部楼层
楼主的方法在高速串口中实时处理单帧很有用!

回复【53楼】anyeliuxingzy
参考了21ic上的,思路是:配置外部中断,将接收引脚(rx)的外部中断打开,当接收第一个数据的起始位时产生外部中断,在外部中断处理程序中,关闭外部中断功能,同时使能定时器,在定时器中断中,计数器加一,当计数器达到延时计数值时,表明dma接收完数据。此时停止定时器,计算已经接收数据的长度,设置接收结束标志,并对数据进行处理,对接收的数据进行处理后,重新初始化dma,并打开接收引脚(rx)的外部中断功能。 dma的接收缓冲区比最长数据还长。

-----------------------------------------------------------------------

你所说的正是楼主的方法。
重新初始化dma--可以用循环模式

出0入0汤圆

发表于 2011-11-28 11:52:12 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-28 22:13:45 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-29 13:26:43 | 显示全部楼层
硬件没留呀,貌似找不到更好的方法了……

出0入0汤圆

发表于 2011-11-29 13:27:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-29 13:42:23 | 显示全部楼层
真是不错,下次改进到我的程序中

出0入0汤圆

 楼主| 发表于 2011-12-1 13:52:56 | 显示全部楼层

出0入0汤圆

发表于 2011-12-10 10:12:11 | 显示全部楼层
定时器中断检查cndtr判断超时方案的路过,感觉也没问题

出0入0汤圆

发表于 2011-12-10 16:21:33 | 显示全部楼层
两年前,ST的工程师就已经将该方式的代码公布在网上了。

出0入228汤圆

发表于 2011-12-11 01:02:35 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-12-11 11:13:00 | 显示全部楼层
记号,备用。

出0入0汤圆

发表于 2011-12-11 13:37:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-11 15:57:17 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-11 20:24:15 | 显示全部楼层
8错8错,学习了。呵呵

出0入0汤圆

发表于 2011-12-12 09:13:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-12 09:33:07 | 显示全部楼层
mark!!!!

出0入0汤圆

 楼主| 发表于 2011-12-12 16:41:17 | 显示全部楼层
回复【74楼】Jun120036  
-----------------------------------------------------------------------

方便的话 还能给个链接 我们在学习学习。

出0入0汤圆

发表于 2011-12-12 16:51:03 | 显示全部楼层
马赛克

出0入0汤圆

发表于 2011-12-13 16:41:03 | 显示全部楼层
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal还是DMA_Mode_Circular?;

出0入0汤圆

发表于 2011-12-19 15:53:46 | 显示全部楼层
good

出0入0汤圆

发表于 2011-12-19 20:59:03 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-19 21:14:31 | 显示全部楼层
看过了,看来我的工程又要改一下了!这个方法好!

出0入0汤圆

发表于 2011-12-19 22:09:22 | 显示全部楼层
GOOD!

出0入0汤圆

发表于 2011-12-19 22:24:47 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-26 17:58:21 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-26 22:03:46 | 显示全部楼层
mark profibus

出0入0汤圆

发表于 2011-12-26 22:40:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-27 09:22:54 | 显示全部楼层
mark!,好方法

出0入0汤圆

发表于 2011-12-27 09:44:03 | 显示全部楼层
这种方法很早以前就已经实现了,不过还是感谢楼主的共享出来给大家。

出0入0汤圆

发表于 2012-1-7 20:15:32 | 显示全部楼层
看一下!

出10入12汤圆

发表于 2012-1-7 21:28:42 | 显示全部楼层
这个要

出0入0汤圆

发表于 2012-1-8 01:24:27 | 显示全部楼层
很实用!

出0入0汤圆

发表于 2012-1-8 02:21:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-2-22 00:33:37 | 显示全部楼层
回复【楼主位】weif40423p  
-----------------------------------------------------------------------

厉害呀
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-7 03:38

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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