5. 串口通信
📝本节您将了解串口通信(UART)的基本原理和协议格式,学习如何配置 MSPM0G3519 的 UART 外设,实现天巧星开发板与电脑之间的数据收发。
🏆本章目标
1️⃣ 理解串口通信的工作原理和参数含义
2️⃣ 了解 MSPM0G3519 的 UART 外设资源
3️⃣ 通过 SysConfig 配置 UART0 通信参数
4️⃣ 实现开发板向电脑发送数据和接收数据
5.1 串口通信概述
前面几章我们通过 GPIO 控制 LED 亮灭,本质是"电平状态控制"。串口通信则不同——它传递的是"一串消息"。就像打电话一样,一句完整的话里可以包含很多内容,而不是简单地"亮"或"灭"。
串口通信(UART,Universal Asynchronous Receiver/Transmitter)通过 TX(发送)和 RX(接收)两根线实现数据双向传输。发送方把数据拆成一个个位,按固定速率一位一位发出去;接收方按同样速率一位一位收回来,再拼成完整数据。
三个核心概念:
| 概念 | 说明 | 类比 |
|---|---|---|
| 异步通信 | 双方各自维护时钟,不需要时钟线 | 两人约定同样的语速聊天,不需要节拍器 |
| 全双工 | TX 和 RX 可同时工作 | 电话——双方可以同时说话 |
| 波特率 | 每秒传输的位数,双方必须一致 | 语言——你说中文我说英文,互相听不懂 |
串口帧格式 — 一帧数据由以下几个部分构成:
空闲(高) → 起始位(低) → 数据位(D0~D7) → [校验位] → 停止位(高) → 空闲(高)| 组成 | 说明 |
|---|---|
| 起始位 | 1 位低电平,标志一帧开始 |
| 数据位 | 常用 8 位,低位先发 |
| 校验位 | 可选,用于检测传输错误 |
| 停止位 | 1~2 位高电平,标志一帧结束 |
最常用的配置为 115200 8N1(波特率 115200 / 8 数据位 / 无校验 / 1 停止位)。
5.2 天巧星串口资源
MSPM0G3519 内部集成多个 UART 外设。天巧星开发板上被使用的串口资源:
| UART | TX 引脚 | RX 引脚 | 用途 | 默认波特率 |
|---|---|---|---|---|
| UART0 | PA10 | PA11 | CH340 USB-C 转串口 → 电脑 | 9600 |
| UART7 | PB17 | PB18 | 无线串口模块 | 115200 |
天巧星板载 CH340 USB 转串口芯片,UART0 通过 CH340 连接到 USB-C 接口。电脑端安装 CH340 驱动后,插上 USB 线即可在设备管理器中看到虚拟串口(COM 口),无需额外接线。
接线说明
天巧星的 UART0 已通过板载 CH340 连接到 USB-C 口,不需要额外接线。只要用 USB-C 数据线连接开发板和电脑即可通信。
如果需要使用排针上的 UART0 引脚(PA10/PA11)与其他设备通信,注意 TX/RX 交叉连接:
- 天巧星 TX(PA10) → 对方 RX
- 天巧星 RX(PA11) → 对方 TX
- GND → GND(必须共地)
5.3 SysConfig 配置 UART
5.3.1 添加 UART 外设
- 打开
.syscfg文件 - 左侧面板找到 UART 选项卡
- 点击 ADD 添加一个 UART 实例
5.3.2 配置 UART 参数
| 参数 | 设置值 | 说明 |
|---|---|---|
| Name | UART_0 | 实例名称 |
| UART Module | UART0 | 选择 UART0 外设 |
| Baud Rate | 9600 | 波特率(与 CH340 默认一致) |
| Word Length | 8 Bits | 数据位 8 位 |
| Parity | None | 无校验 |
| Stop Bits | One | 1 位停止位 |
| Flow Control | Disable HW flow control | 无硬件流控 |
| Direction | TX and RX | 收发双向 |
点击查看截图 — UART 参数配置

