搜档网
当前位置:搜档网 › STM32的SPI通信总结(含DMA)

STM32的SPI通信总结(含DMA)

STM32的SPI通信总结(含DMA)
STM32的SPI通信总结(含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). CPHA有两个值SPI_CPHA_1Edge (=0) 和SPI_CPHA_2Edge(=1)

CPOL表示时钟在空闲状态的极性是高电平还是低电平,而CPHA则表示数

据是在什么时刻被采样的,手册中如下:

我的程序中主、从机的这两位设置的相同都是设置成1,即空闲时时钟是高电平,数据在第二个时钟沿被采样,实验显示数据收发都正常。

(要特别注意极性和相位的设置否则,数据传输会出现错位的现象)

一般主从机的这两个位要设置的一样,但是网上也有人说不能设置成一样的,在后文中我对主从机极性和相位的配置的16种情况都做了测试,结果见下文。

下图很好的描述了4种模式下的时序状况

引用网友的一句话::

“SPI主模块和与之通信的外设备时钟相位和极性应该一致。个人理解这句话有2层意思:其一,主设备SPI时钟和极性的配置应该由外设的从设备来决定;其二,二者的配置应该保持一致,即主设备的SDO同从设备的SDO配置一致,主设备的SDI同从设备的SDI配置一致。因为主从设备是在SCLK的控制下,同时发送和接收数据,并通过2个双向移位寄存器来交换数据。”

5.SPI_BaudRatePrescaler 波特率的设置

这在主机模式中,这一位的设置直接决定了通信的传输速率,而从机的设置不会影响数据传输的速率,手册中有这样一句话:

(实际测试中发现:当STM32作为从机时,它对波特率的设置会影响数据的通信,特别是在大数据两传输时,当主机SPI时钟设置为15M时,STM32从机如果是2分频即18M则会在多次传输时出现错误,我记得在资料中看到过有前辈的经验贴说SPI从机的时钟设置不能高于SPI主机的时钟设置,虽然理论上从机的时钟设置不影响SPI通信,但是在试验中我也验证,当STM32从机时钟设为4分频9M,低于15M时,通信就不会出现问题。所以SPI从机波特率的设置最好低于SPI主机波特率的设置。)

6.SPI_FirstBit 这一位是设置首先传输的高字节还是低字节

SPI_FirstBit_MSB 是先传输高字节,SPI_FirstBit_LSB 是先传输低字节

注意在初始化函数里还有两项重要的内容就是在初始化之前先使能SPI的时钟和在初始化配置完成后使能SPI。

(………..初始化配置……………)

三、SPI的读写函数

SPI有一个16位的数据寄存器SPI_DR,它对应两个缓冲区,1个发送缓冲区,1个接收缓冲区,当在控制寄存器里SPI_CR1里对DFF位设置数据帧格式为8位时,发送和接收只用到SPI_DR[7:0]这8位,15-8位被强制为0,帧格式设置成16位时全用。

读写过程在手册中是这样描述的:

简而言之,

发送时,可以通过检测SPI_SR中的TXE位,当数据寄存器里有数据时,TXE 位是0,当数据全部从数据寄存器的发送缓冲区传输到移位寄存器时TXE 位被置1,这时候可以再往数据寄存器里写入数据。可以通过

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) 来检测。

SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) 是库函数,可以检测SPI的一些状态位。接收时,可以通过检测SPI_SR中的RXNE位,当数据寄存器里有数据时,

RXNE位是0,当数据全部从数据寄存器的接收缓冲区传输到移位寄存器时RXNE位被置1,这时候可以从数据寄存器里读出数据。可以通过

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); 来检测。源程序如下,SPI 读写一个字节,读写一体

当能成功发送和接收一个字节时,发送数组数据就变的简单了,只需要一个for循环,和指针变量的递增即可。以下仅为参考:

(有一点特别注意,从机数据传输时要依赖主机的时钟,所以主机在接收从机发送的数据时要往从机发送哑巴字节,这个字节可以自己定义0xff,0xfe等什么字节都可以)

读写分开的函数:

/*

Description:spi1通信发送数据

*/

void SPI_Ecah_Buffer_Send(u8* pBuffer, u16 NumByteToRead)

{

for(int i = 0; i < NumByteToRead; i++)

{

SPI_Conmunication_SendByte(*pBuffer);

pBuffer++;

}

}

/*

Description:spi1通信接收收据

*/

void SPI_Buffer_Receive(u8* pBuffer, u16 NumByteToRead)

{

while (NumByteToRead--) /* while there is data to be read */

{

*pBuffer = SPI_Conmunication_SendByte (Dummy_Byte);

pBuffer++;

}

}

读写一体的函数

/*

Description:spi1通信发送接收读写数据

*/

void SPI_Ecah_Buffer_Send(u8* str , u8* pBuffer, u16 NumByteToRead)

{

for(int i = 0; i < NumByteToRead; i++)

{

*str = SPI_Conmunication_SendByte(*pBuffer);

pBuffer++;

str++;

}

}

四、SPI的中断配置

在SPI的SPI_CR2 中可以配置,STM32的SPI的通信一共有8个中断其中最常用的是如下4个。

TXEIE:发送缓冲区空中断使能

在发送过程中,数据全部从数据寄存器的发送缓冲区传输到移位寄存器时TXE位被置1这时如果使能了TXEIE 就会触发发送完成的中断请求。在中断服务函数里可以做你想做的事情,也可以用一个标志位,在外面完成相应的操作。

