搜索
bottom↓
回复: 149

STM32实现USART+DMA接收未知长度的数据和发送

  [复制链接]

出0入0汤圆

发表于 2012-7-14 23:22:52 | 显示全部楼层 |阅读模式
STM32学习笔记三 竹天笑

前言:开始学USART+DMA的时候看到帖子《STM32 UART DMA实现未知数据长度接收》,觉得方法妙极了。此下出自此帖子——(整体的思路是这样的,一开始设置好DMA接收,可以把缓冲区长度设置为帧最大长度,我们可以把RX连接到定时器的管脚输入端,并且一开始设置输入并且使能引脚下降沿中断,当帧的第一个字节发送时,因为起始位为低电平,空闲时UART为高电平,满足条件,进入中断,禁止中断,并且在中断中开启定时器,该定时器工作在复位模式,上升沿复位,并且设置好定时器输出比较值为超时时间,比如20ms,这样,在传输后面字节时,肯定会有高低电平出现,即便是传输的是0x00,0xFF,虽然UART数据区不变,但是都为1,或都为0,但是因为起始位为低电平,停止位是高电平,所以肯定会有上升沿,定时器会一直复位,输出定时器的计数器一直到达不了输出比较值,当一帧传输结束后,定时在最后一个字节复位后,由于没有数据继续到达,无法复位,则计数器就能计到输出比较值,这时发出中断,在定时器中断中可以计算出接收数据的长度,并且通知外部数据已经接收完毕。)

