找回密码
 立即注册
楼主: cb20cb24

LED12864全彩万年历 双8H8K64U

[复制链接]
已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 15:05:30 | 显示全部楼层
Ayb_*** 发表于 2026-10-13 14:58
显示要放在定时中断中

大神说的是杂点是因为使用PWM的原因吗?
麻烦看看程序,要怎么改
#include <STC8H.H>
#include "intrins.h"

#define     u16    unsigned int
#define     u8   unsigned char

sbit R1        =P2^0;          //蓝色数据1
sbit G1        =P2^1;                 //绿色数据1
sbit b1        =P2^2;                 //红色数据1
sbit R2        =P2^3;                 //蓝色数据2
sbit G2        =P2^4;                 //绿色数据2
sbit b2        =P2^5;                 //红色数据2
sbit CLK =P3^6;                //ICN2037时钟信号
sbit LE        =P5^1;                //ICN2037锁存信号
sbit OE        =P3^4;                 //点阵屏显示片选信号
sbit IA  =P4^0;   //行控制线A
sbit IB  =P4^1;   //行控制线B
sbit IC  =P4^2;   //行控制线C
sbit ID  =P4^3;   //行控制线D
sbit IEN =P4^4;   //行控制线E(控制上半屏和下半屏)

sbit    SPI_SS  = P5^4;
sbit    SPI_SI  = P1^3;
sbit    SPI_SO  = P1^4;
sbit    SPI_SCK = P1^5;

sbit LED1 = P5^3;
sbit LED2 = P0^5;
sbit LED3 = P0^6;

#define BUF_LENGTH          4096   //缓存空间是4096字节
#define BUF_LENGTL          4096
#define idex1      (BUF_LENGTH)   //SPI缓冲长度
#define idex2      (BUF_LENGTL)   //SPI缓冲长度
volatile u16  SPI_Cnt ;    //SPI计数
volatile bit spi_frame = 0;//缓存转换标志

xdata u8   SpiBuff1[idex1];//128*32行=4096字节缓存
xdata u8   SpiBuff2[idex2];

u16 ADC_temp;

//行扫描函数
void scan(u8 Hang)
{
        PWMB_ENO = 0x00;                //关显示
        switch(Hang)
        {
                        case  0: IA=0;IB=0;IC=0;ID=0;IEN=0;break;
                        case  1: IA=1;IB=0;IC=0;ID=0;IEN=0;break;
                        case  2: IA=0;IB=1;IC=0;ID=0;IEN=0;break;
                        case  3: IA=1;IB=1;IC=0;ID=0;IEN=0;break;
                        case  4: IA=0;IB=0;IC=1;ID=0;IEN=0;break;
                        case  5: IA=1;IB=0;IC=1;ID=0;IEN=0;break;
                        case  6: IA=0;IB=1;IC=1;ID=0;IEN=0;break;
                        case  7: IA=1;IB=1;IC=1;ID=0;IEN=0;break;
                        case  8: IA=0;IB=0;IC=0;ID=1;IEN=0;break;
                        case  9: IA=1;IB=0;IC=0;ID=1;IEN=0;break;
                        case 10: IA=0;IB=1;IC=0;ID=1;IEN=0;break;
                        case 11: IA=1;IB=1;IC=0;ID=1;IEN=0;break;
                        case 12: IA=0;IB=0;IC=1;ID=1;IEN=0;break;
                        case 13: IA=1;IB=0;IC=1;ID=1;IEN=0;break;
                        case 14: IA=0;IB=1;IC=1;ID=1;IEN=0;break;
                        case 15: IA=1;IB=1;IC=1;ID=1;IEN=0;break;
                        case 16: IA=0;IB=0;IC=0;ID=0;IEN=1;break;
                        case 17: IA=1;IB=0;IC=0;ID=0;IEN=1;break;
                        case 18: IA=0;IB=1;IC=0;ID=0;IEN=1;break;
                        case 19: IA=1;IB=1;IC=0;ID=0;IEN=1;break;
                        case 20: IA=0;IB=0;IC=1;ID=0;IEN=1;break;
                        case 21: IA=1;IB=0;IC=1;ID=0;IEN=1;break;
                        case 22: IA=0;IB=1;IC=1;ID=0;IEN=1;break;
                        case 23: IA=1;IB=1;IC=1;ID=0;IEN=1;break;
                        case 24: IA=0;IB=0;IC=0;ID=1;IEN=1;break;
                        case 25: IA=1;IB=0;IC=0;ID=1;IEN=1;break;
                        case 26: IA=0;IB=1;IC=0;ID=1;IEN=1;break;
                        case 27: IA=1;IB=1;IC=0;ID=1;IEN=1;break;
                        case 28: IA=0;IB=0;IC=1;ID=1;IEN=1;break;
                        case 29: IA=1;IB=0;IC=1;ID=1;IEN=1;break;
                        case 30: IA=0;IB=1;IC=1;ID=1;IEN=1;break;
                        case 31: IA=1;IB=1;IC=1;ID=1;IEN=1;break;
                        default:break;
        }       
        PWMB_ENO = 0x40;                //开显示
}