(使用中断时要特别注意,及时的清除中断标志,为下一次能够触发中断做准备。而清除中断的操作可以放在中断服务函数中,或者其他你认为何时的地方。)

RXNEIE:接收缓冲区非空中断使能

接收同发送。

TXDMAEN:发送缓冲区DMA使能

RXDMAEN:接收缓冲区DMA使能

手册中有这样一句话,“不能同时设置TXEIE和TXDMAEN”这一点要特别注意。也就是说如果你在SPI的通信中不用DMA则使能TXEIE的中断,禁能TXDMAEN的中断,如果在SPI中使用DMA传输,则禁能TXEIE 的中断,只使能TXDMAEN 的中断。

五、SPI的DMA操作

DMA(Direct Memory Access)直接内存存取,直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU任何干预,通过DMA数据可以快速地移动。使用DMA最大的特点就是数据传输不经过CPU这就节省了CPU的资源,让CPU能有更多的时间来做其他的事情。

SPI的DMA操作,就是在SPI->TXE为1时,会向对应的DMA通道发出请求,DMA通道会发出应答信号,SPI收到应答信号后撤销请求信号,DMA撤销应答信号,并把内存值装入SPI_DR的发送缓区,SPI的传送开始。

DMA的初始化

DMA_PeripheralBaseAddr是值外设数据的地址,用SPI1故DMA外设地址对应的是SPI1_DR_Addr,

DMA_MemoryBaseAddr是内存地址,它的值可以使,你要发送的数据所存放的数组的名,因为数组名代表的是数组数据存放的首地址,在SPI-DMA 的发送中可以理解为把DMATX[]数组里的数据传送到SPI1_DR_Addr

DMA_DIR 是指数据传输的方向,其值发送时其值为DMA_DIR_PeripheralDST 即外设是目的地,方向是DMATX—> SPI1_DR_Addr, 在接受收时其值为DMA_DIR_PeripheralSRC,即外设是数据的来源,传输方向是SPI1_DR_Addr—>用户指定的数据存储数组。

DMA_BufferSize 用来设置传输数据的个数,在STM32的DMA中其值的范围是0—65536.

DMA_Mode 指DMA的传输模式DMA_Mode_Normal为正常工作模式DMA_Mode_Circular 是循环工作模式,这里对循环模式的解释我认为有位网友解释的很不错如下:

“循环的意思是指DMA的传输数量计数器会重置初值,由于DMA每传一个数据,传输数量计数器减一,只有在传输数量计数器的值不为零时,才会响应请求。在循环模式下,当传输计数器的值减为0后,会重新装载;而内存(缓存)地址则不管循环非循环模式,都会在每次传输完成后重置为基地址。所以,如果我们把DMA设置会正常模式,那么在下次传输前,只需对DMA的传输数量计数器重新写入就行。循环模式一般用于数据更新,比如ADC采用需要不停更新数据。”

在初始化完成之后要开启DMA的中断,在我的程序中开启的是DMA传输完成中断。

DMA传输有3个中断标志位,常用的是传输完成的中断。如下:

这样在传输完设定的数据个数之后就会触发传输完成的中断,用户可以再中断服务函数中,进行相应的操作,有一点特别注意,就是要及时清除中断标志位,为下次能够正常触发中断做准备。

在我的中断服务函数中有一个标志位SpiCommon,被置1后再中断之外进行其他的处理,同时调用DMA_ClearITPendingBit(DMA1_IT_TC2)来及时清除中断标志。

在进行DMA的数据传输时要先禁能DMA的通道,重置传输数据个数的值,数据的存储位置等,再使能DMA的通道,等待DMA的传输完成。

我的操作时这样的,先往DMATX[]里写入相应的数据,然后如下

这样可能有一点不好的地方,因为只改变了SpiTXSize的值,却又重新执行了DMATXInit() 函数,可能此处能够再改善一下。

六测试中出现的问题及原因和解决方法

示波器观察主机能够产生正确的时钟,主机输出引脚也能产生正确的数据,但是从机不能接受数据。

可能原因:

1.从机的接收中断配置不正确,或者没有打开相应的中断。

2.在从机中TXEIE的中断和TXDMAEN的中断都被使能,手册中说,这两个

中断只能使能1个.

从机能接收数据,但是接收的数据乱码

可能原因:

1.主从机的时钟相位和极性的配置导致的,关于这一点想做一下说明,网

上有人说,主从机时钟的相位和极性要配置的一样,也有人说不能配置的一样,而我对于主从机的相位和极性的16种组合情况全做了试验,结果如下:(主机LPC1114的SPI1从机STM32的SPI1)

(√表示能正常通信)

(当然可能上述的结果也跟测试环境有关,当对其有所怀疑时,读者不妨自己实验看一下。)

2.乱码的第二个原因可能是两个设备没有共地而造成的,在出现问题时一

定要先检查一下硬件的连接是否正确,是否有虚焊接触不好的地方而导致通讯不正常。(在信号要求高的电路里一定单独用一根线把主从机的地连接在一起),关于共地,不仅是要在电源接通时用万用表测试两点共地,在切断电源后用万用表测试,连点依然共地才是真正的共地。

3.乱码还有一个很重要的原因,就是主机能发出时钟,但是时钟的高电平

