ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

直接用IO驱动段码LCD:原理、接线与扫描代码详解

直接用IO驱动段码LCD:原理、接线与扫描代码详解 简介面向STC单片机开发者的一份段码液晶驱动资源聚焦“直接用输入输出口驱动段码LCD”这一常见需求提供真实可编译的工程代码与配套硬件说明适合正在学习单片机IO控制、液晶显示原理的嵌入式开发者或学生参考。包内共含29个文件压缩后约1.72MB既有C语言源码与头文件也有Keil工程配置、编译生成的hex/obj等中间文件以及PDF和DOC格式的应用电路文档可帮助理解不同偏压3BIAS/2BIAS下的驱动电路连接方式。已有1729人学习或下载过该资源实用性获得初步验证。通过对照源码、工程文件和电路文档读者可以快速掌握段码液晶的初始化步骤、段线与公共线的电平配合、动态扫描刷新以及定时中断调度等关键实现从而缩短自研驱动库的开发周期并灵活移植到STC系列其他项目中。1. 直接用IO驱动段码LCD先分清“玻璃屏”和“自带驱动IC的模组”再动手段码LCD不是发光二极管很多工程师第一次拿到段码液晶屏会下意识按LED数码管的玩法给引脚灌高低电平结果不是显示全黑就是出现擦不掉的残影。直接用IO驱动段码LCD本质上是把MCU的普通GPIO当成一个软件版LCD控制器自己产生交流扫描波形代替HT1621这类驱动IC完成COM/SEG的轮询与偏压切换。这条路适合引脚富余、显示段数不夸张、想省一颗驱动IC或纯粹想把LCD驱动原理吃透的项目。如果你买到的段码LCD模组本身已经带了驱动IC直接用IO模拟三线时序去操作它那也是可行的但那属于“协议驱动”和驱动裸玻璃屏是两套思路。这篇文章以驱动裸玻璃屏为主把IO直驱的前提、电路、扫描代码和调试手段一次讲完。2. 段码LCD的电极结构与交流驱动为什么普通IO必须配合扫描和偏压2.1 每个显示段是一个“夹在COM和SEG之间的电容”段码LCD的显示单元不是独立的发光体而是一小滴被封在玻璃基板里的液晶材料。液晶层上下两侧分别有透明电极其中一个电极叫公共端COM另一个叫段电极SEG两个电极之间的液晶分子在电场作用下改变取向配合偏光片就会呈现出“透”或“不透”的状态。从电路模型看一个显示段等效于一个小电容并联着非常大的绝缘电阻容值通常在几pF到几十pF泄漏电流在微安级以下。因为是电容负载真正决定液晶显示状态的是电极两端电压的有效值RMS而不是瞬时极性。反过来液晶材料对直流非常敏感长期施加直流电场会导致液晶分子发生电化学反应屏体发黑、电极腐蚀、对比度永久劣化。所以段码LCD的驱动电压必须是交流方波并且要让每个显示段在两个方向上的电压积分一致平均直流分量无限接近0。这个要求直接决定了用IO驱动的第一行代码定时器翻转极性。2.2 多路复用是省引脚的代价DUTY、BIAS和鬼影段码LCD为了减少电极数量通常会把所有显示段排成一个矩阵若干个COM做行扫描几十个SEG做列。显示一个段时只有该段所在COM被选通时SEG才有意义其他COM则要进入“非选通”状态。这种扫描方式用时间换取引脚代价是引入了两个参数DUTY和BIAS。DUTY是扫描占空比DUTY1/2表示2个COM轮流选通DUTY1/3、1/4类推。BIAS偏压比则是非选通COM与SEG之间剩余电压的比例用来压低非目标段的RMS值避免不该亮的段被“串扰电压”点亮。1/2偏压意味着非选通电极被拉到VDD/21/3偏压则是让非选通电极出现在VDD/3或2VDD/3的电位上。普通IO口只有推挽输出的高电平和低电平两个状态没有VDD/2或VDD/3这种中间电平。因此不是所有段码LCD都能用IO直接驱动。常见选型经验是单COM静态屏DUTY1IO直驱没有偏压问题双COM的DUTY1/2、BIAS1/2可以用两个IO配合等值电阻给COM引出中间电平而DUTY1/3、1/4的屏需要1/3偏压纯IO直驱会非常别扭。下表是一个简单的可直驱判断表。DUTYCOM数所需偏压IO直驱可行性说明1静态1不需要完全可行每段需要独立SEG引脚多1/221/2可行COM用双IO等值电阻产生VDD/21/331/3不推荐SEG也需要中间电平IO数量暴涨1/441/3不建议直驱直接用驱动IC更现实这里提到的BIAS不是可选项如果跳过偏压非选通段的RMS会乱掉表现为不该显示的段出现浅灰的“鬼影”或者选通段对比度忽高忽低。市面上常见的1/4 duty段码屏老老实实挂HT1621或PCF8576驱动IC比用IO硬刚省心得多。2.3 帧翻转是IO直驱的核心缺了它屏会“中毒”交流驱动不能简单理解成COM输出一个方波就行SEG必须根据显示内容在“同相”和“反相”之间切换。以静态驱动为例COM输出50%占空比方波某个段需要点亮时SEG输出与COM完全反相的方波需要熄灭时SEG输出与COM完全同相的方波。这样点亮的段两端电压是持续的±VDD方波平均直流为0熄灭的段两端电压恒为0。“帧翻转”就是把整个波形周期拉长COM在周期前半段按“COM1”驱动SEG后半段整体翻转为“COM0”再驱动一遍。软件里通常用一个phase变量记录当前极性每次定时器中断把它翻转一次。如果少了这步点亮段的电压会变成单向脉冲一段时间后液晶就会出现不可逆损伤。IO直驱和驱动IC最大的区别就在这驱动芯片内部自动完成偏压和极性切换而IO直驱需要自己用中断代码维护这套状态机。3. 直接用IO驱动段码LCD的硬件接线从单COM到双COM的偏压网络3.1 单COM玻璃屏的最小接线如果你的段码LCD是单背电极的老式静态屏硬件连接是最简单的一个COM引脚接MCU任意一个IO其余SEG引脚分别接MCU的普通IO即可。比如STM32F103上可以用PA0接COMPA1到PA8接SEG0到SEG7。COM和SEG之间不要串电阻直接连因为LCD的负载电流极小串了电阻反而会破坏方波边沿。上电顺序比接线更值得注意。MCU复位瞬间绝大多数GPIO处于浮空输入状态IO口输入状态的阻抗很高但LCD电极上如果残留了电荷可能会保持一段时间的直流偏置。建议初始化代码先把所有LCD引脚配成输出模式并统一输出低电平让COM和SEG之间的电压归零再启动定时器开始扫描。实际项目里还可以在每根LCD电极对地并一个10MΩ泄放电阻帮助快速释放残余电荷但这属于可选项。GPIO模式统一选推挽输出。不要用开漏输出加外部上拉开漏结构只能主动拉低高电平靠上拉电阻建立拉低和释放的边沿不对称方波会出现直流分量。LCD屏的工作电流通常在微安级STM32这类MCU的IO驱动能力完全够反而要小心个别工程师为了让波形更陡把引脚配置成高速翻转过冲毛刺可能通过LCD电极耦合到其他段上。3.2 双COM用“两个IO两个等值电阻”产生VDD/22个COM的段码屏属于1/2 duty驱动非选通COM需要被拉到VDD/2。普通IO给不了中间电平但可以用一个经典的电阻网络解决每个COM用两个IO口两个等值电阻串联电阻中间抽头接LCD的COM电极两个IO分别接电阻两端。电路上就是“IO_A—R—COM—R—IO_B”的结构。两个IO都输出低电平时节点COM被拉到GND两个IO都输出高电平时节点被拉到VDD一个输出高、一个输出低时等值电阻分压节点正好是VDD/2。这样虽然多占了一倍IO却获得了三电平驱动能力。电阻值建议选100kΩ到220kΩ太小会使分压网络产生多余功耗太大会让波形边沿变缓导致LCD对比度下降。这个结构只适用于COM电极SEG不需要中间电平仍然用普通推挽IO直连。COM电阻网络状态IO_AIO_BCOM电压接GND000分压10VDD/2分压01VDD/2接VDD11VDD两个电阻值必须严格等值否则分压点偏离VDD/2非选通段会残留直流分量。批量生产时选1%精度电阻调试阶段用普通5%电阻也能应付。注意两个IO不能在没有电阻的情况下直接一个输出1一个输出0那是MCU内部电源短路。3.3 引脚分配与GPIO参数推挽、开漏、上拉怎么选一个典型的双COM、8段测试板可以这样分配引脚COM0用PB0和PB1加两个100kΩ电阻COM1用PB2和PB3加两个100kΩ电阻SEG0到SEG7用PB4到PB11。初始化顺序分三步先使能GPIO时钟再把这些引脚全部配置为推挽输出并输出低电平最后才配置定时器NVIC并开中断。如果中途某个引脚意外进入高阻态LCD两端悬浮显示段会出现随机残留。信号MCU引脚GPIO模式备注COM0_APB0推挽输出与PB1配合产生0/VDD/VDD/2COM0_BPB1推挽输出等值分压电阻到COM0COM1_APB2推挽输出与PB3配合产生0/VDD/VDD/2COM1_BPB3推挽输出等值分压电阻到COM1SEG0~SEG7PB4~PB11推挽输出按显示缓冲输出同相/反相不要用内部上拉代替外部电阻网络内部上拉阻值离散、温度系数差产生的中间电平不准。还有一个容易被忽略的点如果MCU有SWD复用引脚比如PB4和PB3在STM32F103上默认是JTAG引脚必须先关闭JTAG才能当普通IO用。不同型号的默认复用不一样画板前查一下引脚定义否则下载器会干扰扫描波形。4. 软件扫描实现定时器中断、显示缓冲和极性翻转4.1 静态驱动代码先点亮一个COM上的8个段静态驱动是所有IO直驱方案的基础代码简单便于验证LCD好坏和接线。下面这段代码用定时器中断驱动phase翻转中断周期设为8ms则COM方波周期16ms对应62.5Hz既能避免闪烁也不会因为频率过高白白增加IO翻转功耗。#define LCD_COM_PORT GPIOA #define LCD_COM_PIN GPIO_PIN_0 #define LCD_SEG_PORT GPIOA #define LCD_SEG_MASK (GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4) static volatile uint8_t lcd_phase 0; static volatile uint16_t lcd_seg_bits 0x000F; // bit1 表示对应SEG亮 void LCD_Timer_IRQHandler(void) { uint16_t out; lcd_phase ^ 1; if (lcd_phase) { // COM1亮段SEG输出0灭段SEG输出1 HAL_GPIO_WritePin(LCD_COM_PORT, LCD_COM_PIN, GPIO_PIN_SET); out (~lcd_seg_bits) LCD_SEG_MASK; } else { // COM0亮段SEG输出1灭段SEG输出0 HAL_GPIO_WritePin(LCD_COM_PORT, LCD_COM_PIN, GPIO_PIN_RESET); out lcd_seg_bits LCD_SEG_MASK; } LCD_SEG_PORT-BRR LCD_SEG_MASK; // 先全部清0 LCD_SEG_PORT-BSRR out; // 再置位需要为1的引脚 }这段代码的逻辑是lcd_phase1时COM为高点亮段要让SEG为低所以输出缓冲取反lcd_phase0时COM为低点亮段要让SEG为高所以缓冲原样输出。灭段始终与COM同相两端电压为零。用BRR和BSRR寄存器一次性更新所有SEG引脚避免用循环逐脚翻转造成时间差时间差会在LCD上表现为段间亮度不均。中断周期决定方波频率公式是F 1000 / (2 * T_ms)。T_ms8时F62.5Hz如果LCD驱动电压偏低可以降到40Hz左右保住对比度但低于30Hz人眼会看到明显闪烁。lcd_seg_bits由应用层修改中断里只读修改时最好先关中断或使用临时变量防止16位读写被中断打断。4.2 段码映射从显示缓冲到SEG引脚段码LCD的引脚和显示段的对应关系没有统一标准必须按屏的规格书或实测结果建立映射表。以最常见的7段数字加小数点为例子可以先给每个段位分配一个bit再写一个从数字到段码数组的映射// 假设 bit0a, bit1b, bit2c, bit3d, bit4e, bit5f, bit6g, bit7dp const uint8_t digit_seg[16] { 0x3F, // 0 0x06, // 1 0x5B, // 2 0x4F, // 3 0x66, // 4 0x6D, // 5 0x7D, // 6 0x07, // 7 0x7F, // 8 0x6F, // 9 0x77, // A 0x7C, // b 0x39, // C 0x5E, // d 0x79, // E 0x71, // F }; // 更新显示缓冲 void lcd_display_digit(uint8_t pos, uint8_t value) { if (pos 7) return; if (value 15) value 0; uint8_t seg digit_seg[value]; // 按位写入lcd_seg_bits对应位置 for (uint8_t i 0; i 8; i) { if (seg (1u i)) { lcd_seg_bits | (1u (pos * 8 i)); } else { lcd_seg_bits ~(1u (pos * 8 i)); } } }上面这份映射只适用于“a段对应bit0”的屏实际拿到一块屏更快的办法是用一根飞线依次碰触SEG引脚观察哪个笔画亮把结果填回映射表。段码LCD没有“标准引脚图”这一说相同型号的屏也可能因为PCB走线不同而映射完全不一样这是调试时最容易翻车的地方。4.3 1/2 duty双COM扫描的真值表和代码骨架双COM扫描时两个COM分时选通非选通COM固定为VDD/2SEG仍然只有高低两个状态。显示数据从一维缓冲变成二维数组lcd_buf[2][N_SEG]分别表示两个COM上每个SEG是否点亮。极性翻转依然靠phase变量完成但COM选通和SEG输出要做一次真值表映射。phase选通COMCOM0电平COM1电平SEG点亮输出SEG熄灭输出0COM0VDDVDD/2010COM1VDD/2VDD011COM0GNDVDD/2101COM1VDD/2GND10可以看到点亮段在phase0时输出与选择电平相反的低电平在phase1时输出高电平整体仍是一对反相方波。代码骨架可以这样组织static uint8_t active_com 0; // 当前选通COM static uint8_t frame_phase 0; // 极性翻转标志 static void lcd_com_set(uint8_t com, uint8_t level) { // level: 0GND, 1VDD, 2VDD/2 // 内部通过双IO等值电阻实现见3.2节 } void LCD_Timer_IRQHandler(void) { uint8_t i, seg_level, sel; LCD_SEG_PORT-BRR LCD_SEG_MASK; // 先关SEG防止切换COM瞬间产生直流 if (active_com 0) { lcd_com_set(0, frame_phase ? 0 : 1); // 选择电平随极性翻转 lcd_com_set(1, 2); // 非选通COM固定VDD/2 } else { lcd_com_set(0, 2); lcd_com_set(1, frame_phase ? 0 : 1); } sel frame_phase ? 0 : 1; for (i 0; i N_SEG; i) { if (lcd_buf[active_com] (1u i)) { seg_level sel ? 0 : 1; // 亮段反相 } else { seg_level sel; // 灭段同相 } HAL_GPIO_WritePin(LCD_SEG_PORT, seg_pin[i], seg_level ? GPIO_PIN_SET : GPIO_PIN_RESET); } active_com ^ 1; if (active_com 0) { frame_phase ^ 1; // 一个完整帧结束极性翻转 } }代码里先BRR把所有SEG拉到低再去切换COM是为了避免新COM电平建立之前SEG还保持着上一个时间片的旧电平导致瞬间出现违反真值表的电压组合。这个细节对对比度和寿命都有影响。中断周期这时不再是半帧而是1/4周期因为一个完整驱动周期里包含两个COM时隙和两次极性翻转。若目标帧率60Hz中断周期约4.16ms若用8ms中断最终帧率约31Hz会看到轻微闪烁。4.4 关键参数表与调参顺序参数推荐范围说明帧率50Hz~80Hz低于30Hz闪烁高于100Hz功耗上升时隙长度帧率×COM数 的倒数2COM、60Hz时约4.16ms偏压电阻100kΩ~220kΩ影响VDD/2精度和波形沿驱动电压按LCD规格书常见3.0V~3.3V过高会残影相位翻转必须完整帧后执行漏翻会造成直流偏置调参时先固定中断周期让COM方波频率落在60Hz附近再用示波器看选中SEG和COM的相位关系最后才去调偏压电阻和驱动电压。顺序反了容易把显示异常误判成代码bug。5. 直接用IO驱动段码LCD的调试波形验证、残影处理和更省IO的出路5.1 示波器验证测量平均电压和相位IO直驱段码LCD的调试不能靠肉眼必须依赖示波器。把CH1接到当前COM引脚CH2接到SEG引脚触发模式设为正常先确认两者都是方波。点亮状态下两个通道应该是反相的而且占空比都接近50%熄灭状态下两个通道同相。接着用示波器的平均测量功能看COM和SEG的直流平均值正常应该在0V附近误差不要超过50mV。如果直流偏置超过100mV说明帧翻转没有正确执行或者COM的VDD/2电阻网络不对称。对于双COM的屏还要单独检查VDD/2节点。万用表直流档测COM非选通时段的对地电压稳定在VDD/2附近偏差超过10%就要换电阻。示波器探头会引入约几十pF负载测量高频边沿时会看到波形变缓这是正常现象不要因此去缩短中断周期。5.2 常见现象残影、鬼影、对比度低现象最可能原因对策某段一直隐隐显示该段存在直流偏置检查该SEG与COM是否保持同相/反相上电瞬间整屏黑块IO上电顺序错误初始化先全部输出低再开扫描不该亮的段有浅灰感偏压比不对或VDD/2不准换1%电阻校准分压点显示内容拖尾消退很慢帧率太低或扫描时间过长提高到60Hz以上温度升高后对比度下降LCD特性随温度变化确认驱动电压在规格书范围残影还有一个隐蔽来源MCU进入低功耗模式前没有停止LCD扫描而是直接把GPIO切成了输入态导致LCD电极悬空。进入Stop模式前应先把所有COM和SEG统一输出低电平再停定时器。5.3 如果IO不够IO模拟三线操作HT1621段数超过32段或需要1/4 duty时继续坚持IO直驱会非常难受。业界更常规的做法是换用带驱动IC的段码LCD模组比如HT1621MCU用三根普通IO模拟其CS、WR、DATA时序HT1621内部自己完成1/4 duty扫描和1/3偏压。代码结构和上面的静态驱动很类似只是把“定时器翻转”换成“按位写入命令/数据”显示缓冲改在驱动芯片内部。这时候说“直接用IO驱动段码LCD”指的是直接操作IO协议而不是直接驱动玻璃屏——上手调试前先确认好手里屏的类型。先把COM和SEG的波形调到“亮段反相、灭段同相平均值接近0V”再谈对比度调节否则所有后续优化都是在不稳的地基上盖楼。本文还有配套的精品资源点击获取
返回列表