嵌入式开发代码实践——串口通信(UART)开发

串口通信(UART)开发详解

一、UART通信基础概念

1.1 什么是UART?

UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种异步串行通信接口。它是嵌入式系统中最常用的通信方式之一。

1.2 UART通信特点

  • 异步通信:无需时钟信号,靠起始位、停止位同步

  • 全双工:可同时发送和接收数据

  • 点对点通信:通常用于两个设备之间的通信

  • 传输距离:TTL电平约1米,RS-232可达15米

1.3 UART数据帧格式

┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ │空闲│起始│数据位0│数据位1│...│数据位7│校验位│停止位│空闲│ ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤ │高 │低 │数据内容 │可选 │高 │高 │ └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
  • 起始位:1位低电平

  • 数据位:通常8位(也可5、6、7位)

  • 校验位:可选(奇校验、偶校验)

  • 停止位:1或2位高电平

二、硬件原理分析

2.1 i.MX6ULL UART硬件框图

┌─────────────────────┐ ┌─────────────────────┐ │ i.MX6ULL │ │ PC主机 │ │ │ │ │ │ UART1控制器 │◄────►│ USB转串口 │ │ - 发送寄存器 │ │ (CH340) │ │ - 接收寄存器 │ │ │ │ - 控制寄存器 │ └─────────────────────┘ └─────────┬───────────┘ │ ▼ ┌─────────────────────┐ │ 硬件引脚 │ │ TXD (发送) │───┐ │ RXD (接收) │◄──┘ └─────────────────────┘

2.2 引脚定义(参考原理图)

  • UART1_TX:发送数据引脚,数据从芯片发送出去

  • UART1_RX:接收数据引脚,数据从外部接收进来

  • 波特率:115200 bps(每秒传输115200位)

三、代码详细解析

3.1 头文件定义(uart.h)

#ifndef _UART_H_ #define _UART_H_ // 声明UART相关函数 extern void uart1_init(void); // UART1初始化 extern void putc(unsigned char d); // 发送一个字符 extern void puts(const char *s); // 发送字符串 extern unsigned char getc(void); // 接收一个字符 #endif // !_UART_H_

3.2 UART初始化函数(uart.c)

