思考再三:终究是要拿出一些干货--单片机基础核心代码,串口的高效率使用请这里开始。--举一反三,我只列出串口一的双dma缓冲应用范例,剩下的自己扩展。并给与了我迄今觉得最好的串口配置架构-感谢野火的高质量代码

#include "sys.h"
#include "usart.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h" //蓝牙
//////////////////////////////////////////////////////////////////////////////////
uart_find uart1s;//定义串口一的接受处理结构体 //局部定义以便实现模块化 //USART
#define USART USART1
#define USART_CLK RCC_APB2Periph_USART1
#define USART_CLK_SET RCC_APB2PeriphClockCmd #define USART_GPIO_CLK_SET RCC_APB2PeriphClockCmd
#define USART_RX_GPIO_PORT GPIOA
#define USART_RX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART_RX_PIN GPIO_Pin_10
#define USART_RX_IRQ USART1_IRQn
#define USART_RX_IRQ_HANDLER USART1_IRQHandler //USART3_IRQHandler #define USART_TX_GPIO_PORT GPIOA
#define USART_TX_GPIO_CLK RCC_APB2Periph_GPIOA
#define USART_TX_PIN GPIO_Pin_9 #define USART_BAUDRATE 115200 //DMA tx
#define USART_DR_BASE (USART1_BASE+0x04) // 0x40013800 + 0x04 = 0x40013804,串口数据寄存器地址
#define SEND_BUFF_SIZE 128 //发送的数据量,SEND_BUFF_SIZE * DMA_MemoryDataSize
#define USART_TX_DMA_CLK RCC_AHBPeriph_DMA1
#define USART_TX_DMA_CHANNEL DMA1_Channel4
#define USART_TX_DMA_IRQ DMA1_Channel4_IRQn//中断接口
#define USART_TX_DMA_IRQ_HANDLER DMA1_Channel4_IRQHandler//中断接口
#define USART_Tx_DMA_FLAG DMA1_FLAG_GL4
//错误标志
#define USART_Tx_ERR_DMA_FLAG DMA1_FLAG_GL4
//DMA rx
#define USART_DR_BASE (USART1_BASE+0x04) // 0x40013800 + 0x04 = 0x40013804,串口数据寄存器地址
#define REC_BUFF_SIZE 128 //发送的数据量,SEND_BUFF_SIZE * DMA_MemoryDataSize
#define USART_RX_DMA_CLK RCC_AHBPeriph_DMA1
#define USART_RX_DMA_CHANNEL DMA1_Channel5
#define USART_RX_DMA_IRQ DMA1_Channel5_IRQn//中断接口
#define USART_RX_DMA_IRQ_HANDLER DMA1_Channel5_IRQHandler//中断接口
#define USART_Rx_DMA_FLAG DMA1_FLAG_GL5
//错误标志
#define USART_Rx_ERR_DMA_FLAG DMA1_FLAG_GL5 static uint8_t SendBuff[SEND_BUFF_SIZE];//发送测试缓冲 static uint8_t rec_by=;//缓冲位置
static uint8_t recBuff[REC_BUFF_SIZE]; //接受测试缓冲 临时缓冲
static uint8_t recBuff1[REC_BUFF_SIZE]; //接受测试缓冲
static uint8_t recBuff2[REC_BUFF_SIZE]; //接受测试缓冲 static u16 rec_counter=; //static uint8_t *send_buff = SendBuff; //锁定发送地址
//static uint8_t *rec_buff1 = recBuff1; //锁定接收地址1
//static uint8_t *rec_buff2 = recBuff2; //锁定接收地址2 static void uart_dma_send(u8 *buff,u8 len);
static void USART_DMA_Config(void);
static void user_heander(void);
static void USART_Config(void);
/**********************************
定义函数接口 ************************************/
void blue_uart_int(void)
{
uart1s.uart_send = uart_dma_send; uart1s.uart_rxbuf_len = &rec_counter;
uart1s.uart_init = USART_Config;
//初始化
uart1s.uart_init(); uart1s.uart_rxbuf1 = recBuff1;
uart1s.uart_rxbuf2 = recBuff2; } /**
* @brief USART GPIO 配置,工作模式配置。115200 8-N-1
* @param 无
* @retval 无
*/
static void USART_Config(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; /*配置使用DMA模式*/
USART_DMA_Config();
USART_GPIO_CLK_SET( USART_RX_GPIO_CLK|USART_TX_GPIO_CLK, ENABLE); /* Enable UART clock */
USART_CLK_SET(USART_CLK, ENABLE); //时钟将会出现大问题
USART_DeInit(USART); //复位串口
/* Configure USART Tx as alternate function */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = USART_TX_PIN ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(USART_TX_GPIO_PORT, &GPIO_InitStructure); /* Configure USART Rx as alternate function */
GPIO_InitStructure.GPIO_Pin = USART_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(USART_RX_GPIO_PORT, &GPIO_InitStructure); // /* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART_RX_IRQ; // 发送DMA通道的中断配置 满中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; // 优先级设置
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); /* USART mode config */
USART_InitStructure.USART_BaudRate = USART_BAUDRATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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(USART, &USART_InitStructure); USART_Cmd(USART, ENABLE);
// USART_ITConfig(USART, USART_IT_RXNE, ENABLE);//开启中断
//
USART_ITConfig(USART, USART_IT_IDLE, ENABLE); // 开启 串口空闲IDEL 中断
/* Enable USARTy DMA TX request */
USART_ITConfig(USART,USART_IT_TC,DISABLE);
// USART_DMACmd(USART, USART_DMAReq_Tx, ENABLE); // 开启串口DMA发送 这两个不能随便开启 开启就是发送
USART_DMACmd(USART, USART_DMAReq_Rx, ENABLE); // 开启串口DMA接收 接受可以提前开启
USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE); // 开启串口DMA发送 printf("串口2初始化\r\n"); } /**
* @brief USART1 TX DMA 配置,内存到外设(USART1->DR)
* @param 无
* @retval 无
*/
static DMA_InitTypeDef DMA_InitStructure1;
static void USART_DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure; /*usart1 tx对应dma2,通道4,数据流7*/ /*开启DMA时钟*/
RCC_AHBPeriphClockCmd(USART_TX_DMA_CLK, ENABLE);
DMA_Cmd(USART_TX_DMA_CHANNEL, DISABLE);
// 关DMA通道
DMA_DeInit(USART_TX_DMA_CHANNEL); // 恢复缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART->DR);// 设置串口发送数据寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff; // 设置发送缓冲区首地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 设置外设位目标,内存缓冲区 -> 外设寄存器
DMA_InitStructure.DMA_BufferSize = uart1s.uart_txbuf_len; // 需要发送的字节数,这里其实可以设置为0,因为在实际要发送的时候,会重新设置次值
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不做增加调整,调整不调整是DMA自动实现的
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存缓冲区地址增加调整
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据宽度8位,1个字节
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 单次传输模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; // 优先级设置
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 关闭内存到内存的DMA模式
DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); // 写入配置
DMA_ClearFlag(USART_Tx_DMA_FLAG); // 清除DMA所有标志
DMA_Cmd(USART_TX_DMA_CHANNEL, DISABLE); // 关闭DMA
DMA_ITConfig(USART_TX_DMA_CHANNEL, DMA_IT_TC, ENABLE);
//中断配置
DMA_ITConfig(USART_TX_DMA_CHANNEL, DMA_IT_TC, ENABLE); NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART_TX_DMA_IRQ; // 发送DMA通道的中断配置 满中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; // 优先级设置
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); /**************************************************************/
//****************************配置接收
/*--- LUMMOD_UART_Rx_DMA_Channel DMA Config ---*/
//启动DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_Cmd(USART_RX_DMA_CHANNEL, DISABLE); // 关DMA通道
DMA_DeInit(USART_RX_DMA_CHANNEL); // 恢复缺省值
DMA_InitStructure1.DMA_PeripheralBaseAddr = (uint32_t)(&USART->DR);// 设置串口接收数据寄存器
DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)recBuff1; // 设置接收缓冲区首地址
DMA_InitStructure1.DMA_DIR = DMA_DIR_PeripheralSRC; // 设置外设为数据源,外设寄存器 -> 内存缓冲区
DMA_InitStructure1.DMA_BufferSize = *uart1s.uart_rxbuf_len; // 需要最大可能接收到的字节数 不能为零
DMA_InitStructure1.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不做增加调整,调整不调整是DMA自动实现的
DMA_InitStructure1.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存缓冲区地址增加调整
DMA_InitStructure1.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 外设数据宽度8位,1个字节
DMA_InitStructure1.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 内存数据宽度8位,1个字节
DMA_InitStructure1.DMA_Mode = DMA_Mode_Normal; // 单次传输模式
DMA_InitStructure1.DMA_Priority = DMA_Priority_VeryHigh; // 优先级设置
DMA_InitStructure1.DMA_M2M = DMA_M2M_Disable; // 关闭内存到内存的DMA模式
DMA_Init(USART_RX_DMA_CHANNEL, &DMA_InitStructure1); // 写入配置
DMA_ClearFlag(USART_Rx_DMA_FLAG); // 清除DMA所有标志
DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE); // 开启接收DMA通道,等待接收数据
//DMA_ITConfig(LUMMOD_UART_Rx_DMA_Channel, DMA_IT_TC, ENABLE); // 开启接收完成DMA通道中断 /* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART_RX_DMA_IRQ; // 发送DMA通道的中断配置 满中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ; // 优先级设置
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*********************************
dma 发送
***********************************/
static void uart_dma_send(u8 *buff,u8 len)
{
memset(SendBuff,,SEND_BUFF_SIZE);
memcpy(SendBuff,buff,len); DMA_SetCurrDataCounter(USART_TX_DMA_CHANNEL,len); //数据传输量
DMA_Cmd(USART_TX_DMA_CHANNEL, ENABLE); //开启DMA传输
/* USART1 向 DMA发出TX请求 */
USART_DMACmd(USART, USART_DMAReq_Tx, ENABLE);//开始发送
} /*********************************************END OF FILE**********************/
/*下面代码我们直接把中断控制逻辑写在中断服务函数内部。*/
//DMA传输接收完成中断
void USART_RX_DMA_IRQ_HANDLER(void)
{ if(DMA_GetITStatus(USART_Rx_DMA_FLAG) != RESET)
{
DMA_ClearITPendingBit(USART_Rx_DMA_FLAG);
// Dma_FreeBuf_Ok = 1;//有准备好的数据了
//数据溢出会出现在这里
}
else
{
DMA_ClearFlag(USART_Rx_ERR_DMA_FLAG);
}
}
/*********************
参数说明:
dma串口通道切换
**********************/
static void buf_chn2(void)
{
if(rec_by==)
{
rec_by=;
DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)recBuff2; // 设置接收缓冲区首地址
DMA_Init(USART_RX_DMA_CHANNEL, &DMA_InitStructure1); // 写入配置
}
else
{
rec_by=;
DMA_InitStructure1.DMA_MemoryBaseAddr = (uint32_t)recBuff1; // 设置接收缓冲区首地址
DMA_Init(USART_RX_DMA_CHANNEL, &DMA_InitStructure1); // 写入配置
}
DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE);
}
//串口1中断服务程序
void USART_RX_IRQ_HANDLER(void)
{
u8 res;
if(USART_GetITStatus(USART, USART_IT_RXNE) != RESET)//接收到数据
{
res=USART->DR; //读取就是清空
//
// while((USART1->SR&0X40)==0);//等待发送结束
// USART1->DR=res;
}
else if(USART_GetITStatus(USART, USART_IT_IDLE) != RESET)//空闲中断
{
u8 clear;
clear=USART->SR;//读SR寄存器
clear=USART->DR;//读DR寄存器 清空数据
/*******************************/
DMA_Cmd(USART_RX_DMA_CHANNEL, DISABLE); // 关闭DMA ,防止干扰
DMA_ClearFlag( USART_Rx_ERR_DMA_FLAG ); // 清DMA标志位
rec_counter = REC_BUFF_SIZE - DMA_GetCurrDataCounter(USART_RX_DMA_CHANNEL); //获得接收到的字节数
USART_RX_DMA_CHANNEL->CNDTR = REC_BUFF_SIZE; // 重新赋值计数值,必须大于等于最大可能接收到的数据帧数目
//开始切换buff
buf_chn2();
// printf("当前是通道二:%s\r\n",recBuff1);
DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE);
//数据转移
memset(recBuff,,REC_BUFF_SIZE);
if(rec_by==)
{
memcpy(recBuff,recBuff1,REC_BUFF_SIZE);
memset(recBuff1,,REC_BUFF_SIZE);
}
else
{
memcpy(recBuff,recBuff2,REC_BUFF_SIZE);
memset(recBuff2,,REC_BUFF_SIZE);
}
user_heander();
//cc3200_rec(); //some things doing
/* DMA 开启,等待数据。注意,如果中断发送数据帧的速率很快,MCU来不及处理此次接收到的数据,中断又发来数据的话,这里不能开启,否则数据会被覆盖。有2种方式解决。
1. 在重新开启接收DMA通道之前,将LumMod_Rx_Buf缓冲区里面的数据复制到另外一个数组中,然后再开启DMA,然后马上处理复制出来的数据。
2. 建立双缓冲,在LumMod_Uart_DMA_Rx_Data函数中,重新配置DMA_MemoryBaseAddr 的缓冲区地址,那么下次接收到的数据就会保存到新的缓冲区中,不至于被覆盖。*/
//注意双缓冲:只需要重新配置,数据地址即可
}
}
//dma2 7 tx 发送完成中断实验
void USART_TX_DMA_IRQ_HANDLER(void)
{
if(DMA_GetITStatus(USART_Tx_DMA_FLAG)!=RESET)
{
DMA_ClearFlag(USART_Tx_DMA_FLAG); // 清除标志
DMA_Cmd(USART_TX_DMA_CHANNEL, DISABLE); // 关闭DMA通道
}
else
{
DMA_ClearFlag(USART_Tx_ERR_DMA_FLAG); // 清除所有错误标志
}
}
/********************************
用户处理程序
**********************************/
static void user_heander(void)
{
// your code
//rest
printf("your printf : %s",recBuff);
}
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h" typedef struct
{
uint8_t * uart_rxbuf1;//接收缓存1
uint8_t * uart_rxbuf2;//接收缓存1 uint8_t * uart_rxbuf;//接收缓存 u16 *uart_rxbuf_len;
//uint8_t rxbuf_counter;//接收位置 uint8_t *uart_txbuf;//接收缓存
uint8_t txbuf_counter;//接收位置
u16 uart_txbuf_len; u8 buff_by;//双缓冲标志 uint8_t recby;//接收标志
uint8_t clear;//清除标志 void (* uart_init)(void); //初始化函数
void (* uart_send)(u8 *buff,u8 len); //发送函数
}uart_find; extern uart_find uart1s;//定义串口一的接受处理结构体
////////////////////uart2
extern uart_find uart2s;//定义串口一的接受处理结构体
///////////////////uart3//////////////////////////////
extern uart_find uart3s;//定义串口一的接受处理结构体 void uart_int(void); void wifi_uart_int(void);
void debug_uart_int(void);
void blue_uart_int(void); //void USART_Config_test(void); u8 String_match(u8 *str_aim,u8 *str_buf,u8 len,u8 len1);//数据匹配函数
u8 String_collect(u8 * aim_buf,u8 *buff,u8 start);
#endif