今天我在工作中调通了另一种USART+DMA接收未知数据长度的接收,使用的是USRAT空闲总线中断接收,这种方法也在网站上比较多见,以前没试过,今天才知道如此的爽,另外我使用DMA发送USART数据替代了以前的查询法发送,发现更加爽了。其速度快了很多,尤其是在大量数据传输与发送的时候其优势更加明显。
我举个例子:1、后台数据->USART1-> USART2->其它设备,其它设备数据->USART2-> USART1->后台,这两个数据过程也可能同时进行。
2、由于硬件的限制,USART1和USART2的传输波特率不一样,比如USART1使用GPRS通信,USART2使用短距离无线通信;或者USART1使用以太网通信,USART2使用485总线通信。
由于在寝室只有笔记本电脑,只有一个串口转USB,没办法实现两个串口之间的数据转发了,只好实现串口各自的数据转发。
现在我把我实现的过程简单描述一下:
1、        初始化设置:USART1_RX+DMA1_ Channel5,USART2_RX+DMA1_ Channel6,USART1_TX+DMA1_ Channel4,USART2_TX+DMA1_ Channel7(具体设置请看程序包)。
2、        当数据发送给USART1接收完毕时候会引起USART1的串口总线中断,计算DMA1_ Channel5内存数组剩余容量,得到接收的字符长度。将接收的字符复制给DMA1_ Channel4内存数组,启动DMA1_ Channel4通道传输数据,(传输完成需要关闭。)下一次数据接收可以在启动DMA1_ Channel4时候就开始,不需要等待DMA1_ Channel4数据传输完成。但是上一次DMA1_ Channel4完成之前,不可以将数据复制给DMA1_ Channel4内存数组,会冲掉以前数据。
3、        USART2类同USART1。
呵呵,下面贴程序:
  1. IO口定义:
  2. void GPIO_Configuration(void)
  3. {
  4.           GPIO_InitTypeDef GPIO_InitStructure;
  5.           /* 第1步:打开GPIO和USART部件的时钟 */
  6.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  7.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  8.           /* 第2步:将USART Tx的GPIO配置为推挽复用模式 */
  9.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  10.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  11.           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.           GPIO_Init(GPIOA, &GPIO_InitStructure);
  13.           /* 第3步:将USART Rx的GPIO配置为浮空输入模式
  14.           由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
  15.           但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
  16.           */
  17.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  18.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  19.           GPIO_Init(GPIOA, &GPIO_InitStructure);
  20.         /* 第1步:打开GPIO和USART2部件的时钟 */
  21.         //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
  22.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  23.         /* 第2步:将USART2 Tx的GPIO配置为推挽复用模式 */
  24.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  25.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  26.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  27.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  28.         /* 第3步:将USART2 Rx的GPIO配置为浮空输入模式
  29.                 由于CPU复位后,GPIO缺省都是浮空输入模式,因此下面这个步骤不是必须的
  30.                 但是,我还是建议加上便于阅读,并且防止其它地方修改了这个口线的设置参数
  31.         */
  32.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  33.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  34.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  35.         /*  第3步已经做了,因此这步可以不做
  36.                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  37.         */
  38.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  39. }
  40. 串口初始化:
  41. void USART_Configuration(void)
  42. {
  43.         USART_InitTypeDef USART_InitStructure;
  44.           /* 第4步:配置USART参数
  45.           - BaudRate = 115200 baud
  46.           - Word Length = 8 Bits
  47.           - One Stop Bit
  48.           - No parity
  49.           - Hardware flow control disabled (RTS and CTS signals)
  50.           - Receive and transmit enabled
  51.           */
  52.           USART_InitStructure.USART_BaudRate = 19200;
  53.           USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  54.           USART_InitStructure.USART_StopBits = USART_StopBits_1;
  55.           USART_InitStructure.USART_Parity = USART_Parity_No;
  56.           USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  57.           USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  58.           USART_Init(USART1, &USART_InitStructure);
  59.           //空闲中断
  60.           USART_ITConfig(USART1, USART_IT_IDLE , ENABLE);
  61.         /* 第5步:使能 USART, 配置完毕 */
  62.           USART_Cmd(USART1, ENABLE);  
  63.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  64.           如下语句解决第1个字节无法正确发送出去的问题 */
  65.           USART_ClearFlag(USART1, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */
  66.         USART_InitStructure.USART_BaudRate = 9600;
  67.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  68.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  69.         USART_InitStructure.USART_Parity = USART_Parity_No;
  70.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  71.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  72.           USART_Init(USART2, &USART_InitStructure);
  73.           USART_ITConfig(USART2, USART_IT_IDLE , ENABLE);//开启空闲,帧错,噪声,校验错中断
  74.         USART_Cmd(USART2, ENABLE);
  75.         /* CPU的小缺陷:串口配置好,如果直接Send,则第1个字节发送不出去
  76.           如下语句解决第1个字节无法正确发送出去的问题 */
  77.           USART_ClearFlag(USART2, USART_FLAG_TC); /* 清发送外城标志,Transmission Complete flag */
  78. }
  79. DMA配置:
  80. void DMA_Configuration(void)
  81. {
  82.   DMA_InitTypeDef DMA_InitStructure;
  83.   /* DMA clock enable */
  84.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1
  85.   /* DMA1 Channel4 (triggered by USART1 Tx event) Config */
  86.   DMA_DeInit(DMA1_Channel4);  
  87.   DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
  88.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SEND_DATA;
  89.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  90.   DMA_InitStructure.DMA_BufferSize = 512;
  91.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  92.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  93.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  94.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  95.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  96.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  97.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  98.   DMA_Init(DMA1_Channel4, &DMA_InitStructure);
  99.   DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
  100.   DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);
  101.   /* Enable USART1 DMA TX request */
  102.   USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
  103.   DMA_Cmd(DMA1_Channel4, DISABLE);
  104.   /* DMA1 Channel5 (triggered by USART2 Tx event) Config */
  105.   DMA_DeInit(DMA1_Channel7);  
  106.   DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
  107.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_SEND_DATA;
  108.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  109.   DMA_InitStructure.DMA_BufferSize = 512;
  110.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  111.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  112.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  113.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  114.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  115.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  116.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  117.   DMA_Init(DMA1_Channel7, &DMA_InitStructure);
  118.   DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
  119.   DMA_ITConfig(DMA1_Channel7, DMA_IT_TE, ENABLE);
  120.   /* Enable USART1 DMA TX request */
  121.   USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
  122.   DMA_Cmd(DMA1_Channel7, DISABLE);
  123.   /* DMA1 Channel5 (triggered by USART1 Rx event) Config */
  124.   DMA_DeInit(DMA1_Channel5);  
  125.   DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
  126.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DATA;
  127.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  128.   DMA_InitStructure.DMA_BufferSize = 512;
  129.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  130.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  131.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  132.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  133.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  134.   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  135.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  136.   DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  137.   DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
  138.   DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);
  139.   
  140.   /* Enable USART1 DMA RX request */
  141.   USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
  142.   DMA_Cmd(DMA1_Channel5, ENABLE);
  143.   /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
  144.   DMA_DeInit(DMA1_Channel6);  
  145.   DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;
  146.   DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_RECEIVE_DATA;
  147.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  148.   DMA_InitStructure.DMA_BufferSize = 512;
  149.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  150.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  151.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  152.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  153.   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  154.   DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  155.   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  156.   DMA_Init(DMA1_Channel6, &DMA_InitStructure);
  157.   DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
  158.   DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);
  159.   /* Enable USART2 DMA RX request */
  160.   USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
  161.   DMA_Cmd(DMA1_Channel6, ENABLE);
  162. }
  163. 中断优先级配置:
  164. void NVIC_Configuration(void)
  165. {
  166.   NVIC_InitTypeDef NVIC_InitStructure;
  167.   /* Configure one bit for preemption priority */
  168.   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  
  169.   /* Enable the USART1 Interrupt */
  170.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  171.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  172.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  173.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  174.   NVIC_Init(&NVIC_InitStructure);
  175.   /* Enable the USART2 Interrupt */
  176.   NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  177.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  178.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  179.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  180.   NVIC_Init(&NVIC_InitStructure);
  181.   //Enable DMA Channel4 Interrupt
  182.   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
  183.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  184.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  185.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  186.   NVIC_Init(&NVIC_InitStructure);
  187.   //Enable DMA Channel7 Interrupt
  188.   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
  189.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  190.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  191.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  192.   NVIC_Init(&NVIC_InitStructure);
  193.   /*Enable DMA Channel5 Interrupt */
  194.   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;
  195.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  196.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  197.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  198.   NVIC_Init(&NVIC_InitStructure);
  199.   /*Enable DMA Channel6 Interrupt */
  200.   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
  201.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  202.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  203.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  204.   NVIC_Init(&NVIC_InitStructure);
  205. }
  206. 数组定义,含义如题名:
  207. u8 USART1_SEND_DATA[512];     
  208. u8 USART2_SEND_DATA[512];
  209. u8 USART1_RECEIVE_DATA[512];
  210. u8 USART2_RECEIVE_DATA[512];
  211. u8 USART1_TX_Finish=1;// USART1发送完成标志量
  212. u8 USART2_TX_Finish=1; // USART2发送完成标志量
  213. USART1中断服务函数
  214. void USART1_IRQHandler(void)
  215. {
  216.         u16 DATA_LEN;
  217.         u16 i;
  218.         if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//如果为空闲总线中断
  219.     {
  220.                 DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
  221.                 //USART_RX_STA = USART1->SR;//先读SR,然后读DR才能清除
  222.         //USART_RX_STA = USART1->DR;
  223.                   DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel5);
  224.                 if(DATA_LEN > 0)
  225.         {                       
  226.                         while(USART1_TX_Finish==0)//等待数据传输完成才下一次
  227.             {
  228.                 ;
  229.             }
  230.                         //将数据送DMA存储地址
  231.             for(i=0;i<DATA_LEN;i++)
  232.             {
  233.                 USART1_SEND_DATA[i]=USART1_RECEIVE_DATA[i];
  234.             }
  235.             //USART用DMA传输替代查询方式发送,克服被高优先级中断而产生丢帧现象。
  236.             DMA_Cmd(DMA1_Channel4, DISABLE); //改变datasize前先要禁止通道工作
  237.             DMA1_Channel4->CNDTR=DATA_LEN; //DMA1,传输数据量
  238.             USART1_TX_Finish=0;//DMA传输开始标志量
  239.             DMA_Cmd(DMA1_Channel4, ENABLE);                       
  240.                 }
  241.                 //DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
  242.                 DMA_ClearFlag(DMA1_FLAG_GL5 | DMA1_FLAG_TC5 | DMA1_FLAG_TE5 | DMA1_FLAG_HT5);//清标志
  243.                 DMA1_Channel5->CNDTR = 512;//重装填
  244.                 DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA
  245.                 //读SR后读DR清除Idle
  246.                 i = USART1->SR;
  247.                 i = USART1->DR;
  248.         }
  249.         if(USART_GetITStatus(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出错
  250.         {
  251.                 USART_ClearITPendingBit(USART1, USART_IT_PE | USART_IT_FE | USART_IT_NE);
  252.         }
  253.           USART_ClearITPendingBit(USART1, USART_IT_TC);
  254.           USART_ClearITPendingBit(USART1, USART_IT_IDLE);
  255. }
  256. USART2中断服务函数
  257. void USART2_IRQHandler(void)
  258. {
  259.         u16 DATA_LEN;
  260.         u16 i;
  261.         if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET) //如果为空闲总线中断
  262.     {
  263.                 DMA_Cmd(DMA1_Channel6, DISABLE);//关闭DMA,防止处理其间有数据
  264.                 //USART_RX_STA = USART1->SR;//先读SR,然后读DR才能清除
  265.         //USART_RX_STA = USART1->DR;
  266.                   DATA_LEN=512-DMA_GetCurrDataCounter(DMA1_Channel6);
  267.                 if(DATA_LEN > 0)
  268.         {                       
  269.                         while(USART2_TX_Finish==0)//等待数据完成才下一次
  270.             {
  271.                 ;
  272.             }
  273.                         //将数据送DMA存储地址
  274.             for(i=0;i<DATA_LEN;i++)
  275.             {
  276.                 USART2_SEND_DATA[i]=USART2_RECEIVE_DATA[i];
  277.             }
  278.             //USART用DMA传输替代查询方式发送,克服被高优先级中断而产生丢帧现象。
  279.             DMA_Cmd(DMA1_Channel7, DISABLE); //改变datasize前先要禁止通道工作
  280.             DMA1_Channel7->CNDTR=DATA_LEN; //DMA1,传输数据量
  281.             USART2_TX_Finish=0;//DMA传输开始标志量
  282.             DMA_Cmd(DMA1_Channel7, ENABLE);                       
  283.                 }
  284.                 //DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
  285.                 DMA_ClearFlag(DMA1_FLAG_GL6 | DMA1_FLAG_TC6 | DMA1_FLAG_TE6 | DMA1_FLAG_HT6);//清标志
  286.                 DMA1_Channel6->CNDTR = 512;//重装填
  287.                 DMA_Cmd(DMA1_Channel6, ENABLE);//处理完,重开DMA
  288.                 //读SR后读DR清除Idle
  289.                 i = USART2->SR;
  290.                 i = USART2->DR;
  291.         }
  292.         if(USART_GetITStatus(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//出错
  293.         {
  294.                 USART_ClearITPendingBit(USART2, USART_IT_PE | USART_IT_FE | USART_IT_NE);
  295.         }
  296.           USART_ClearITPendingBit(USART2, USART_IT_TC);
  297.           USART_ClearITPendingBit(USART2, USART_IT_IDLE);
  298. }
  299. DMA1_Channel5中断服务函数
  300. void DMA1_Channel5_IRQHandler(void)
  301. {
  302.   DMA_ClearITPendingBit(DMA1_IT_TC5);
  303.   DMA_ClearITPendingBit(DMA1_IT_TE5);
  304.   DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据
  305.   DMA1_Channel5->CNDTR = 580;//重装填
  306.   DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA
  307. }
  308. DMA1_Channel6中断服务函数
  309. void DMA1_Channel6_IRQHandler(void)
  310. {
  311.   DMA_ClearITPendingBit(DMA1_IT_TC6);
  312.   DMA_ClearITPendingBit(DMA1_IT_TE6);
  313.   DMA_Cmd(DMA1_Channel6, DISABLE);//关闭DMA,防止处理其间有数据
  314.   DMA1_Channel6->CNDTR = 580;//重装填
  315.   DMA_Cmd(DMA1_Channel6, ENABLE);//处理完,重开DMA
  316. }
  317. DMA1_Channel4中断服务函数
  318. //USART1使用DMA发数据中断服务程序
  319. void DMA1_Channel4_IRQHandler(void)
  320. {
  321.   DMA_ClearITPendingBit(DMA1_IT_TC4);
  322.   DMA_ClearITPendingBit(DMA1_IT_TE4);
  323.   DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMA
  324.   USART1_TX_Finish=1;//置DMA传输完成
  325. }
  326. DMA1_Channel7中断服务函数
  327. //USART2使用DMA发数据中断服务程序
  328. void DMA1_Channel7_IRQHandler(void)
  329. {
  330.   DMA_ClearITPendingBit(DMA1_IT_TC7);
  331.   DMA_ClearITPendingBit(DMA1_IT_TE7);
  332.   DMA_Cmd(DMA1_Channel7, DISABLE);//关闭DMA
  333.   USART2_TX_Finish=1;//置DMA传输完成
  334. }
复制代码
呵呵,全部完,但是程序在开始启动时会出现自己发几个不知道什么字符,之后一切正常。如有什么问题,请大神指教。个人认为问题不大,因为在工作的时候通过STM32访问后台或者后台访问STM32大量的间隔密的数据时没有出现问题。而如果没有使用DMA,单帧数据发收可以,多帧数据经过USART1转USART2,就收不到从USART2反馈的第二帧数据了。不一定是速度上的问题,可能是我处理顺序的问题,但是不管是巧合,还是瞎撞的,总归解决办法的就是好办法。
工程下载地址:http://115.com/file/dpj82l3j#
USART_DMA_Interrupt.rar
说明文档下载地址:http://115.com/file/dpj8i8ov#
STM32实现USART+DMA接收未知长度的数据和发送.doc

出0入0汤圆

发表于 2012-7-14 23:36:33 | 显示全部楼层
如果你是用STM32F0的话,哈哈,就有更好的方法啦。
USART有超时中断或帧尾检测

出0入0汤圆

 楼主| 发表于 2012-7-14 23:50:50 | 显示全部楼层
lollipop 发表于 2012-7-14 23:36
如果你是用STM32F0的话,哈哈,就有更好的方法啦。
USART有超时中断或帧尾检测 ...

说的我心痒痒的,可木有办法啊,不能改变硬件了。真想买一块试一下,可惜公司太抠门了。

出0入0汤圆

发表于 2012-7-15 00:33:40 | 显示全部楼层
说明文档无法下载啊

出0入0汤圆

发表于 2012-7-15 00:52:08 | 显示全部楼层
请问串口中断处理中的最后两条语句是作什么用?
USART_ClearITPendingBit(USART1, USART_IT_TC);
USART_ClearITPendingBit(USART1, USART_IT_IDLE);

出0入0汤圆

发表于 2012-7-15 01:02:18 | 显示全部楼层
好东西,支持下~~~

出0入22汤圆

发表于 2012-7-15 01:09:36 | 显示全部楼层
mark!

出0入0汤圆

 楼主| 发表于 2012-7-15 02:42:39 | 显示全部楼层
dosomething 发表于 2012-7-15 00:33
说明文档无法下载啊

已修复。

出0入0汤圆

 楼主| 发表于 2012-7-15 02:43:54 | 显示全部楼层
yzhu 发表于 2012-7-15 00:52
请问串口中断处理中的最后两条语句是作什么用?
USART_ClearITPendingBit(USART1, USART_IT_TC);
USART_Cle ...

清中断标记。

出0入0汤圆

发表于 2012-7-15 08:50:35 | 显示全部楼层
lollipop 发表于 2012-7-14 23:36
如果你是用STM32F0的话,哈哈,就有更好的方法啦。
USART有超时中断或帧尾检测 ...

确实,F0有超时中断,这个连F4都没有。看来后出的芯片功能就是完善呀。

出0入0汤圆

发表于 2012-7-15 09:51:56 | 显示全部楼层
tiancaigao7 发表于 2012-7-15 08:50
确实,F0有超时中断,这个连F4都没有。看来后出的芯片功能就是完善呀。

嗯,有时候追新当小白鼠还是有好处的。

这个功能我已经用上了。

做modbus简单方便。

出0入0汤圆

发表于 2012-7-15 15:05:10 | 显示全部楼层
串口超时中断是不是M0的有的呀,芯唐的M0516也有,做MODBUS确实爽!

出0入0汤圆

发表于 2012-7-15 23:22:23 | 显示全部楼层
再次请问:为什么要清TC中断标记?

出0入0汤圆

 楼主| 发表于 2012-7-16 08:43:18 | 显示全部楼层
yzhu 发表于 2012-7-15 23:22
再次请问:为什么要清TC中断标记?

呵呵,也是哦,应该清接收完成中断,当时复制别人的代码,没注意,也没出错就这样搞了,我回去注释掉试一下,如果没有问题就是不要。

出0入30汤圆

发表于 2012-7-16 18:05:59 | 显示全部楼层
嗯,值得一试。支持。

出0入0汤圆

 楼主| 发表于 2012-7-16 19:19:03 | 显示全部楼层
akwkevin2011 发表于 2012-7-16 08:43
呵呵,也是哦,应该清接收完成中断,当时复制别人的代码,没注意,也没出错就这样搞了,我回去注释掉试一 ...

这句不要。
//USART_ClearITPendingBit(USART1, USART_IT_TC);
呵呵,态度很严谨啊,向你学习。

出0入0汤圆

发表于 2012-8-6 21:26:01 | 显示全部楼层
,不错,值得学习的方法

出0入0汤圆

发表于 2012-8-10 16:26:22 | 显示全部楼层
mark 谢谢楼主

出0入0汤圆

发表于 2012-8-10 18:00:42 | 显示全部楼层
学习了,谢谢楼主

出0入0汤圆

发表于 2012-8-11 12:20:08 | 显示全部楼层
MARK!
头像被屏蔽

出0入0汤圆

发表于 2012-8-29 14:52:30 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2012-8-29 17:26:50 | 显示全部楼层
果断MARK

出0入0汤圆

发表于 2012-8-29 21:46:41 | 显示全部楼层
mark  mark

出0入0汤圆

发表于 2012-8-30 21:39:18 | 显示全部楼层
下来学习,谢谢楼主!

出0入0汤圆

发表于 2012-9-2 21:59:03 | 显示全部楼层
好文,学习了!

出0入0汤圆

发表于 2012-9-2 22:12:36 | 显示全部楼层
不错!MARK

出0入0汤圆

发表于 2012-9-3 10:18:15 | 显示全部楼层
我觉得使用这种超时中断或者F0的中断检测会存在一些缺陷问题:
1,如果发送机器是一个高速的机器,缓存中已经拼好了几帧或者几十帧的数据准备向UART发送。在它发送期间,很有可能会不间断而连续发送,形成“只有一帧”的这种假像,在接收方看来,由於这种帧是不断地,所以不一定会引起定时器的复位,或者F0的中断检测(其实我不太懂F0的中断检测机制,如果F0的中断检测仅仅是以一帧超时来算的话,也会引起同样的问题)。这时,接收方只能一直接收,当缓存小的时候,就会覆盖掉原来的数据,这样会有问题。
2,其中解决的方法不需要太复杂,使用内部定时器隔段时间检测DMA接收到的个数就可以了。例如,如果使用9600通信,最大10字节,那麽你可能就会每接收5个字节为超时时间来检测,即5MS会检测一下DMA的接收个数(按连续接收来说,会接收到5个字节),如果>=10个字节的话,赶紧撤出缓存进行处理。而且,这种结构对环形缓存来说也合适,并不需要在运行时改动RXDMA~

出0入0汤圆

 楼主| 发表于 2012-9-3 14:59:01 | 显示全部楼层
nazily215 发表于 2012-9-3 10:18
我觉得使用这种超时中断或者F0的中断检测会存在一些缺陷问题:
1,如果发送机器是一个高速的机器,缓存中已 ...

你说的这种情况是在DMA缓存长度小于数据长度的情况下,解决方法1:如阁下所说的,定时取数据,然后清空DMA,这个时候会涉及到几帧拼成一帧或者多帧的问题。解决方法2:可以增大DMA的缓存空间,最大可以设置为65535(当然具体情况具体分析),将一次数据全部收过来,这个时候涉及到的就是将帧分成几帧的问题。一般来说数据帧都会有头文件和尾文件,至于拼帧和解帧都不是问题。关键在于不丢帧。个人认为解帧更容易一些。如果是一个高速发送的机器,只要在下一次收到数据前从DMA取出来即可。

出0入0汤圆

 楼主| 发表于 2012-9-3 15:00:16 | 显示全部楼层
nazily215 发表于 2012-9-3 10:18
我觉得使用这种超时中断或者F0的中断检测会存在一些缺陷问题:
1,如果发送机器是一个高速的机器,缓存中已 ...

另外我这个是空闲总线接收,不是定时器接收。

出0入0汤圆

发表于 2012-9-3 17:08:39 | 显示全部楼层
akwkevin2011 发表于 2012-9-3 14:59
你说的这种情况是在DMA缓存长度小于数据长度的情况下,解决方法1:如阁下所说的,定时取数据,然后清空DM ...

缓存MCU只有20-64KB,建议不要轻易放大DMA缓存,毕竟资源不是有限的,况且,往那么大缓存的话,使用效率可能不高。

出0入0汤圆

发表于 2012-9-3 17:10:07 | 显示全部楼层
akwkevin2011 发表于 2012-9-3 15:00
另外我这个是空闲总线接收,不是定时器接收。

嗯,DMA这种是总线空闲接收。那向上层通知接收完的触发机制是?

出0入0汤圆

 楼主| 发表于 2012-9-3 19:40:39 | 显示全部楼层
nazily215 发表于 2012-9-3 17:10
嗯,DMA这种是总线空闲接收。那向上层通知接收完的触发机制是?

空闲总线中断是USART的,触发机制是串口总线上空闲了,即无数据在接收。只不过数据是用DMA方式接收,中断处理程序还在在USART中,需要重新给DMA赋值。

出0入0汤圆

 楼主| 发表于 2012-9-3 19:43:37 | 显示全部楼层
nazily215 发表于 2012-9-3 17:08
缓存MCU只有20-64KB,建议不要轻易放大DMA缓存,毕竟资源不是有限的,况且,往那么大缓存的话,使用效率 ...

呵呵,你说的是,不过具体情况具体分析,如果这个模块只负责转发数据和一些分割数据和组合数据的话,DMA大点也是可以的。

出0入0汤圆

发表于 2012-9-3 20:34:33 | 显示全部楼层
akwkevin2011 发表于 2012-9-3 19:40
空闲总线中断是USART的,触发机制是串口总线上空闲了,即无数据在接收。只不过数据是用DMA方式接收,中断 ...

那試下跑壓力測試吧,跑得過的話就沒問題了,PC使用工具一直向下位機發數據~~

出0入0汤圆

 楼主| 发表于 2012-9-3 21:11:27 | 显示全部楼层
nazily215 发表于 2012-9-3 20:34
那試下跑壓力測試吧,跑得過的話就沒問題了,PC使用工具一直向下位機發數據~~ ...

早测试过了,OK的,数据密度忘记了,一般产品的速度够了。

出0入0汤圆

发表于 2012-9-4 02:20:12 | 显示全部楼层
这么慢的频率下的确需要DMA

出0入0汤圆

发表于 2012-9-7 17:49:25 | 显示全部楼层
我在STM32F0 Discovery板上移植了你写的程序。功能是实现了,但是DMA1_Channel5接收完成中断总是进不去。而且我有点疑问,有了IDLE中断之后还需要Channel5的发送完成中断吗?
另外,在F0系列里面找不到
                i = USART2->SR;
                i = USART2->DR;
但是有USART_ClearITPendingBit(USART2, USART_IT_IDLE);
这两句有什么区别吗?

出0入0汤圆

 楼主| 发表于 2012-9-7 20:54:33 | 显示全部楼层
DMA1_Channel5接收完成中断是在缓冲区接收满了才会进入,而我在USART2中断里重新给DMA1_Channel5赋予计数,也就是说只要帧长不超过缓冲区长度是不会进入DMA1_Channel5接收完成中断。

在USART_DR寄存器中写入了最后一个数据字后,在关闭USART模块之前或设置微控制器进入低功耗模式之前,必须先等待TC=1。
使用下列软件过程清除TC位:
1.读一次USART_SR寄存器;
2.写一次USART_DR寄存器。
在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏最后一次传输。

USART_ClearITPendingBit(USART2, USART_IT_IDLE);是清空闲总线中断标志位。

出0入0汤圆

 楼主| 发表于 2012-9-7 20:54:59 | 显示全部楼层
znsword 发表于 2012-9-7 17:49
我在STM32F0 Discovery板上移植了你写的程序。功能是实现了,但是DMA1_Channel5接收完成中断总是进不去。而 ...

DMA1_Channel5接收完成中断是在缓冲区接收满了才会进入,而我在USART2中断里重新给DMA1_Channel5赋予计数,也就是说只要帧长不超过缓冲区长度是不会进入DMA1_Channel5接收完成中断。

在USART_DR寄存器中写入了最后一个数据字后,在关闭USART模块之前或设置微控制器进入低功耗模式之前,必须先等待TC=1。
使用下列软件过程清除TC位:
1.读一次USART_SR寄存器;
2.写一次USART_DR寄存器。
在USART_DR寄存器中写入最后一个数据字后,要等待TC=1,它表示最后一个数据帧的传输结束。当需要关闭USART或需要进入停机模式之前,需要确认传输结束,避免破坏最后一次传输。

USART_ClearITPendingBit(USART2, USART_IT_IDLE);是清空闲总线中断标志位。


出0入0汤圆

发表于 2012-9-7 23:22:49 | 显示全部楼层
akwkevin2011 发表于 2012-9-7 20:54
DMA1_Channel5接收完成中断是在缓冲区接收满了才会进入,而我在USART2中断里重新给DMA1_Channel5赋予计数 ...

多谢!有点明白了。
1.读一次USART_SR寄存器;
2.写一次USART_DR寄存器。
作用跟
USART_ClearITPendingBit(USART2, USART_IT_TC);
是差不多的。

出0入0汤圆

发表于 2012-9-10 18:35:49 | 显示全部楼层
怎么下载不了啊?哪位能发份给我吗,正在调这个USART,谢谢啊

出0入0汤圆

发表于 2012-9-10 20:30:07 | 显示全部楼层
不错不错,学习中

出0入0汤圆

发表于 2012-9-10 21:46:36 | 显示全部楼层
我在STM32F4里也用的这种总线空闲中断,不过和楼主的有所不同,串口接收发送都是DMA,
DMA发送完成中断;
接收是循环模式,没开中断,初始化后就一直没管了;
串口就开空闲中断,在中断里就给个标志变量,在主程序中直接查这个标志变量就知道有没有收到一帧数据。

出0入0汤圆

发表于 2012-9-10 21:50:30 | 显示全部楼层
我在STM32F4里面也用了这种总线空闲中断,不过和楼主的有所不同,串口数据接收发送都是DMA,
发送完成开中断;
接收是循环模式,初始化后就没管了;
串口就开个空闲中断,中断里就给个标志变量,在主程序中查询这个变量就知道有没有收到一帧数据了。

出0入0汤圆

 楼主| 发表于 2012-9-11 12:27:18 | 显示全部楼层
jiang47 发表于 2012-9-10 21:50
我在STM32F4里面也用了这种总线空闲中断,不过和楼主的有所不同,串口数据接收发送都是DMA,
发送完成开中断 ...

呵呵,我提个疑问,要是数据连收到两帧呢?

出0入0汤圆

 楼主| 发表于 2012-9-11 12:31:22 | 显示全部楼层
llq_ARM 发表于 2012-9-10 18:35
怎么下载不了啊?哪位能发份给我吗,正在调这个USART,谢谢啊

程序重新上传:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-9-11 13:43:30 | 显示全部楼层
akwkevin2011 发表于 2012-9-11 12:27
呵呵,我提个疑问,要是数据连收到两帧呢?

你说的接连收到2帧是  nazily215  所说的情况?就是2帧数据变成了一帧;
还有种就是我收到一帧了,标志位置位了,但是我主程序还没进入串口处理部分,这个时候又收到一帧,就是2次置位了标志位,这种情况因该也是没问题的,解析时一样可以判断出来。
DMA接收区域超过2个帧长,在给2个变量,一个用来指示我已经读到接收区域的位置(就是上次处理完的位置),还一个变量用来指示当前接收的位置,这样应该可以啊。

出0入0汤圆

发表于 2012-9-11 22:51:30 | 显示全部楼层
为什么用STM32F207在
DMA DISABLE后再ENABLE 就再也ENBALE不了,手册上提到 READ LOW,但还是不行
DMA_Cmd(DMA1_Stream2, DISABLE);  
DMA_SetCurrDataCounter(DMA1_Stream2,PC_BUFL);                        
DMA_Cmd(DMA1_Stream2, ENABLE);

出0入0汤圆

 楼主| 发表于 2012-9-12 08:30:43 | 显示全部楼层
没搞过207,有推荐的开发板么?

出675入8汤圆

发表于 2012-9-12 08:42:59 | 显示全部楼层
不错,值得学习的方法

出0入0汤圆

发表于 2012-9-12 08:48:32 | 显示全部楼层
没买过开发板,对着官网原理图做的PCB
但我想407应该是一样的

出0入0汤圆

发表于 2012-9-12 09:00:17 | 显示全部楼层
akwkevin2011 发表于 2012-9-3 21:11
早测试过了,OK的,数据密度忘记了,一般产品的速度够了。

我用空閒也實測了一下,當上層不斷地發送數據,即使是9600波特率,也會導致DMA不斷接收,環形緩沖的話只會覆蓋掉原來的數據,不會產生空閒中斷,所以?
請教一下你的壓力測試是不是一直發數據?用什麼工具測?(有試過用PC工具每1ms發1K個數據,9600之類的?)
但如果有接收一旦出現空閒的話,空閒中斷的方法是很好的。

出0入0汤圆

 楼主| 发表于 2012-9-12 10:35:31 | 显示全部楼层
nazily215 发表于 2012-9-12 09:00
我用空閒也實測了一下,當上層不斷地發送數據,即使是9600波特率,也會導致DMA不斷接收,環形緩沖的話只 ...

我又修改了一下,在DMA完成中断的时候,将DMA的数据全部发出去,这个类似于定长发送形式,并且按照你的方法测试,能发,但是发的速度都没有收的快,数据会出错啊。
这是我改过以后的程序:,求指教如何保护发送的数据不出错。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-9-12 13:52:25 | 显示全部楼层
akwkevin2011 发表于 2012-9-12 10:35
我又修改了一下,在DMA完成中断的时候,将DMA的数据全部发出去,这个类似于定长发送形式,并且按照你的方 ...

粗略看了一下你代碼,有幾點建議一下:
1)你的ISR竟然使用WHILE(1)循環?不妨拖到main函數裏執行?這樣其他中斷能進入,如果你很很充分考慮了優先級問題,累不?或者,出錯了,能調得出來?
2)關於數據出錯推測:A.你的接收是用DMA,然後通過IDLE中斷再進行處理,而且是在ISR裏面做的。B.在ISR裏,你用到了WHILE(1)為的是等TX DMA完成,在此時你又想保證數據接收正確,所以關了RX的DMA。C.直到TX DMA發送完成,把RX DMA的緩存數據向TX DMA緩存起來,準備下一輪的發送。
3)上面B直接導致了問題:其中嚴重的是關了RX DMA,你為的是確保接收正確,的確,接收是正確了,但接收不一定完整,大可能是少了的,在你WHILE的時候,很可能會存在RX有數據進來的情況,而且由於關了RX DMA而不被拿走,不妨檢測一下OVR標誌驗證一下?雖然我沒幫你驗證。
4)發送沒有接收的快,不大清楚你是怎麼測知的。不過通過代碼推,你都是接收完再發送,並在發送時關接收,這樣重複,這無形是一個半雙工狀態,如果你跑測試工具(PC一直發數據),肯定跑不過,會丟一半的包,難道這就是你說的發送沒接收的快?
5)至於出錯就是由於B的原因了。
個人意見,僅供參考,畢竟我沒細讀,只是大致瀏覽。嘿~