不到3.3V,我在调试中就出现过主机时钟和数据看波形正常,但是高电平只有2.3V左右,但从机的数据波形的高电平为3.3V左右,收发数据乱码,一直没找到原因,后来发现主机的高电平较低,怀疑是硬件的问题,更换主机后,SPI通信正常了,所以出现了问题一定要先检查硬件是否合格,在保证硬件无误的情况下再分析软件程序的问题。

从机能接收数据,但接收的数据不全,又丢字节的现象发生。

可能原因:

1.如果是通过串口打印来观察接收数据,那要看一下数据中是否有0,结

合自己的串口函数分析一下,因为打印数组或者字符串时遇0会截止。

2.看一下接收的数组中,其指针是否是递增的。

3.如果使用了CS片选信号,看一下主机发出的数据是否都在CS拉低的范

围内。

4.在使用DMA的传输时一定要注意传输的数据个数一定要和DMA初始

化中设置的传输个数相同否则,收到的数据可能会出现字节丢失的现象。

关于STM32串口空闲中断IDEL的问题

关于STM32串口空闲中断IDEL的问题 1.空闲中断是接受数据后出现一个byte 的高电平(空闲)状态,就会触发空闲 中断.并不是空闲就会一直中断,准确的说应该是上升沿(停止位)后一个 byte,如果一直是低电平是不会触发空闲中断的(会触发break 中断)。 2.关于第二点有要铺垫的三个情况,datasheet 中”当一空闲帧被检测到时,其处 理步骤和接收到普通数据帧一样,但如果IDLEIE 位被设置将产生一个中断”“空 闲符号被视为完全由'1'组成的一个完整的数据帧,后面跟着包含了数 据的下一帧的开始位'1'的位数也包括了停止位的位数”空闲符号的 配图后面跟这一个低电平.有人理解为只有收到下一个数据的起始位才会触发中 断,这样理解是不对的,应该是数据后有空闲了一帧就会触发. 3.清中断的方式感觉奇怪,使用函数USART_ClearITPendingBit( USART1, USART_IT_IDLE )清除不了中断的.我用的是3.5 的库,查看函数说明,里面的 @param 参数并没有IDLE,后面的@note 中,这样说:”PE(Parity error),FE(Framing error),NE(Noise error),ORE(OverRun error) and IDLE(Idle line detected) pending bits are cleared by software sequence: a read operation to USART_SR register (USART_GetITStatus()) followed by a read operation to USART_DR register (USART_ReceiveData()).”我是通过语句”USART1->DR;”来清除IDLE 中断的. 现在有很多数据处理都要用到不定长数据,而单片机串口的RXNE 中断一次 只能接收一个字节的数据,没有缓冲区,无法接收一帧多个数据,现提供两种 利用串口IDLE 空闲中断的方式接收一帧数据,方法如下: 方法1:实现思路:采用STM32F103 的串口1,并配置成空闲中断IDLE 模 式且使能DMA 接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成 之后,当外部给单片机发送数据的时候,假设这帧数据长度是200 个字节,那

TMS320F28335外部中断总结

TMS320F28335外部中断总结 作者:Free 文章来源:Free 点击数:93 更新时间:2010-8-26 在这里我们要十分清楚DSP的中断系统。C28XX一共有16个中断源,其中有2个不可屏蔽的中断RESET和NMI、定时器1和定时器2分别使用中断13 和14。这样还有12个中断都直接连接到外设中断扩展模块PIE上。说的简单一点就是PIE 通过12根线与28335核的12个中断线相连。而PIE的另外 一侧有12*8根线分别连接到外设,如AD、SPI、EXINT等等。这样PIE共管理12*8=96个外部中断。这12组大中断由28335核的中断寄存器IER来控 制,即IER确定每个中断到底属于哪一组大中断(如IER |= M_INT12;说明我们要用第12组的中断,但是第12组里面的什么中断CPU并不知道需 要再由PIEIER确定)。接下来再由PIE模块中的寄存器PIEIER中的低8确定该中断是这一组的第几个中断,这些配置都要告诉CPU(我们不难想 象到PIEIER共有12总即从PIEIER1-PIEIER12)。另外,PIE模块还有中断标志寄存器PIEIFR,同样它的低8位是来自外部中断的8个标志位,同 样CPU的IFR寄存器是中断组的标志寄存器。由此看来,CPU的所有中断寄存器控制12组的中断,PIE的所有中断寄存器控制每组内8个的中断。 除此之外,我们用到哪一个外部中断,相应的还有外部中断的寄存器,需要注意的就是外部中断的标志要自己通过软件来清零。而PIE和CPU的 中断标志寄存器由硬件来清零。 EALLOW; // This is needed to write to EALLOW protected registers PieVectTable.XINT2 = &ISRExint; //告诉中断入口地址 EDIS; // This is needed to disable write to EALLOW protected registers PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block使能PIE PieCtrlRegs.PIEIER1.bit.INTx5= 1; //使能第一组中的中断5 IER |= M_INT1; // Enable CPU 第一组中断

最新stm32学习之串口usart复习进程

