显示器超频

对处理器或内存进行超频是可以理解的,但是为什么对显示器的背光进行超频呢?



关于采用LED背光灯的23英寸旧三星SyncMaster BX2340(于2011年1月发布)。 随着时间的流逝,他开始注意到为他工作很累,并且越来越难以集中精力。 而且不仅工作,例如阅读。 监视器本身保持不变,但是对我来说却变得更加困难。 对于其他屏幕,它的效果还不错。

上网后,我便了解到带有OLED显示屏且刷新率为240 Hz的手机用户的主观感受。 感到疲劳和头痛。 并且有参考文献(没有证据)研究背光源的调光频率对身体的影响:尽管眼睛在240 Hz处看不到闪烁,但大脑对此有反应。 持续发光或频率超过3 kHz不会以这种方式使大脑负荷。

然后在YouTube上,我得到了一段视频,内容涉及如何重新制作显示器的背光以产生直流电。 对该计划的干预是主要的。 视频下方有关于电线上低电流时颜色偏移的评论。 我的背光灯工作在10-25%,因为房间很暗。 UPD :在视频中,作者只有一个LED花环,而我只有4个。

决定离开使用PWM的亮度控制,但增加频率。 我什至没有开始通过使用光敏电阻或光电二极管的非侵入式方法来测量闪烁,我立即拆下了显示器。



背光控制器-OZ9993CN。 没有正常的数据表,只有O 2 Micro制造的组背光驱动器。 事实证明,驱动器还涉及使用强大的外部场效应晶体管和电感来提高电压(根据从14.4 V至54.6 V的测量值)。

其中一个电路与驱动器的含义相似;引脚号不匹配:



在板上,到驱动器的PWM信号路径被标记为B-Dim(背光调光?),我不必搜索。 接下来,在PC端结合了sigrok的USBee AX USB数字示波器的克隆开始了。 测量显示背光频率为180 Hz(这还不够!)。 高信号电平-5V。



现在,您需要以某种方式每16次将PWM频率提高到千赫兹值。首先想到的是将微控制器插入PWM轨道间隙中以接收信号并将其播放速度提高16倍。 我们需要2个计时器,一个计时器将测量低电平和高电平的持续时间,另一个计时器将给出PWM信号。 拿到分频器的系数后,我们只需复制就可以完全不用算术。 不,Arduino不会。 也不会有汇编程序,会有GCC。 带有至少两个计时器的小型MK(来自库存)是ATtiny15。 但是WinAVR不想使用它,因此我不得不使用一个较旧的版本-ATtiny45(ATtiny25 / 85也可以使用)。

方案:

100n ┌───────┤├───────┐ │ ┌────────────┐ │ │ │ 1 8 ├─┴─ VCC │ │ 2 7 ├─ PB2 (INT0) INPUT │ │ 3 6 ├─ PB1 (OC1A) OUTPUT GND ─┴─┤ 4 5 │ └────────────┘ ATtiny45 

我们选择定时器分频器的因数。 从内置的RC发生器中获取大约8 MHz的CPU频率。

  • 测量计时器。 调光期间有多少措施? 8000000/180\约44444。 为了使其以最小的精度损失装入定时器的八位寄存器中,我们采用预分频器256,计数器的最大值为 8,000,000/180/256\约$173.
  • PWM定时器 我们将频率提高16倍: 180 cdot16=2880,则预分频器会小很多倍: 256/16=16

