目录
1. 通信分类
1.1 按数据传输方式
方式 | 特点 | 优点 | 缺点 |
---|---|---|---|
串行 | 数据按位顺序传输 | 占用引脚资源少 | 速度相对较慢 |
并行 | 数据各个位同时传输 | 速度快 | 占用引脚资源多 |
1.2 按照数据传送方向
方式 | 特点 |
---|---|
单工 | 数据传输只支持数据在一个方向上传输 |
半双工 | 允许数据在两个方向上传输,但是在某一个时刻只需要数据在一个方向上传输,实际上相当于一种切换方向的单工通信 |
全双工 | 允许数据同时在两个方向上传输,因此全双工通信是两个单工通信方式的结合,要求发送设备和接收设备都有独立的接受和发送能力 |
1.3 按照通信方式
方式 | 特点 |
---|---|
同步 | 带时钟同步信号传输 |
异步 | 不带时钟同步信号 |
2. 接口类型
名称 | 引脚 | 双工 | 时钟 | 电平 | 设备 | 优点 | 缺点 |
---|---|---|---|---|---|---|---|
USART | TX,RX | 全 | 异 | 单段 | 点对点 | 只需两根数据线;无需时钟信号;有奇偶校验位;通信稳定 | 效率较低;抗干扰性弱;传输距离有限 |
IIC | SCL,SDA | 半 | 同 | 单段 | 点对多 | 硬件资源节约,使用广泛且易移植 | 传输速率较慢 |
SPI | SCLK,MOSI,MISO,CS | 全 | 同 | 单段 | 点对多 | 通信简单、数据传输速率快 | 没有指定的流控制和应答 |
CAN | CAN_H,CAN_L | 半 | 异 | 差分 | 点对多 | 实时性强;传输距离较远;抗电磁干扰能力强;成本低;检错能力强,可在高噪声干扰环境中工作;具有优先权和仲裁功能;多个控制模块通过CAN 控制器挂到CAN-bus 上,形成多主机局部网络;可根据报文的ID决定接收或屏蔽该报文 | 信道出错堵塞;不一致性;不可预测性 |
USB | DP,DM | 半 | 异 | 差分 | 点对点 | 可以热拔插(数据线比供电线短);传输速度快;使用方便;连接灵活;独立供电 | 传输距离短;开发调试难度大 |
2.1 USART协议
在STM32F103ZET6 系统控制器有三个 USART(同/异步) 和两个 UART(异步),其中 USART1 的时钟来源于 APB2 总线时钟,其最大频率为 72MHz,其他四个的时钟来源于 APB1 总线时钟,其最大频率为 36MHz。 UART 只是异步传输功能,所以没有 SCLK、nCTS 和 nRTS 功能引脚。
引脚 | USART1 | USART2 | USART3 | UART4 | UART5 |
---|---|---|---|---|---|
TX | PA9 | PA2 | PB10 | PC10 | PC12 |
RX | PA10 | PA3 | PB11 | PC11 | PD2 |
SCLK | PA8 | PA4 | PB12 | ||
nRTS | PA11 | PA0 | PB13 | ||
nCTS | PA12 | PA1 | PB14 |
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
nRTS:请求以发送 (Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当 USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送 (Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
注:USART可以当作UART进行异步传输,此外流控部分可以不写。
2.1.1 USART的基本流程
图1 USART基本结构图
当时钟信号经过波特率发送器分频后发送到发送/接收控制器中,之后由数据寄存器和位移寄存器配合并通过I/O口按位进行数据的发送/接收(低位先行),最后可以通过标准位(TXE/RXNE)来判断是否传输成功。
2.1.2 USART的软件设计思路
首先要了解到可以通过查询和中断两种方式进行串口数据的发送和接受,本文以中断方式为例。
①串口时钟使能,GPIO 时钟使能,复用时钟使能
②串口复位
③GPIO 端口模式设置
④串口参数初始化
下面是串口初始化的结构体
typedef struct {
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 字长
uint16_t USART_StopBits; // 停止位
uint16_t USART_Parity; // 校验位
uint16_t USART_Mode; // USART 模式(可以将接受和发送方式都选中)
uint16_t USART_HardwareFlowControl; // 硬件流控制
}USART_InitTypeDef;
⑤初始化 NVIC并开启中断
2.2 IIC协议
IIC(I2C)总线是一种由 PHILIPS 公司开发的两线式串行总线,由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。 在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
2.2.1 IIC的基本流程
IIC 总线在传送数据过程中共有三种类型信号,分别是:开始信号、结束信号和应答信号。这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
信号种类 | 电平 |
---|---|
开始信号 | SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据 |
结束信号 | SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据 |
应答信号 |
接收数据的 IC 在接收到 8bit 数据后,向发送数据的 IC 发出特定的低电平脉冲,
表示已收到数据
|
在数据传输时,发送端需要在SCL上升前把数据依次放到SDA上等待读取(高位先行),在读取期间需保持SCL为高电平,依次循环8次即可传输一个字节。其中从机的地址一般来说是厂家定义好的8位([7:1]是默认定义的地址,[0/1]是表明后续的数据操作是写入/读取)地址,在主机发出信号来寻找从机时,从机会发出低电平进行回答,之后便可以进行通信。
图2 IIC基本结构图
要注意的是IIC分为模拟IIC(一般是用GPIO管脚,用软件控制管脚状态以模拟IIC通信波形)和
(硬件IIC对应芯片上的IIC外设,有相应IIC驱动电路,其所使用的IIC管脚也是专用)。虽然硬件IIC的效率要远高于软件的,但stm32内部只含有IIC1和IIC2两个硬件IIC且较为复杂,所以一般使用模拟IIC(即按照时序表手动置位SCL和SDA)。
图3 IIC基本结构图
2.2.2 IIC的软件设计思路
2.2.2.1 模拟IIC方式
①串口时钟使能,GPIO 时钟使能,复用时钟使能
②编写常用函数
函数 | 作用 |
---|---|
IIC_Start( )
| 在SCL高电平时拉低SDA |
IIC_Stop( )
| 在SCL高电平时拉高SDA |
IIC_Ack( )
| 在回应阶段时拉低SDA |
IIC_Nack( )
| 在回应阶段时回弹SDA |
IIC_Send_Byte(u8 dat)
| 按位发送字节,高位先行 |
IIC_Read_Byte(u8 dat)
| 按位接收字节,高位先行 |
③MCU扫描从机地址
④从机回应
⑤发送寄存器地址并赋值
⑥接收或发送数据
注:若要读取数据,需要重新发送启始条件并更改8位从机地址的最后一位。
2.2.2.2 硬件IIC方式
硬件和软件方式一般只有底层不太一样,在使用库函数后会主动进行电平的变化,不需要手动赋值SCL和SDA。
名称 | 作用 |
---|---|
I2C_GenerateSTART( ) | 创建启示条件 |
I2C_GenerateSTOP( ) | 创建终止条件 |
I2C_CheckEvent( ) | 同时检验单个或者多个标志 |
I2C_AcknowledgeConfig( ) | 设置是否给主机应答 |
I2C_SendData( ) | 发送数据 |
I2C_ReceiveData( ) | 接收数据 |
I2C_Send7bitAddress( ) | 发送7位从机地址和数据传输方向 |
I2C_GetFlagStatus( ) | 检查某一个标志位 |
①串口时钟使能,GPIO 时钟使能,复用时钟使能
②使用结构体对IIC进行配置
I2C_InitTypeDef I2C_InitStructure;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //IIC模式
I2C_InitStructure.I2C_ClockSpeed = 50000; //时钟速度(400kHz<)
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //时钟占空比(>100kHz时有效)
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //应答使能
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //地址位数(做从机时有效)
I2C_InitStructure.I2C_OwnAddress1 = 0x00; //自身地址(做从机时有效)
I2C_Init(I2C2, &I2C_InitStructure);
③使能IIC
2.3 SPI通信
SPI 是串行外围设备接口,主要应用在 EEPROM,FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为 PCB 的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议。
图4 SPI基本结构
MISO:主设备数据输入,从设备数据输出。
MOSI:主设备数据输出,从设备数据输入。
SCLK(串行时钟信号):由主设备产生。
CS(从设备片选信号):由主设备控制,用来作为“片选引脚”对从机进行选中。
2.3.1 SPI的基本流程
SPI的数据交换是通过数据交换实现的,每一个时钟上升沿时会使得从机移位寄存器的数据通过MISO向左移动到主机的位移寄存器中,与此同时主机的数据也由MOSI传输到从机的位移寄存器中,形成了一个闭环。
图5 SPI工作流程
2.3.2 SPI的4种工作模式
SPI 总线四种工作方式 SPI 模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果 CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果 CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI 主模块和与之通信的外设备时钟 相位和极性应该一致。
模式 | 电平 | 状态 |
---|---|---|
0 | CPOL=0, CPHA=0 | 此时空闲态时,SCLK处于低电平;数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变;所以数据采样是在上升沿,数据发送是在下降沿 |
1 | CPOL=0, CPHA=1 | 此时空闲态时,SCLK处于低电平;数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变;所以数据采样是在下降沿,数据发送是在上升沿 |
2 | CPOL=1, CPHA=0 | 此时空闲态时,SCLK处于高电平;数据采样是在第1个边沿,也就是SCLK由高电平到低电平的跳变;所以数据采集是在下降沿,数据发送是在上升沿 |
3 | CPOL=1, CPHA=1 | 此时空闲态时,SCLK处于高电平;数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变;所以数据采集是在上升沿,数据发送是在下降沿 |
图6 SPI时序
2.3.3 SPI软件设计思路(硬件方式)
①串口时钟使能,GPIO 时钟使能,复用时钟使能
②初始化并使能SPI
typedef struct
{
uint16_t SPI_Direction; //设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行
发和串行收方式
uint16_t SPI_Mode; //设置 SPI 的主从模式
uint16_t SPI_DataSize; //设置数据为 8 位还是 16 位帧格式选择项
uint16_t SPI_CPOL; //用来设置时钟极性
uint16_t SPI_CPHA; //用来设置时钟相位
uint16_t SPI_NSS; //设置 NSS 信号由硬件(NSS 管脚)还是软件控制
uint16_t SPI_BaudRatePrescaler; //设置 SPI 波特率预分频值
uint16_t SPI_FirstBit; //设置数据传输顺序是 MSB 位在前还是 LSB 位在前
uint16_t SPI_CRCPolynomial; //来设置 CRC 校验多项式
}SPI_InitTypeDef
③接收或发送数据
u8 SPI2_ReadWriteByte(u8 Data)
{
u8 count=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //等待发送区空(含超时)
{
count++;
if(count) return 0;
}
SPI_I2S_SendData(SPI1, TxData); //通过外设 SPIx 发送一个数据
count=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) //等待接收
{
count++;
if(retry>200) return 0;
}
return SPI_I2S_ReceiveData(SPI1); //返回通过 SPIx 最近接收的数据
}
注:一般来说TXE和RXNE是硬件置位软件恢复的,但在向SPI_DR发送数据时会自动清除。
④查看传输标志
注:SPI也可以使用模拟方式进行,具体仿照模拟IIC实验即可。
2.4 CAN通信
CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信协议。CAN 控制器根据两根线上的电位差来判断总线电平,且总线电平分为显性电平和隐性电平。发送方通过使总线电平发生变化,将消息发送给接收方。
CAN 协议具有一下特点:
- 多主控制。在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级。两个以上的单元同时开始 发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
- 系统的柔软性。与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。
- 通信速度较快,通信距离远。最高 1Mbps(距离小于 40M),最远可达 10KM(速率低于 5Kbps)。
- 具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。
- 故障封闭功能。CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将引起此故障的单元从总线上隔离出去。
- 连接节点多。CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
2.4.1 CAN的基本结构
CAN具有两个国际标准(ISO11519以及ISO11898),其中前者是针对通信速率为 125Kbps以下的低速、远距离“开环网络”,它的最大传输距离为 1km,最高通讯速率为 125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻。而ISO11898 标准是高速、短距离“闭环网络”,它的总线最大长度为 40m,通信速度最高为 1Mbps,总线的两端各要求有一个“120 欧”的电阻。
图7 CAN链接图
由于CAN通信是利用差分信号方式传输(即CAN_H - CAN_L),所以将二者的电平差作为判别逻辑1/0的依据,如下图8所示。
图8 CAN的差分信号电平
2.4.2 CAN的协议
CAN 协议是通过以下 5 种类型的帧进行的:数据帧、要控帧 、错误帧 、过载帧 、帧间隔。其中,数据帧和遥控帧有标准格式和扩展格式两种格式。
帧类型 | 帧用途 |
---|---|
数据帧 | 用于发送单元向接收单元传送数据的帧 |
要控帧 | 用于接收单元向具有相同 ID 的发送单元请求数据的帧 |
错误帧 |
用于当检测出错误时向其它单元通知错误的帧
|
过载帧 | 用于接收单元通知其尚未做好接收准备的帧 |
帧间隔 | 用于将数据帧及遥控帧与前面的帧分离开来的帧 |
数据帧一般由 7 个段构成,即:
(1) 帧起始。表示数据帧开始的段。
(2) 仲裁段。表示该帧优先级的段。若两个节点同时竞争 CAN 总线的占有权,当它们发送报文时,若首先出现隐性电平(高电平),则会失去对总线的占有权,进入接收状态。
(3) 控制段。表示数据的字节数及保留位的段。
(4) 数据段。数据的内容,一帧可发送 0~8 个字节的数据。
(5) CRC 段。检查帧的传输错误的段。
图9 CRC段的构成
(6) ACK 段。表示确认正常接收的段,发送 2 个位的隐性位,而接收到正确消息的单元在 ACK 槽(ACK Slot)发送显性位,通知发送单元正常接收结束,这个过程叫发送 ACK/返回 ACK。发送 ACK 的是在既不处于总线关闭态也不处于休眠态的所有接收单元中,接收到正常消息的单元(发送单元不发送 ACK)。
图10 ACK段的构成
(7) 帧结束。表示数据帧结束的段。
t图11 数据帧的构成
其中,RTR是用来区别是数据帧(1)还是远程请求帧(0);IDE用来控制是标准格式还是拓展格式。
2.4.3 CAN的控制器
STM32 自带的是 bxCAN,即基本扩展 CAN。它支持 CAN 协议 2.0A(只可处理标准数据帧) 和 2.0B。它的设计目标是,以最小的 CPU 负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用,bxCAN 提供所有支持时间触发通信模式所需的硬件功能。
图11 双CAN框图
CAN控制器是由CAN控制内核、CAN发送邮箱、CAN接受FIFO、验收筛选器和整体控制逻辑构成。
- CAN控制内核:包含各种寄存器,可以配置模式和波特率等。
- CAN发送邮箱:用来缓存待发送的报文,最多缓存三个。
- CAN接受FIFO:用来缓存接收到的有效报文。
- 验收筛选器(14个主滤波器):筛选有效报文。
- 整体控制逻辑构成。
STM32 的 bxCAN 的主要特点有:
- 支持 CAN 协议 2.0A 和 2.0B 主动模式
- 波特率最高达 1Mbps
- 支持时间触发通信
- 具有 3 个发送邮箱
- 具有 3 级深度的 2 个接收 FIFO
- 可变的过滤器组(也叫滤波器和筛选器,最多 28 个)
CAN控制器的工作模式有三种:初始化模式、正常模式、睡眠模式。
工作模式 | 电平变化 | 特点 |
---|---|---|
初始化 | SLAK=0,INAK=1 | 当bxCAN处于初始化模式时,禁止报文的接收和发送,并且CANTX引脚输出隐性位(高电平) |
正常 | SLAK=0,INAK=0 | CAN总线开始同步,可以收发数据 |
睡眠 | SLAK=1,INAK=0 | bxCAN的时钟停止,但软件仍然可以访问邮箱寄存器 |
CAN控制器的测试模式也有三种:静默模式、回环模式、回环静默模式。
测试模式 | 电平变化 | 特点 |
---|---|---|
静默 | CANTX=1 | 只能向总线发1,可以接收数据 |
回环 | 发送的数据直接到输入,不可以接收总线的数据 | |
静默回环 | CANTX=1 | 发送的数据直接到输入,不可以接收总线的数据 |
STM32 把传播时间段和相位缓冲段 1(STM32 称之为时间段 1)合并了,所以 STM32 的 CAN 一个位只有 3 段:同步段(SYNC_SEG)、时间段 1(BS1)和时间段2(BS2)。STM32 的 BS1 段可以设置为 1~16 个时间单元,刚好等于传播时间段和相位缓冲段 1 之和。
2.4.4 CAN的工作流程
CAN 发送流程为:程序选择 1 个空置的邮箱(TME=1)→设置标识符(ID)、数据长度(DLC)和发送数据(DATA)→设置 CAN_TIxR 的 TXRQ 位为 1,请求发送→邮箱挂号(等待成为最高优先级)→预定发送(等待总线空闲)→发送→邮箱空置。
CAN 接收流程为:FIFO空置→收到有效报文→挂号_1(存入 FIFO 的一个邮箱,由硬件控制)→收到有效报文→挂号_2→收到有效报文→挂号_3→收到有效报文→溢出。
2.4.5 CAN的软件设计
①CAN时钟使能,复用时钟使能
②设置CAN的工作模式和波特率
typedef struct
{
uint16_t CAN_Prescaler; //分频系数
uint8_t CAN_Mode; //测试模式设置
uint8_t CAN_SJW; //重新同步跳跃宽度为几个时间单位
uint8_t CAN_BS1; //时间段 1 占用几个时间单位
uint8_t CAN_BS2; //时间段 2 占用几个时间单位
FunctionalState CAN_TTCM; //非时间触发通信模式
FunctionalState CAN_ABOM; //软件自动离线管理
FunctionalState CAN_AWUM; //睡眠模式通过软件唤醒
FunctionalState CAN_NART; //禁止报文自动传送
FunctionalState CAN_RFLM; //报文不锁定,新的覆盖旧的
FunctionalState CAN_TXFP; //优先级由报文标识符决定
} CAN_InitTypeDef;
③设置滤波器
typedef struct
{
uint16_t CAN_FilterIdHigh; //32位id高16位
uint16_t CAN_FilterIdLow; //32位id高16位
uint16_t CAN_FilterMaskIdHigh; //32位屏蔽id高16位
uint16_t CAN_FilterMaskIdLow; //32位屏蔽id低16位
uint16_t CAN_FilterFIFOAssignment; //设置 FIFO 和过滤器的关联关系
uint8_t CAN_FilterNumber; //设置初始化的过滤器组号
uint8_t CAN_FilterMode; //设置过滤器的模式
uint8_t CAN_FilterScale; //设置过滤器的位宽
FunctionalState CAN_FilterActivation; //激活过滤器
} CAN_FilterInitTypeDef;
④发送接收消息
⑤CAN状态获取
3. DMA方式
DMA(Direct Memory Access),即直接存储器访问,DMA 传输将数据从一个地址空间复制到另外一个地址空间。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,能使 CPU 的效率大为提高。STM32 最多有 DMA1(有 7 个通道)和DMA2(有 5 个通道)两个DMA控制器,并且每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁起来协调各个 DMA 请求的优先权。
STM32 的 DMA 有以下一些特性:
- 每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发,这些功能通过软件来配置。下图是DMA1的一些硬件请求:
- 在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。
- 独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
- 支持循环的缓冲器管理
- 每个通道都有 3 个事件标志(DMA 半传输,DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。
- 存储器和存储器间的传输
- 外设和存储器,存储器和外设的传输
- 闪存、SRAM、外设的 SRAM、APB1、APB2 和 AHB 外设均可作为访问的源和目标。
- 可编程的数据传输数目:最大为 65536
3.1 DMA的基本框架
由上图可以看到DMA方式可以让外设寄存器和存储器直接进行数据传输,并通过控制方向的参数进行输入输出设置。此外,在存储器内部中也可以由FLASH到SRAM的传输,但由于FLASH是只读的,所以这种传输不可以逆向。外设和存储器都需要进行起始地址、数据宽度和地址是否自增的设计,但一般外设的地址不需要自增。
注:若源数据宽度小于目标数据宽度,则会自动在高位补零;若源数据宽度大于目标数据宽度,则会自动舍弃高位。
3.2 DMA的寄存器
寄存器名称 | 寄存器功能 |
---|---|
DMA 中断状态寄存器(DMA_ISR)
| 发生中断后自动置标志位 |
DMA 中断标志清除寄存器(DMA_IFCR)
| 清除标志位 |
DMA 通道 x 配置寄存器(DMA_CCRx)
| 设置括数据宽度、外设及存储器的宽度、通道优先级、增量模式、传输方向、中断允许、使能等 |
DMA 通道 x 传输数据量寄存器(DMA_CNDTRx)
|
控制 DMA 通道 x 的每次传输所要传输的数据量
|
DMA 通道 x 的外设地址寄存器(DMA_CPARx)
| 指定外设的地址 |
DMA 通道 x 的存储器地址寄存器(DMA_CMARx)
| 指定存储器的地址 |
3.3 DMA的设计思路
①初始化DMA通道参数
typedef struct
{
uint32_t DMA_PeripheralBaseAddr; //外设基地址
uint32_t DMA_MemoryBaseAddr; //内存基地址
uint32_t DMA_DIR; //数据传输方向
uint32_t DMA_BufferSize; //单次传输数据量
uint32_t DMA_PeripheralInc; //外设地址是否自增
uint32_t DMA_MemoryInc; //内存地址是否递增
uint32_t DMA_PeripheralDataSize; //外设的数据长度
uint32_t DMA_MemoryDataSize; //内存的数据长度
uint32_t DMA_Mode; //DMA 模式是否循环采集(是否重装计数器)
uint32_t DMA_Priority; //优先级
uint32_t DMA_M2M; //是否是存储器互传
}DMA_InitTypeDef;
注:接收和发送通道的数据传输方向相反:
DMA_DIR_PeripheralSRC:从外设到内存设备。
DMA_DIR_PeripheralDST:从内存设备到外设。
②DMA 时钟使能(以串口1的发送通道为例)
DMA_Init(DMA1_Channel4 , &DMA_InitStructure); //初始化DMA1_Channel4
DMA_ClearFlag(DMA1_FLAG_GL4);
DMA_Cmd(DMA1_Channel4 , DISABLE); //禁用DMA通道传输
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); //开启串口DMA发送
③DMA数据传输函数(以串口1收发程序)
void DMA_send(){
//开启计数器,在传输过程中,DMA控制器会持续地递减该计数器的值,直到计数器为0,表示数据传输完成。
int len = sizeof(data);
memcpy(USART1_DMA_TX_Buffer, (uint8_t*)data, len);
DMA_SetCurrDataCounter(DMA1_Channel4,USART2_DMA_TX_BUFFER_MAX_LENGTH);
DMA_Cmd(DMA1_Channel4, ENABLE);//开启DMA传输
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) != SET);
DMA_Cmd(DMA1_Channel4, DISABLE);//关闭DMA传输
DMA_ClearFlag(DMA1_FLAG_TC7);
}
④查询DMA传输通道状态:利用库函数FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
这里贴一个别的UP写的程序例程,大家可以借鉴一下:GitHub - JinliangYan/stm32-usart-uart-dma-rx-tx: UART ADM Rx and Tx, using STM32F10x_StdPeriph_Driver lib
免责声明:本文所引用的各种资料均用于自己学习使用,这里感谢正点原子和野火官方的资料以及各位优秀的创作者。