中颖SH79F9476 的LED驱动笔记
我的理解:
就是运用该芯片内部的LED驱动器的RAM表,有2种不同的驱动方式。
需要呼吸灯效果的,只能选择模式1:单次扫描,使用RAM2 的表
通过软件选择当前要扫描的COM(单COM),启动扫描,该COM扫描结束后,表示该次扫描结束;COM扫描期间,
SEG01/SEG02中每个bit位控制一个SEG,当该bit位为0时,该SEG口状态由IO控制;当该bit位为1时,该SEG口输出恒流。
该次扫描结束后,LED驱动器对应的中断标志位COMIF位置1,LED停止扫描。
SEG的输出宽度有两种控制方式
方式1:SEG的输出周期宽度与COM的宽度一样(当COM_CON的BIT5=0时)
方式2:SEG的输出周期宽度由RAM2控制(当COM_CON的BIT5=1时)
COM输出结束中断处理函数中,设置:
for (led_isr_seg = 0; led_isr_seg < 16; led_isr_seg++)
{
*pled = RcomDuty[led_isr_seg]; // seg1~seg16
pled++; // 将数组的内容按顺序填充到RAM2中,真正刷新SEG显示亮度duty的地方
}
COM_CON |= 0x88; // GO
for (led_isr_seg = 0; led_isr_seg < 16; led_isr_seg++)
{ // 加载下一帧
RcomDuty[led_isr_seg] = ComSegDutyBuf[led_isr_com][led_isr_seg]; //
}
将当前COM口的16个SEG数据通过赋值刷新到RAM2的表中,实现硬件的LED刷新。
准备下一个COM的16个SEG数据。
在主循环中修改这个8*16个ComSegDutyBuf数组的内容即可。
出现鬼影啦!
猜想:可能是因为正反推的原因,导致会有给占空比赋值是0时候,产生“鬼影”。
因此需要调整刷新的程序结构。
调整后的部分代码如下:
void isr_LEDMC(void) interrupt 8
{
unsigned char geWei = 0;
unsigned char shiWei = 0;
unsigned char baiWei = 0;
_push_(INSCON);
INSCON &= 0xBF; // 选择特殊功能寄存器页0
p_seg_duty = R_ledDATA_RAM_ADDR2; // SEG1duty地址 赋值给指针变量
// COM_CON &= 0xB0; //清除 COM 输出结束中断标志位
COM_CON &= 0x38; // 清除 COM 输出结束中断标志位
led_isr_com++;
//-----------------------------------------------------------------------------------------
if (100 != battery_level) // 处理电量显示
{
geWei = battery_level % 10;
shiWei = battery_level / 10;
baiWei = 0;
}
else
{
geWei = 0;
shiWei = 0;
baiWei = 1;
}
//-----------------------------------------------------------------------------------------
switch (led_isr_com)
{
case 1: // COM1
#if (LEDCOMIO & 0x01) // 保证条件是1
COM_CON |= 0x00;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
duan(0, shiWei, 250); // com1 显示"8"
break;
#else
led_isr_com++;
#endif
case 2: // COM2
#if (LEDCOMIO & 0x02)
COM_CON |= 0x01;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
duan(1, geWei, 250); // com2 显示"8"
break;
#else
led_isr_com++;
#endif
case 3: // COM3
#if (LEDCOMIO & 0x04)
COM_CON |= 0x02;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
scanOne(baiWei, 250); // com3 显示"1"
scanLowPower(lowpower); // com3 显示低电量灯
ComSegDutyBuf[2][14] = 0xFF; // 显示 "%"
break;
#else
led_isr_com++;
#endif
case 4: // COM4
#if (LEDCOMIO & 0x08)
COM_CON |= 0x03;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
scanD1(flag_d1);
scanD2(flag_d2);
scanD3(flag_d3);
scanD4(flag_d4);
scanD5(flag_d5);
scanD6(flag_d6);
scanD7(flag_d7);
scanD8(flag_d8);
break;
#else
led_isr_com++;
#endif
case 5: // COM5
#if (LEDCOMIO & 0x10)
COM_CON |= 0x04;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
scanD11(flag_d11);
scanD12(flag_d12);
scanD14(flag_d14);
scanD18(flag_d18);
break;
#else
led_isr_com++;
#endif
case 6: // COM6
#if (LEDCOMIO & 0x20)
COM_CON |= 0x05;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
scanD19(flag_d19);
scanD21(flag_d21);
scanD22(flag_d22);
scanD23(flag_d23);
break;
#else
led_isr_com++;
#endif
case 7: // COM7
#if (LEDCOMIO & 0x40)
COM_CON |= 0x06;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
scanD24(flag_d24);
scanD25(flag_d25);
scanD69(flag_d69);
scanD70(flag_d70);
break;
#else
led_isr_com++;
#endif
case 8: // COM8
#if (LEDCOMIO & 0x80)
COM_CON |= 0x07;
SEG01 = 0; // 选择 SEG1-8
SEG02 = 0; // 选择 SEG9-16
SEG01 = 0xFF; // 选择 SEG1-8
SEG02 = 0xFF; // 选择 SEG9-16
#endif
led_isr_com = 0;
break;
}
for (led_isr_seg = 0; led_isr_seg < 16; led_isr_seg++)
{
*p_seg_duty = SegDuty[led_isr_seg]; // seg1~seg16
p_seg_duty++; // 将数组的内容按顺序填充到RAM2中,真正刷新SEG显示亮度duty的地方
}
COM_CON |= 0x88; // GO
for (led_isr_seg = 0; led_isr_seg < 16; led_isr_seg++)
{ // 加载下一帧
SegDuty[led_isr_seg] = ComSegDutyBuf[led_isr_com][led_isr_seg]; //
}
_pop_(INSCON);
}
消除鬼影后,最后程序的效果就是这样啦!
可留言发原理图~
中颖单片机驱动洗地机LED面板