基于DMA方式的STM32串口通信
- 格式:pptx
- 大小:411.65 KB
- 文档页数:6
STM32CubeMx——串⼝使⽤DMA收发数据⽤到的是DMA发送数据,DMA接收,在中断回调⾥发送出去。
⼀.代码⽣成1.按以前的⽅法设置好时钟和调试⽅式,这⾥就不多说了。
2.设置串⼝1。
3.在DMA Setting⾥点击Add添加USART1_TX,Mode有两种模式,⼀种是普通模式,使⽤⼀次发送语句就发⼀次,另⼀种是循环模式,使⽤⼀次发送会⼀直发送。
这⾥发送我选择普通模式,接收选择循环模式。
4.在中断设置⾥打开串⼝1的中断。
5.时钟和⽂件路径等设置好,然后点⽣成代码。
⼆.代码编写1.先定义发送和接收的数组。
/* USER CODE BEGIN 0 */uint8_t aRxBuffer[1];uint8_t aTxBuffer[]="ok";/* USER CODE END 0 */2.打开串⼝DMA的发送使能,while循环可以放⼀些LED的闪烁。
/* USER CODE BEGIN 2 */HAL_UART_Receive_DMA(&huart1,aRxBuffer,1);HAL_UART_Transmit_DMA(&huart1,aTxBuffer,sizeof(aTxBuffer));/* USER CODE END 2 */3.最后加上⼀个串⼝接收函数的回调函数,把接收到的数据再发出去。
/* USER CODE BEGIN 4 */void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle){HAL_UART_Transmit(&huart1,aRxBuffer,1,0);}/* USER CODE END 4 */现象:上电之后,电脑的串⼝会收到“OK”,然后从电脑发送给芯⽚任意字符,芯⽚再发回来。
总结:使⽤DMA做发送处理,接收数据后⽤串⼝发出去。
为什么接收到数据后不⽤HAL_UART_Transmit_DMA发送出去呢?使⽤这个发现丢包情况,因为这⾥只是测试DMA接收数据情况,接收到之后⼀般是作运算处理的,所以⽤⼀般串⼝发送验证接收的数据正确。
基于stm32的串口通信课程设计基于STM32的串口通信课程设计可以涵盖以下方面的内容:硬件准备:选择适合的STM32微控制器开发板,如STM32F4 Discovery或STM32F103C8T6等。
连接串口调试器(如USB转串口模块)与开发板的串口接口。
连接相关外设(如传感器,显示器等)到开发板的其他GPIO引脚。
开发环境设置:下载并安装STM32CubeIDE或其他适用的开发环境。
配置开发环境以支持选定的STM32开发板。
串口通信基础:学习串口通信的基本原理和通信协议(如UART)。
了解STM32的串口模块的配置和使用方法。
串口发送和接收:学习如何在STM32上配置和初始化串口模块。
实现串口数据的发送和接收功能。
使用中断或DMA方式处理串口数据的发送和接收。
数据解析和显示:设计数据帧格式,包括起始标志、数据字段、校验等。
实现数据解析算法,将接收到的数据解析为可识别的信息。
将解析后的数据通过LCD显示或其他方式展示出来。
通信协议扩展:实现更复杂的通信协议,如帧同步、差错校验、数据压缩等。
添加数据加密、认证或其他安全性功能。
支持多设备通信,如主从通信或多点通信。
实际应用案例:根据实际需求设计和实现一个具体的应用,如传感器数据采集和监控系统、远程控制系统等。
在设计课程时,可以结合理论讲解、实验演示和实际项目实践,使学生能够全面理解串口通信的原理和应用。
此外,建议提供相应的教学资源,如开发板的用户手册、技术文档和示例代码,以便学生更好地学习和实践。
以下是一个基于STM32的串口通信课程设计的简单示例:课程目标:设计一个基于STM32的温度监测系统,通过串口将采集到的温度数据发送到计算机,并在计算机上进行实时显示。
课程内容:硬件准备:使用STM32F4 Discovery开发板和一个温度传感器(例如LM35)。
连接温度传感器到开发板的一个模拟输入引脚(如PA0)。
连接开发板的串口接口(如USART2)到计算机的串口调试器。
串口接收不定长度数据及数据粘包解析的实现1、如何让串口接收不定长度数据想让Stm32 串口接收不定长度数据,这就需要我们开启串口空闲中断(IDLE)方式,所谓串口空闲中断指的是stm32的数据总线在接收数据的过程中,如果总线在接收一个字节所需要的时间内没有再接收到数据,单片机就会判定此时数据已经接收完成了,这时单片机会自动触发空闲中断IDLE标志位,引发空闲中断,我们只需要进入中断取数据就可以了。
使用IDLE空闲中断我们就可以用串口接收任意长度的数据了。
2、串口接收不定长度数据的实现思路我们实现串口接收不定长度数据的思路是:首先我们要定义一个接收数据的缓冲区,一般用数组接收数据,在串口初始化时要开启串口的空闲中断和接收中断。
然后在有中断产生时,我们需要在串口中断函数里判断是空闲中断还是正常接收一个字节数据引起的接收中断,如果是正常接收字节的中断,那么我们需要把接收到的这个字节数据存放到缓冲数组中,如果是IDLE空闲中断,表示串口数据已经接收完成了,我们需要在IDEL中断处理函数中设置一个数据接收完成标志位表示已经完整的接收到一帧数据了,如:RecFlag=1;3、数据粘包解析的实现思路数据粘包是多个数据包发送时由于线路延时,或者发送端发送多个数据包的时间延时很小,导致几个数据包几乎同时到达接收端(数据包到达接收端的时间间隔小于一个字节时间),这样单片机接收数据时就会将这几个数据包当做一帧数据来接收存放。
那么我们如何将这几个数据包合成的一帧数据拆解成几个数据包呢?其实,实现的方法也很简单,这就需要我们在发送端和接收端的数据格式上做一个统一的约定,约定了统一的数据发送格式在发送数据时就严格按照这个格式来发送。
一般来说约定的格式我们要明确规定数据头和数据长度。
然后我们再根据定义的数据头是什么数据,在这一帧数据中逐个去判断当前数据是不是数据头,如果是就说明这个是一个小数据包的开始位置,在根据数据长度就可以解析出一个数据包了。
stm32 uart dma 接收原理-回复STM32 UART DMA 接收原理一、引言串行通信是一种常用的数据传输方式,UART(通用异步收发传输器)是其中一种常见的串行通信接口。
对于STM32微控制器,它支持使用DMA (直接内存访问)来处理UART的接收和发送操作。
本文将重点讨论STM32 UART DMA 接收的原理,详细介绍DMA的工作原理以及如何在STM32中配置和使用DMA来实现UART的接收功能。
二、DMA 简介DMA是一种由硬件支持的直接内存访问技术,它可以在不依赖CPU的情况下,实现外设和内存之间的数据传输。
在传统的方式中,CPU需要花费大量的时间和资源来处理数据的传输,而DMA可以减轻CPU的负担,提高数据传输的效率。
对于STM32微控制器,它提供了多个DMA通道,可以与不同的外设进行数据传输。
三、UART 接收过程UART的接收过程通常分为两步:接收数据和处理数据。
1. 接收数据:UART接收数据的原理是通过接收数据寄存器(Receive Data Register)将接收到的数据保存在寄存器中,然后CPU读取该寄存器以获得接收到的数据。
在传统的方式中,CPU需要不断地查询是否有接收到的数据,并进行读取操作。
但这种方式会浪费CPU的时间和资源。
2. 处理数据:接收到的数据通常需要进行处理,例如判断数据的格式是否正确、提取有效的数据等。
这些处理过程需要CPU的参与,因此如果CPU在不断查询接收数据的过程中被占用,那么处理数据的效率将会大大降低。
四、DMA 接收原理DMA 可以在不依赖CPU的情况下自动执行数据传输操作,因此可以大大提高数据传输的效率。
对于UART的接收过程,STM32提供了DMA 来进行数据的接收,并提供了相应的寄存器和寄存器位来进行配置。
1. 配置UART DMA 模式:首先需要配置UART和DMA的工作模式。
通过UART的控制寄存器和DMA的配置寄存器,可以设置相关的模式。
STM32--—SPI(DMA)通信的总结(库函数操作)本文主要由7项内容介绍SPI并会在最后附上测试源码供参考:1.SPI的通信协议2.SPI通信初始化(以STM32为从机,LPC1114为主机介绍)3.SPI的读写函数4.SPI的中断配置5.SPI的SMA操作6.测试源码7.易出现的问题及原因和解决方法一、SPI的通信协议SPI(Serial Peripheral Interface)是一种串行同步通讯协议,由一个主设备和一个或多个从设备组成,主设备启动一个与从设备的同步通讯,从而完成数据的交换。
SPI 接口一般由4根线组成,CS片选信号(有的单片机上也称为NSS),SCLK时钟信号线,MISO数据线(主机输入从机输出),MOSI数据线(主机输出从机输入),CS 决定了唯一的与主设备通信的从设备,如没有CS 信号,则只能存在一个从设备,主设备通过产生移位时钟信号来发起通讯。
通讯时主机的数据由MISO输入,由MOSI 输出,输入的数据在时钟的上升或下降沿被采样,输出数据在紧接着的下降或上升沿被发出(具体由SPI的时钟相位和极性的设置而决定).二、以STM32为例介绍SPI通信1.STM32f103 带有3个SPI模块其特性如下:2SPI 初始化初始化SPI 主要是对SPI要使用到的引脚以及SPI通信协议中时钟相位和极性进行设置,其实STM32的工程师已经帮我们做好了这些工作,调用库函数,根据自己的需要来修改其中的参量来完成自己的配置即可,主要的配置是如下几项:引脚的配置SPI1的SCLK,MISO ,MOSI分别是PA5,PA6,PA7引脚,这几个引脚的模式都配置成GPIO_Mode_AF_PP 复用推挽输出(关于GPIO的8种工作模式如不清楚请自己百度,在此不解释),如果是单主单从,CS引脚可以不配置,都设置成软件模式即可.通信参数的设置1.SPI_Direction_2Lines_FullDuplex把SPI设置成全双工通信;2.在SPI_Mode 里设置你的模式(主机或者从机),3.SPI_DataSize是来设置数据传输的帧格式的SPI_DataSize_8b是指8位数据帧格式,也可以设置为SPI_DataSize_16b,即16位帧格式4.SPI_CPOL和SPI_CPHA是两个很重要的参数,是设置SPI通信时钟的极性和相位的,一共有四种模式在库函数中CPOL有两个值SPI_CPOL_High(=1)和SPI_CPOL_Low (=0)。
STM32串⼝采⽤DMA⽅式收发FROM:什么是DMA —- Directional Memory Access, 直接存储器存取⽤来提供在外设和存储器之间或者存储器和存储器之间的⾼速数据传输。
⽆须CPU⼲预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作我们通过以下⼏⽅⾯学习串⼝DMA:⼀、如何理解DMA对于DMA,打个⽐⽅就很好理解:⾓⾊预设:淘宝店主 —- STM32 MCU快递员 —- 外设(如UART,SPI)发货室 —- DMA1、⾸先你是⼀个淘宝店主,如果每次发货收货都要跟快递沟通交涉会很浪费时间和精⼒。
2、然后你就⾃⼰建了⼀个发货室,发货室⾥有好多个货柜箱⼦,每个箱⼦上都写着快递名字(如果申通快递,顺丰快递等)。
3、每次发什么快递,你就找到对应的货柜箱⼦,把货物放进去即可,然后跟快递通知⼀声。
4、快递取⾛快件。
5、如果是收货,快递直接把快件放到对应的柜⼦,然后通知你⼀下。
6、你过来提取货物。
通过上⾯的⽅式,你可以不需要直接跟快递打交道,就可以轻松发货成功,DMA处理⽅式跟上⾯例⼦是⼀样的。
如果下图:⼆、STM32 DMA 配置那么DMA在STM32上是具体怎么实现的呢?我们先了解⼀下STM32关于DMA的相关配置。
1、两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道)ps:对应我们例⼦,就是有两个⼤的发货室,⼀个有7个货柜,另个有5个货柜。
2、在同⼀个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很⾼、⾼、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推)ps: 店主可以跟每个快递公司签订协议,可以在货柜前贴上加急(很⾼),很急(⾼),急(中),⼀般(低),如果同时有⼏个快递员过来取货,优先根据上⾯的优先级先取件。
3、独⽴数据源和⽬标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。
源和⽬标地址必须按数据传输宽度对齐。
stm32f103 dma案例STM32F103 DMA(Direct Memory Access)是一种用于高效数据传输的技术,通过在外设和内存之间设置数据传输通道,可以减轻CPU 的负担,提高系统的效率。
在这里,我们将介绍一个使用STM32F103的DMA功能的案例,具体来说是使用DMA传输数据到USART串口。
首先,我们需要在STM32F103上配置USART串口和DMA通道。
我们将USART串口配置为发送模式,并且使能DMA功能。
然后,我们设置DMA通道的传输方向为从内存到外设(USART),并设置传输的数据长度以及数据传输的起始地址。
接下来,我们需要准备要发送的数据,可以是一个字符串、一个数组或者其他形式的数据。
在本例中,我们将准备一个字符串,用于发送到USART串口。
然后,我们需要编写一个函数来启动DMA传输。
在这个函数中,我们首先需要初始化并配置DMA通道。
然后,我们将准备好的数据作为源地址传递给DMA,并设置传输的长度。
最后,我们启动DMA传输。
在主函数中,我们调用启动DMA传输的函数,并通过USART串口发送了一段文本。
在运行程序时,DMA将负责将数据从内存传输到USART串口,而不需要CPU的干预。
这样,我们可以节省CPU的处理时间,并提高系统的效率。
下面是一个使用STM32F103的DMA功能的示例代码:```c#include "stm32f10x.h"#define USART1_DMA_CHANNEL DMA1_Channel4#define USART1_DMA_STREAM DMA1_Stream4#define USART1_DR_ADDRESS ((uint32_t)0x40013804)void DMA_USART_Send(char* data, uint16_t length) {DMA_InitTypeDef dmaInitStruct;/*开启DMA和USART时钟*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);/*初始化DMA通道*/DMA_DeInit(USART1_DMA_CHANNEL);DMA_StructInit(&dmaInitStruct);dmaInitStruct.DMA_PeripheralBaseAddr = USART1_DR_ADDRESS;dmaInitStruct.DMA_MemoryBaseAddr = (uint32_t)data;dmaInitStruct.DMA_DIR = DMA_DIR_PeripheralDST;dmaInitStruct.DMA_BufferSize = length;dmaInitStruct.DMA_PeripheralInc =DMA_PeripheralInc_Disable;dmaInitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;dmaInitStruct.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte;dmaInitStruct.DMA_MemoryDataSize =DMA_MemoryDataSize_Byte;dmaInitStruct.DMA_Mode = DMA_Mode_Normal;dmaInitStruct.DMA_Priority = DMA_Priority_High; dmaInitStruct.DMA_M2M = DMA_M2M_Disable;DMA_Init(USART1_DMA_CHANNEL, &dmaInitStruct); /*配置USART串口*/USART_InitTypeDef usartInitStruct;USART_StructInit(&usartInitStruct); ART_BaudRate = 9600;USART_Init(USART1, &usartInitStruct);/*启动DMA传输*/DMA_Cmd(USART1_DMA_CHANNEL, ENABLE);USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); }int main(void) {/*初始化串口*/USART_InitTypeDef usartInitStruct;USART_StructInit(&usartInitStruct);ART_BaudRate = 9600;USART_Init(USART1, &usartInitStruct);/*启动DMA传输*/char data[] = "Hello, DMA!";DMA_USART_Send(data, sizeof(data));while(1);return 0;}```以上代码中,我们使用了STM32F103的库函数来进行配置和操作,使得编程更加方便快捷。
STM32F103多个串口配置DMA程序(纯代码版详解)软件:KeilMDK芯片:STM32F103/STM32F107串口数量:4备注:4个串口均配置为DMA读取//串口1初始化函数void uart1_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_A PB2Periph_GPIOA, ENABLE);//使能USART1,GPIOA时钟USART_DeInit(USART1); //复位串口1//USART1_TX PA.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9//USART1_RX PA.10GPIO_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=1 ; //抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器/*Enable DMA Channel4 Interrupt */NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/*Enable DMA Channel5 Interrupt */NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel5_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);//USART 参数初始化设置USART_/doc/c517407538.html,ART_B audRate = bound;//一般设置为9600;USART_/doc/c517407538.html,ART_W ordLength = USART_WordLength_8b;//字长为8位数据格式USART_/doc/c517407538.html,ART_St opBits = USART_StopBits_1;//一个停止位USART_/doc/c517407538.html,ART_Parity = USART_Parity_No;//无奇偶校验位USART_/doc/c517407538.html,ART_H ardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_/doc/c517407538.html,ART_M ode = USART_Mode_Rx | USART_Mode_Tx;//收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断USART_ITConfig(USART1, USART_IT_IDLE , ENABLE); //开启空闲中断USART_Cmd(USART1, ENABLE); //使能串口}//串口2初始化函数void uart2_init(u32 bound){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENAB LE);//使能USART2时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENAB LE);//复位串口2RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISAB LE);//停止复位USART_/doc/c517407538.html,ART_B audRate = bound;//一般设置为9600;USART_/doc/c517407538.html,ART_W ordLength = USART_WordLength_8b;//8位数据长度USART_/doc/c517407538.html,ART_St opBits = USART_StopBits_1;//一个停止位USART_/doc/c517407538.html,ART_Pa rity = USART_Parity_No;///奇偶校验位USART_/doc/c517407538.html,ART_H ardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_/doc/c517407538.html,ART_M ode = USART_Mode_Rx | USART_Mode_Tx;//收发模式USART_Init(USART2, &USART_InitStructure); ; //初始化串口NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级2级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级2级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器//////////////////////Enable DMA Channel7 Interrupt //////////////////////////////NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/*Enable DMA Channel6 Interrupt */NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断USART_ITConfig(USART2, USART_IT_IDLE , ENABLE); //开启空闲中断USART_Cmd(USART2, ENABLE); //使能串口}//串口3初始化函数void uart3_init(u32 bound){//GPIO端口设置GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //使能GPIOB时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENAB LE); //使能USART3时钟USART_DeInit(USART3); //复位串口3//USART1_TX PB.10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB.11//USART1_RX PB.11GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB//USART 初始化设置//#ifdef EN_USART3_RX //如果使能了接收USART_/doc/c517407538.html,ART_B audRate = bound;//一般设置为9600;USART_/doc/c517407538.html,ART_W ordLength = USART_WordLength_8b;//字长为8位数据格式USART_/doc/c517407538.html,ART_St opBits = USART_StopBits_1;//一个停止位USART_/doc/c517407538.html,ART_Pa rity = USART_Parity_No;//无奇偶校验位USART_/doc/c517407538.html,ART_H ardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_/doc/c517407538.html,ART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART3, &USART_InitStructure); //初始化串口//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;/ /抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC 寄存器///////////////////// /*Enable DMA Channel2 Interrupt *//////////////////NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/*Enable DMA Channel3 Interrupt */NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启中断USART_ITConfig(USART3, USART_IT_IDLE , ENABLE); //开启空闲中断USART_Cmd(USART3, ENABLE); //使能串口}//串口4初始化函数void uart4_init(u32 bound){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;DMA_InitTypeDef DMA_InitStructure; //定义DMA初始化结构体DMA_InitStructure// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //选择NVIC优先级分组0 RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE );// 打开串口外设的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);//串口4所使用管脚输出输入定义//定义UART4 Tx (PC.10)脚为复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //IO口的第2脚GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //IO口复用推挽输出GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化串口1输出IO口//定义 UART4 Rx (PC.11)为悬空输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //IO口的第3脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//IO口悬空输入GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化串口1输入IO口//串口4参数初始化定义部分,串口1参数为9600 ,8 ,1 ,N 接收中断方式USART_/doc/c517407538.html,ART_B audRate = bound; //设定传输速率USART_/doc/c517407538.html,ART_W ordLength = USART_WordLength_8b; //设定传输数据位数USART_/doc/c517407538.html,ART_St opBits = USART_StopBits_1; //设定停止位个数USART_/doc/c517407538.html,ART_Pa rity = USART_Parity_No ; //不用校验位USART_/doc/c517407538.html,ART_H ardwareFlowControl =USART_HardwareFlowControl_None;//不用流量控制USART_/doc/c517407538.html,ART_M ode = USART_Mode_Rx | USART_Mode_Tx; //使用接收和发送功能USART_Init(UART4, &USART_InitStructure); //初始化串口4USART_ITConfig(UART4, USART_IT_IDLE,ENABLE); //使能串口4接收中断USART_Cmd(UART4, ENABLE); //使能串口4USART_ClearFlag(UART4, USART_FLAG_TC); // 清标志(后增加) DMA_DeInit(DMA2_Channel3); //重置DMA 2通道配置DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004C04; //外设地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART4_RECEIVE_DATA; //存地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据目的地DMA_InitStructure.DMA_BufferSize = 512; //DMA缓存大小:BufferSizeDMA_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_PeripheralDataSize_Byte; //存数据宽度为8位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在正常缓存模式DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //设置DMA通道优先级为高DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止DMA通道设置为存至存传输DMA_Init(DMA2_Channel3, &DMA_InitStructure); //初始化DMA_ITConfig(DMA2_Channel3, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA2_Channel3, DMA_IT_TE, ENABLE);USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA2_Channel3, ENABLE);//使能串口4中断NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);USART_Cmd(UART4, ENABLE);}//DMA的配置void DMA_Configuration(void){DMA_InitTypeDef DMA_InitStructure;/* DMA clock enable */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1////////////////////////串口 1 dma配置///////////////////////////////////////////////* DMA1 Channel4 (串口1 TX) Config */DMA_DeInit(DMA1_Channel4);DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_SEND_DATA;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA工作模式DMA_Mode_Circular DMA_Mode_Normal DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel4, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel4, DMA_IT_TE, ENABLE);/* Enable USART1 DMA TX request */USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);DMA_Cmd(DMA1_Channel4, DISABLE); //使能/* DMA1 Channel5 (串口1 RX) Config */DMA_DeInit(DMA1_Channel5);DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RECEIVE_DATA;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA工作模式DMA_Mode_Circular DMA_Mode_Normal DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel5, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel5, DMA_IT_TE, ENABLE);/* Enable USART1 DMA RX request */USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Channel5, ENABLE); //使能////////////////////串口 2 dma配置/////////////////////////////////* DMA1 Channel7 (串口2 TX) Config */DMA_DeInit(DMA1_Channel7);DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_SEND_DATA;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA工作模式DMA_Mode_Circular DMA_Mode_NormalDMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel7, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel7, DMA_IT_TE, ENABLE);/* Enable USART1 DMA TX request */USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);DMA_Cmd(DMA1_Channel7, DISABLE); //使能/* DMA1 Channel6 (串口2 RX) Config */DMA_DeInit(DMA1_Channel6);DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2_RECEIVE_DATA; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA工作模式DMA_Mode_Circular DMA_Mode_Normal DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel6, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);/* Enable USART2 DMA RX request */USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Channel6, ENABLE); //使能////////////////////串口 3 dma配置/////////////////////////////////* DMA1 Channel2 (串口3 TX) Config */DMA_DeInit(DMA1_Channel2);DMA_InitStructure.DMA_PeripheralBaseAddr =0x40004804;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART3_SEND_DATA;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA工作模式DMA_Mode_Circular DMA_Mode_NormalDMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel2, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel2, DMA_IT_TE, ENABLE);/* Enable USART1 DMA TX request */USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);DMA_Cmd(DMA1_Channel2, DISABLE); //使能/* DMA1 Channel3 (串口3 RX) Config */DMA_DeInit(DMA1_Channel3);DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004804;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART3_RECEIVE_DATA; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 512;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA工作模式DMA_Mode_Circular DMA_Mode_Normal DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel3, &DMA_InitStructure);DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);DMA_ITConfig(DMA1_Channel3, DMA_IT_TE, ENABLE);/* Enable USART2 DMA RX request */USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);DMA_Cmd(DMA1_Channel3, ENABLE); //使能}//////////////////使用DMA发数据中断服务程序////////////////////////void DMA1_Channel4_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TC4);DMA_ClearITPendingBit(DMA1_IT_TE4);DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMAUSART1_TX_Finish=1;//置DMA传输完成// UART_CTL_R;//JIANGYU 新加发完变为接收}void DMA1_Channel5_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TC5);DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据 DMA1_Channel5->CNDTR = 580;//重装填DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA}//2012-7-13add(e)//2012-7-13add(s)//USART2使用DMA发数据中断服务程序void DMA1_Channel7_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TC7);DMA_ClearITPendingBit(DMA1_IT_TE7);DMA_Cmd(DMA1_Channel7, DISABLE);//关闭DMAUSART2_TX_Finish=1;//置DMA传输完成}void DMA1_Channel6_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TC6);DMA_ClearITPendingBit(DMA1_IT_TE6);DMA_Cmd(DMA1_Channel6, DISABLE);//关闭DMA,防止处理其间有数据 DMA1_Channel6->CNDTR = 580;//重装填DMA_Cmd(DMA1_Channel6, ENABLE);//处理完,重开DMA}void DMA2_Channel3_IRQHandler(void){DMA_ClearITPendingBit(DMA2_IT_TC3);DMA_ClearITPendingBit(DMA2_IT_TE3);DMA_Cmd(DMA2_Channel3, DISABLE);//关闭DMA,防止处理其间有数据 DMA2_Channel3->CNDTR = 580;//重装填DMA_Cmd(DMA2_Channel3, ENABLE);//处理完,重开DMA}//USART3使用DMA发数据中断服务程序void DMA1_Channel2_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TC2);DMA_ClearITPendingBit(DMA1_IT_TE2);DMA_Cmd(DMA1_Channel2, DISABLE);//关闭DMAUSART3_TX_Finish=1;//置DMA传输完成}void DMA1_Channel3_IRQHandler(void){DMA_ClearITPendingBit(DMA1_IT_TE3);DMA_Cmd(DMA1_Channel3, DISABLE);//关闭DMA,防止处理其间有数据DMA1_Channel3->CNDTR = 580;//重装填DMA_Cmd(DMA1_Channel3, ENABLE);//处理完,重开DMA}//串口1中断服务函数void USART1_IRQHandler(void) //串口1中断服务程序{unsigned char i = 0,Clear = Clear;unsigned int wCrcCal;u16 DATA_LEN;if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET){DMA_Cmd(DMA1_Channel5, DISABLE);//关闭DMA,防止处理其间有数据USART_ReceiveData(USART1);//读取数据注意:这句必须要,否则不能够清除中断标志位。
STM32---SPI(DMA)通信的总结(库函数操作)本文主要由7项内容介绍SPI并会在最后附上测试源码供参考:1.SPI的通信协议2.SPI通信初始化(以STM32为从机,LPC1114为主机介绍)3.SPI的读写函数4.SPI的中断配置5.SPI的SMA操作6.测试源码7.易出现的问题及原因和解决方法一、SPI的通信协议SPI(Serial Peripheral Interface)是一种串行同步通讯协议,由一个主设备和一个或多个从设备组成,主设备启动一个与从设备的同步通讯,从而完成数据的交换。
SPI 接口一般由4根线组成,CS片选信号(有的单片机上也称为NSS),SCLK时钟信号线,MISO数据线(主机输入从机输出),MOSI数据线(主机输出从机输入),CS 决定了唯一的与主设备通信的从设备,如没有CS 信号,则只能存在一个从设备,主设备通过产生移位时钟信号来发起通讯。
通讯时主机的数据由MISO输入,由MOSI 输出,输入的数据在时钟的上升或下降沿被采样,输出数据在紧接着的下降或上升沿被发出(具体由SPI的时钟相位和极性的设置而决定)。
二、以STM32为例介绍SPI通信1.STM32f103 带有3个SPI模块其特性如下:2SPI 初始化初始化SPI 主要是对SPI要使用到的引脚以及SPI通信协议中时钟相位和极性进行设置,其实STM32的工程师已经帮我们做好了这些工作,调用库函数,根据自己的需要来修改其中的参量来完成自己的配置即可,主要的配置是如下几项:引脚的配置SPI1的SCLK, MISO ,MOSI分别是PA5,PA6,PA7引脚,这几个引脚的模式都配置成GPIO_Mode_AF_PP 复用推挽输出(关于GPIO的8种工作模式如不清楚请自己百度,在此不解释),如果是单主单从, CS引脚可以不配置,都设置成软件模式即可。
通信参数的设置1.SPI_Direction_2Lines_FullDuplex把SPI设置成全双工通信;2.在SPI_Mode 里设置你的模式(主机或者从机),3.SPI_DataSize是来设置数据传输的帧格式的SPI_DataSize_8b是指8位数据帧格式,也可以设置为SPI_DataSize_16b,即16位帧格式4.SPI_CPOL和SPI_CPHA是两个很重要的参数,是设置SPI通信时钟的极性和相位的,一共有四种模式在库函数中CPOL有两个值SPI_CPOL_High(=1)和SPI_CPOL_Low ( =0). CPHA有两个值SPI_CPHA_1Edge (=0) 和SPI_CPHA_2Edge(=1)CPOL表示时钟在空闲状态的极性是高电平还是低电平,而CPHA则表示数据是在什么时刻被采样的,手册中如下:我的程序中主、从机的这两位设置的相同都是设置成1,即空闲时时钟是高电平,数据在第二个时钟沿被采样,实验显示数据收发都正常。