打印
[其他ST产品]

STM32F1常用外设介绍

[复制链接]
楼主: 范德萨发额
手机看帖
扫描二维码
随时随地手机跟帖
241
范德萨发额|  楼主 | 2023-2-28 21:05 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
右边的模块用于产生同步的时钟信号,配合发送移位寄存器输出,发送移位寄存器每移位一次,同步时钟就跳变一个周期,时钟告诉对方,我移出去一位数据了,看是否需要时钟信号来指导接受一下,这个时钟只支持输出不支持输入,两个USART之间,不能实现同步的串口通信,这个时钟信号的用途,第一个就是兼容别的协议,比如串口加上时钟之后,和SPI协议特别像,所以有了时钟输出的串口,就可以兼容SPI,这个时钟也可以做自适应波特率,比如接受设备不确定发送设备给的什么波特率,可以测量一下这个时钟的周期,然后计算得到波特率(需要另外写程序来实现这个功能)

唤醒单元:实现串口挂在多设备,串口一般是点对点的通信,点对点,只支持两个设备互相通信,想发数据直接发就行,而多设备,在一条总线上,可以接多个从设备,每个设备分配一个地址,先跟某个设备通信,就先进行寻址,确定通信对象,在定义数据收发,这个唤醒单元就可以用来实现多设备的功能,可以给串口分配一个地址,当我发送指定地址时,此设备唤醒开始工作,当我发送别的设备地址时,别的设备就唤醒工作,这个设备没收到地址,就会保持沉默,这样实现多设备的串口通信了。

使用特权

评论回复
242
范德萨发额|  楼主 | 2023-2-28 21:05 | 只看该作者
中断输出控制:中断申请位就是状态寄存器的各种标志位,状态寄存器这里有两个标志位比较重要,一个是TXE发送寄存器空,另一个是RXNE接收寄存器空,这两个是判断发送状态和接收状态的必要标志位,中断输出控制就是配置中断是不是能够通向NVIC

使用特权

评论回复
243
范德萨发额|  楼主 | 2023-2-28 21:05 | 只看该作者
波特率发生器:其实就是分频器,APB时钟进行分频,得到发送和接收移位的时钟,时钟输入是发PCLKx(x=1或2),因为USART1挂载在APB2,所以就是PCLK2的时钟,一般是72M,其他的USART都挂载在APB1,所以是PCLK1的时钟,一般是36M,之后时钟在进行一个分频,除以一个USARTDIV的分频系数,USARTDIV是一个数值,分为整数部分和小数部分,因为有些波特率,用72M除于一个整数的话,可能除不尽,会有误差,所以这里的分频系数是支持小数点后4位的,分频就更加精准,之后分频完还要再除个16,得到发送时钟和接收器时钟,通向控制部分,然后右边,如果TE(TX Enable)为1,就是发送器使能,发送部分的波特率就有效,如果RE(RX Enable)为1,就是接收器使能了,接收部分的波特率就有效。

使用特权

评论回复
244
范德萨发额|  楼主 | 2023-2-28 21:05 | 只看该作者
USART的基本结构


最左边的是波特率发生器,用于产生约定的通信速率,时钟来源是PCLK2或1,经过波特率发生器分频后,产生的时钟通向发送控制器和接收控制器,发送控制器和接收控制器用来控制发送移位和接收移位,之后由发送数据寄存器和发送移位寄存器这两个寄存器的配合,将数据一位一位的移出去,通过GPIO口的复用输出,输出到TX引脚,产生串口协议规定的波形,这个移位寄存器是向右移的,是低位先行,当数据由数据寄存器转移到移位寄存器时,会置一个TXE的标志位,通过判断这个标志位,就可以知道是不是可以写入下一个数据了,接收部分也是类似的,RX引脚的波形,通过GPIO输入,在接收控制器的控制下,一位一位地移入接收移位寄存器,移完一帧数据后,数据就会统一转运到接收数据寄存器,在转移的同时,置一个RXNE标志位,检查这个标志位,就可以知道是不是收到数据了,同时这个标志位也可以去申请中断,这样就可以在收到数据时,直接进入中断函数,快速的读取和保存数据,虽然有四个寄存器但是在软件层面上,只有一个DR寄存器可以供我们读写,写入DR时,数据走上面这条路,进行发送,读取DR时,数据走下面这条路,进行接收,这就是USART进行串口数据收发的过程,右下角是个开关控制。

使用特权

评论回复
245
范德萨发额|  楼主 | 2023-2-28 21:06 | 只看该作者


四种选择:9位字长,有校验或无校验,8位字长有校验或者无校验,最好选择9位字长,有校验或者8位字长无校验,这样每一帧的有效载荷都是1字节,

使用特权

评论回复
246
范德萨发额|  楼主 | 2023-2-28 21:06 | 只看该作者

STM32的串口可以配置停止位为0.5、1、1.5、2,这四种参数的区别,就是停止位的时长不一样,1位停止位,这时停止位的时长就和数据位的一位,时长一样,1.5停止位就是数据位一位,时长的1.5倍,2个停止位,那停止位时长就是2倍,0.5个停止位,时长就是0.5倍,一般选择1位停止位。、