STM32学习之串口USART STM32 的串口是相当丰富的。最多可提供5路串口,有分数波特率发生器、支持单线光通信和半双工单线通讯、支持LIN、智能卡协议和IrDA SIR ENDEC 规范(仅串口3 支持)、具有DMA 等。串口最基本的设置,就是波特率的设置。STM32 的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应IO口的模式,然后配置一下波特率,数据位长度,奇偶校验位等信息,就可以使用了。 1、串口时钟使能。串口作为STM32 的一个外设,其时钟由外设始终使能寄存器控制,这里我们使用的串口1是在APB2ENR 寄存器的第14 位。除了串口1 的时钟使能在APB2ENR寄存器,其他串口的时钟使能位都在APB1ENR。 1、串口的作用:用在STM32板子和PC机通信的。我们调试的时候,无法知道是否正确,就可以用STM32的cpu,给串口输出一些信息给PC,我们通过屏幕(实际上是终端串口软件),可以看到这些信息,从而知道当前程序的错误可能出现的位置。当然,也可以在PC的键盘敲打命令,让串口帮传递给STM32板子,来执行这些命令。 2、串口的工作模式一般有两种方式:查询和中断 (1)查询:串口程序不断地循环查询,看看当前有没有数据要它传,如果有,就帮助传送(可以从PC到STM32板子,也可以从STM32 板子到PC)。 (2)中断:平时串口只要打开中断即可。如果发现有一个中断来,则意味着要它帮助传输数据——它就马上进行数据的传送。同样,可以从PC到STM32板子,也可以从STM32板子到PC 。 步骤一从硬件开始学习。大家先打开芯达STM32开发板附带的原理图。找到串口部分。笔者把它截图如下。我们发现,串口模块的电路是这样的:STM32的CPU引脚,通过两个PA端口的引脚PA10和PA9(此两个引脚复用USART),连接到一个SP3232芯片,或者MAX232芯片。然后再连接到DB9串口座上。由于232芯片可以允许走两路信号,因此,我们扩展了一个串口COM2,请注意,如无特别说明,我们都将使用COM1。

STM32串口中断接收方式详细比较

本例程通过PC机的串口调试助手将数据发送至STM32,接收数据后将所接收的数据又发送至PC机,具体下面详谈。。。 实例一: void USART1_IRQHandler(u8 GetData) { u8 BackData; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志. GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR; USART1_SendByte(GetData); //发送数据 GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED闪烁,接收成功发送完成 delay(1000); GPIO_ResetBits(GPIOE, GPIO_Pin_8 ); } } 这是最基本的,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main函数里无其他要处理的。 优点:简单,适合很少量数据传输。 缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失。 实例二: void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2); Uart2_Rx_Num++; } if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) //判断最后接收的数据是否为设定值,确定数据正确性 Uart2_Sta=1; if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出 { USART_ClearFlag(USART2,USART_FLAG_ORE); //读SR USART_ReceiveData(USART2); //读DR } } if( Uart2_Sta ) { for(Uart2_Tx_Num=0;Uart2_Tx_Num < Uart2_Rx_Num;Uart2_Tx_Num++)

STM32 无中断串口代码

STM32 无中断串口代码2010-05-14 16:09 串口,是我们日常使用最多的一部分,刚开始做电子工程师的,基本都是从这个开始的,下面的代码是我使用STM32库编写的串口输出和读取的代码。 1、串口初始化函数:void USART_Ini(USART_TypeDef* USARTx,u16 buad) 2、串口中断开启和关闭:USART_IT(USART_TypeDef* USARTx,FunctionalState NewState) 3、串口接收:u16 Getch(USART_TypeDef* USARTx) 4、串口单个字符输出:void Putch(USART_TypeDef* USARTx,u16 ch) 5、串口输出字符串:void PutStr(USART_TypeDef* USARTx,u16 *SendBuf,u16 Length) #include "stm32f10x_lib.h" u16 RecDateBuffer[100]; u16 RecLen; u8 SendDateBuffer[100]; /************************************************************* ****************** * Function Name : Uart_Ini * Description : 串口初始化 * Input : * Output : None * Return : ************************************************************** *****************/ void USART_Ini(USART_TypeDef* USARTx,u16 buad) { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockIni; GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Configure USART1 Rx (PA.10) as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;

stm32 串口中断总结

本文以USART1为例,叙述串口中断的编程过程。 1、先来讲述一下在应用串口中断时涉及到的一些库文件。 首先对于STM32外设库文件的应用编程,misc.c和stm32f10x_rcc.c是肯定要添加到。 接下来就是我们要用到的相关外设了。毫无疑问,串口文件stm32f10x_usart.c是必须的。串口通信是对通用GPIO端口引脚的功能复用,所以还需要stm32f10x_gpio.c文件。另外,因为有中断的产生,所以中断文件stm32f10x_it.c也是必要的,当然这个文件一般和main.c 放在一个文件夹下(一般习惯为User文件夹),因为我们的中断响应函数是要在里面自己编写的。 当然还有其他的基本必须文件如系统配置文件等在这地方就不说了,这个是创建一个工程应该知道的。 2、初始化 对于串口通信的初始化,不仅仅只是对串口的初始化(这个地方是比较烦人的,不像别的芯片那样简洁明了)。 ●?首先时钟使能配置。STM32内部的时钟有很多,感兴趣的自己看看参考手册。此处 以USART1为例说明。有USART1时钟、GPIOA时钟、GPIO复用(AFIO)时钟。由于 此处USART1和GPIOA、AFIO均在APB2上,所以可以一次配置完成。如下: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB 2Periph_USART1 ,ENABLE); ●?其次中断配置。主要有优先级组设定、USART1中断使能、该中断的优先级,中断初 始化。程序如下: void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//选择分组方式0 /* 使能 USART1中断 */ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } ●?然后GPIO复用功能配置。一般情况下我们使用原始的外设和GPIO端口引脚的映射 关系,如果要改变其映射的话,请另外查看参考手册上关于GPIO重映射部分。对 于GPIO的复用,其引脚的输入与输出模式都有要求,在参考手册上有详细说明。 void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 配置 USART1 Rx 作为浮空输入 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(USARTy_GPIO, &GPIO_InitStructure); /* 配置 USART1 Tx 作为推挽输出 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