干货---stm32f103之DMA双缓冲__也算我为网络贡献的微薄之力的更多相关文章

  1. C++双缓冲多线程分析大文件词频

    实习生活告一段落,我正式从一名.NET程序员转入Java阵营,不得不说刚开始用Java的东西是多么的不习惯,但是经过三个月的使用与开发,我也发现了Java的优势:不在于语言,而在于开源.这意味着有更多 ...

  2. (转载)GDI+双缓冲

    双缓冲在GDI+里可以有效的提高描画效率.改善显示的质量. 下面的代码是一个最简单的双缓冲的模板.可以根据需要,做简单的修改即可. Bitmap CacheImage( [Width], [Heigh ...

  3. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  4. MFC双缓冲绘图(2015.09.24)

    问题引入: 最近在尝试编写贪吃蛇游戏时遇到这么一个问题:当系统以较快频率向窗口发送WM_PAINT消息时,调用OnPaint()函数在窗口中绘制图形就会发生闪烁现象. 问题分析: 当我们把绘图过程放在 ...

  5. winform上控件太多,绘制时会逐个出现,通常说双缓冲能解决但实际不能解决的问题的解决方法。

    protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle ...

  6. Winform打砖块游戏制作step by step第6节---双缓冲应用

    一 引子 为了让更多的编程初学者,轻松愉快地掌握面向对象的思考方法,对象继承和多态的妙用,故推出此系列随笔,还望大家多多支持. 二 本节内容---双缓冲应用 1.  主界面截图如下: 2.  什么是双 ...

  7. C++实现双缓冲

    首先声明下,这篇资料也是整理别人的资料的基础上,总结来的. 在图形图像处理过程中,双缓冲技术是一种比较常见的技术.窗体在响应WM_PAINT消息时,需要对图像进行绘制处理.如果图像绘制次数过多,重绘过 ...

  8. OpenGL的消隐与双缓冲

    首先是大家可能已经发现,在我们之前提到的所有例子中,在图形的旋转过程中整个图形都有一定程度的闪烁现象,显得图形的过渡极不平滑,这当然不是我们所要的效果,幸好opengl 支 持一个称为双缓存的技术,可 ...

  9. win32下的双缓冲绘图技术

    一:双缓冲原理 为了解决窗口刷新频率过快所带来的闪烁问题,利用双缓冲技术进行绘图.所谓双缓冲技术,就是将资源加载到内存,然后复制内存数据到设备DC(这个比较快),避免了直接在设备DC上绘图(这个比较慢 ...

随机推荐

  1. 2018-2019-2 20165315 《网络对抗技术》Exp3 免杀原理与实践

    2018-2019-2 20165315 <网络对抗技术>Exp3 免杀原理与实践 一.实验内容 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion ...

  2. Spring+Quartz集群环境下定时调度的解决方案

    集群环境可能出现的问题 在上一篇博客我们介绍了如何在自己的项目中从无到有的添加了Quartz定时调度引擎,其实就是一个Quartz 和Spring的整合过程,很容易实现,但是我们现在企业中项目通常都是 ...

  3. K3精益版给物料添加属性,并在BOM中新增字段引用该属性

    1.给物料新增属性 打开“系统--基础资料--公共资料--核算项目管理”,然后双击物料,弹出核算项目类别-修改对话框.再点新增按钮: 输入你想新增字段的类型,长度,想要放置的位置. 相关属性里面选的是 ...

  4. python chardet

    chardet:字符编码检测工具 字符串编码一直是令人非常头疼的问题,尤其是我们在处理一些不规范的第三方网页的时候.虽然Python提供了Unicode表示的str和bytes两种数据类型,并且可以通 ...

  5. echarts 图表重新加载,原来的数据依然存在图表上

    问题 在做一个全国地图上一些饼图,并且向省一级的地图钻取的时候,原来的饼图依然显示 原因 echars所有添加的图表都在一个series属性集合中,并且同一个echars对象默认是合并之前的数据的,所 ...

  6. skynet记录6:定时器

    稍后填坑 kernel中,每一次时钟中断会trap到kernel code,这个时间间隔称之为jiffies,每秒钟发生的次数为HZ 如果是4核,分配到每个核就是HZ/4 cat /boot/conf ...

  7. 解决删除镜像时image is referenced in multiple repositories

    1.查看镜像 docker images rt@:~# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hours ago MB f8ab12e0 ...

  8. django .all .values .value_list 数据库获取数据

    .all 获取所有的对象 .values 获取所有的字典 .value_list 获取所有的元组

  9. graph_base_pic_segmentation里面的细节和代码

    https://github.com/zhangbo2008/graph_base_pic_segmentation_analyzing/blob/master/README.md

  10. Spring-bean的自动装配

    bean的自动装配:可以让一个bean对象自动的引用其他bean byType:按照类型进行装配.  缺点:如果在IOC容器中存在多个类型相同的bean的时候,会出现异常. <bean id=& ...