从CuteCom到代码手把手教你用I.MX6ULL实现串口双向通信在嵌入式开发中串口通信是最基础也最关键的调试手段之一。无论是简单的日志输出还是复杂的数据交互串口都扮演着不可或缺的角色。本文将带你从零开始在I.MX6ULL平台上构建一个完整的串口通信系统从上层调试工具到底层驱动实现形成一个完整的闭环。1. 环境准备与工具配置在开始编码之前我们需要搭建好开发环境。这包括硬件和软件两个部分硬件准备I.MX6ULL开发板如正点原子或野火的开发板USB转TTL模块如CH340、CP2102等杜邦线若干软件准备Ubuntu系统推荐18.04或20.04 LTS版本CuteCom串口调试工具ARM交叉编译工具链代码编辑器VSCode或Vim等安装CuteCom非常简单在Ubuntu终端中执行以下命令即可sudo apt-get install cutecom安装完成后我们需要配置CuteCom以连接开发板将USB转TTL模块连接到电脑通常会自动识别为/dev/ttyUSB0设备打开CuteCom在设备选择下拉菜单中选择对应的设备设置波特率为115200与开发板默认设置一致数据位8位无校验位停止位1位8N1点击Open Device按钮打开串口注意确保你的用户有访问串口设备的权限。如果没有可以执行sudo usermod -a -G dialout $USER命令将当前用户加入dialout组然后重新登录。2. I.MX6ULL UART硬件基础I.MX6ULL处理器提供了多个UART接口我们需要先了解其硬件特性特性参数UART数量8个UART1-UART8最大波特率5Mbps数据位5-8位可配置停止位1或2位校验位无/奇/偶校验FIFO深度64字节在硬件连接上我们通常使用UART1作为调试串口其引脚定义如下UART1_TXD发送数据线输出UART1_RXD接收数据线输入GND地线必须连接在开发板上这些引脚通常已经连接到USB转串口芯片我们只需要通过USB线连接电脑即可。3. UART驱动开发3.1 寄存器配置I.MX6ULL的UART控制器通过一组寄存器进行配置主要寄存器包括// UART寄存器基地址 #define UART1_BASE 0x02020000 // 主要寄存器偏移量 #define URXD 0x0 // 接收数据寄存器 #define UTXD 0x40 // 发送数据寄存器 #define UCR1 0x80 // 控制寄存器1 #define UCR2 0x84 // 控制寄存器2 #define UCR3 0x88 // 控制寄存器3 #define UCR4 0x8C // 控制寄存器4 #define UFCR 0x90 // FIFO控制寄存器 #define USR1 0x94 // 状态寄存器1 #define USR2 0x98 // 状态寄存器2 #define UESC 0x9C // 转义字符寄存器 #define UTIM 0xA0 // 超时寄存器 #define UBIR 0xA4 // 波特率增量寄存器 #define UBMR 0xA8 // 波特率乘数寄存器 #define UBRC 0xAC // 波特率计数寄存器3.2 初始化代码实现下面是UART初始化的完整代码实现void uart_init(void) { // 1. 使能UART时钟 *((volatile unsigned int *)0x020C406C) | (1 0); // CCM_CCGR5_CG12 // 2. 设置UART1_TXD复用为UART功能 *((volatile unsigned int *)0x020E0084) ~(0xF 20); *((volatile unsigned int *)0x020E0084) | (0x1 20); // 3. 设置UART1_RXD复用为UART功能 *((volatile unsigned int *)0x020E0088) ~(0xF 0); *((volatile unsigned int *)0x020E0088) | (0x1 0); // 4. 禁用UART *((volatile unsigned int *)(UART1_BASE UCR1)) 0; // 5. 设置UART参数 *((volatile unsigned int *)(UART1_BASE UCR2)) 0; *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 5); // 发送使能 *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 2); // 接收使能 *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 1); // 8位数据 // 6. 设置波特率为115200 *((volatile unsigned int *)(UART1_BASE UFCR)) 0x81; // 分频器1分频 *((volatile unsigned int *)(UART1_BASE UBIR)) 0x0F; *((volatile unsigned int *)(UART1_BASE UBMR)) 0x16A; // 7. 使能UART *((volatile unsigned int *)(UART1_BASE UCR1)) | 0x1; }3.3 发送与接收函数实现实现基本的字符发送和接收函数// 发送一个字符 void uart_putc(char c) { while (!(*((volatile unsigned int *)(UART1_BASE USR2)) (1 3))); *((volatile unsigned int *)(UART1_BASE UTXD)) c; } // 接收一个字符 char uart_getc(void) { while (!(*((volatile unsigned int *)(UART1_BASE USR1)) (1 0))); return *((volatile unsigned int *)(UART1_BASE URXD)) 0xFF; } // 发送字符串 void uart_puts(const char *s) { while (*s) { uart_putc(*s); } }4. 实现串口回显功能现在我们可以将上述代码组合起来实现一个简单的回显功能开发板接收到任何字符后立即将其发送回去。4.1 主程序实现int main(void) { // 初始化UART uart_init(); // 打印欢迎信息 uart_puts(\r\nUART Echo Demo\r\n); uart_puts(Type anything and it will echo back\r\n); // 主循环 while (1) { char c uart_getc(); uart_putc(c); // 回显接收到的字符 } return 0; }4.2 编译与下载编写Makefile文件进行编译CROSS_COMPILE arm-linux-gnueabihf- CC $(CROSS_COMPILE)gcc LD $(CROSS_COMPILE)ld OBJCOPY $(CROSS_COMPILE)objcopy CFLAGS -Wall -O2 -nostdlib -fno-builtin -Iinclude TARGET uart_echo all: $(TARGET).bin %.o: %.S $(CC) $(CFLAGS) -c -o $ $ %.o: %.c $(CC) $(CFLAGS) -c -o $ $ $(TARGET).elf: start.o main.o $(LD) -T imx6ull.lds -o $ $^ $(TARGET).bin: $(TARGET).elf $(OBJCOPY) -O binary -S $ $ clean: rm -rf *.o $(TARGET).elf $(TARGET).bin编译完成后将生成的uart_echo.bin文件下载到开发板中运行。5. 功能验证与调试5.1 使用CuteCom进行测试打开CuteCom确保串口参数设置正确复位开发板应该能看到欢迎信息在CuteCom的输入框中输入任意字符观察回显情况5.2 常见问题排查如果遇到问题可以按照以下步骤排查无任何输出检查硬件连接是否正确确认波特率设置是否匹配检查程序是否正确下载到开发板输出乱码确认波特率设置是否正确检查时钟配置是否正确部分字符丢失检查发送和接收函数的等待条件可能需要增加适当的延时在实际项目中我发现最容易出错的地方是波特率配置。确保开发板和CuteCom使用相同的波特率参数包括数据位、停止位和校验位的设置。
从CuteCom到代码:手把手教你用I.MX6ULL实现串口双向通信(附完整工程)
发布时间:2026/5/16 22:38:23
从CuteCom到代码手把手教你用I.MX6ULL实现串口双向通信在嵌入式开发中串口通信是最基础也最关键的调试手段之一。无论是简单的日志输出还是复杂的数据交互串口都扮演着不可或缺的角色。本文将带你从零开始在I.MX6ULL平台上构建一个完整的串口通信系统从上层调试工具到底层驱动实现形成一个完整的闭环。1. 环境准备与工具配置在开始编码之前我们需要搭建好开发环境。这包括硬件和软件两个部分硬件准备I.MX6ULL开发板如正点原子或野火的开发板USB转TTL模块如CH340、CP2102等杜邦线若干软件准备Ubuntu系统推荐18.04或20.04 LTS版本CuteCom串口调试工具ARM交叉编译工具链代码编辑器VSCode或Vim等安装CuteCom非常简单在Ubuntu终端中执行以下命令即可sudo apt-get install cutecom安装完成后我们需要配置CuteCom以连接开发板将USB转TTL模块连接到电脑通常会自动识别为/dev/ttyUSB0设备打开CuteCom在设备选择下拉菜单中选择对应的设备设置波特率为115200与开发板默认设置一致数据位8位无校验位停止位1位8N1点击Open Device按钮打开串口注意确保你的用户有访问串口设备的权限。如果没有可以执行sudo usermod -a -G dialout $USER命令将当前用户加入dialout组然后重新登录。2. I.MX6ULL UART硬件基础I.MX6ULL处理器提供了多个UART接口我们需要先了解其硬件特性特性参数UART数量8个UART1-UART8最大波特率5Mbps数据位5-8位可配置停止位1或2位校验位无/奇/偶校验FIFO深度64字节在硬件连接上我们通常使用UART1作为调试串口其引脚定义如下UART1_TXD发送数据线输出UART1_RXD接收数据线输入GND地线必须连接在开发板上这些引脚通常已经连接到USB转串口芯片我们只需要通过USB线连接电脑即可。3. UART驱动开发3.1 寄存器配置I.MX6ULL的UART控制器通过一组寄存器进行配置主要寄存器包括// UART寄存器基地址 #define UART1_BASE 0x02020000 // 主要寄存器偏移量 #define URXD 0x0 // 接收数据寄存器 #define UTXD 0x40 // 发送数据寄存器 #define UCR1 0x80 // 控制寄存器1 #define UCR2 0x84 // 控制寄存器2 #define UCR3 0x88 // 控制寄存器3 #define UCR4 0x8C // 控制寄存器4 #define UFCR 0x90 // FIFO控制寄存器 #define USR1 0x94 // 状态寄存器1 #define USR2 0x98 // 状态寄存器2 #define UESC 0x9C // 转义字符寄存器 #define UTIM 0xA0 // 超时寄存器 #define UBIR 0xA4 // 波特率增量寄存器 #define UBMR 0xA8 // 波特率乘数寄存器 #define UBRC 0xAC // 波特率计数寄存器3.2 初始化代码实现下面是UART初始化的完整代码实现void uart_init(void) { // 1. 使能UART时钟 *((volatile unsigned int *)0x020C406C) | (1 0); // CCM_CCGR5_CG12 // 2. 设置UART1_TXD复用为UART功能 *((volatile unsigned int *)0x020E0084) ~(0xF 20); *((volatile unsigned int *)0x020E0084) | (0x1 20); // 3. 设置UART1_RXD复用为UART功能 *((volatile unsigned int *)0x020E0088) ~(0xF 0); *((volatile unsigned int *)0x020E0088) | (0x1 0); // 4. 禁用UART *((volatile unsigned int *)(UART1_BASE UCR1)) 0; // 5. 设置UART参数 *((volatile unsigned int *)(UART1_BASE UCR2)) 0; *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 5); // 发送使能 *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 2); // 接收使能 *((volatile unsigned int *)(UART1_BASE UCR2)) | (1 1); // 8位数据 // 6. 设置波特率为115200 *((volatile unsigned int *)(UART1_BASE UFCR)) 0x81; // 分频器1分频 *((volatile unsigned int *)(UART1_BASE UBIR)) 0x0F; *((volatile unsigned int *)(UART1_BASE UBMR)) 0x16A; // 7. 使能UART *((volatile unsigned int *)(UART1_BASE UCR1)) | 0x1; }3.3 发送与接收函数实现实现基本的字符发送和接收函数// 发送一个字符 void uart_putc(char c) { while (!(*((volatile unsigned int *)(UART1_BASE USR2)) (1 3))); *((volatile unsigned int *)(UART1_BASE UTXD)) c; } // 接收一个字符 char uart_getc(void) { while (!(*((volatile unsigned int *)(UART1_BASE USR1)) (1 0))); return *((volatile unsigned int *)(UART1_BASE URXD)) 0xFF; } // 发送字符串 void uart_puts(const char *s) { while (*s) { uart_putc(*s); } }4. 实现串口回显功能现在我们可以将上述代码组合起来实现一个简单的回显功能开发板接收到任何字符后立即将其发送回去。4.1 主程序实现int main(void) { // 初始化UART uart_init(); // 打印欢迎信息 uart_puts(\r\nUART Echo Demo\r\n); uart_puts(Type anything and it will echo back\r\n); // 主循环 while (1) { char c uart_getc(); uart_putc(c); // 回显接收到的字符 } return 0; }4.2 编译与下载编写Makefile文件进行编译CROSS_COMPILE arm-linux-gnueabihf- CC $(CROSS_COMPILE)gcc LD $(CROSS_COMPILE)ld OBJCOPY $(CROSS_COMPILE)objcopy CFLAGS -Wall -O2 -nostdlib -fno-builtin -Iinclude TARGET uart_echo all: $(TARGET).bin %.o: %.S $(CC) $(CFLAGS) -c -o $ $ %.o: %.c $(CC) $(CFLAGS) -c -o $ $ $(TARGET).elf: start.o main.o $(LD) -T imx6ull.lds -o $ $^ $(TARGET).bin: $(TARGET).elf $(OBJCOPY) -O binary -S $ $ clean: rm -rf *.o $(TARGET).elf $(TARGET).bin编译完成后将生成的uart_echo.bin文件下载到开发板中运行。5. 功能验证与调试5.1 使用CuteCom进行测试打开CuteCom确保串口参数设置正确复位开发板应该能看到欢迎信息在CuteCom的输入框中输入任意字符观察回显情况5.2 常见问题排查如果遇到问题可以按照以下步骤排查无任何输出检查硬件连接是否正确确认波特率设置是否匹配检查程序是否正确下载到开发板输出乱码确认波特率设置是否正确检查时钟配置是否正确部分字符丢失检查发送和接收函数的等待条件可能需要增加适当的延时在实际项目中我发现最容易出错的地方是波特率配置。确保开发板和CuteCom使用相同的波特率参数包括数据位、停止位和校验位的设置。