5.3.3 配置引脚
| 参数 | 设置值 |
|---|---|
| TX Pin | PA10 |
| RX Pin | PA11 |
点击查看截图 — UART 引脚配置

5.3.4 配置中断(接收中断)
如果需要接收数据,建议使能 RX 中断:
| 参数 | 设置值 |
|---|---|
| Enable Interrupts | Receive |
| Interrupt Priority | Default |
点击查看截图 — UART 中断配置

保存 .syscfg 并编译。
SysConfig 生成的宏和常量
UART_0_INST— UART 外设实例UART_0_INT_IRQN— UART 中断号UART_0_INST_IRQHandler— 中断服务函数名(如UART0_IRQHandler)
5.4 UART 相关函数
常用 UART DriverLib 函数
发送单字节:
void DL_UART_Main_transmitData(UART_Regs *uart, uint8_t data);向 UART 发送缓冲区写入一个字节。调用前需确认发送缓冲区为空。
接收单字节:
uint8_t DL_UART_Main_receiveData(UART_Regs *uart);从 UART 接收缓冲区读取一个字节。通常在 RX 中断中调用。
查询发送缓冲区状态:
bool DL_UART_Main_isBusy(UART_Regs *uart);返回 true 表示 UART 正在发送数据,false 表示发送完成。
5.5 实验一:向电脑发送数据
5.5.1 发送单字节
#include "ti_msp_dl_config.h"
// 发送单个字节(阻塞等待发送完成)
void uart_send_byte(uint8_t data)
{
// 等待发送缓冲区空闲
while (DL_UART_Main_isBusy(UART_0_INST));
DL_UART_Main_transmitData(UART_0_INST, data);
}
int main(void)
{
SYSCFG_DL_init();
while (1) {
uart_send_byte('A'); // 发送字符 'A'
delay_cycles(32000000); // 间隔 1 秒
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

5.5.2 发送字符串
#include "ti_msp_dl_config.h"
#include <string.h>
void uart_send_byte(uint8_t data)
{
while (DL_UART_Main_isBusy(UART_0_INST));
DL_UART_Main_transmitData(UART_0_INST, data);
}
// 发送字符串
void uart_send_string(const char *str)
{
while (*str) {
uart_send_byte(*str++);
}
}
int main(void)
{
SYSCFG_DL_init();
while (1) {
uart_send_string("Hello Tianqiaoxing!\r\n");
delay_cycles(32000000); // 间隔 1 秒
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

5.5.3 电脑端接收
- 将天巧星通过 USB-C 数据线连接电脑
- 打开串口调试工具(如 SSCOM、PuTTY、Arduino Serial Monitor 等)
- 选择对应 COM 口(设备管理器中查看 CH340 对应的端口号)
- 设置参数:9600 波特率、8 数据位、无校验、1 停止位
- 打开串口,即可看到接收到 "Hello Tianqiaoxing!" 字符串
串口乱码排查
如果收到乱码,按以下顺序检查:
- 波特率是否一致 — 开发板和电脑端必须设置相同的波特率(9600)
- 时钟配置是否正确 — 波特率的精度依赖系统时钟。默认 32MHz SYSOSC 在常温下精度足够
- COM 口是否选对 — 拔插 USB 线观察哪个 COM 口出现/消失
- 数据位/校验/停止位是否匹配 — 双方必须完全一致
5.6 实验二:接收数据(中断方式)
5.6.1 接收回显
实现功能:电脑发送任意字符,天巧星收到后原样发回(回显)。
#include "ti_msp_dl_config.h"
void uart_send_byte(uint8_t data)
{
while (DL_UART_Main_isBusy(UART_0_INST));
DL_UART_Main_transmitData(UART_0_INST, data);
}
int main(void)
{
SYSCFG_DL_init();
// 使能 UART0 中断
NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
while (1) {
__WFI();
}
}
// UART0 中断服务函数
void UART0_IRQHandler(void)
{
uint8_t data;
switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) {
case DL_UART_MAIN_IIDX_RX:
// 接收到数据,读取并回发
data = DL_UART_Main_receiveData(UART_0_INST);
uart_send_byte(data);
break;
default:
break;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

5.6.2 接收控制 LED
实现功能:电脑发送 '1' 点亮 LED,发送 '0' 熄灭 LED。
#include "ti_msp_dl_config.h"
void uart_send_byte(uint8_t data)
{
while (DL_UART_Main_isBusy(UART_0_INST));
DL_UART_Main_transmitData(UART_0_INST, data);
}
void uart_send_string(const char *str)
{
while (*str) {
uart_send_byte(*str++);
}
}
int main(void)
{
SYSCFG_DL_init();
NVIC_EnableIRQ(UART_0_INT_IRQN);
uart_send_string("Tianqiaoxing UART Ready\r\n");
while (1) {
__WFI();
}
}
void UART0_IRQHandler(void)
{
switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) {
case DL_UART_MAIN_IIDX_RX: {
uint8_t data = DL_UART_Main_receiveData(UART_0_INST);
switch (data) {
case '1':
DL_GPIO_clearPins(LED_PORT, LED_B22_PIN); // LED亮
uart_send_string("LED ON\r\n");
break;
case '0':
DL_GPIO_setPins(LED_PORT, LED_B22_PIN); // LED灭
uart_send_string("LED OFF\r\n");
break;
default:
uart_send_string("Unknown command\r\n");
break;
}
break;
}
default:
break;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

实验操作
- SysConfig 中同时配置 GPIO(LED PB22 输出)和 UART0
- 编译下载运行
- 打开串口工具,连接后应看到 "Tianqiaoxing UART Ready"
- 发送字符 '1',LED 亮,串口回显 "LED ON"
- 发送字符 '0',LED 灭,串口回显 "LED OFF"
5.7 printf 重定向(可选)
在调试阶段,使用 printf 输出格式化信息非常方便。可以通过重定向 printf 到 UART 实现:
#include "ti_msp_dl_config.h"
#include <stdio.h>
void uart_send_byte(uint8_t data)
{
while (DL_UART_Main_isBusy(UART_0_INST));
DL_UART_Main_transmitData(UART_0_INST, data);
}
// 重定向 fputc(CCS TI ARM Compiler)
int fputc(int ch, FILE *stream)
{
while( DL_UART_isBusy(UART_0_INST) == true );
DL_UART_Main_transmitData(UART_0_INST, ch);
return ch;
}
//重定向fputs函数
int fputs(const char* restrict s, FILE* restrict stream) {
uint16_t char_len=0;
while(*s!=0)
{
while( DL_UART_isBusy(UART_0_INST) == true );
DL_UART_Main_transmitData(UART_0_INST, *s++);
char_len++;
}
return char_len;
}
int puts(const char* _ptr)
{
return 0;
}
int main(void)
{
SYSCFG_DL_init();
int count = 0;
while (1) {
printf("Count: %d\r\n", count++);
delay_cycles(32000000);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

注意
printf会增加代码体积(引入格式化库),对 Flash 空间有限的场景需注意printf为阻塞调用,频繁调用会影响实时性- 生产代码中建议使用自定义的轻量级打印函数
5.8 知识总结
| 内容 | 说明 |
|---|---|
| 通信方式 | 异步、全双工、点对点 |
| 最少接线 | TX、RX、GND 三根 |
| 关键参数 | 波特率、数据位、校验位、停止位 |
| 天巧星 UART0 | PA10(TX) / PA11(RX) → CH340 → USB-C |
| 收发方式 | 发送用轮询,接收用中断(推荐) |
| 乱码原因 | 99% 是波特率不匹配 |
串口通信是嵌入式开发中最重要的调试手段之一。后续章节中,我们会频繁使用串口输出调试信息。下一章将学习定时器,实现精确的周期定时功能。