输入信号连接到外部中断脚。 处理程序:

 /* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { uint8_t timer = TCNT0; //     if (PINB & 1<<PB2) { //  .   -    OCR1C = timer; //   TCNT0 = 0; //     } else { //   -  OCR1A = timer; //   } reti(); } 

什么是ISR_NAKED?
“ ISR_NAKED”表示丢弃/恢复处理器的寄存器和标志,这样做是为了加快速度。 可以通过确保它们在主循环中不受影响(我们在其中只有一个无限的while(1) {} )并且不会从子例程进行调用来完成此操作。 好吧,最后,我们规定了从函数返回的结果,其中包含了reti()中断reti()标志。

焊接,闪烁-确实有效!



但是油门开始吱吱作响。 我们看一下现场控制器的门上有什么东西,它控制流过功率电感器的电流:



一切都与节气门保持一致,它继续以320 kHz的频率运行,但是如果更早的PWM频率为180 Hz,几乎听不到(仅当您带上耳朵时),那么2.9 kHz的声音还是可以听见的。 并且舒适度显然没有增加。 但是,如果您使频率超过可听度上限,该怎么办? 举个例子 180 cdot128=23040? 我们将PWM定时器分频器的乘法器从16更改为2,并对其进行闪烁。 事实证明,一切都井井有条。 差不多了

在这种情况下,八位定时器是不够的,您需要更多的矿物质 。 这以亮度的低频波动形式表现出来,几秒钟的频率平滑地增加和消失。 为了应对这种祸害,您可以使晶体更胖,但这不是我们的方法。 我们将以编程方式增加测量计时器的位深度,并引入一个阈值(磁滞),以可靠地检测用户的亮度切换(分辨率为1的0-100)。 我们将测量计时器的精度提高了256倍,并且乘数因子等于1。

使用选项“出了点问题并且持续了水平的持续时间”来测量计时器溢出处理程序:

 /* Timer/Counter0 Overflow */ ISR(TIM0_OVF_vect, ISR_NAKED) { #define TIME_H_LIM (UCHAR_MAX-1) if (time_h < TIME_H_LIM) { // Normal way time_h += 1; } else { // High part overflowed if (PINB & 1<<PB2) { OCR1A = TIME_H_LIM; // Always on } else { OCR1A = 0; // Always off } OCR1C = TIME_H_LIM; time_h = 0; time_cycle = 0; time_on = 0; } reti(); // Because ISR_NAKED } 

外部中断现在也更加复杂:

 /* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { // F_CPU / Timer1 prescaler / F_PWM_IN / grades / 4 #define THRESHOLD (F_CPU / 1 / F_PWM_IN / 100 / 4) uint16_t time; uint8_t time_l = TCNT0; if ((TIFR & 1<<TOV0) && (time_l <= UCHAR_MAX/2)) { // Overflow occured right now time_l = UCHAR_MAX; // 0xff } time = (time_h << 8) + time_l; if (PINB & 1<<PB2) { // Risen if (abs(time - time_cycle) > THRESHOLD) { time_cycle = time; OCR1C = time_h; } TCNT0 = 0; time_h = 0; if (TIFR & 1<<TOV0) { TIFR = 1<<TOV0; // Clear Timer0 overflow flag } } else { // Falled if (abs(time - time_on) > THRESHOLD) { time_on = time; OCR1A = time_h; } } reti(); // Because ISR_NAKED } 

我将全局变量放入寄存器中,毕竟我们已经超频了。 SRAM仅在进入中断处理程序时用于存储返回地址。 间隔测量计数器的最高部分在变量time_h中,而测量的PWM周期长度和占空比的值分别在time_cycle和time_on中。 阈值-用于检测亮度变化的阈值。

现在一切都按预期工作了。

完整代码
 /* PWM frequency multiplier x128 100n ┌───────┤├───────┐ │ ┌────────────┐ │ │ │ 1 8 ├─┴─ VCC │ │ 2 7 ├─ PB2 (INT0) INPUT │ │ 3 6 ├─ PB1 (OC1A) OUTPUT GND ─┴─┤ 4 5 │ └────────────┘ ATtiny45 fuses: lfuse=0xe2 hfuse=0xdf */ #include <avr/interrupt.h> #include <avr/wdt.h> #include <stdlib.h> #include <limits.h> #define F_CPU 8000000UL #define F_PWM_IN 180U register uint8_t time_h asm("r4"); // High part of time counter register uint16_t time_cycle asm("r12"); // Period register uint16_t time_on asm("r14"); // H level duration __attribute__((naked)) int main(void) { time_h = 0; time_cycle = 0; time_on = 0; ACSR |= 1<<ACD; // Comparator disable // Timer0 TCCR0A = 0; // CK/1 TCCR0B = 1<<CS00; // Timer1 DDRB |= 1<<PB1; // PWM output // CK/2, Clear the OC1A output line TCCR1 = 1<<CTC1|1<<PWM1A|2<<COM1A0|2<<CS10; TIMSK |= 1<<TOIE0; // Timer0 overflow // Ext int 0 MCUCR |= 1<<ISC00; // Any logical change on INT0 generates an interrupt request GIMSK |= 1<<INT0; // External Interrupt Request 0 Enable PORTB |= 1<<PB2; // Input wdt_enable(WDTO_120MS); // Watchdog on sei(); // Interrupts enable while (1) { // Do not use flags or registers wdt_reset(); // Watchdog reset } } /* External Interrupt 0 */ ISR(INT0_vect, ISR_NAKED) { // F_CPU / Timer1 prescaler / F_PWM_IN / grades / 4 #define THRESHOLD (F_CPU / 1 / F_PWM_IN / 100 / 4) uint16_t time; uint8_t time_l = TCNT0; if ((TIFR & 1<<TOV0) && (time_l <= UCHAR_MAX/2)) { // Overflow occured right now time_l = UCHAR_MAX; // 0xff } time = (time_h << 8) + time_l; if (PINB & 1<<PB2) { // Risen if (abs(time - time_cycle) > THRESHOLD) { time_cycle = time; OCR1C = time_h; } TCNT0 = 0; time_h = 0; if (TIFR & 1<<TOV0) { TIFR = 1<<TOV0; // Clear Timer0 overflow flag } } else { // Falled if (abs(time - time_on) > THRESHOLD) { time_on = time; OCR1A = time_h; } } reti(); // Because ISR_NAKED } /* Timer/Counter0 Overflow */ ISR(TIM0_OVF_vect, ISR_NAKED) { #define TIME_H_LIM (UCHAR_MAX-1) if (time_h < TIME_H_LIM) { // Normal way time_h += 1; } else { // High part overflowed if (PINB & 1<<PB2) { OCR1A = TIME_H_LIM; // Always on } else { OCR1A = 0; // Always off } OCR1C = TIME_H_LIM; time_h = 0; time_cycle = 0; time_on = 0; } reti(); // Because ISR_NAKED } 


您可以称之为自动建议,但是结果是:生活变得更好,生活变得更加有趣! 甚至长期的项目也继续前进。

如果您的情况下背光频率不会以任何方式影响您的健康和生产力,请考虑自己。 大概吧 以及确保房间中CO 2含量超过0.2%(2000 ppm )时绝对舒适的人们。

但是到github的链接呢?

Source: https://habr.com/ru/post/zh-CN448730/


All Articles