UART(SCI)串口配置与使用

目录

  1. SCI基础
  2. 与STM32对比
  3. SCI寄存器
  4. 手动配置SCI
  5. SysConfig配置SCI
  6. 实战示例

SCI基础

F280049C的串口模块称为SCI (Serial Communications Interface):

  • SCI数量: 2个独立的SCI模块(SCIA, SCIB)
  • 通信模式: 全双工异步通信
  • 数据位: 1-8位可配置
  • 停止位: 1或2位
  • 校验位: 无校验、奇校验、偶校验
  • 波特率: 可编程,最高可达LSPCLK/8

SCI特性

  • 独立的发送和接收FIFO(16级深度)
  • 支持中断和DMA传输
  • 硬件流控(RTS/CTS)可选
  • 自动波特率检测
  • 多处理器通信模式

SCI引脚

每个SCI模块有2个引脚:

  • SCITXD: 发送数据
  • SCIRXD: 接收数据

与STM32对比

术语对比

STM32 F280049C 说明
USART SCI 串口模块名称
USART1 SCIA 串口1
USART2 SCIB 串口2
TX SCITXD 发送引脚
RX SCIRXD 接收引脚

配置流程对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// STM32 HAL库
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(&huart1);

// F280049C DriverLib
SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);

SCI寄存器

主要寄存器

1. SCIxCCR - 通信控制寄存器

1
2
3
4
SciaRegs.SCICCR.bit.SCICHAR = 7;    // 8位数据(0-7表示1-8位)
SciaRegs.SCICCR.bit.STOPBITS = 0; // 1个停止位
SciaRegs.SCICCR.bit.PARITYENA = 0; // 禁用校验
SciaRegs.SCICCR.bit.LOOPBKENA = 0; // 禁用回环模式

2. SCIxCTL1 - 控制寄存器1

1
2
3
SciaRegs.SCICTL1.bit.RXENA = 1;     // 使能接收
SciaRegs.SCICTL1.bit.TXENA = 1; // 使能发送
SciaRegs.SCICTL1.bit.SWRESET = 1; // 退出复位状态

3. SCIxCTL2 - 控制寄存器2

1
2
SciaRegs.SCICTL2.bit.RXBKINTENA = 1;  // 使能接收中断
SciaRegs.SCICTL2.bit.TXINTENA = 1; // 使能发送中断

4. SCIxHBAUD/SCIxLBAUD - 波特率寄存器

1
2
3
4
5
// 波特率计算公式
// BRR = (LSPCLK / (波特率 × 8)) - 1
uint16_t brr = (DEVICE_LSPCLK_FREQ / (115200 * 8)) - 1;
SciaRegs.SCIHBAUD.all = (brr >> 8) & 0xFF;
SciaRegs.SCILBAUD.all = brr & 0xFF;

5. SCIxRXBUF/SCIxTXBUF - 数据缓冲区

1
2
3
4
5
// 发送数据
SciaRegs.SCITXBUF.all = 'A';

// 接收数据
uint16_t data = SciaRegs.SCIRXBUF.all;

6. SCIxFIFOTX/SCIxFIFORX - FIFO控制

1
2
3
SciaRegs.SCIFFTX.bit.SCIFFENA = 1;    // 使能FIFO
SciaRegs.SCIFFTX.bit.TXFIFOXRESET = 1; // FIFO复位
SciaRegs.SCIFFRX.bit.RXFIFORESET = 1; // 接收FIFO复位

手动配置SCI

方法1: 直接寄存器操作

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
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
53
#include "F28x_Project.h"