3.2.1 引脚配置
void uart1_init(void) { // 1. 复用功能配置 - 将引脚配置为UART功能 IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0); // RX引脚复用为UART IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0); // TX引脚复用为UART // 2. 电气特性配置 - 设置引脚的电气参数 IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0); // RX引脚电气特性 IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0); // TX引脚电气特性

详细解释:

  • IOMUXC_SetPinMux():选择引脚功能

    • 第一个参数:引脚名称(如IOMUXC_UART1_RX_DATA_UART1_RX

    • 第二个参数:复用选择器(0表示选择主要功能)

  • IOMUXC_SetPinConfig():配置引脚电气特性

    • 参数0x10B0含义:

      • 0x:十六进制前缀

      • 10B0:配置驱动强度、上下拉、速度等参数

3.2.2 复位UART控制器
// 3. 软件复位UART控制器 UART1->UCR2 &= ~(1 << 0); // 清除UART使能位,相当于复位

寄存器解释:

  • UART1->UCR2:UART控制寄存器2

  • 位0(UARTEN):UART使能位

    • 0:禁用UART(复位状态)

    • 1:使能UART

  • 先清除此位,再重新配置,确保从干净状态开始

3.2.3 配置UART参数
// 4. 配置UART控制寄存器2 unsigned int t; t = UART1->UCR2; // 读取当前值 t |= (1 << 14); // 设置IRTS位,忽略RTS流控 t &= ~(1 << 8); // 清除PREN位,禁用奇偶校验 t &= ~(1 << 6); // 清除STPB位,1个停止位 t |= (1 << 5); // 设置WS位,8位数据位 t |= (1 << 2); // 设置TXEN位,使能发送器 t |= (1 << 1); // 设置RXEN位,使能接收器 UART1->UCR2 = t; // 写回寄存器

UCR2寄存器位详解:

位 名称 功能 ────────────────────────── 0 UARTEN UART使能位 1 RXEN 接收器使能 2 TXEN 发送器使能 5 WS 字长选择(0=7位,1=8位) 6 STPB 停止位数量(0=1位,1=2位) 8 PREN 奇偶校验使能 14 IRTS 忽略RTS流控(必须设置为1)
3.2.4 配置其他UART寄存器
// 5. 配置UART控制寄存器3 UART1->UCR3 |= (1 << 2); // 设置RXDMUXSEL位(必须为1) // 6. 配置FIFO控制寄存器 UART1->UFCR &= ~(7 << 7); // 清除参考时钟分频位 UART1->UFCR |= (5 << 7); // 设置1分频(参考时钟分频器)

UCR3寄存器:

  • 位2(RXDMUXSEL):接收数据多路复用器选择

    • 必须设置为1,芯片工作在MUXED模式

UFCR寄存器:

  • 位7-9(RFDIV):参考时钟分频器

    • 101(十进制5)= 1分频

    • 公式:分频值 = 6 - RFDIV

3.2.5 配置波特率
// 7. 波特率配置(115200 bps) UART1->UBIR = 999; // 增量寄存器 UART1->UBMR = 43401; // 模数寄存器 // 8. 使能UART UART1->UCR1 |= (1 << 0); // 设置UARTEN位,使能UART }

波特率计算公式:

BaudRate = Ref_Freq / (16 × ((UBMR + 1) / (UBIR + 1)))

其中:

  • Ref_Freq= 80MHz(系统参考时钟)

  • UBIR= 999(增量寄存器值)

  • UBMR= 43401(模数寄存器值)

计算验证:

波特率 = 80,000,000 / (16 × ((43401 + 1) / (999 + 1))) = 80,000,000 / (16 × (43402 / 1000)) = 80,000,000 / (16 × 43.402) = 80,000,000 / 694.432 ≈ 115200 bps

3.3 字符发送函数

void putc(unsigned char d) { // 等待发送完成(检查TXDC标志位) while ((UART1->USR2 & (1 << 3)) == 0); // 写入要发送的数据到发送寄存器 UART1->UTXD = d; }

工作原理:

  1. UART1->USR2 & (1 << 3):检查状态寄存器2的TXDC位(位3)

    • 0:发送器忙,正在发送数据

    • 1:发送完成,可以发送新数据

  2. while循环:一直等待,直到发送完成标志为1

  3. UART1->UTXD = d:将数据写入发送寄存器,自动开始发送

状态寄存器2(USR2)位:

  • 位3(TXDC):发送完成标志

    • 0:发送器忙或禁用

    • 1:发送缓冲区和移位寄存器都为空

3.4 字符串发送函数

void puts(const char *s) { // 遍历字符串,逐个发送字符 while (*s) { putc(*s++); // 发送当前字符,指针后移 } putc('\n'); // 发送换行符,便于阅读 }

工作原理:

  1. while (*s):检查当前字符是否为字符串结束符'\0'

  2. putc(*s++):发送当前字符,然后指针s指向下一个字符

  3. 循环直到遇到字符串结束符

  4. putc('\n'):额外发送换行符

3.5 字符接收函数

unsigned char getc(void) { // 等待接收数据就绪(检查RDR标志位) while ((UART1->USR2 & (1 << 0)) == 0); // 读取接收寄存器中的数据 return (unsigned char)UART1->URXD; }

工作原理:

  1. UART1->USR2 & (1 << 0):检查状态寄存器2的RDR位(位0)

    • 0:没有接收到数据

    • 1:有数据可以读取

  2. while循环:一直等待,直到有数据可读

  3. (unsigned char)UART1->URXD:读取接收寄存器并转换为无符号字符

状态寄存器2(USR2)位:

  • 位0(RDR):接收数据就绪标志

    • 0:没有接收到新数据

    • 1:接收到新数据,可以读取

接收寄存器(URXD)注意:

  • URXD寄存器是只读的

  • 读取后,RDR标志会自动清除

四、主程序中的UART使用

4.1 主程序调用(main.c)

int main(void) { // 系统初始化 system_interrupt_init(); // 中断系统初始化 clock_init(); // 时钟初始化 led_init(); // LED初始化 beep_init(); // 蜂鸣器初始化 key_init(); // 按键初始化 gpt1_init(); // 定时器初始化 // UART初始化(重点) uart1_init(); // 初始化UART1,配置为115200波特率 unsigned char ch; // 用于存储接收到的字符 while(1) { // 延时1秒 delay_us(1000 * 1000); // 控制LED和蜂鸣器翻转 led_nor(); // LED状态翻转 beep_nor(); // 蜂鸣器状态翻转 // UART通信部分 ch = getc(); // 从串口接收一个字符(会等待直到有数据) putc(ch); // 将接收到的字符发送回去(回显功能) puts("\nhello world!"); // 发送字符串 } return 0; }

4.2 程序流程图

开始 ↓ 初始化系统(时钟、中断等) ↓ 初始化UART(配置引脚、波特率115200) ↓ ┌─────────────────────────────┐ │ 主循环 │ │ ↓ │ │ 延时1秒 │ │ ↓ │ │ LED和蜂鸣器翻转 │ │ ↓ │ │ 等待接收串口数据 │←──┐ │ ↓ │ │ │ 将接收的数据发送回去 │ │ │ ↓ │ │ │ 发送"hello world!"字符串 │ │ │ ↓ │ │ │ (循环继续) │ │ └──────────────┬──────────────┘ │ │ │ └──────────────────┘

五、常见问题与调试

5.1 常见问题

  1. 没有输出/全是乱码

    • 检查波特率是否匹配(PC端和开发板都设为115200)

    • 检查TX、RX线是否接反

    • 检查电源是否正常

  2. 只能发送不能接收

    • 检查RX引脚配置是否正确

    • 检查PC端串口工具是否已打开串口

    • 检查线路连接是否良好

  3. 发送数据不完整

    • 检查发送函数是否正确等待发送完成标志

    • 检查是否有其他中断影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1206958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高职学历销售如何破局

学历劣势的应对策略高职学历在销售行业并非绝对劣势&#xff0c;关键在于如何通过技能和数据分析能力提升竞争力。以下为具体策略&#xff1a;策略具体方法效果强化数据分析能力学习基础数据分析工具&#xff08;Excel、Python&#xff09;、考取CDA数据分析师证书提升客户画像…

中专学历如何通过数据分析转型科技公司

质检QC岗位与数据分析存在一定关联性&#xff0c;例如数据收集、流程优化、问题诊断等。通过系统学习数据分析技能&#xff0c;积累项目经验&#xff0c;可逐步实现向科技公司的转型。以下是具体路径和方法&#xff1a; 核心技能提升路径 阶段学习内容资源/工具目标基础阶段Ex…

神奇二维码WPO

拿到附件是一个二维码,扫码发现一个base64值进行base64解析![] 拷贝的被骗了 1.一般我们尝尝考察的就是二维码是不是有隐写,然后使用010 Editor这种分析工具去分析文件的结构构成 分析一下文件的大小,正常的二维码一…

吴恩达深度学习课程五:自然语言处理 第二周:词嵌入(五)GloVe 算法

此分类用于记录吴恩达深度学习课程的学习笔记。 课程相关信息链接如下:原课程视频链接:[双语字幕]吴恩达深度学习deeplearning.ai github课程资料,含课件与笔记:吴恩达深度学习教学资料 课程配套练习(中英)与答案…

半导体 IT 基础设施转型实践合集|以自建云平台支持研发与核心生产,实现 VMware 替代

在飞速发展的科技时代&#xff0c;半导体日益成为全球经济发展的关键驱动力。半导体设计、制造、封测与材料/设备等细分领域采用的 IT 系统有所区别&#xff0c;对 IT 基础架构的需求也不尽相同&#xff1a; 半导体设计领域需要可灵活扩容、支持容器环境的 IT 基础设施&#x…

怪奇物语第五季, 附 win11如何禁止系统自动更新教程步骤

怪奇物语第5季百度网盘4K 链接: https://pan.baidu.com/s/1R7I3VkG6RQRd6-Srq1em4Q?pwd38pg 提取码: 38pg win11如何禁止系统自动更新 关闭Windows系统的自动更新可以通过多种方法实现&#xff0c;以下将详细介绍六种不同的方法。请注意&#xff0c;关闭自动更新可能会使您的…

AI驱动验收测试:重塑软件交付流程的智能引擎

测试工程师的困境与AI破局 在敏捷开发成为主流的今天&#xff0c;测试团队面临两大核心矛盾&#xff1a; 需求爆炸&#xff1a;每周迭代数百需求&#xff0c;人工编写验收用例耗时占比超40% 场景黑洞&#xff1a;金融/医疗等领域复杂业务流&#xff0c;传统脚本覆盖不足30%关…

灵活的自定义 WebView 组件(新版本)

效果图: 1.1 什么是 MyWebViewNew MyWebViewNew 是一个功能强大的自定义 WebView 组件,专为 Android 平台设计。它继承自原生 WebView,同时采用组合模式,提供了高度的灵活性和可扩展性。 1.2 设计理念 继承与组合并存:继承 WebView 保持 API 兼容性,同时使用组合模式实…

‌实战分享:AI在Web应用测试中的高效方案‌

测试行业的智能化拐点 2025年全球测试自动化渗透率突破65%&#xff08;Gartner&#xff09;&#xff0c;但传统脚本维护成本仍占据测试总时长40%。本文基于金融、电商领域实战案例&#xff0c;解析如何通过AI技术实现测试效率的指数级提升。 一、AI重构测试核心环节 1.1 智能…

AI驱动、0代码,设计并构建属于你的多平台原生 APP?

想必做移动端的朋友们肯定或多或少听说过 Kotlin 和 Compose Multiplatform, 前者是 JetBrains 开源、Google 首推用于 Android 开发(自2019 年 Google I/O 大会起)的现代开发语言, 后者是使用 Compose API 开发多端(Android、iOS、桌面端、Web端等)应用的UI框架。 但是…

‌软件开发前沿:生成式AI的实战挑战——给软件测试从业者的深度实战指南

一、生成式AI正在重塑测试工作流&#xff1a;从“手工编写”到“智能协同”‌ 生成式AI已不再是测试领域的实验性工具&#xff0c;而是成为‌日常质量保障流水线的核心引擎‌。根据2025年行业调研&#xff0c;‌75%的软件企业已将生成式AI纳入测试流程‌&#xff0c;其渗透率远…

ARM Q 饱和运算快速入门指南

在 ARM 嵌入式开发(尤其是信号处理、音视频编解码、传感器数据处理)中,普通算术运算的 “数值回绕” 问题极易导致数据错误,而**Q 饱和运算**是解决该问题的核心方案。在 ARM 嵌入式开发(尤其是信号处理、音视频编…

‌测试从业者调研:AI工具痛点与解决方案‌

AI测试工具的崛起与挑战 随着人工智能技术深入软件测试领域&#xff0c;AI工具如生成式对抗网络&#xff08;GAN&#xff09;、强化学习&#xff08;RL&#xff09;和自然语言处理&#xff08;NLP&#xff09;正重塑测试流程&#xff0c;提升效率与覆盖率。然而&#xff0c;测…

深入浅出 Julia:从零基础到科学机器学习

1. 引言&#xff1a;打破“双语言问题”的科学计算新范式 在很长一段时间里&#xff0c;科学计算和高性能工程领域被一种被称为“双语言问题”&#xff08;Two-Language Problem&#xff09;的现象所困扰。科学家和工程师们通常使用 Python 或 MATLAB 这样的高级动态语言进行算…

SCIR框架:基于自校正迭代精炼的增强型信息提取范式

1. 论文核心概要 (Executive Summary) 本论文提出了一种名为SCIR&#xff08;Self-Correcting Iterative Refinement&#xff09;的全新信息提取范式&#xff0c;旨在解决传统大语言模型微调范式中存在的高训练成本及偏好对齐困难等核心痛点&#xff0c;通过引入“即插即用”的…

为什么你的大模型微调项目像个“无底洞”?

—— 揭秘 LLM 落地中的高昂成本与“版本陷阱”在 AI 浪潮下&#xff0c;很多企业和开发者都有一个共识&#xff1a;“想让大模型在我的垂直领域&#xff08;如医疗、金融、法律&#xff09;表现好&#xff0c;必须进行微调&#xff08;Fine-tuning&#xff09;。”这听起来很美…

揭秘大模型微调中的【偏好对齐】陷阱

在 AI 落地应用中&#xff0c;我们经常遇到一种令人抓狂的现象&#xff1a; 你花大价钱微调了一个行业大模型&#xff0c;让它处理信息提取&#xff08;Information Extraction, IE&#xff09;任务&#xff0c;比如从合同中提取条款或从病历中提取诊断结果。 然而&#xff0c;…

详解无线网络的“防撞”智慧

无线网络&#xff08;Wi-Fi&#xff09;和蓝牙是我们每天都在用的技术&#xff0c;但你有没有想过&#xff1a;当几十台手机同时在一个房间里抢网速时&#xff0c;为什么信号没有在空气中撞成一锅粥&#xff1f; 答案在于一套精心设计的“交通规则”。今天我们结合6张核心技术…

数据仓库生命周期管理:从建模到退役全流程

数据仓库生命周期管理&#xff1a;从建模到退役全流程 关键词&#xff1a;数据仓库、生命周期管理、维度建模、ETL、数据退役、数据归档、数据质量监控 摘要&#xff1a;数据仓库就像企业的“数字大脑”&#xff0c;存储着海量业务数据&#xff0c;支撑着决策分析。但你知道吗&…