使用特权

评论回复
247
范德萨发额|  楼主 | 2023-2-28 21:06 | 只看该作者
串口的输出TX比输入RX简单很多,输出就定时翻转TX引脚高低电平就可以,输入不仅要保证采样频率和波特率一致,还要保证每次输入采样的位置,要正好处于每一位的正中间,只有在每一位的正中间采样,这样高低电平读进来,才是最可靠的,如果采样点过于靠前或者靠后,那有可能高低电平正在翻转,电平还不稳定,或者稍有误差,数据就采样错了,输入最好还要对噪声有一定的判断能力,如果是噪声,最好能置个标志位提醒一下,STM32设计的输入电路,上图展示的是USART的起始位侦测,当输入电路侦测到一个数据帧的起始位后,就会以波特率的频率,连续采样一帧数据,同时,从起始位开始,采样位置就要对齐到位的正中间,只要第一位对齐了,后面都是对齐的,为了实现这些功能对输入的电路对采样时钟进行了细分,它会以波特率的16倍频率进行采样,也就是在一位地时间里,可以进行16次采样,它的策略是最开始,空闲状态高电平,那采样就一直是1,在某个位置突然采集到一个0,那么就说明在这两次采样之间,出现了下降沿,如果没有任何噪声,那之后就应该是起始位了,在起始位,会进行连续16次采样,没有噪声的话,这16次采样,肯定都是0,实际电路有噪声,即使出现下降沿了,后序也要再采样几次,以防万一,这个接收电路还会再下降沿之后的第3次、5次、7次,进行一批采样,在第8次、9次、10次,再进行一批采样,且这两批采样,都要要求每3位里面至少有2个0,没有噪声就全是0,满足情况,如果有轻微的噪声,导致3位里面,只有两个0,另一个是1,也算是检测到了起始位,但是在状态寄存器里会置一个NE(Noise Error),噪声标志位,提醒一下,数据收到了,但是有噪声,如果3位里面只有一个0,就不算检测到了起始位,这时电路就忽略前面的数据,重新开始捕捉下降沿,这就是STM32的串口,在接收过程中,对噪声的处理,如果通过了这个起始位侦测,那接收状态就由空闲,变为接收起始位,同时,第8、9、10次采样的位置,就正好是起始位的正中间,之后接收数据位时,就都在第8、9、10次,进行采样,这样就能保证采样位置在位的正中间了,这就是起始位侦测和采样位置对齐的策略

使用特权

评论回复
248
范德萨发额|  楼主 | 2023-2-28 21:06 | 只看该作者
串口初始化:

第一步,开启时钟,把需要用的USART和GPIO的时钟打开

第二步,GPIO初始化,把TX配置成复用输出,RX配置成输入

第三步,配置USART,直接用一个结构体,就可以配置好所有参数

第四步,如果只需要发送的功能就直接开启USART,如果需要接收的功能,还需要再配置中断,在开启USART之前,加上ITConfig和NVIC的代码就可以了

使用特权

评论回复
249
范德萨发额|  楼主 | 2023-2-28 21:06 | 只看该作者
回复缺省值函数

void USART_DeInit(USART_TypeDef* USARTx);

使用特权

评论回复
250
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
配置结构体函数

void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);

使用特权

评论回复
251
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
给结构体配置默认值函数

void USART_StructInit(USART_InitTypeDef* USART_InitStruct);

使用特权

评论回复
252
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
配置同步时钟输出函数

包括时钟是否输出,时钟的极性相位等参数

void USART_ClockInit(USART_TypeDef* USARTx, USART_ClockInitTypeDef* USART_ClockInitStruct);
void USART_ClockStructInit(USART_ClockInitTypeDef* USART_ClockInitStruct);

使用特权

评论回复
253
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
开启串口函数

void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);

使用特权

评论回复
254
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
开启串口中断函数

void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);

使用特权

评论回复
255
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
开启USART到DMA的触发通道函数

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);

使用特权

评论回复
256
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
设置地址函数

void USART_SetAddress(USART_TypeDef* USARTx, uint8_t USART_Address);

使用特权

评论回复
257
范德萨发额|  楼主 | 2023-2-28 21:07 | 只看该作者
唤醒函数

void USART_WakeUpConfig(USART_TypeDef* USARTx, uint16_t USART_WakeUp);

使用特权

评论回复
258
范德萨发额|  楼主 | 2023-2-28 21:08 | 只看该作者
LIN函数

void USART_ReceiverWakeUpCmd(USART_TypeDef* USARTx, FunctionalState NewState);

使用特权

评论回复
259
范德萨发额|  楼主 | 2023-2-28 21:08 | 只看该作者
发送数据函数

写DR寄存器

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

使用特权

评论回复
260
范德萨发额|  楼主 | 2023-2-28 21:08 | 只看该作者
接收数据
读DR寄存器函数

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则