void SPI_Isr() interrupt 9
{        
                SPSTAT = 0xc0; //清中断标志       
         if (SPI_Cnt < 4096)
    {               
                        if(spi_frame)                //切换缓存
                        {
                                SpiBuff2[SPI_Cnt] = SPDAT;
                                SPI_Cnt++;
                        }
                        else
                        {
                                SpiBuff1[SPI_Cnt] = SPDAT;
                                SPI_Cnt++;                       
                        }
                }               
                if (SPI_Cnt >= 4096)
                        {
                                SPI_Cnt = 0;
                                spi_frame = !spi_frame; // 一帧接收完毕,切换缓冲
                        }
}

void SPI_init(void)
{
        SPI_SS = 1;
        SPCTL = 0x64;       //使能 SPI 从机模式进行待机,传输期间SS引脚一直为低
//        P_SW1 |= 0x00;                  // P3.5 P3.4 P3.3 P3.2
        IE2 = ESPI;        //使能 SPI 中断
        SPSTAT = 0xc0;                   //清中断标志
        SPI_Cnt = 0;                        //计数标志
        spi_frame = 0;                //缓存转换标志
}
//显示函数
void display()
{
    bit frame;
    u8 r, i;
    u16 j;
     
    EA = 0;
    frame = spi_frame; // 锁定当前要显示缓存
                LED1 = frame;
    EA = 1;
   
    if(frame)   
    {   
        for(r = 0; r < 32; r++)
        {                                    
                                                scan(r);     // 换行       
                                               
            j = r * 128; // 每行开始前,j定位到该行的第一个字节
                                               
            for(i = 0; i < 128; i++)   
            {
                P2 = SpiBuff1[j]; // 取出一个字节 (P2.0~P2.5 对应6根数据线)
                j++;  
                                                       
                CLK = 1;
                CLK = 0;
            }
            LE = 1;       
            LE = 0;                                                       
        }
    }   
    else                      //切换到另一个缓存
    {
        for(r = 0; r < 32; r++)
        {                                   
                                        scan(r);     // 换行
                                       
                                        j = r * 128;
                               
                                        for(i = 0; i < 128; i++)   
                                        {
                                                        P2 = SpiBuff2[j];
                                                        j++;              
                                                        CLK = 1;
                                                        CLK = 0;
                                        }
            LE = 1;       
            LE = 0;                                                       
        }        
    }
}
void PWM8_Init(void)
{
    PWMB_PSCRH = 0x00;
    PWMB_PS = 0x40;                                //使用P3.4  pwm8
    PWMB_CCER2 = 0x00;
    PWMB_CCMR4 = 0x60;
    PWMB_CCER2 = 0x10;
    PWMB_ARR  = 2601;
    PWMB_CCR8 = 2550;
    PWMB_ENO = 0x40;
    PWMB_BKR = 0x80;
    PWMB_CR1 = 0x01;
}