STM32个人总结

基础入门编 1.搭建开发环境 详情看光盘资料,主要是软件安装和设置。 2.新建工程 可以直接用模板,了解每个文件的含义,会使用chm帮助。 3.STM32库 库的含义。 4.GPIO流水灯 认识RCC,GPIO的各种模式,寄存器的种类和作用。 5.POLLING按键 主要介绍了各种模式,实验通过不断读取GPIO的状态以达到判断按键的目的。 6.EXTI按键 使用了GPIO的EXTI中断来判断按键,记住EXTI要开AFIO(重映射也要开),另外SYSTICK不归NVIC管。注意NVIC_IRQChannelSubPriority(),最多可以判断16种优先级,即16种中断,同一个中断入口的引脚引发的中断也算是同一种中断,同种种中断不能相互嵌套。(响应优先级是在抢占优先级相同时,同时发生才有用,其中一个发生后无用)。 7.SYSTICK 关键是SYSTICK的初始化函数,了解那几个寄存器的作用和特殊的宏定义(就是选择自己想选择的位),根据配置可以延时不同的时间,详情看代码。 8.串口通信 开启相应RCC,做好Iint,配置好中断(可选,主要用于接收),然后弄好fputc(),可以直接用printf()直接输出。 9.DMA 不经CPU处理直接相互传输,开启相应的DMA,配置好from..to..,字节大小等,用cmd 命令后可以开启传输。 10.ADC(DMA) 主要就是初始化好ADC,什么通道模式之类的,详情看代码,由于使用了DMA模式,要配置好DMA,有ADC_DMACmd()开始传输。 11..FSMC显示英文 用FSMC直接写入液晶的控制芯片的显存,注意使用的是16位的颜色,线的接法要注意(RGB为5:6:5)。 由于用的是模拟的方法,输入数据时用的都是宏,该地址线用来作为C/D,16位是往前移了一位的,因此要乘以2. 值得注意的是开窗的显示手法,在显示字符前先“开”一个窗,当一行数据写完时,自动换到下一行继续写。 在写数据的函数那里可以更换字的背景色,也可以修改该函数的.h的BACKGROUND 的宏定义。 FSMC的初始化暂时不清楚,应该是关于NOR FLASH的。控制代码是配好的,具体的设置看参考文档(有关定位坐标和扫描方式都与此有关)。 (NOR-FLASH 有4个bank,NE[3:0],区分不同的bank,实验用NE1;DataAddress_Mux 数据域地址线复用;8位地址线25:0->24:0 16位地址线25:1->24:0,宏定义是16位的地址线,对应的机内地址*2左移1位) 12.IIC-EEPROM

STM32 Uart串口中断响应、发送接收详细程序

程序实现功能:可以直接接收USART1的数据,并通过串口调试输出显示 #include"stm32f10x_lib.h" void NVIC_Configuration(void); void RCC_Configuration(void); void GPIO_Configuration(void); ErrorStatus HSEStartUpStatus; USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; int main() { #ifdef DEBUG debug #endif RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); /*串口传输速率的大小必须与RCC所设定的时钟相对应起来*/ USART_https://www.sodocs.net/doc/cc18436507.html,ART_BaudRate = 9600; //设置USART的传输速率/*设定数据的接收发送模式*/ USART_https://www.sodocs.net/doc/cc18436507.html,ART_WordLength = USART_WordLength_8b;//在一帧中传输或接受8位数据位 USART_https://www.sodocs.net/doc/cc18436507.html,ART_StopBits = USART_StopBits_1; //定义在帧的结尾传输一个停止位 USART_https://www.sodocs.net/doc/cc18436507.html,ART_Parity = USART_Parity_No; //奇偶失能 USART_https://www.sodocs.net/doc/cc18436507.html,ART_HardwareFlowControl = USART_HardwareFlowControl_None; //指定硬件流控制模式RTS和CTS使能 USART_https://www.sodocs.net/doc/cc18436507.html,ART_Mode = USART_Mode_Rx | USART_Mode_Tx; //指定使能或失能发送和接受模式Tx发送使能和Rx接收使能 USART_Clock https://www.sodocs.net/doc/cc18436507.html,ART_Clock = USART_Clock_Disable; //提升USART时钟时使能还是失能,钟低电平活动 USART_https://www.sodocs.net/doc/cc18436507.html,ART_CPOL = USART_CPOL_Low; //指定SLCK引脚上时钟的极性 USART_https://www.sodocs.net/doc/cc18436507.html,ART_CPHA = USART_CPHA_2Edge; //时钟第二个边缘进行数据捕获 USART_https://www.sodocs.net/doc/cc18436507.html,ART_LastBit = USART_LastBit_Disable; //在SCLK引脚上输出最后发送的那个数据字的脉冲不从SCLK输出 USART_ClockInit(USART1, &USART_ClockInitStructure); USART_Init(USART1, &USART_InitStructure); /*输入输出的中断使能*/ // USART_ITConfig(USART1, USART_IT_TXE, ENABLE); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

