[CW32F030系列]

【有那么点详细的CW32学习笔记】通用异步收发器—发送篇

[复制链接]
240|2
手机看帖
扫描二维码
随时随地手机跟帖
CW32生态社区|  楼主 | 2024-4-29 11:45 | 显示全部楼层 |阅读模式
本章介绍CW32通用异步收发器的使用。
虽然大部分时候会被简单称为“串口”,但实际上用“串口”来指代UART并不正确。串口对应并口的概念,在串口通信中,数据被以二进制形式发送,并且每次发送都只传输1比特位(当然,传输速度可能会很快),像SPI、IIC其实也属于串口。而对传输速度的描述,也就是波特率即是描述的每秒传输的比特位数量,例如波特率是9600,就代表该串口每秒可以传输9600bit的数据。与之相对应的并口,则是使用多个物理信道传输数据,一批数据会同时在多个物理信道上传输,这种并行通信会占用很多IO资源,但是传输速度也得到了显著提高。
UART作为一种异步通信方式,他不需要时钟线,在供电正常的情况下一共就只需要两根数据线,非常适合一对一的通信需求。CW32F030拥有3个UART外设,此文章介绍UART1的使用,那么按照惯例,先总览一下使用UART需要做哪些准备工作。
需要将IO设置为输出,并复用为UART模式。
需要使能UART这个外设,并设置通信协议的必要参数(关于UART协议本身,互联网有很多优质教程,读者可以自行搜索),完成初始化。
编写发送和接收函数,调用函数实现发送和接收的功能。
第一步的进行非常简单,查询芯片《数据表》的引脚定义,发现LQFP48封装下,PA8 & PA9是UART1的发送和接收,因此只需要配置好这两个IO的功能,第一步就算是完成了。
8e112eef93d3b132dac80209dfefcc0e
eb4c361ee7bdc9bf7fa04904a551a54b
配置代码如上图,但有读者表示自己找不到设置复用功能的函数,那我们就来看看功能复用函数的本质是什么。
b41d99092cbe0d1a254e837a5c5f9438
这是PA9的复用函数,可以看到这是一个宏函数,其内容表明设置复用其实就是设置了对应GPIO复用寄存器的值,PA9属于A组IO的第9号口,是高位Pin口,因此要找到高位口的复用寄存器,并设置复用功能为(0010)2,也就是AF2,具体设置如下图所示。
9dedbf5448eba69929183e6f52fd2cf5
因此配置复用的时候,如果找不到对应的复用函数,可以直接配置此寄存器来完成复用配置,但为了方便读者,配置IO复用的宏函数均位于cw32xxxxx_gpio.h这个文件中,此头文件包含了相当多的宏函数,均是常用的IO操作,如反转、置位、闪烁等,感兴趣的读者可以前往翻阅。
话题拽回到UART这边,接下来要进行的是第二步,配置UART的必要参数,这里先讲解发送功能需要进行的配置。
不论是什么单片机,想要使用任何一个片上外设,必须要使能该外设的时钟总线,直接在工程的函数列表中找到时钟配置文件下的全部函数,根据函数的名字可以快速定位使能UART1时钟的函数
ee77f76b07a7c6f87b318d60ec06c580
我们可以看到这个函数本质上就是在操作APBEN2这个寄存器,通过查看芯片手册,我们也可以找到各个外设所属的时钟线。

731012d29d4e56cc02d3f325a1c2a969
随后就是UART通信参数的结构体了,结构体同样对应了寄存器,但使用结构体可以简化开发者的配置步骤,且看下图:
500834a42d5a37be43669c17576aeea1

7e249e9b903d44e8b76b7619fbf6b99a

此结构体成员拥有相当详细的注释,这里直接按照开发者意图配置即可,我在这里配置为:波特率115200、PCLK时钟源、1个停止位、无校验位、全双工模式,配置完成后初始化结构体即可。
值得注意的是,在芯片内部并没有一个直接的波特率数值寄存器,为了保证异步通讯的可靠,波特率越精准越好,切既有的系统时钟不一定能够刚好提供波特率倍数的时基,因此实际上的波特率是一个浮点数,它拥有整数部分和小数部分的2个寄存器。具体的计算公式在芯片手册的通用异步收发器章节有写,这里只列举初始化函数中的相关操作:
2a7663030325d1eddcf3a8e9607aa880
由于我选择的是16倍采样,初始化函数会执行上述代码,代码的计算过程复刻了手册中的计算过程(如下图),这里是先计算时钟源在16倍采样模式下能够直接取得的波特率结果temp,temp包含了整数部分和小数部分,整数部分直接赋值即可,小数部分则是将公式变型得到的。开发者在使用时不需要手写计算BRRI和BRRF的寄存器值,初始化函数会自动完成该计算。
c02b1a2c0271015e8fe41aaac7e7df41
皆大欢喜,到目前为止已经成功完成两步了,还差最后一步就可以使用UART的发送功能了,那就是自己写一个UART1的发送函数。我手里刚好就有一个自己写的发送函数,长这个样子:
0b27519caf5d65809a721a76990dccee
a9723a17cb0ad06c6f91ce8760821bdb 这段简易代码会发送这个字符串作为UART1的调试参数。
这段代码的主要逻辑在芯片手册里面也有详细描述:

2e03e4659eada7495b8a86190399dc64

Tips:在编写各类通信函数这里,我建议一定要加上至少两个功能。第一个就是发送的状态,成功还是失败,这很重要,出问题之后的排查工作基本就靠这个了;第二个就是超时跳出功能,有的时候可能硬件故障或者什么别的原因导致发送一直失败,如果死等就让程序全部死掉了,超时跳出可以保证其他大部分程序的正常运行,当然使用看门狗是一种更优解。
在轮询函数中调用调试函数即可实现间隔100ms发送一次的功能,效果如下:
a7390bc12f8e316e3ca5d3c83039bcc1 64a684fbfb3cd32640e97e302ca4a155

从时间上来看,100ms的定时发送还是很精确的,这种方式占用CPU的时间资源实现发送,虽然传统但是有效可控。
要点总结:
1、注意区分串口和并口的概念。
2、CW32的UART虽然有2个波特率寄存器,但是并不需要开发者手算寄存器参数。

使用特权

评论回复
AdaMaYun| | 2024-5-9 19:26 | 显示全部楼层
轮询时间上会更长吗?

使用特权

评论回复
OKAKAKO| | 2024-5-11 11:16 | 显示全部楼层
串口通用异步收发器是很重要的一种通讯模式

使用特权

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

本版积分规则

9

主题

9

帖子

1

粉丝