void ADC_Init(void)
{
    ADCTIM = 0x3f; //设置 ADC 内部时序
    ADCCFG = 0x20; //设置 ADC 时钟为系统时钟/2/1
    ADC_CONTR = 0x80; //使能 ADC
}
// 启动一次通道 10(光敏) 的 AD 转换
int ADCRead()
{       
    ADC_CONTR |= 0x40; //启动 AD 转换
    _nop_();
    _nop_();
    _nop_();
    _nop_();

    while (!(ADC_CONTR & 0x20)); //查询 ADC 完成标志
    ADC_CONTR &= ~0x20; //清完成标志
   return (ADC_RES << 8) | ADC_RESL; //读取 ADC 结果  
}

void main()
{       
        u8 count;
       
        P_SW2 |= 0X80;
        P0M0 = 0x00; P0M1 = 0x07; //p0.0高阻,ADC10
        P1M0 = 0x00; P1M1 = 0x00;
        P2M0 = 0xff; P2M1 = 0x00;
        P3M0 = 0x00; P3M1 = 0x00;
        P4M0 = 0x00; P4M1 = 0x00;
        P5M0 = 0x00; P5M1 = 0x00;
        P6M0 = 0x00; P6M1 = 0x00;
        P7M0 = 0x00; P7M1 = 0x00;  
        P2SR = 0xff;    //转换速度最快
        P1SR |= 0x38;
        P5SR |= 0x10;

        ADC_Init();
        PWM8_Init();
        SPI_init();
  EA=1;
    while(1)
    {
                        count++;
                        if(count > 32)                                //不想频繁转换亮度,随便多少都可以
                        {
                                count = 0;
                                ADC_CONTR = 0x80|10; //通道10
                                ADC_temp =        ADCRead();                                        //进行亮度AD转换
                               
                                if(ADC_temp<3300)PWMB_CCR8 = 2450;                                                                        //最亮
                                if(ADC_temp>=3330 && ADC_temp<3360)PWMB_CCR8 = 2465;
                                if(ADC_temp>=3360 && ADC_temp<3390)PWMB_CCR8 = 2480;
                                if(ADC_temp>=3390 && ADC_temp<3420)PWMB_CCR8 = 2495;
                                if(ADC_temp>=3420 && ADC_temp<3450)PWMB_CCR8 = 2510;
                                if(ADC_temp>=3450 && ADC_temp<3480)PWMB_CCR8 = 2525;
                                if(ADC_temp>=3480 && ADC_temp<3510)PWMB_CCR8 = 2540;
                                if(ADC_temp>=3510 && ADC_temp<3540)PWMB_CCR8 = 2555;
                                if(ADC_temp>=3540 && ADC_temp<3570)PWMB_CCR8 = 2570;
                                if(ADC_temp>=3570 && ADC_temp<3590)PWMB_CCR8 = 2585;                               
                                if(ADC_temp>=3590)PWMB_CCR8 = 2599;                  //最暗                       
                        }
                        display();                                       
    }
}
回复

使用道具 举报 送花

已绑定手机

24

主题

701

回帖

2731

积分

金牌会员

积分
2731
发表于 2026-10-13 15:58:24 | 显示全部楼层
cb20*** 发表于 2026-10-13 15:05
大神说的是杂点是因为使用PWM的原因吗?
麻烦看看程序,要怎么改
#include

我只是按一般情况说的,不知道你这屏是什么接口的,如果自带控制器的,不需要中断显示
回复

使用道具 举报 送花

已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 16:39:19 | 显示全部楼层
Ayb_*** 发表于 2026-10-13 15:58
我只是按一般情况说的,不知道你这屏是什么接口的,如果自带控制器的,不需要中断显示 ...

是HUB75E接口。
回复

使用道具 举报 送花

已绑定手机

20

主题

1456

回帖

4428

积分

论坛元老

积分
4428
发表于 2026-10-13 17:47:40 | 显示全部楼层
我测试过HUB75接口红绿双色的126*64显示屏,直接用定时器刷新显示即可,一片8H8K64U对付128*64的LED屏不会有问题,程序可以再优化。
回复

使用道具 举报 送花

已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 17:49:31 | 显示全部楼层
21cns*** 发表于 2026-10-13 17:47
我测试过HUB75接口红绿双色的126*64显示屏,直接用定时器刷新显示即可,一片8H8K64U对付128*64的LED屏不会 ...

大神能把程序发上来,学习一下吗?感谢
回复

使用道具 举报 送花

已绑定手机

2

主题

153

回帖

466

积分

中级会员

积分
466
发表于 2026-10-13 18:25:57 | 显示全部楼层
当for循环正在显示SpiBuff1时,
spi把SpiBuff2填满了,
然后切换到SpiBuff1继续填充buf,
接着越过了当前正在显示的部分,
显示出来的结果就是有部分字是乱的,出现杂点,
如:某字左半像素是SpiBuff1,字的后半像素是刚写进的。




回复

使用道具 举报 送花

已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 18:52:20 | 显示全部楼层
jrc*** 发表于 2026-10-13 18:25
当for循环正在显示SpiBuff1时,
spi把SpiBuff2填满了,
然后切换到SpiBuff1继续填充buf,

感谢,我把PWM注释掉,用IO口直驱就不会有杂点,仔细看时间显示部分,只有秒数据是变化的,但是秒部分则很少有杂点。杂点则多半是出现在左半屏,我也试过只用一组缓存,不用PWM也是显示正常的。
回复

使用道具 举报 送花

已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 18:57:38 | 显示全部楼层
cb20*** 发表于 2026-10-13 18:52
感谢,我把PWM注释掉,用IO口直驱就不会有杂点,仔细看时间显示部分,只有秒数据是变化的,但是秒部分则 ...

不知道是不是干扰的问题,毕竟是用转换盘加洞洞板焊接的,PWM换过3个引脚都不行
回复

使用道具 举报 送花

已绑定手机

1

主题

11

回帖

191

积分

注册会员

积分
191
 楼主| 发表于 2026-10-13 20:09:21 | 显示全部楼层
jrc*** 发表于 2026-10-13 18:25
当for循环正在显示SpiBuff1时,
spi把SpiBuff2填满了,
然后切换到SpiBuff1继续填充buf,

非常感谢您的回复,其实最早我也考虑过这个问题,只用一个缓存,为什么也能够正常显示,也迷惑就像您说的那样:某字左半像素是SpiBuff1,字的后半像素是刚写进的。刚才我又看了看,数据处理那部分,终于明白是为什么了,在每次读数据的时候都会清屏(因为不清屏的话显示乱码)在一帧数据里面新的数据变化的话也是清屏的数据,是0,所以完全没有必要使用双缓存。使用一个就行。我使用的是全屏清屏,不知道怎么判断数据的变化,所以不会使用局部清屏。
回复

使用道具 举报 送花

已绑定手机

2

主题

153

回帖

466

积分

中级会员

积分
466
发表于 2026-10-13 21:00:34 | 显示全部楼层
cb20*** 发表于 2026-10-13 20:09
非常感谢您的回复,其实最早我也考虑过这个问题,只用一个缓存,为什么也能够正常显示,也迷惑就像您说的 ...

我说的那个,满足的条件不容易,
当spi主机的时钟比较快时,才可能追上for循环中的显示。
只是表示有可能而已。

既然屏蔽pwm就没问题,那就是其他原因了,
可能是你说的干扰。
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 10:34 , Processed in 0.075373 second(s), 84 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表