出0入0汤圆

发表于 2012-9-12 13:58:10 | 显示全部楼层
jiang47 发表于 2012-9-11 13:43
你说的接连收到2帧是  nazily215  所说的情况?就是2帧数据变成了一帧;
还有种就是我收到一帧了,标志位 ...

其實有一個可能對你產品不會存在,但理論上一定有的問題,就是,當我把你的數據幀拉到超過你的DMA緩沖(或者把“N個幀”拼成“1個幀”),然後再發給你,會出現什麼情況?IDLE中斷是不會通知你的,這時?

出0入0汤圆

发表于 2012-9-12 15:45:57 | 显示全部楼层
nazily215 发表于 2012-9-3 10:18
我觉得使用这种超时中断或者F0的中断检测会存在一些缺陷问题:
1,如果发送机器是一个高速的机器,缓存中已 ...

我觉得在设计系统的时候,串口的帧间隔是要考虑的,一个字节或者两个字节的帧间隔做进去,实现起来不难,后面做关联应用的时候会方便

出0入0汤圆

 楼主| 发表于 2012-9-14 11:30:07 | 显示全部楼层
nazily215 发表于 2012-9-12 13:52
粗略看了一下你代碼,有幾點建議一下:
1)你的ISR竟然使用WHILE(1)循環?不妨拖到main函數裏執行?這 ...

