STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷
STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷 http://www.openedv.com/thread-63849-1-1.html
实现思路:采 用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数 据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里 面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。
关键代码分析:
usart.H
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h" #define DMA_Rec_Len 200 //定义一个长度为200个字节的数据缓冲区。(建议定义的长度比你可能接收到的最长单帧数据长度长!) void uart_init(u32 bound);
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx); #endif usart.C
//初始化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_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟 USART_DeInit(USART1); //复位串口1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9 //USART1_RX A.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10 //Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
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(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE); //使能串口1 DMA接收
USART_Cmd(USART1, ENABLE); //使能串口 //相应的DMA配置
DMA_DeInit(DMA1_Channel5); //将DMA的通道5寄存器重设为缺省值 串口1对应的是DMA通道5
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设读取发送到内存
DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len; //DMA通道的DMA缓存的大小
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_Normal; //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA1_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道 DMA_Cmd(DMA1_Channel5, ENABLE); //正式驱动DMA传输
} //串口中断函数
void USART1_IRQHandler(void) //串口1中断服务程序
{ if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度 //***********帧数据处理函数************//
printf ("The lenght:%d\r\n",Usart1_Rec_Cnt);
printf ("The data:\r\n");
Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);
printf ("\r\nOver! \r\n");
//*************************************//
USART_ClearITPendingBit(USART1, USART_IT_IDLE); //清除中断标志
MYDMA_Enable(DMA1_Channel5); //恢复DMA指针,等待下一次的接收
} }
这种方式和传统的uart接收中断里面处理数据(解析协议的比较):
//普通方式
uart_rcv_irq()
{
DISABLE_UARTX
if G_Counter >= MAXLEN
clear buffer and counter;
else
G_Buffer[G_Counter]= GetData(UARTX);
G_Counter++;
if OK==unpack(G_Buffer,G_Counter)
clear buffer and counter;
set flag;
ENABLE_UARTX
}
//idle中断 + dma方式
G_Buffer
G_Counter
G_DMARcvBuffer
uart_idle_irq()
{
G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
copy G_DMARcvBuffer to G_Buffer;
if OK==unpack(G_Buffer,G_Counter)
clear buffers and counter;
set flag;
USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
}
DMAx_OVERFLOW_IRQHandler()
{
G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
copy G_DMARcvBuffer to G_Buffer;
if OK==unpack(G_Buffer,G_Counter)
clear buffers and counter;
set flag;
RESET DMA
}
STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷的更多相关文章
- 串口1配合DMA接收不定长数据(空闲中断+DMA接收)
1.空闲中断和别的接收完成(一个字节)中断,发送完成(发送寄存器控)中断的一样是串口中断: 2.空闲中断是接收到一个数据以后,接收停顿超过一字节时间 认为桢收完,总线空闲中断是在检测到在接收数据后, ...
- 串口配合DMA接收不定长数据(空闲中断+DMA接收)-(转载)
1.空闲中断和别的接收完成(一个字节)中断,发送完成(发送寄存器控)中断的一样是串口中断: 2.空闲中断是接收到一个数据以后,接收停顿超过一字节时间 认为桢收完,总线空闲中断是在检测到在接收数据后, ...
- STM32之串口DMA接收不定长数据
STM32之串口DMA接收不定长数据 引言 在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是不定长的有如何高效接收呢? 同学A:数据来了就会进入串口 ...
- STM32 HAL库使用中断实现串口接收不定长数据
以前用DMA实现接收不定长数据,DMA的方法接收串口助手的数据,全部没问题,不过如果接收模块返回的数据,而这些数据如果包含回车换行的话就会停止接收,例如接收:AT\r\nOK\r\n,就只能接收到AT ...
- 关于socket客户端接收不定长数据的解决方案
#!/usr/bin/env python3.5 # -*-coding:utf8-*- """ 本实例客户端用于不断接收不定长数据,存储到变量res "&qu ...
- STM32串口接收不定长数据原理与源程序(转)
今天说一下STM32单片机的接收不定长度字节数据的方法.由于STM32单片机带IDLE中断,所以利用这个中断,可以接收不定长字节的数据,由于STM32属于ARM单片机,所以这篇文章的方法也适合其他的A ...
- Python3的tcp socket接收不定长数据包接收到的数据不全。
Python Socket API参考出处:http://blog.csdn.net/xiangpingli/article/details/47706707 使用socket.recv(pack_l ...
- STM32 ~ USART接收不定长数据
IDLE中断什么时候发生? IDLE就是串口收到一帧数据后,发生的中断.什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据. ...
- Stm32使用串口空闲中断,基于队列来接收不定长、不定时数据
串口持续地接收不定长.不定时的数据,把每一帧数据缓存下来且灵活地利用内存空间,下面提供一种方式供参考.原理是利用串口空闲中断和DMA,每当对方发来一帧完整的数据后,串口接收开始空闲,触发中断,在中断处 ...
随机推荐
- web应用之监听器
package com.log.service; import java.util.Enumeration; import javax.servlet.ServletContext; import j ...
- Linux 网络编程: echo Service
前言 大病初愈,感谢某人的陪伴,感谢王乐庆同学和赵攀同学的细心照顾.原以为过了第八周就不忙了,却没想到还有明天的党章考试.还是写代码比背党章有意思~趁着服务器还没过期,赶紧把 echo 完成了.关于错 ...
- Object-c KVC的使用和举例
如果我们的对象需要使用KVC,必须符合object-c的非正式协议NSKeyValueCoding.我们可以简单的来理解KVC,即所有符合KVC机制的对象都看成一个字典(NSDictionary),对 ...
- jQuery File Upload
jQuery File Upload介绍.............................................. 2 实现基本原理......................... ...
- LintCode-丢失的第一个正整数
题目描述: 给出一个无序的正数数组,找出其中没有出现的最小正整数. 样例 如果给出 [1,2,0], return 3 如果给出 [3,4,-1,1], return 2 挑战 只允许时间复杂度O(n ...
- delphi 编译生成ipa文件
找IPA文件 开发模式ipa文件和发布模式ipa文件,路径不同. http://www.itnose.net/detail/6101808.html 一.开发模式Development 不需要真机,可 ...
- Move WriteBuffer ReadBuffer String
在实际编程中,经常会用到Buffer,当string作为Buffer传值时需要注意的是 1, string的值的起始索引是1,千万记住! 2, 有时候需要先告诉系统去开辟出内存空间,用SetLengt ...
- leetCode解题报告5道题(六)
题目一: Longest Substring Without Repeating Characters Given a string, find the length of the longest s ...
- 【从0開始Tornado建站】群聊
群聊的前台主要代码: {%block content%} <!--<p class='text-success h3'>測试版本号,每天凌晨4:00清水,enjoy it~~:-)& ...
- Struts2之—集成Json插件实现Ajax
上篇博客介绍了Struts2中自己定义结果集实现Ajax,也分析了它的缺点:这样自己定义的结果集,写死了,不能做到client须要什么数据就传什么数据:Struts2之-自己定义结果集实现aja ...