void SCIA_Init_Register(void)
{
EALLOW;

// 1. 配置GPIO引脚复用
GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 1; // SCITXDA
GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 1; // SCIRXDA
GpioCtrlRegs.GPAPUD.bit.GPIO28 = 0; // 使能上拉
GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;
GpioCtrlRegs.GPAQSEL2.bit.GPIO29 = 3; // 异步输入

// 2. 进入复位状态
SciaRegs.SCICTL1.bit.SWRESET = 0;

// 3. 配置通信格式(8位数据,1个停止位,无校验)
SciaRegs.SCICCR.bit.SCICHAR = 7; // 8位数据
SciaRegs.SCICCR.bit.STOPBITS = 0; // 1个停止位
SciaRegs.SCICCR.bit.PARITYENA = 0; // 禁用校验
SciaRegs.SCICCR.bit.LOOPBKENA = 0; // 禁用回环

// 4. 配置波特率(115200)
// LSPCLK = 50MHz, BRR = (50MHz / (115200 × 8)) - 1 = 53
SciaRegs.SCIHBAUD.all = 0x00;
SciaRegs.SCILBAUD.all = 53;

// 5. 使能FIFO
SciaRegs.SCIFFTX.bit.SCIFFENA = 1;
SciaRegs.SCIFFTX.bit.TXFIFOXRESET = 1;
SciaRegs.SCIFFRX.bit.RXFIFORESET = 1;

// 6. 使能发送和接收
SciaRegs.SCICTL1.bit.RXENA = 1;
SciaRegs.SCICTL1.bit.TXENA = 1;

// 7. 退出复位状态
SciaRegs.SCICTL1.bit.SWRESET = 1;

EDIS;
}

void SCIA_SendChar(char data)
{
while(SciaRegs.SCIFFTX.bit.TXFFST != 0); // 等待FIFO空
SciaRegs.SCITXBUF.all = data;
}

char SCIA_ReceiveChar(void)
{
while(SciaRegs.SCIFFRX.bit.RXFFST == 0); // 等待数据
return SciaRegs.SCIRXBUF.all;
}

方法2: DriverLib库函数

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "driverlib.h"
#include "device.h"

void SCIA_Init_DriverLib(void)
{
// 1. 配置GPIO引脚
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setQualificationMode(28, GPIO_QUAL_ASYNC);

GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode(29, GPIO_QUAL_ASYNC);

// 2. 配置SCI(115200, 8N1)
SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

// 3. 使能FIFO
SCI_enableFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);

// 4. 使能模块
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);
}

void SCIA_SendChar_DriverLib(char data)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, data);
}

char SCIA_ReceiveChar_DriverLib(void)
{
return SCI_readCharBlockingFIFO(SCIA_BASE);
}

void SCIA_SendString(const char *str)
{
while(*str)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, *str++);
}
}

波特率计算

公式

1
BRR = (LSPCLK / (波特率 × 8)) - 1

常用波特率配置(LSPCLK = 50MHz)

1
2
3
4
5
6
7
8
// 9600
BRR = (50000000 / (9600 × 8)) - 1 = 650

// 115200
BRR = (50000000 / (115200 × 8)) - 1 = 53

// 921600
BRR = (50000000 / (921600 × 8)) - 1 = 6

SysConfig配置SCI

步骤1: 添加SCI模块

  1. 在SysConfig中找到 SCI
  2. 点击 “+” 添加SCI实例
  3. 选择 SCIASCIB

步骤2: 配置参数

1
2
3
4
5
6
7
8
9
SCI Instance: SCIA
├── Baud Rate: 115200
├── Data Bits: 8
├── Stop Bits: 1
├── Parity: None
├── Enable FIFO: ✓
├── Enable TX: ✓
├── Enable RX: ✓
└── Enable Interrupts: ✓ (可选)

步骤3: 配置引脚

在Pin Mux视图中:

1
2
SCIA_TX → GPIO28
SCIA_RX → GPIO29

步骤4: 使用生成的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "board.h"

void main(void)
{
Device_init();
Device_initGPIO();

// 调用SysConfig生成的初始化
Board_init();

// 发送字符串
const char *msg = "Hello from F280049C!\r\n";
while(*msg)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, *msg++);
}

while(1)
{
// 回显接收到的字符
char c = SCI_readCharBlockingFIFO(SCIA_BASE);
SCI_writeCharBlockingFIFO(SCIA_BASE, c);
}
}

