嵌入式硬件——基于IMX6ULL的UART(通用异步收发传输器)

UART(通用异步收发传输器)功能实现与配置

UART(Universal Asynchronous Receiver/Transmitter)是嵌入式系统中常用的串行通信外设,用于实现设备间的异步数据传输(如开发板与电脑的串口调试)。本文详细讲解了 UART1 的硬件配置、寄存器初始化、收发功能实现及使用方法。

一、UART 概述与硬件基础

I.MX6ULL UART 核心特性

兼容 TIA/EIA-232F 标准,最高传输速率可达 5Mbit/s;

支持 8/9 位数据位、1/2 位停止位、奇 / 偶 / 无校验;

支持自动波特率检测(本次实验禁用,使用固定 115200 波特率);

时钟源默认采用pll3_80m(80MHz),可通过分频适配不同波特率;

本次实验使用UART1,通过 USB-TTL 模块与电脑串口调试助手通信。

硬件引脚配置

I.MX6ULL 的 UART1 需通过引脚复用实现功能,开发板上 UART1 的 TX/RX 引脚与 GPIO 复用,具体配置如下:

功能 引脚名称 复用配置 电气属性配置值
UART1_TX UART1_TX_DATA 复用为 UART1 发送引脚 0x10B0
UART1_RX UART1_RX_DATA 复用为 UART1 接收引脚 0x10B0

电气属性 0x10B0 含义(参考IOMUXC引脚配置规则):

  • bit16(HYS):0(关闭迟滞比较器);
  • bit15:14(PUS):01(47K 上拉电阻,防止引脚悬空);
  • bit12(PKE):1(使能上下拉功能);
  • bit7:6(SPEED):10(中速 100MHz);
  • bit5:3(DSE):110(驱动能力 R0/6);
  • bit0(SRE):0(低压摆率,降低 EMC 干扰)。

二、UART 初始化实现(寄存器配置)

UART 的初始化核心是引脚复用配置与寄存器参数设置,需按步骤完成时钟、数据格式、波特率等配置。以下基于uart.c的init_uart1函数展开讲解。

引脚复用与电气属性配置

通过 NXP SDK 提供的IOMUXC_SetPinMux和IOMUXC_SetPinConfig函数,将指定引脚复用为 UART1 功能,并配置电气特性:

c 复制代码
#include "uart.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"

void init_uart1(void)
{
    // 1. 引脚复用配置:将引脚复用为UART1_TX/RX
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);  // TX引脚复用
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);  // RX引脚复用
    
    // 2. 引脚电气属性配置:上拉、速度、驱动能力等
    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0);
UART 核心寄存器初始化

I.MX6ULL 的 UART 通过多个控制寄存器配置工作模式,需按顺序初始化(关键寄存器及作用如下)。

关闭 UART 并清零配置

先清零UCR1(控制寄存器 1)和UCR2(控制寄存器 2),确保初始状态无残留配置:

c 复制代码
    UART1->UCR1 = 0;  // 关闭UART,清零所有控制位
    UART1->UCR2 = 0;  // 清零接收/发送控制配置
配置 UCR2(数据格式与收发使能)

UCR2是 UART 配置的核心,用于设置数据位、停止位、收发使能等关键参数:

c 复制代码
    // UCR2配置:IRTS(忽略RTS) + WS(8位数据) + TXEN(发送使能) + RXEN(接收使能)
    UART1->UCR2 |= (1 << 14) | (1 << 5) | (1 << 2) | (1 << 1);
    // 说明:
    // bit14(IRTS):1=忽略RTS引脚(无需硬件流控)
    // bit5(WS):1=8位数据位(默认无校验)
    // bit2(TXEN):1=使能发送功能
    // bit1(RXEN):1=使能接收功能
配置 UCR3(接收路径选择)

UCR3的RXDMUXSEL位(bit2)是 I.MX6ULL 手册强制要求配置的位,必须设为 1 以选择正确的接收路径:

c 复制代码
    UART1->UCR3 |= (1 << 2);  // RXDMUXSEL=1,选择正确的接收数据路径
配置 UFCR(时钟分频)

UFCR(波特率预分频寄存器)用于设置 UART 时钟的预分频系数,确保波特率计算基于正确的时钟频率:

c 复制代码
    UART1->UFCR |= (5 << 7);  // 预分频系数=5(对应1分频,时钟源为80MHz)
    // 说明:I.MX6ULL UART时钟源默认是pll3_80m(80MHz),此处配置为1分频,实际时钟=80MHz
配置 UBIR 与 UBMR(波特率设置)

波特率由UBIR(波特率整数寄存器)和UBMR(波特率分子寄存器)共同决定,计算公式如下(手册 P3592):

BaudRate= 16× (UBIR+1)/(UBMR+1) × Ref Freq

参数说明:Ref Freq=80MHz(UART 时钟),目标波特率 = 115200;

计算结果:代入公式得 (UBIR+1)/(UBMR+1) ≈43.402,取UBIR=999、UBMR=43402(验证:80MHz/(16∗(43402+1)/(999+1))≈115200)。

代码配置如下:

c 复制代码
    UART1->UBIR = 999;     // 波特率整数部分
    UART1->UBMR = 43402;   // 波特率分子部分
使能 UART

最后通过UCR1的UARTEN位(bit0)使能 UART1:

c 复制代码
    UART1->UCR1 |= (1 << 0);  // 使能UART1
}

三、UART 收发功能实现

基于 UART 状态寄存器(USR2)的状态位判断,实现单字符发送、字符串发送、单字符接收功能,确保数据传输的完整性。

单字符发送(putc)

发送单个字符时,需等待发送缓冲(TxFIFO)和移位寄存器为空(USR2->TXDC位为 1),避免数据覆盖:

c 复制代码
void putc(unsigned char ch)
{
    // 等待发送完成(TXDC=1:发送缓冲和移位寄存器为空)
    while((UART1->USR2 & (1 << 3)) == 0);  
    UART1->UTXD = ch;  // 将字符写入发送数据寄存器(UTXD)
}
字符串发送(puts)

通过循环调用putc实现字符串发送,直到遇到字符串结束符'\0':

c 复制代码
void puts(const char *p)
{
    while(*p)  // 遍历字符串,直到'\0'
    {
        putc(*p++);  // 逐个发送字符
    }
    // 可选:添加换行符(适配串口助手换行显示)
    // putc('\r');
    // putc('\n');
}
单字符接收(getc)

接收单个字符时,需等待接收缓冲有数据(USR2->RDR位为 1),避免读取无效数据:

c 复制代码
unsigned char getc(void)
{
    // 等待接收完成(RDR=1:接收缓冲至少有1个字节数据)
    while((UART1->USR2 & (1 << 0)) == 0);  
    return UART1->URXD & 0xFF;  // 读取接收数据寄存器(URXD),保留低8位
}
适配标准库的raise函数

移植printf等标准库函数时需提供raise函数(空实现即可,用于异常处理):

c 复制代码
void raise(void)
{
    // 空实现,适配标准库编译
}

完整的UART.C函数

cs 复制代码
#include "uart.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"


void init_uart1(void)
{
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);

    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0);

    UART1->UCR1 = 0;
    UART1->UCR2 = 0;
    UART1->UCR2 |= (1 << 14) | (1 << 5) | (1 << 2) | (1 << 1);
    UART1->UCR3 |= (1 << 2);
    UART1->UFCR |= (5 << 7);
    UART1->UBIR = 999;     // 必须在前面
    UART1->UBMR = 43402;
    UART1->UCR1 |= (1 << 0);


}

void putc(unsigned char ch)
{
    while((UART1->USR2 & (1 << 3)) == 0);
    UART1->UTXD = ch;

}

void puts(const char *p)
{
    while(*p)
    {
        putc(*p++);
    }
}

unsigned char getc(void)
{
    while((UART1->USR2 & (1 << 0)) == 0);
    return UART1->URXD & 0xFF;  // 把后八位保留,前面的清除
}

void raise(void)
{
    
}

四、UART 使用示例

在主函数中初始化 UART1 后,即可调用收发函数实现串口通信(如与电脑串口调试助手交互)。

示例代码(main.c 片段)
c 复制代码
#include "uart.h"
#include "delay.h"

int main(void)
{
    unsigned char recv_data;  // 接收缓存
    
    // 1. 初始化系统时钟(UART时钟依赖系统时钟)
    init_clock();
    // 2. 初始化UART1(115200, 8N1:8位数据、无校验、1位停止位)
    init_uart1();
    
    // 3. 发送欢迎信息
    puts("UART1 Test: 115200 8N1");
    puts("Please enter a character: ");
    
    while(1)
    {
        // 4. 接收电脑发送的字符
        recv_data = getc();
        // 5. 回显接收的字符(将接收的字符再发送回电脑)
        puts("You entered: ");
        putc(recv_data);
        putc('\r');  // 换行
        putc('\n');
    }
    return 0;
}
串口调试助手配置
  • 波特率:115200;
  • 数据位:8;
  • 停止位:1;
  • 校验位:无;
  • 流控:无。

五、关键注意事项

  • 引脚复用正确性:需确保 UART1 的 TX/RX 引脚复用配置正确(IOMUXC_UART1_TX_DATA_UART1_TX和IOMUXC_UART1_RX_DATA_UART1_RX),错误复用会导致通信失败;
  • 波特率匹配:开发板 UART 波特率(115200)需与电脑串口调试助手配置完全一致,否则会出现乱码;
  • 状态位检查:收发数据前必须检查USR2的TXDC(发送完成)和RDR(接收就绪)位,避免数据丢失或覆盖;
  • 时钟依赖:UART 时钟源(pll3_80m)需通过init_clock正确初始化,否则波特率计算会偏差,导致通信异常。

UART 功能扩展(可选)

  • 中断收发:当前为查询模式,可通过 UART 中断(如接收中断、发送中断)实现无阻塞通信,减少 CPU 占用;
  • 多字节接收:扩展gets函数,实现字符串接收(需处理换行符或终止符);
  • 波特率切换:通过动态修改UBIR和UBMR,支持不同波特率的切换(需重新计算寄存器值)。

通过以上配置,I.MX6ULL 的 UART1 可稳定实现与电脑的串口通信,为嵌入式程序调试(如打印变量、日志)提供核心支持。

相关推荐
A9better2 小时前
嵌入式开发学习日志32——stm32之PWM
stm32·单片机·嵌入式硬件·学习
眰恦ゞLYF6 小时前
嵌入式硬件——基于IMX6ULL的GPT(通用定时器)实现
单片机·嵌入式硬件·gpt·imx6ull
充哥单片机设计9 小时前
【STM32项目开源】基于STM32的智能老人拐杖
stm32·单片机·嵌入式硬件
10001hours9 小时前
(基于江协科技)51单片机入门:6.串口
科技·嵌入式硬件·51单片机
眰恦ゞLYF9 小时前
嵌入式硬件——基于IMX6ULL的I2C实现
嵌入式硬件·i2c
常州晟凯电子科技1 天前
君正T32开发笔记之固件烧写
人工智能·笔记·嵌入式硬件·物联网
李永奉1 天前
51单片机-驱动LCD1602液晶显示屏教程
单片机·嵌入式硬件·51单片机
straw_hat.1 天前
PCB学习——STM32F103VET6-STM32接口部分
stm32·嵌入式硬件·学习