STM32串口中断接收方式详细比较

串口中断接收方式详细比较 串口调试,以前也调过,只是没这么深入的琢磨过,最近又在弄,感觉串口很基本,也很有学问,要是出现BUG可能导致系统奔溃。。。现在贴出来,欢迎拍砖指正!!! 本例程通过PC机的串口调试助手将数据发送至STM32,STM32通过SP3232芯片采用中断接收方式完成,然后接收数据后将所接收的数据又发送至PC机,具体下面详谈。。。 实例一: void USART1_IRQHandler(u8 GetData) { u8 BackData; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志. GetData = UART1_GetByte(BackData); //也行GetData=USART1->DR; USART1_SendByte(GetData); //发送数据 GPIO_SetBits(GPIOE, GPIO_Pin_8 ); //LED闪烁,接收成功发送完成 delay(1000); GPIO_ResetBits(GPIOE, GPIO_Pin_8 ); } } 这是最基本的,将数据接收完成后又发送出去,接收和发送在中断函数里执行,main 函数里无其他要处理的。 优点:简单,适合很少量数据传输。 缺点:无缓存区,并且对数据的正确性没有判断,数据量稍大可能导致数据丢失。 实例二: void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx_Num] = USART_ReceiveData(USART2); Uart2_Rx_Num++; } if((Uart2_Buffer[0] == 0x5A)&&(Uart2_Buffer[Uart2_Rx_Num-1] == 0xA5)) //判断最后接收的数据是否为设定值,确定数据正确性 Uart2_Sta=1; if(USART_GetFlagStatus(USART2,USART_FLAG_ORE) == SET) //溢出

stm32学习总结

学习总结 单片机学习经历总结 自从大二寒假接受了一次初始培训开始,我便开始了单片机的学习,一开始借了一块 MSP430G2553的板子,于是便从MSP开始学习单片机。一开始的我对于单片机一窍不通,只能对照着数据手册学习,逐渐开始了解什么是IO口,中断,定时器,AD转换等。开学来了以后接受了四次培训,期间又重新认识这些模块并在学长指导下开始写了一些程序作为练习。后续的学习中我在串口通讯这里遇到了很大阻碍,不太能理解其中的含义,网上的解释又不太看得懂,便找了一些STM32的视频来学习串口,期间发现51和MSP已经不是主流的板子了,现在的厂商更多的是用STM32这样的板子,于是后来的学习重心开始放到了STM32上,因为有了前面的基础,这次从头的学习就更加容易理解STM32的原理与使用了。 MSP430G2553一些模块的总结 (一).IO口模块, 1.我们实用的MSP430G2553有两组IO口,是P1和P 2. 2.IO口的寄存器有:方向选择寄存器PxDIR,输出寄存器PxOUT,输入寄存器PxIN,IO口内部上拉或下拉电阻使能寄存器PxREN, IO口功能选择寄存器PxSEL和PxSEL2,IO口中断使能寄存器PxIE,中断沿选择寄存器PxIES,IO口中断标志寄存器PxIFG。 3.所有的IO都带有中断,其中所有的P1口公用一个中断向量,所有的P2口公用一个中断向量。所以在使用中断时,当进入中断后,还要判断到底是哪一个IO口产生的中断,判断方法可以是判断各个IO口的电平。 4.中断标志PxIFG需要软件清除,也可以用软件置位,从而用软件触发一个中断。 5.PxOUT:如果引脚选择了内部的上拉或下拉电阻使能,则PxOUT设定电阻是上拉还是下拉,0:下拉,1:上拉 (二).时钟系统 1.MSP430的时钟源有: (1).外接低频晶振LFXT1CLK:低频模式32768Hz,高频模式450KHz~8MHz (2).外接高速晶振XT2CLK:8MHz; (3).内部数字控制振荡器DCO: (4).超低功耗低频振荡器VLO: 2.时钟模块:430的时钟模块有MCLK SMCLK ACLK : (1).主系统时钟MCLK:提供给MSP430的CPU时钟。可以来自LFXT1CLK XT2CLK DCO VLO 可选,默认为DCO。

STM32串口典型配置

usart.h : 头文件 /*------------------------------------------------------------------------------------------------------------------*/ #ifndef __USART_H #define __USART_H /* Include -------------------------------------------------------------------*/ #include "stm32f10x.h" #include #include //#include /* Define & Typedef ----------------------------------------------------------*/ /* Macro Switch ---------------------------------------------*/ /*注:以下宏供移植时选择和修改*/ #define USE_RS485 2 //使用RS485 #define USE_USART1 //使用串口1 #define USE_USART2 //使用串口2 #define USE_USART3 //使用串口3 //#define USE_UART4 //使用串口4 //#define USE_UART5 //使用串口5 #define MAX_LEN 256 //打印函数字符串输入最大字节数 #define PUTX fputc //fputc重定向函数 #ifdef USE_RS485 #define RS485 0 #define RS232 1 #define RS24_CONFIG RS24_Configration //RS485-232选择控制端口配置函数 #define RSCHOOSEFLAG SeM.Bit.RSChooseFlag //RS485-232选择标志 #define RS485_T GPIO_SetBits(GPIOA,GPIO_Pin_1) //RS485进入发送状态 #define RS485_R GPIO_ResetBits(GPIOA,GPIO_Pin_1) //RS485进入接收状态

STM32 串口简介

串口作为MCU的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。STM32的串口资源相当丰富的,功能也相当强劲。ALIENTEK战舰STM32开发板所使用的STM32F103ZET6最多可提供5路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持LIN、支持调制解调器操作、智能卡协议和IrDASIRENDEC规范、具有DMA等。用过单片机的人肯定都接触过串口,设置串口无非就是设置波特率、数据位、停止位、奇偶校验位。发送接收也就三种基本方式,轮询、中断和DMA。STM32F10x 的USART 模块也不过如此。所以我重点讲讲我在调试代码时犯得各种错误,那些很容易得到的代码就不详细的讲解了。 串口设置的一般步骤可以总结为如下几个步骤: 1)串口时钟使能,GPIO时钟使能 2)串口复位 3)GPIO端口模式设置 4)串口参数初始化 5)开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤) 6)使能串口 7)编写中断处理函数 与串口基本配置直接相关的几个固件库函数。这些函数和定义主要分布在 stm32f10x_usart.h和stm32f10x_usart.c文件中。 1.串口时钟使能。串口是挂载在APB2下面的外设,所以使能函数为: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1); 2.串口复位。当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是在函数USART_DeInit()中完成: void USART_DeInit(USART_TypeDef*USARTx);//串口复位 比如我们要复位串口1,方法为: USART_DeInit(USART1);//复位串口1 3:GPIO端口设置,首先要是能gpio时钟,然后将用到的串口占用的io口设置一下属性。 4.串口参数初始化。串口初始化是通过USART_Init()函数实现的, void USART_Init(USART_TypeDef*USARTx,USART_InitTypeDef*USART_InitStruct); 这个函数的第一个入口参数是指定初始化的串口标号,这里选择USART1。