实战示例

示例1: 串口发送字符串

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "driverlib.h"
#include "device.h"

void SCIA_Init(void)
{
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);

SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

SCI_enableFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);
}

void SCIA_SendString(const char *str)
{
while(*str)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, *str++);
}
}

void main(void)
{
Device_init();
Device_initGPIO();

SCIA_Init();

SCIA_SendString("F280049C UART Test\r\n");
SCIA_SendString("Hello World!\r\n");

while(1);
}

示例2: 串口回显

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
27
28
29
30
31
32
33
34
35
36
37
38
#include "driverlib.h"
#include "device.h"

void SCIA_Init(void)
{
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);

SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

SCI_enableFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);
}

void main(void)
{
Device_init();
Device_initGPIO();

SCIA_Init();

while(1)
{
// 接收字符
char c = SCI_readCharBlockingFIFO(SCIA_BASE);

// 回显字符
SCI_writeCharBlockingFIFO(SCIA_BASE, c);
}
}

示例3: 串口中断接收

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
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "driverlib.h"
#include "device.h"

#define RX_BUFFER_SIZE 128
char rxBuffer[RX_BUFFER_SIZE];
volatile uint16_t rxIndex = 0;

// 接收中断服务函数
__interrupt void sciaRxISR(void)
{
// 读取所有FIFO中的数据
while(SCI_getRxFIFOStatus(SCIA_BASE) != SCI_FIFO_RX0)
{
char c = SCI_readCharNonBlocking(SCIA_BASE);

if(rxIndex < RX_BUFFER_SIZE - 1)
{
rxBuffer[rxIndex++] = c;

// 检测到换行符,处理数据
if(c == '\n')
{
rxBuffer[rxIndex] = '\0';
// 处理接收到的数据
rxIndex = 0;
}
}
}

// 清除中断标志
SCI_clearInterruptStatus(SCIA_BASE, SCI_INT_RXFF);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
}

void SCIA_Init_Interrupt(void)
{
// 配置GPIO
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);

// 配置SCI
SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

// 配置FIFO
SCI_enableFIFO(SCIA_BASE);
SCI_setFIFOInterruptLevel(SCIA_BASE, SCI_FIFO_TX0, SCI_FIFO_RX1);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);

// 使能接收中断
SCI_enableInterrupt(SCIA_BASE, SCI_INT_RXFF);

// 使能模块
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);

// 配置中断
Interrupt_register(INT_SCIA_RX, &sciaRxISR);
Interrupt_enable(INT_SCIA_RX);
}

void main(void)
{
Device_init();
Device_initGPIO();

Interrupt_initModule();
Interrupt_initVectorTable();

SCIA_Init_Interrupt();

EINT;
ERTM;

while(1)
{
// 主循环
}
}

示例4: printf重定向

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
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
53
54
55
#include "driverlib.h"
#include "device.h"
#include <stdio.h>

void SCIA_Init(void)
{
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);

SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

SCI_enableFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);
}

// 重定向putchar函数
int fputc(int ch, FILE *f)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, ch);
return ch;
}

// 重定向getchar函数
int fgetc(FILE *f)
{
return SCI_readCharBlockingFIFO(SCIA_BASE);
}

void main(void)
{
Device_init();
Device_initGPIO();

SCIA_Init();

// 现在可以使用printf
printf("F280049C printf test\r\n");
printf("Counter: %d\r\n", 123);
printf("Float: %.2f\r\n", 3.14159);

uint32_t counter = 0;
while(1)
{
printf("Count: %lu\r\n", counter++);
DEVICE_DELAY_US(1000000); // 1秒延时
}
}

示例5: 命令行解析

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
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "driverlib.h"
#include "device.h"
#include <string.h>

#define CMD_BUFFER_SIZE 64
char cmdBuffer[CMD_BUFFER_SIZE];
uint16_t cmdIndex = 0;