首先非常谢谢前辈的指点。

但我又提出如下几点疑问:

回复4、关于你说的半双工状态,mcu收到数据肯定要处理了,处理数据的话,没收完,能处理吗?(程序中的转发过程等效于实际的处理过程)
回复1、有了回复4这个理由,当然需要判断处理完成没有,因此有了你说的那个while(1),等待数据处理完成。
回复2、3,呵呵,就是你说的这样,但是我也不知道如何处理了。数据一直不断的来,我又需要不断的取出来,取数据的过程还在进数据,只有取的不够快(我这明显慢一些,要出问题),取的肯定是不准的。这个时候空闲总线检测已经失效,那如果实际真那么密集的数据量,那就不能用空闲总线了,还不如就用接收中断,然后用个计数器(或者阁下所说的定时器),取数据即可。

出0入0汤圆

 楼主| 发表于 2012-9-14 11:30:48 | 显示全部楼层
Achin 发表于 2012-9-12 15:45
我觉得在设计系统的时候,串口的帧间隔是要考虑的,一个字节或者两个字节的帧间隔做进去,实现起来不难, ...

恩恩,同意阁下的观点。

出0入0汤圆

发表于 2012-9-14 12:57:40 | 显示全部楼层
akwkevin2011 发表于 2012-9-14 11:30
首先非常谢谢前辈的指点。

