news 2026/8/19 22:11:51

ARM架构——LCD 显示与 PWM 背光控制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ARM架构——LCD 显示与 PWM 背光控制

目录

一、LCD 基本概念

1.1 LCD 基本构成

1.2 数据传输模式

1.3 LCD 时序详解

1.3.1 水平时序

1.3.2 垂直时序

1.3.3 时钟频率计算

二、PWM 背光控制原理

三、LCD 驱动实现

3.1 引脚配置

3.2 时钟配置

3.3 LCDIF 模块初始化

3.4 显示功能实现

四、PWM 驱动实现

4.1 引脚配置与模块初始化

4.2 占空比调节

4.3 应用层控制

五、总结


一、LCD 基本概念

1.1 LCD 基本构成

LCD(Liquid Crystal Display)是一种非自发光型显示屏,需要背光支持。其核心由以下部分组成:

  • 像素阵列:每个像素由 R(红)、G(绿)、B(蓝)三原色子像素构成。
  • 驱动电路:逐行扫描,每行点亮后快速切换至下一行。
  • 控制器:负责发送数据、同步信号和时钟。

在 IMU6ULL 系统中,使用的是TFT-LCD 屏幕,分辨率为800×480,采用RGB888 格式(24位真彩色),即每个像素占用 3 字节(R:8bit, G:8bit, B:8bit)。

1.2 数据传输模式

IMX6ULL 通过eLCDIF(Enhanced LCD Interface)模块连接到 LCD 模块,采用并行同步单工通信方式

信号类型数量功能
数据线24根RGB888 数据传输(8r+8g+8b)
控制线4根DE(Data Enable)、HSYNC、VSYNC、PCLK
地址/控制总线32位用于 DMA 写入帧缓冲区
片选 / 使能若干控制 LCD 是否响应

关键点:所有信号都由主控芯片产生,LCD 只需接收并解析这些信号即可刷新画面。

1.3 LCD 时序详解

LCD时序图

1.3.1 水平时序

针对 “一行像素” 的传输周期。水平方向上,一个完整的行周期分为以下几个阶段:

  • HFP(行前沿,40):位于行同步脉冲之前的空闲周期。为LCD准备下一行的显示。
  • HSYNC(行同步脉冲,48):实际的行同步信号。触发LCD开始新的一行扫描。
  • HBP(行后沿,88):位于行同步脉冲之后的空闲周期。为下一行扫描做准备。
  • 有效数据段(800):传输当前行的有效像素数据。

总水平周期 = 40 + 48 + 88 + 800 =976

1.3.2 垂直时序

针对 “一整幅画面” 的传输周期。垂直方向上,一帧图像包含多个行周期,其划分如下:

  • VFP(场前沿,13):位于场同步脉冲之前的空闲行数。为新的一帧图像显示做准备。
  • VSYNC(场同步脉冲,3):实际的场同步信号。触发LCD开始新的一帧图像。
  • VBP(场后沿,32):位于场同步脉冲之后的空闲行数。为下一帧图像显示做准备。
  • 有效行段(480):传输一帧的所有有效行数据。

总垂直周期 = 13 + 3 + 32 + 480=528

1.3.3 时钟频率计算

  • 像素时钟 PCLK 频率决定了刷新速度。
  • 对于 800×480,60Hz,所需 PCLK = (976 * 528) * 60 ≈ 30.92 MHz

二、PWM 背光控制原理

PWM(Pulse Width Modulation,脉冲宽度调制)是控制 LCD 背光亮度的核心技术:

  • 工作原理:通过调整高电平持续时间(占空比)来控制平均功率
  • 占空比:高电平时间 / 周期时间,0% 表示完全关闭,100% 表示全亮
  • 频率选择:通常选择 1-2kHz,高于人眼视觉暂留频率(约60Hz),避免可见闪烁

三、LCD 驱动实现

LCD 驱动的核心是硬件配置(引脚 + 时钟)+ 时序参数初始化 + 帧缓存管理。

3.1 引脚配置

IMX6ULL 的 GPIO 引脚支持多功能复用,LCD 驱动需将指定引脚复用为 LCDIF(LCD 接口)功能,并配置电气特性(驱动能力、上下拉等)。

  • 代码实现:
// 引脚复用:将24根数据线+4根控制信号复用为LCDIF功能 IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0); // 数据引脚0 ... IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0); // 数据引脚23 IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0); // LCD像素时钟 IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0); // 水平同步信号 IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0); // 垂直同步信号 IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0); // 显示使能信号 // 电气特性配置:0xB9对应高速驱动、上拉、100MHz速率 IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0xB9); ... IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0xB9); IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0xB9); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_GPIO1_IO08, 0xB9); // 将背光引脚输出高电平 GPIO1->GDIR |= (1 << 8); GPIO1->DR |= (1 << 8);

3.2 时钟配置

LCD 的像素时钟(PCLK)直接影响显示稳定性,IMX6ULL 通过 PLL5(VIDEO PLL)生成 LCDIF 所需时钟。

  • 代码实现:
// 配置PLL5:输入时钟1MHz,倍频31倍,输出31MHz CCM_ANALOG->PLL_VIDEO_NUM = 0; // 分子为0(默认1) CCM_ANALOG->PLL_VIDEO_DENOM = 1; // 分母为1 unsigned int t = CCM_ANALOG->PLL_VIDEO; t &= ~(3 << 19); t |= (2 << 19); // 倍频系数31 t &= ~(0x7F << 0); t |= (31 << 0); // 参考分频系数 CCM_ANALOG->PLL_VIDEO = t; CCM_ANALOG->PLL_VIDEO |= (1 << 13); // 使能PLL5 // 配置LCDIF时钟路径:PLL5 -> 预分频 -> 分频 -> LCDIF CCM->CSCDR2 |= (2 << 15); // 选择PLL5为时钟源 CCM->CSCDR2 |= (3 << 12); // 预分频系数4(3+1) CCM->CBCMR |= (5 << 23); // 后分频系数6(5+1),最终PCLK=31MHz/(4*6)≈1.3MHz(适配800×480刷新率)

3.3 LCDIF 模块初始化

LCDIF(LCD 接口控制器)是 IMX6ULL 专门用于 LCD 驱动的外设,需配置时序参数、帧缓存地址、像素格式等。

  • 代码实现:
// LCD设备参数初始化(与硬件时序一致) lcd_dev.width = 800; // 屏幕宽度 lcd_dev.height = 480; // 屏幕高度 lcd_dev.pix_size = 4; // 像素字节数(ARGB8888) lcd_dev.hspw = 48; // HSYNC脉冲宽度(对应硬件参数) lcd_dev.hbp = 88; // 行后沿(HSYNC后到有效数据的时间) lcd_dev.hfp = 40; // 行前沿(有效数据后到HSYNC的时间) lcd_dev.vspw = 3; // VSYNC脉冲宽度 lcd_dev.vbp = 32; // 场后沿 lcd_dev.vfp = 13; // 场前沿 lcd_dev.frame_addr = _FRAME_RAM_ADDRESS; // 帧缓存地址(SDRAM分配) // 配置LCDIF控制寄存器 LCDIF->CTRL |= (1 << 19) | (1 << 17) | (3 << 10) | (3 << 8) | (1 << 5); // CTRL1:像素格式配置(ARGB8888) LCDIF->CTRL1 = (0x07 << 16); // 传输尺寸(高度+宽度) LCDIF->TRANSFER_COUNT = (lcd_dev.height << 16) | (lcd_dev.width << 0); // 帧缓存地址(当前+下一个,单缓存模式) LCDIF->CUR_BUF = lcd_dev.frame_addr; LCDIF->NEXT_BUF = lcd_dev.frame_addr; // 垂直时序配置 LCDIF->VDCTRL0 = (1 << 28) | (1 << 24) | (1 << 21) | (1 << 20) | (lcd_dev.vspw << 0); LCDIF->VDCTRL1 = lcd_dev.height + lcd_dev.vspw + lcd_dev.vbp + lcd_dev.vfp; // 垂直总周期 LCDIF->VDCTRL2 = lcd_dev.hspw << 18 | (lcd_dev.width + lcd_dev.hspw + lcd_dev.hbp + lcd_dev.hfp); // 水平总周期 LCDIF->CTRL |= (1 << 0); // 使能LCDIF screen_clear(lcd_dev.back_color); // 清屏(填充背景色)

3.4 显示功能实现

基于帧缓存机制,通过操作内存实现绘图功能:

// 清屏(填充整个屏幕为指定颜色) void screen_clear(unsigned int color) { int j = 0, i = 0; for (j = 0; j < lcd_dev.height; j++) for (i = 0; i < lcd_dev.width; i++) lcd_drawpoint(i, j, color); } // 绘制单个像素点 void lcd_drawpoint(int x, int y, unsigned int color) { unsigned int *p = (unsigned int *)lcd_dev.frame_addr; if (x >= lcd_dev.width || y >= lcd_dev.height) return; // 边界检查 *(p + lcd_dev.width * y + x) = color; // 直接操作帧缓存 } // 绘制横线 void screen_h_line(int x, int y, int len, unsigned int color) { int i = 0; for (i = x; i < x + len; i++) lcd_drawpoint(i, y, color); }

四、PWM 驱动实现

PWM(脉冲宽度调制)的核心是通过改变高电平占空比控制外设(如 LCD 背光亮度)。基于 IMX6ULL 的 PWM1 模块,实现占空比 0~100% 循环调节。

4.1 引脚配置与模块初始化

  • 代码实现:
// 引脚复用:GPIO1_IO08 -> PWM1_OUT IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0); // 电气特性配置(与LCD引脚一致,适配高速输出) IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0xB9); // PWM模块配置 PWM1->PWMCR |= (1 << 3); // 软件复位PWM while ((PWM1->PWMCR & (1 << 3)) != 0); // 等待复位完成 PWM1->PWMCR |= (1 << 26); // 使能自动重载 PWM1->PWMCR |= (1 << 16); // 中断使能(周期结束触发) PWM1->PWMCR |= (65 << 4); // 预分频系数66(65+1) PWM1->PWMCR |= (3 << 1); // 时钟源选择IPG_CLK(66MHz) PWM1->PWMIR |= (1 << 0); // 使能周期中断 // PWM周期设置:PWMPR = 周期计数-2 PWM1->PWMPR = 1000 - 2; // 中断配置:注册中断服务函数,使能GIC中断 system_interrupt_register(PWM1_IRQn, pwm_interrupt_handler); GIC_EnableIRQ(PWM1_IRQn); GIC_SetPriority(PWM1_IRQn, 0); // 最高优先级 set_ratio(0.5); // 初始占空比50% PWM1->PWMCR |= (1 << 0); // 使能PWM输出

4.2 占空比调节

通过中断服务函数实时更新占空比,核心是修改 PWMSAR(PWM 输出比较寄存器):

static float g_dc = 0.5; // 全局占空比变量 // 设置占空比(dc范围0~1) void set_ratio(float dc) { unsigned short temp = PWM1->PWMPR; int i = 0; for (i = 0; i < 4; i++) // 多次写入确保稳定性 PWM1->PWMSAR = temp * dc; // 占空比=dc,高电平计数=周期×dc } // PWM中断服务函数(周期结束触发) void pwm_interrupt_handler(void) { if ((PWM1->PWMSR & (1 << 3)) != 0) // 检查周期中断标志 { set_ratio(g_dc); // 更新占空比 PWM1->PWMSR |= (1 << 3); // 清除中断标志 } }

4.3 应用层控制

main 函数中循环修改 g_dc 变量,实现占空比 0~100% 循环:

float dc = 0.5; while (1) { delay_ms(1000); set_g_dc(dc); // 更新全局占空比 dc += 0.1; // 每次增加10% if (dc > 1.0) // 超过100%则重置为0 dc = 0.0; }

五、总结

核心实现要点:

  • LCD 驱动:关键是引脚复用、时钟稳定性、时序参数匹配硬件规格,帧缓存机制是绘图功能的基础;
  • PWM 驱动:核心是时钟源选择、周期配置、中断驱动的占空比更新,确保信号平滑无抖动;
  • 联动设计:利用 PWM 调节 LCD 背光,是嵌入式系统中 “显示 + 控制” 的典型组合。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/18 15:28:33

DeepSeek-R1-Distill-Llama-8B效果展示:AIME 2024 pass@1达50.4%实录

DeepSeek-R1-Distill-Llama-8B效果展示&#xff1a;AIME 2024 pass1达50.4%实录 你有没有试过让一个8B参数的模型&#xff0c;解出一道真正的AIME数学竞赛题&#xff1f;不是那种“看起来像数学题”的模拟题&#xff0c;而是2024年真实考卷里、连很多高中生都要卡壳的压轴题。…

作者头像 李华
网站建设 2026/8/16 16:56:10

从下载到训练,YOLO11镜像全流程演示

从下载到训练&#xff0c;YOLO11镜像全流程演示 1. 为什么用镜像跑YOLO11&#xff1f;省掉三天环境踩坑时间 你有没有试过&#xff1a; pip install ultralytics 后报错 torch not compatible with torchvision&#xff1b;下载完模型权重&#xff0c;发现路径写错八次才对上…

作者头像 李华
网站建设 2026/8/16 16:56:59

Qwen3-Reranker-0.6B多场景应用:专利无效检索中权利要求匹配重排

Qwen3-Reranker-0.6B多场景应用&#xff1a;专利无效检索中权利要求匹配重排 在知识产权实务中&#xff0c;专利无效宣告程序是技术对抗最激烈的战场之一。其中&#xff0c;如何从海量对比文件中精准定位与权利要求高度相关的段落&#xff0c;直接决定无效证据链的强弱。传统B…

作者头像 李华
网站建设 2026/8/19 16:41:12

Z-Image Turbo应用场景深挖:短视频封面智能设计

Z-Image Turbo应用场景深挖&#xff1a;短视频封面智能设计 1. 为什么短视频封面正在成为“流量第一触点” 你有没有注意到&#xff0c;刷短视频时&#xff0c;真正决定你停不停下来的&#xff0c;往往不是前两秒的视频内容&#xff0c;而是那一张静止的封面图&#xff1f; 它…

作者头像 李华
网站建设 2026/8/1 13:46:13

零基础入门OCR检测:用cv_resnet18_ocr-detection轻松实现证件识别

零基础入门OCR检测&#xff1a;用cv_resnet18_ocr-detection轻松实现证件识别 OCR&#xff08;光学字符识别&#xff09;技术早已不是实验室里的概念&#xff0c;而是每天在银行柜台、政务大厅、快递分拣站默默工作的“数字员工”。但对大多数开发者来说&#xff0c;从零搭建一…

作者头像 李华