void SCIA_Init(void)
{
GPIO_setPinConfig(GPIO_28_SCIA_TX);
GPIO_setPinConfig(GPIO_29_SCIA_RX);
GPIO_setPadConfig(28, GPIO_PIN_TYPE_STD);
GPIO_setPadConfig(29, GPIO_PIN_TYPE_PULLUP);

SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
(SCI_CONFIG_WLEN_8 |
SCI_CONFIG_STOP_ONE |
SCI_CONFIG_PAR_NONE));

SCI_enableFIFO(SCIA_BASE);
SCI_resetTxFIFO(SCIA_BASE);
SCI_resetRxFIFO(SCIA_BASE);
SCI_enableModule(SCIA_BASE);
SCI_resetChannels(SCIA_BASE);
}

void SCIA_SendString(const char *str)
{
while(*str)
{
SCI_writeCharBlockingFIFO(SCIA_BASE, *str++);
}
}

void ProcessCommand(char *cmd)
{
if(strcmp(cmd, "help") == 0)
{
SCIA_SendString("Available commands:\r\n");
SCIA_SendString(" help - Show this help\r\n");
SCIA_SendString(" led on - Turn on LED\r\n");
SCIA_SendString(" led off - Turn off LED\r\n");
SCIA_SendString(" status - Show system status\r\n");
}
else if(strcmp(cmd, "led on") == 0)
{
GPIO_writePin(31, 1);
SCIA_SendString("LED ON\r\n");
}
else if(strcmp(cmd, "led off") == 0)
{
GPIO_writePin(31, 0);
SCIA_SendString("LED OFF\r\n");
}
else if(strcmp(cmd, "status") == 0)
{
SCIA_SendString("System OK\r\n");
}
else
{
SCIA_SendString("Unknown command. Type 'help' for help.\r\n");
}
}

void main(void)
{
Device_init();
Device_initGPIO();

// 配置LED
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPinConfig(GPIO_31_GPIO31);

SCIA_Init();

SCIA_SendString("\r\nF280049C Command Line\r\n");
SCIA_SendString("Type 'help' for commands\r\n");
SCIA_SendString("> ");

while(1)
{
char c = SCI_readCharBlockingFIFO(SCIA_BASE);

// 回显字符
SCI_writeCharBlockingFIFO(SCIA_BASE, c);

if(c == '\r' || c == '\n')
{
SCIA_SendString("\r\n");

if(cmdIndex > 0)
{
cmdBuffer[cmdIndex] = '\0';
ProcessCommand(cmdBuffer);
cmdIndex = 0;
}

SCIA_SendString("> ");
}
else if(c == '\b' || c == 127) // 退格键
{
if(cmdIndex > 0)
{
cmdIndex--;
SCIA_SendString(" \b"); // 清除字符
}
}
else if(cmdIndex < CMD_BUFFER_SIZE - 1)
{
cmdBuffer[cmdIndex++] = c;
}
}
}

常见问题

1. 串口无输出?

  • 检查GPIO引脚配置是否正确
  • 检查波特率计算是否正确
  • 检查是否调用了 SCI_enableModule()SCI_resetChannels()
  • 使用示波器或逻辑分析仪检查TX引脚

2. 接收数据乱码?

  • 检查波特率是否匹配
  • 检查数据位、停止位、校验位配置
  • 检查LSPCLK频率是否正确

3. 如何选择SCI模块?

  • SCIA: GPIO28(TX), GPIO29(RX)
  • SCIB: GPIO18(TX), GPIO19(RX) 或其他复用引脚

4. FIFO的作用?

  • 减少中断频率
  • 提高数据吞吐量
  • 防止数据丢失

5. 如何实现高速通信?

  • 使用DMA传输
  • 提高LSPCLK频率
  • 优化中断处理时间

下一步

学习完UART后,继续学习:


参考资料

  • TMS320F28004x Technical Reference Manual - SCI Module
  • C2000Ware DriverLib API Guide - SCI Module
  • SCI Example Code in C2000Ware