但我又提出如下几点疑问:

了解乒乓模式,或者雙緩衝?直接把一個大內存分成2半,用過半中斷吧,DMA是有的,我經常用。一旦用了就變成了雙緩沖了,而且也結合了環形緩沖的特點。這樣就可以很大機會避免WHILE(1),半雙工狀態之類的。至於絕對避免,加幾個變量吧。

出0入0汤圆

发表于 2012-9-14 13:13:46 | 显示全部楼层
mark 学习

出0入0汤圆

发表于 2012-9-15 10:54:51 | 显示全部楼层
akwkevin2011 发表于 2012-9-11 12:31
程序重新上传:

非常感谢

出0入0汤圆

发表于 2012-9-15 16:30:35 | 显示全部楼层
学习下

出0入0汤圆

 楼主| 发表于 2012-9-17 17:03:42 | 显示全部楼层
本帖最后由 akwkevin2011 于 2012-9-17 17:21 编辑
nazily215 发表于 2012-9-12 13:58
其實有一個可能對你產品不會存在,但理論上一定有的問題,就是,當我把你的數據幀拉到超過你的DMA緩沖( ...


非常谢谢nazily215,代码写出来了,用环形DMA方式+空闲总线中断+完成接收中断检测超长,并用任务块的形式将每次收到的数据信息(保存在环形DMA的起始位置)按照任务形式存起来,在发送机制里面一个一个按顺序发,相当于把DMA分成一段一段。

哈哈,估计我程序里面用20个任务块过多了,估计用阁下所说的乒乓就够用。

程序1:,在秒中断里用查询方式查找是否超长,超过512长度,就将其保存起来,可以很准确的保证数据不会超过512,等待发送。
程序2:,在DMA完成接收,过半接收中断里查询数据是否超长,这个时候不能保证数据长度一定是512,介于512-1024之间,(忘了被自己改过了,不是前一句所描述的,是进入了此中断就保存一次数据,改过前的放在程序3)因此所以才会有程序1出现,我又不知道如何在这里面怎么处理了,不可能刚好512就中断吧。
程序3:


这两个经过测试,可用。

还参照了Ya Dan的例程《STM32串口驱动(环形队列+内存动态分配+DMA+拼音检索)》,按照他的思路需要将收到的数据存起来(另外开闭内存空间,涉及到内存空间管理)(这样的程序看的很帅)。
本人还是菜鸟,先不把内存管理移植上来,打算自己写一个。(附,他的程序貌似还有bug,有兴趣自行查找,我上传在此)。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2012-9-17 17:05:39 | 显示全部楼层
一时高兴,忘了给代码做注释了,抱歉,过一久就补上。

出0入0汤圆

发表于 2012-10-5 10:11:09 | 显示全部楼层
很不错的资料啊,严重mark

出0入0汤圆

发表于 2012-10-9 15:15:34 | 显示全部楼层
收藏!!!

出0入0汤圆

发表于 2012-10-15 09:50:18 | 显示全部楼层
留着学习

出0入0汤圆

发表于 2012-10-17 13:06:34 | 显示全部楼层
  不错, 不错。学习了。

出0入0汤圆

发表于 2013-3-15 21:17:42 | 显示全部楼层
多谢   ps  115  真无节操

出0入0汤圆

发表于 2013-3-23 12:01:30 | 显示全部楼层
根据来配置,实现了USART+DMA的接收,串口助手调试通过 感谢LZ

出0入0汤圆

发表于 2013-4-17 00:02:29 | 显示全部楼层
曾经做测试,串口空闲中断作为数据帧超时检测的方法,认为行不通,放弃了这个方法.现在要再研究下这个方法了.

出0入0汤圆

发表于 2013-4-17 23:11:52 | 显示全部楼层
mark下来,好好研究

出0入0汤圆

发表于 2013-4-17 23:16:37 | 显示全部楼层
MARK一下,有空看看

出0入0汤圆

发表于 2013-4-27 10:15:31 | 显示全部楼层
lollipop 发表于 2012-7-14 23:36
如果你是用STM32F0的话,哈哈,就有更好的方法啦。
USART有超时中断或帧尾检测 ...

我目前正在使用STM32F0芯片,要实现Modbus RTU从站功能,目前是使用串口中断接收。单独测试Modbus功能正常。但是和系统其他功能一起跑,Modbus经常会出错。所以想使用DMA来进行接收和发送,释放CPU。可以把你的代码或者思路发给我参考下吗?

emai:zxm0916@qq.com

谢谢!

出0入0汤圆

发表于 2013-5-13 09:54:34 | 显示全部楼层
mark 学习

出0入0汤圆

发表于 2013-5-13 11:58:42 | 显示全部楼层
mark,学习

出0入0汤圆

发表于 2013-5-13 22:10:00 来自手机 | 显示全部楼层
没有硬件fifo就是麻烦

出0入0汤圆

发表于 2013-7-16 22:27:17 | 显示全部楼层
按楼主改后程序,串口助手实现少量数据的简单收发,可是当数据加大,比如一帧80个字节,100ms连续发送就会出错,是什么原因造成的呢?

出0入0汤圆

发表于 2013-7-19 09:51:47 | 显示全部楼层
楼主好人拉

出0入0汤圆

发表于 2013-9-3 20:38:44 | 显示全部楼层
akwkevin2011 发表于 2012-9-17 17:03
非常谢谢nazily215,代码写出来了,用环形DMA方式+空闲总线中断+完成接收中断检测超长,并用任务块的形式 ...

这几个版本,哪一个是比较好用的啊?

出0入0汤圆

发表于 2013-9-9 16:56:54 | 显示全部楼层
文件无法下载

出0入0汤圆

发表于 2013-9-14 14:37:27 | 显示全部楼层
值得研究研究

出0入0汤圆

发表于 2013-9-15 09:38:00 | 显示全部楼层
DMA1_Channel6->CNDTR = 580;//重装填

为什么是580?

出0入0汤圆

 楼主| 发表于 2013-9-20 20:17:14 | 显示全部楼层
wzhenhua 发表于 2013-9-15 09:38
DMA1_Channel6->CNDTR = 580;//重装填

为什么是580?

不好意思,应该是错了,512吧.

出0入0汤圆

 楼主| 发表于 2013-9-20 20:19:58 | 显示全部楼层
xlqiang 发表于 2013-9-3 20:38
这几个版本,哪一个是比较好用的啊?

几个都差不多,你自己也可以写一种.其核心点就是环形接收.

出0入0汤圆

发表于 2013-9-20 20:24:11 | 显示全部楼层
这个用法不错,挺新颖

出0入0汤圆

发表于 2013-9-21 01:41:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-9-23 10:26:45 | 显示全部楼层
单片机效率提高很多

出0入0汤圆

发表于 2013-10-9 21:29:39 | 显示全部楼层
很厉害!

出0入0汤圆

发表于 2013-11-9 17:32:56 来自手机 | 显示全部楼层
mark!^_^

出0入0汤圆

发表于 2013-11-9 17:40:04 | 显示全部楼层
这个方法真心不错,收藏。

出0入0汤圆

发表于 2013-11-26 11:00:29 | 显示全部楼层
mark 好东西

出0入0汤圆

发表于 2013-12-13 17:15:20 | 显示全部楼层
标记一下。细看

出0入0汤圆

发表于 2014-1-5 11:17:47 | 显示全部楼层
mark   整在为串口犯愁呢

出0入0汤圆

发表于 2014-1-10 14:51:54 | 显示全部楼层
worldsing 发表于 2013-5-13 22:10
没有硬件fifo就是麻烦

你用过之后就会发现,原来这个比FIFO好用多了。

出0入0汤圆

发表于 2014-1-14 17:56:42 | 显示全部楼层
MARK MARK

出0入0汤圆

发表于 2014-1-14 20:51:10 | 显示全部楼层
楼主真是有爱啊。赞一个

出0入0汤圆

发表于 2014-1-20 16:45:28 | 显示全部楼层
akwkevin2011 发表于 2012-7-14 23:50
说的我心痒痒的,可木有办法啊,不能改变硬件了。真想买一块试一下,可惜公司太抠门了。 ...

F0这么好啊!

出0入0汤圆

发表于 2014-2-5 10:20:38 | 显示全部楼层
请教楼主一个问题,为仿照你的例程做的串口2的通讯,但是当stm32上电时,通讯异常,按一下复位键通讯就正常了,不知道是怎么回事!启动方式也是没问题的,重新上电和按复位按键有区别吗?谢谢!

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-5-2 06:28

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

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