[APM32F1] 极海APM32F107VC EVAL_V1.0开发板(一) gpio模拟串口

[复制链接]
53|5
a425631571 发表于 2025-11-4 20:31 | 显示全部楼层 |阅读模式
本帖最后由 a425631571 于 2025-11-5 21:38 编辑

一、原理部分
之前用外设都是直接用的硬件自带的库,虽然以前有学过原理和时序,但是因为工作其实也很少会有需要gpio模拟串口的情况,但总会有串口用完,但是需要一个类似打印串口的情况。今天也是开整,然后用硬件的库对比一下。

1、协议要点
①、异步通讯:
        通信双方没有共享时钟信号。依靠预先约定好的波特率 (Baud Rate) 来同步。

②、数据帧格式 (常见)
        起始位 (Start Bit)1位,低电平 (逻辑0)。标志着数据帧的开始,用于同步接收方。

        数据位 (Data Bits)5-9位(通常8位)。从最低有效位 (LSB) 开始发送/接收。

        校验位 (Parity Bit): 可选,1位(奇校验、偶校验或无校验)。用于简单的错误检测。

        停止位 (Stop Bit)1位、1.5位或2位,高电平 (逻辑1)。标志数据帧的结束,并为下一帧提供缓冲空间。

        空闲状态 (Idle State): 当没有数据传输时,数据线保持高电平。

        波特率: 定义了每秒传输的符号(位)数。例如,9600 bps 表示每秒传输9600位数据。位周期 (Bit Time) 是波特率的倒数:T_bit = 1 / BaudRate。这是软件模拟时最关键的参数。

③、时间计算
例如现在波特率为9600T_bit = 1 / 9600 0.0001041667 = 104.1667 微秒 (μs)

用我们最常见的格式,8为数据位,1位起始位,1位停止位,即10

计算传输一个字节 (10) 所需的总时间 (T_frame):
T_frame = 10 * T_bit = 10 * 104.1667 μs 1041.667 μs 1.042 ms

可以理解为 大约 1 毫秒 发送一个字节。

发送端要求:需要在 104.17 μs 的整数倍时间点精确切换GPIO电平。

接收端要求:需要在起始位下降沿后等待1.5*T_bit 156.25us进行第一次采样(定位到数据位中间),之后每隔104.17us 采样一次后续位

波特率115200的话即速度是 9600 波特率的 12 倍,这里就不再写那么长

2GPIO 模拟发送 (TX)
①、配置:
将选定的GPIO引脚配置为推挽输出模式,初始状态设置为高电平(空闲状态)。

②、发送一个字节的流程:
a. 起始位:
GPIO引脚拉低,并保持1个完整的位周期 (T_bit)。这告诉接收方数据开始传输。

b. 数据位 (LSB First)
从要发送字节的最低位 (bit 0) 开始。

根据该位的值是0还是1,将GPIO引脚设置为低电平或高电平。

保持这个电平状态1个完整的位周期 (T_bit)

接着发送下一位 (bit 1),重复上述电平设置和延时过程。

依此类推,直到发送完指定的数据位数 (通常是8)

c. 校验位 (如果启用)
计算已发送数据位的奇偶性 (奇校验或偶校验)

根据计算结果,将GPIO引脚设置为相应的电平 (01)

保持这个电平状态1个完整的位周期 (T_bit)

d. 停止位:
GPIO引脚拉高。

保持高电平状态1(1.5/2) 完整的位周期 (T_bit)。这标志着一帧数据的结束,并使线路恢复到空闲状态。

需要注意的点为:

精确的时序: 每个位(起始位、数据位、校验位、停止位)的电平持续时间必须严格等于位周期 (T_bit)。这是模拟成功的最核心要求。任何累积的时序误差都会导致通信失败。

位顺序: 严格遵守协议约定的位顺序(通常是LSB first)。

中断的影响这里我就先不考虑了,因为我只是回顾下原理,不是真的要用模拟gpio来实现项目需求

3GPIO 模拟接收 (RX)
①、配置:
将选定的GPIO引脚配置为浮空输入或上拉输入模式(确保空闲时为高电平)。

②、检测起始位:
持续轮询(或在中断中检测)GPIO引脚状态。

当检测到引脚从高电平变为低电平(下降沿)时,可能是一个起始位开始。

③、同步与采样:
检测到下降沿后,不能立即采样数据。需要避开信号边沿可能不稳定的区域。

关键延时: 等待 1.5个位周期 (1.5 * T_bit)。这个延时将采样点定位到第一个数据位 (LSB) 的中间位置。这是提高抗噪性和采样稳定性的常用技巧。

