串口通信是嵌入式开发中最常用的外设之一,无论是单片机开发还是嵌入式 Linux 开发,串口都扮演着重要角色。通过串口,我们可以将开发板与电脑连接,使用串口调试助手调试程序,或者与蓝牙、GPS、GPRS 等模块进行通信。在嵌入式 Linux 中,串口通常被用作控制台,因此掌握串口的使用是嵌入式开发的必备技能。
本文将详细介绍 i.MX6ULL 的串口通信机制,包括 UART 的基本原理、硬件配置、寄存器操作以及驱动开发。
1. UART 通信简介
1.1 什么是 UART?
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种异步串行通信协议。它通过两根信号线(TX 和 RX)实现全双工通信,适用于短距离、低速率的通信场景。
1.2 UART 通信格式
UART 通信的数据帧格式如下:
空闲位 | 起始位 | 数据位(5-8位) | 校验位(可选) | 停止位(1-2位) | 空闲位
1 | 0 | D0 D1 D2 D3 D4 D5 D6 D7 | P | 1 | 1
- 空闲位:数据线在空闲状态时为高电平(逻辑“1”)。
- 起始位:数据线从高电平变为低电平(逻辑“0”),表示数据传输开始。
- 数据位:实际传输的数据,通常为 8 位。
- 校验位:用于错误检测(奇校验或偶校验)。
- 停止位:数据线恢复为高电平(逻辑“1”),表示数据传输结束。
1.3 UART 电平标准
- TTL 电平:低电平表示逻辑“0”,高电平表示逻辑“1”。
- RS-232 电平:-3V 到 -15V 表示逻辑“1”,+3V 到 +15V 表示逻辑“0”。
2. i.MX6ULL 的 UART 硬件
i.MX6ULL 集成了 8 个 UART 控制器,每个 UART 控制器支持以下特性:
- 最高波特率:5 Mbps。
- 支持 9 位或多节点模式(RS-485)。
- 可编程的奇偶校验(奇校验或偶校验)。
- 自动波特率检测(最高支持 115.2 Kbps)。
2.1 UART 时钟源
UART 的时钟源由寄存器 CCM_CSCDR1
的 UART_CLK_SEL
位选择:
0
:选择pll3_80m
(80 MHz)。1
:选择osc_clk
(24 MHz)。
通常选择 pll3_80m
作为时钟源,并通过 UART_CLK_PODF
位设置分频值(1~64 分频)。
3. UART 寄存器配置
3.1 重要寄存器
以下是 UART 控制器的主要寄存器:
寄存器名称 | 功能描述 |
---|---|
UARTx_UCR1 | 控制寄存器 1,用于使能 UART 和自动波特率检测。 |
UARTx_UCR2 | 控制寄存器 2,用于配置数据位、停止位、校验位等。 |
UARTx_UCR3 | 控制寄存器 3,用于配置接收多路选择器。 |
UARTx_USR2 | 状态寄存器 2,用于检测发送和接收状态。 |
UARTx_UFCR | FIFO 控制寄存器,用于设置参考时钟分频。 |
UARTx_UBIR | 波特率整数寄存器,用于设置波特率。 |
UARTx_UBMR | 波特率小数寄存器,用于设置波特率。 |
UARTx_URXD | 接收数据寄存器,用于读取接收到的数据。 |
UARTx_UTXD | 发送数据寄存器,用于写入要发送的数据。 |
3.2 波特率计算
波特率的计算公式如下:
[
\text{Baud Rate} = \frac{\text{Ref Freq}}{16 \times (\text{UBMR} + 1) / (\text{UBIR} + 1)}
]
其中:
Ref Freq
:参考时钟频率(如 80 MHz)。UBMR
:波特率小数寄存器的值。UBIR
:波特率整数寄存器的值。
例如,设置波特率为 115200:
Ref Freq = 80 MHz
。UBIR = 71
。UBMR = 3124
。
4. UART 驱动开发
4.1 初始化 UART
以下是 UART 初始化的代码示例:
#include <stdint.h>
#define UART1_BASE_ADDR 0x02020000 // UART1 基地址
#define UART1_UCR1 (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x80))
#define UART1_UCR2 (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x84))
#define UART1_UFCR (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x90))
#define UART1_UBIR (*(volatile uint32_t *)(UART1_BASE_ADDR + 0xA4))
#define UART1_UBMR (*(volatile uint32_t *)(UART1_BASE_ADDR + 0xA8))
#define UART1_URXD (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x00))
#define UART1_UTXD (*(volatile uint32_t *)(UART1_BASE_ADDR + 0x40))
void uart_init(uint32_t baud_rate) {
// 设置波特率
uint32_t uart_clk = 80000000; // 80 MHz
uint32_t baud_div = uart_clk / baud_rate;
UART1_UBIR = (baud_div >> 4) & 0xFFFF;
UART1_UBMR = baud_div & 0xF;
// 配置数据格式:8 位数据,1 位停止位,无校验
UART1_UCR2 |= (1 << 5) | (1 << 2) | (1 << 1);
// 使能 UART
UART1_UCR1 |= (1 << 0);
}
4.2 发送数据
通过 UARTx_UTXD
寄存器发送数据:
void uart_send_char(char c) {
while (!(UART1_UCR2 & (1 << 3))); // 等待发送缓冲区为空
UART1_UTXD = c;
}
void uart_send_string(const char *str) {
while (*str) {
uart_send_char(*str++);
}
}
4.3 接收数据
通过 UARTx_URXD
寄存器接收数据:
char uart_receive_char() {
while (!(UART1_UCR2 & (1 << 0))); // 等待接收数据
return UART1_URXD & 0xFF;
}
void uart_receive_string(char *buffer, uint32_t length) {
for (uint32_t i = 0; i < length; i++) {
buffer[i] = uart_receive_char();
if (buffer[i] == '\n' || buffer[i] == '\r') {
buffer[i] = '\0';
break;
}
}
}
5. 总结
通过本文,我们详细介绍了 i.MX6ULL 的串口通信机制,包括 UART 的基本原理、硬件配置、寄存器操作以及驱动开发。以下是关键点总结:
- UART 通信格式:包括空闲位、起始位、数据位、校验位和停止位。
- UART 寄存器:通过配置寄存器实现波特率设置、数据格式配置和数据收发。
- 驱动开发:通过初始化、发送和接收函数实现串口通信。