STM32串口1中断实验

串口1中断实验 一、实验要求 开发板加电后,先向串口输出一串测试数据,然后在PC端的串口助手类软件上输入结束符为0x0d 0x0a的一串数据,发送到开发板,开发板接收到该字符串后将该字串回传给PC端串口助手软件,传送和接收过程中LED灯闪烁。 二、硬件电路设计 如下图所示,只需要将开发板配套的RS232串口线连接开发板9针串口到PC的串口上,如果电脑上没有串口,可以用USB转串口设备取代标准串口。 三、软件设计思路 根据任务要求,程序内容主要包括: 1. 初始化串口1,使能串口接收中断,通过串口输出相关信息到PC 2. 通过串口中断服务程序检测串口输入信息 3. 将收到的字符发送回PC,然后回到步骤2继续等待 四、程序分析 1.工程结构: 整个工程包含4类源文件,把它们安排在4个组当中:

1)RVMDK组: 仅包含一个启动用汇编源文件startup_stm32f10x_hd.s 。由于奋斗板采用STM32F103大存储器芯片(512k片上FLASH),因此采用STM32标准库中自带的大存储器芯片启动代码.这个文件已经配置好了初始状态,以及中断向量表,可以直接在工程里使用。 如果你在以后的应用中采用了中存储器或者小存储器的STM32芯片,可以将启动代码替换为startup_stm32f10x_md.s (中容量)或者 startup_stm32f10x_ld.s(小容量)。 2)StdPeriph_Driver组: stm32f10x_gpio.c:ST公司的标准库,包含了关于对通用IO口设置的函数。 stm32f10x_rcc.c :ST公司的标准库,包含了关于对系统时钟设置的函数。 stm32f10x_USART.c:ST公司的标准库,包含了关于对USART设置的函数。 Misc.c:ST公司的标准库,包含了关于中断设置的函数。 3)CMSYS组: 是关于整个Cortex-M3平台的系统函数及定义,由ARM公司给出。 4)USER组: main.c:例程的主函数。 stm32f10x_it.c:中断服务函数,此程序只需要增加串口1中断的代码。 2.编译与链接: 编译工程,完成后会提示如下:

STM32使用DMA加串口空闲中断接收数据

STM32使用DMA加串口空闲中断接收数据 STM32中,需要用串口接收数据,是使用串口中断来接收数据。但是用这种方法的话,就要频繁进入串口中断,然后处理,效率就比较低。于是就想到用DMA来接收串口数据,这个STM32也是支持的。但是关键的一点,怎么知道数据接收完毕了呢?如果接收的数据长度固定,那就好办,直接设置DMA的接收数据个数就行了。但是如果长度不固定了,那应该怎么办了? 这个时候,就要用到STM32在串口中提供的另一个好用的东西了,就是串口空闲中断。在STM32的串口控制器中,设置了有串口空闲中断,即如果串口空闲,又开启了串口空闲中断的话,就触发串口空闲中断,然后程序就会跳到串口中断去执行。有了这个,是不是可以判断什么时候串口数据接收完毕了呢?因为串口数据接收完毕后,串口总线肯定是会空闲的嘛,那这个中断肯定是会触发的了。 还有一个问题,这串口空闲中断是只要串口空闲就会产生吗?其实不是的,串口空闲中断要触发的话,是要RXNE位被置位后,串口总线空闲才会触发的。所以我们不用担心,串口数据发送完毕后,会不会触发串口空闲中断了。