④、读取数据位:
在预期的采样点(每个数据位的中间位置),读取GPIO引脚的电平状态。

将读取到的电平值 (01) 存入接收字节的对应位(从LSB开始)。

每读取完一位,等待1个位周期 (T_bit) 到达下一位的采样点。

重复这个过程,读取完所有数据位 (8)

⑤、读取校验位 (如果启用)
在下一个采样点(等待1个位周期后),读取GPIO引脚的电平作为校验位。

根据协议(奇/偶校验)和收到的数据位计算期望的校验位,与实际收到的校验位比较,进行错误检查(可选)。

⑥、检测停止位:
在下一个采样点(等待1个位周期后),读取GPIO引脚的电平。期望是高电平 (1)

如果检测到高电平,说明停止位有效,一帧数据接收基本完成(可考虑校验结果)。

如果检测到低电平,说明发生了帧错误(Frame Error

需要注意的点为:1.5 * T_bit 和后续的 1 * T_bit 延时必须非常准确。采样点定位在位的中间是最佳实践。

二、配置工程
我的板子是APM32F107VC EVAL_V1.0
1.png
因为之前看是pin to pin,我以为是完全兼容,所以用cubemx生成了工程,后来程序一直跑不了,查了一下要用极海官方的sdk才行。
在官方下载sdkpack即可
之前都是用IAR,现在公司用keil,就用回keil
我用的是他串口中断的例程做base
​APM32F107_EVAL_SDK_v1.0\Examples\USART\USART_Interrupt\Project\MDK
2.png
​如上图复制到自己工程的文件夹
3.png
再将路径改一下:
4.png
​然后这里每个都要重新添加一下:
5.png
​file:///C:/Users/LONGHU~1/AppData/Local/Temp/ksohtml36584/wps46.jpg​​编译成功,跑了一下程序OK
26.png
27.png
三、修改程序
定义的结构体和宏
PD13TXPD14RX
6.png
我这里做的波特率9600,没有做太高的​
7.png
tx rx初始化,其中rx配置为中断
8.png
2、初始化
其中rx配置为外部中断
10.png
11.png
两个定时器,定时器5做帧间隔的计时,定时器6为判断数据是否结束
​2、发送部分
单个字符:
12.png
字符串:
13.png
发送数组:
14.png
​这里我是直接延时硬等,可以再加一个定时器用作发送。
3、接收部分
在接收首个低电平的时候,即为起始帧,然后打开定时器5处理后边的数据
15.png
定时器5的中断就是数据处理
17.png
这里我是1为起始位,8位数据位,1位停止位,无校验,依次处理就好,用UART_TEST_Handle.rxBitCount作判断当前在第几位。数据保存到UART_TEST_Handle.rxBuffer这个buff
​file:///C:/Users/LONGHU~1/AppData/Local/Temp/ksohtml36584/wps54.jpg​ 18.png
19.png
然后每收到一个字节都打开定时器6,定时器6做了11位的时间,若是定时器6中断溢出则说明这帧数据结束,标志位置1
20.png
4、主函数
检测标志位是否置1,置1则发送rxbuffer,相当于回显
21.png
22.png
​​​实际上我这里虽然做了发送队列,但我接收buff没做,所以也是只能发一条而已。这个是之前打印其他比较多的时候做的队列
四、验证程序:
成功
23.png
然后发0x55,用逻辑分析仪看看
24.png
25.png
链接:
Apps.zip (4.62 KB, 下载次数: 0)
9.png
梦塑者 发表于 2025-11-4 23:43 | 显示全部楼层
这个实在是意义不大,除了学习。
Gfan 发表于 2025-11-5 13:21 | 显示全部楼层
楼主的图好像得重新链接一下,挂了好多
亿年回响 发表于 2025-11-5 17:03 | 显示全部楼层
串口实在是太普通了。模拟GPIO的方式有些化简为繁吧
 楼主| a425631571 发表于 2025-11-5 21:39 | 显示全部楼层
Gfan 发表于 2025-11-5 13:21
楼主的图好像得重新链接一下,挂了好多

重新传了一下,哈哈 第一次在这个平台搞 复制图片编辑的时候有 不知道发布的时候原来是没有的
 楼主| a425631571 发表于 2025-11-5 21:40 | 显示全部楼层
梦塑者 发表于 2025-11-4 23:43
这个实在是意义不大,除了学习。

基本上实际应用都不会用到,就是写着看看{:lol:}学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部