LCD段码屏(又称段式LCD或段码显示屏)是一种常见的液晶显示技术,主要用于显示简单的数字、字符或固定图形。以下是其核心特点和工作原理的详细说明:
一:LCD基本知识分享:
1. 基本结构
分段显示:屏幕由多个独立的“段”(Segment)组成,每个段对应显示内容的一部分(如数字的某一段笔画、符号或简单图标)。
背电极(COM)与段电极(SEG):通过交叉矩阵控制,每个段的亮灭由对应的电极信号决定。
固定图案:显示内容需预先设计(如计算器、电子表上的数字),无法动态变化。
2. 工作原理
驱动方式:采用静态驱动或动态驱动(多路复用),通过施加电压改变液晶排列,控制光线透过与否。
对比度高:通常为单色(如蓝底白字、黑底灰字),依赖背光或环境光。
低功耗:仅在切换段状态时耗电,适合电池供电设备。
3:RA4L1板载的LCD资料:
液晶显示(LCD)是嵌入式系统中常见的人机交互方式,广泛应用于工业控制、智能家电、医疗设备和消费电子产品。Renesas RA4L1 微控制器(MCU)内置 Segment LCD Controller (SLCDC),可直接驱动 静态、1/2、1/3、1/4 Bias 的段式 LCD 显示屏,无需额外的 LCD 驱动芯片。这种集成方案不仅降低了硬件成本,还简化了设计。
Renesas RA4L1 的 SLCDC 模块提供了一种高效、低功耗、低成本的 LCD 显示方案。通过 FSP 提供的 r_slcdc 驱动,开发者可以快速初始化 LCD,轻松控制显示内容。在实际项目中,合理配置 COM/SEG 引脚、优化时钟和对比度设置,可以进一步提升 LCD 显示效果。
开发板图片如下所示:
二:开发板资料
要将 LCD 屏幕的引脚正确映射到 RA MCU 的 SLCDC(Segment LCD Controller)驱动引脚,需要按照 LCD 的 COM(公共端) 和 SEG(段) 分配关系,将其连接到 MCU 的相应 SLCDC 引脚。LCD映射到 MCU 的 SLCDC 驱动引脚
通过上图,一个数码管驱动需要两个位选来确定,这种和数码管驱动有点区别,大家在驱动的时候,需要格外的注意;
原理图如下所示:
打开fsp配置,对所使用的IO口进行配置
系统时钟的配置如下所示:
三:代码的编写:
3.1底层驱动函数如下:
以第一个数码管驱动做简单的结合扫
在 SLCDC (Segment LCD Controller) 驱动 LCD 数码管时,每个段 (SEGx) 需要与多个公共端 (COMx) 进行组合,以控制哪些段应该点亮。
从第11个段开始,由于只有4个COM,将4个数据写入SLCDC的段寄存器,驱动LCD显示对应图案或数字。
1B 段 和 1C 段 分别映射到:
● 1B → SEG11, COM1
● 1C → SEG11, COM2
要点亮 1B (COM1) 和 1C (COM2),所以需要设置:
● COM1 = 1(对应第 1 位)
● COM2 = 1(对应第 2 位)
● 其他 COM0 和 COM3 = 0
这里只有COM1和COM2需要驱动,对应十六进制为0x6,驱动代码如下所示。
下方代码R_SLCDC_Write中,0代表从 SEG0 开始写入数据,数组segment_data_num1长度sizeof(segment_data_num1),为11。在SEG11写入0x6。
用计算器的二进值确定一下,断码需要点亮时,发送的数据;
R_SLCDC_Write()函数:
R_SLCDC_Write() 的作用是向段式LCD控制器(SLCDC)写入一系列的数据,以控制LCD的显示内容。
数据被写入SLCDC内部的段数据寄存器中,从而控制LCD各段的亮灭状态。
fsp_err_t R_SLCDC_Write (slcdc_ctrl_t * const p_ctrl, uint8_t const start_segment, uint8_t const * p_data, uint8_t const segment_count) { slcdc_instance_ctrl_t * p_instance_ctrl = (slcdc_instance_ctrl_t *) p_ctrl; fsp_err_t err = FSP_SUCCESS; #if (SLCDC_CFG_PARAM_CHECKING_ENABLE) FSP_ASSERT(p_instance_ctrl); FSP_ASSERT(p_data); FSP_ERROR_RETURN(SLCDC_CLOSED != p_instance_ctrl->open, FSP_ERR_NOT_OPEN); if ((BSP_FEATURE_SLCDC_MAX_NUM_SEG <= start_segment) || (((uint8_t) (BSP_FEATURE_SLCDC_MAX_NUM_SEG)) < (start_segment + segment_count))) { return FSP_ERR_INVALID_ARGUMENT; } #else FSP_PARAMETER_NOT_USED(p_instance_ctrl); #endif /* Display data is stored in the LCD segment data register array */ for (uint8_t seg = start_segment; (seg - start_segment) < segment_count; seg++) { R_SLCDC->SEG[seg] = *p_data; p_data++; } return err; }
这里我所使用的驱动函数是:
R_SLCDC_Modify() 是用于修改单个段寄存器中的部分位的函数,属于 SLCDC 驱动的精细控制接口。
fsp_err_t R_SLCDC_Modify (slcdc_ctrl_t * const p_ctrl, uint8_t const segment, uint8_t const data, uint8_t const data_mask) { slcdc_instance_ctrl_t * p_instance_ctrl = (slcdc_instance_ctrl_t *) p_ctrl; #if (SLCDC_CFG_PARAM_CHECKING_ENABLE) FSP_ASSERT(p_instance_ctrl); FSP_ERROR_RETURN(SLCDC_CLOSED != p_instance_ctrl->open, FSP_ERR_NOT_OPEN); if (BSP_FEATURE_SLCDC_MAX_NUM_SEG <= segment) { return FSP_ERR_INVALID_ARGUMENT; } #else FSP_PARAMETER_NOT_USED(p_instance_ctrl); #endif /* Mask and write data to segment */ R_SLCDC->SEG[segment] = (R_SLCDC->SEG[segment] & (uint8_t) (~(data_mask))) | data; return FSP_SUCCESS; }
修改底层的驱动函数代码如下所示:
void OneDisNumber(char number) { switch (number) { case 0 : //准备并写入段显示数据,第一个数码管显示0 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xD, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x7, 0xF); break ; case 1 : //准备并写入段显示数据,第一个数码管显示1 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0x0, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x6, 0xF); break ; case 2 : //准备并写入段显示数据,第一个数码管显示2 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xE, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x3, 0xF); break ; case 3 : //准备并写入段显示数据,第一个数码管显示3 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xA, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x7, 0xF); break ; case 4 : //准备并写入段显示数据,第一个数码管显示4 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0x3, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x6, 0xF); break ; case 5 : //准备并写入段显示数据,第一个数码管显示5 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xB, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x5, 0xF); break ; case 6 : //准备并写入段显示数据,第一个数码管显示6 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xF, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x5, 0xF); break ; case 7 : //准备并写入段显示数据,第一个数码管显示7 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0x0, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x7, 0xF); break ; case 8 : //准备并写入段显示数据,第一个数码管显示8 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xF, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x7, 0xF); break ; case 9 : //准备并写入段显示数据,第一个数码管显示9 R_SLCDC_Modify(&g_slcdc0_ctrl, 3, 0xB, 0xF); R_SLCDC_Modify(&g_slcdc0_ctrl, 11, 0x7, 0xF); break ; default : break ; } }
在主程序添加,对一个第一个数码管的驱动显示部分:
data++; if(data >=10) data = 0 ; OneDisNumber(data); SencoendDisNumber(data); R_BSP_SoftwareDelay (2000, BSP_DELAY_UNITS_MILLISECONDS);
实物测试图如下所示: