最近在做STC32G+I2C OLED屏幕+UART激光测距模块的实验,由于将屏幕刷新写在串口的中断void Uart1_Isr() interrupt 4里面会严重影响单片机性能(可能导致卡死),于是将其改成了不断刷新距离变量LaserRanging_Char,然后通过定时器0定期中断将缓存发送给屏幕(OLED_BuffShow()

void Timer0_Isr(void) interrupt 3
{
    unsigned char Freq_Hz = 1; // 20Hz刷新频率
    Timer0_Counter++;
    if (Timer0_Counter >= (1000/Freq_Hz)) // 1000ms/Freq_Hz
    {
        OLED_BuffShow();
    }
}

void Timer0_Init(void)		//1毫秒@33.1776MHz
{
	AUXR |= 0x80;			//定时器时钟1T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x66;				//设置定时初始值
	TH0 = 0x7E;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
}

于是出现了这样的一幕:

WTF?这屏幕之前用着不是好好的,我寻思代码也没问题啊……

于是,我尝试了包括但不限于以下这些办法:

  • 【失败】更换屏幕硬件

  • 【失败】更换连接排线

  • 【失败】更换供电电源(因为怀疑可能是供电不足导致信号出现问题)

  • 【失败】只让Timer0_Isr定期刷新标志位OLED_Refesh_Flag,然后用主程序刷新屏幕

void Timer0_Isr(void) interrupt 3
{
    unsigned char Freq_Hz = 1; // 20Hz刷新频率
    Timer0_Counter++;
    if (Timer0_Counter >= (1000/Freq_Hz)) // 1000ms/Freq_Hz
    {
        OLED_Refesh_Flag = 1;
        Timer0_Counter = 0;
    }
}

void main(void)
{
    EA = 1;                             //开总中断
    Sys_Init();                         //系统初始化
    Uart1_Init();                       //串口1初始化
    Uart_Port_Init();                   //串口端口初始化
    Timer0_Init();                      //定时器0初始化
    OLED_Init();                        //OLED初始化
    OLED_LaserRanging_UI_Init();        //初始化激光测距UI
    while (1)
    {
        key1_check();                   //检查按键1
        key2_check();                   //检查按键2
        key3_check();                   //检查按键3
        key4_check();                   //检查按键4
        if(OLED_Refesh_Flag)            //刷新OLED
        {
            OLED_Refesh_Flag = 0;
            OLED_BuffShow();
        }
    }
}

然而问题还是没有解决。

最终在某个论坛看到了一篇帖子,也是说OLED显示错位或乱码,其中提到可能是因为I2C通信过程中,被其他中断干扰的原因:

遂修改代码,重新下载:

void main(void)
{
    EA = 1;                             //开总中断
	// 其他代码...
    while (1)
    {
		// 其他代码...
        if(OLED_Refesh_Flag)            //刷新OLED
        {
            OLED_Refesh_Flag = 0;
            EA = 0;                   //关总中断
            OLED_BuffShow();
            EA = 1;                   //开总中断
        }
    }
}

果不其然,在给屏幕发送缓存的时候,暂时关闭总中断,就不会有乱码或者错位的情况了

另外也尝试了一下,直接全部一堆写在中断里面也是不行的……

还是老老实实用main函数处理吧……

代码开源:https://github.com/PatZer0/STC32G_EXP