下面用代码来说明。 1、配置串口。包括设置串口的引脚配置,串口的配置,串口中断的配置,串口的 接收DMA的配置 void USART_init(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; //开启时钟 RCC_APB2PeriphClockCmd(USART_RCC,ENABLE); //配置TX端口 GPIO_InitStructure.GPIO_Pin = GPIO_USART_TX; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIO_USART_TYPE,&GPIO_InitStructure); //配置RX端口

stm32串口接收字符串经验

stm32串口接收字符串经验 https://www.sodocs.net/doc/cc18436507.html,/jishu_578041_1_1.html2016 分享一个stm32的串口就收字符串以十六进制数解析的程序。好多朋友在用stm32写串口接收的时候说用串口发送数据的时候有丢失的现象,或者发送的数据与接收的数据不一样,比如发送01 串口接收到的是40。还有好多好多的不明现象。今天就和大家讨论一下这些问题是怎么出现的。 在调试串口通信的时候首先要确定硬件是好用的,大家应该都用的是开发板所以硬件部分应该是没问题的。如果是最小系统的话要缺定外接串口模块是不是好的也就是rs3232,如果串口不好使,程序在对也是没用的,再有就是关于电平的问题,在这里说几个芯片就是rs3232芯片和ch340芯片这两个芯片大家都很熟悉了专业性的知识咱就不复i述了,为什么要说这两个芯片呢。因为有的童鞋的板子上没有板载 rs3232的芯片,所以直接将九针串口线的的2、3、5引脚直接接到单片机上了,所以出现可上述发送01收到的是40的情况,这种接是错误的要将串口线接到rs3232的串口上才能开始调试。硬件部分就这些,注意一下就行,下面说说软件部分的在写串口程序是首先要配置串口的初始化 我直接贴出程序再说,#include "pbdata.h"uint8_t TxBuffer1[] = "USART Interrupt Example: This isUSART1 DEMO";

uint8_t RxBuffer1[],rec_f,tx_flag;volatile uint8_t TxCounter1 = 0x00;volatile uint8_t RxCounter1 = 0x00; uint32_t Rec_Len;int main(void){ u8 a=0; RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); USART_Config(USART1); while(1) { if(rec_f==1) { rec_f=0; USART_OUT(USART1,&TxBuffer1[0]); if(a==0){GPIO_SetBits(GPIOA, GPIO_Pin_2); a=1;} else{GPIO_ResetBits(GPIOA, GPIO_Pin_2);a=0; } } }}这是主函数部分,在主函数中只有几个函数的初始化,还有就是定义的数组和标志位。在一般的串口历程中大家会看到的就是定义一个缓冲区,将接收到的串口数据通过串口中断存放到缓冲区中然后在发送到串口中,但是在接收字符串的时候就要用到逐位发送,新手自己有些不了程序,所以只能一直处于蒙着的状态。其实个人感觉整点原子的程序写的真的挺好的,建议新手开始学习的时候看他的程序,有的人就是不喜欢他写程序的风格,这个因人而异,在这里只是建议一下。原子的串口就给出了字符串就收的历程,但是用

STM32的串口中断配置

STM32的串口中断配置,也是很简单的. 首先是配置UART的GPIO口 /****************************************************************************** * * Name : UART1_GPIO_Configuration * Deion : Configures the uart1 GPIO ports. * Input : None * Output : None * Return : None ******************************************************************************* / void UART1_GPIO_Configuration(void) { GPIO_InitTypeDef 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); // 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); } 然后是配置串口参数 /****************************************************************************** * * Name : UART1_Configuration * Deion : Configures the uart1 * Input : None * Output : None * Return : None ******************************************************************************* / void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; Uart1_GPIO_Configuration(); USART_https://www.sodocs.net/doc/cc18436507.html,ART_Clock = USART_Clock_Disable; USART_https://www.sodocs.net/doc/cc18436507.html,ART_CPOL = USART_CPOL_Low; USART_https://www.sodocs.net/doc/cc18436507.html,ART_CPHA = USART_CPHA_2Edge;

STM32串口初始化

#include"stm32f10x.h" void USART_Config(void) { USART_InitTypeDef USART_InitStructure; USART_https://www.sodocs.net/doc/cc18436507.html,ART_BaudRate = 9600; //波特率为9600Hz USART_https://www.sodocs.net/doc/cc18436507.html,ART_WordLength = USART_WordLength_8b; //8位数据 USART_https://www.sodocs.net/doc/cc18436507.html,ART_StopBits = USART_StopBits_1; //在帧结尾传输1 个停止位 USART_https://www.sodocs.net/doc/cc18436507.html,ART_Parity = USART_Parity_No; //奇偶失能 USART_https://www.sodocs.net/doc/cc18436507.html,ART_HardwareFlowControl =USART_HardwareFlowControl_None; //硬件流控制失能 USART_https://www.sodocs.net/doc/cc18436507.html,ART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送使能,接收使能 USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //USART_ITConfig:使能或者失能指定的USART中断USART_IT_RXNE, ENABLE:接收中断 USART_Cmd(USART1, ENABLE); //使能USART 外设 USART_ClearFlag(USART1,USART_FLAG_TC); //清除USARTx 的待处理标志位USART_FLAG_TC:发送完成标志位 }

相关主题