版主你好,我的OLED12864驱动芯片是ST7567,MCU为AI8051U,用P2端口。通过你的讲解,硬件SPI硬件驱动成功了 ...
不清楚你说的DMA移植不顺利集体是什么,就先忙猜一下是速度问题。
因为不同型号的控制芯片,时序之类其实都不太一样。比如,即便是驱动程序看起来通用的OLED,不同型号之间,对单片机的速度要求也不完全一样。所以,硬件SPI通过了而DMA没通过,就有可能是SPI的速度配置对了,DMA的速度没配置合适。
而ST7567是LCD液晶屏的驱动芯片,不是OLED的,而是跟TFT彩屏是一个系统的,它们对时序要求更高。
大明狐 发表于 2025-8-25 08:30
不清楚你说的DMA移植不顺利集体是什么,就先忙猜一下是速度问题。
因为不同型号的控制芯片,时序之类其实 ...
我可能描述不清楚,重新交流一下。
就是移植后,SPI硬件驱动(无DMA)屏幕能正常驱动显示。加了DMA后,显示不正常,只有第一行(程序中只能显示一行,即第6page,其它页都显示乱码,且显示不对应)显示正常,其它乱码,怎么修改都不得其法。现将截图和程序贴上,请版主指导! Tuier 发表于 2025-8-25 15:34
我可能描述不清楚,重新交流一下。
就是移植后,SPI硬件驱动(无DMA)屏幕能正常驱动显示。加了DMA后,显 ...
不知道没有DMA的成功代码是什么样。从照片上看,用DMA的这个是只刷新了屏幕的最上面一行。
手头也暂时没有这种屏幕,没法测试想法。
这个DMA的代码里,刷新全屏用的是一次性发送1024个数据。
但是找了下ST7567的资料,控制芯片的结构是每个page有132列,只用到其中128列,类似SH1106的OLED屏幕,而且列地址只在指定行里自增和归零,相当于OLED屏幕的“页地址模式”。
这样的话,128×64的区域应该不能用这种方式填充数据,而是分成8行,每次发送128个数据才对。
把OLED_Refresh函数的一次性发送1024个数据,换成分8行发送,每次128个数据试试看?
大明狐 发表于 2025-8-25 16:50
不知道没有DMA的成功代码是什么样。从照片上看,用DMA的这个是只刷新了屏幕的最上面一行。
手头也暂时没有 ...
还是不行{:4_167:}。未成功代码在12楼末尾
void OLED_Refresh(void)
{
uint8_t cmd;
cmd = 0x40; //设置行起始地址
cmd = 0x00; //设置低列起始地址
cmd = 0x10; //设置高列起始地址
OLED_WR_CMD(cmd, 3);
// OLED_WR_DAT(OledCache, 1024); //写数据...
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
OLED_WR_DAT(OledCache, 128);
} Tuier 发表于 2025-8-26 10:06
还是不行。未成功代码在12楼末尾
void OLED_Refresh(void)
{
12楼末尾的代码看过了,上面的回复就是根据这个代码推测的。
关于OLED_Refresh函数的修改方法,结构可以参考显示图片的函数。
分成8行发送,就是分别定位每一行,然后发送对应的128个数据。
你的这个修改,依旧是在第一行里反复发送缓存数组里的钱128个数据。可以借助一个变量,对行号进行递增,然后发送对应的128个数据。
根据芯片手册里关于设置页地址的指令表,是以0xB0为基础的(1011xxxx),低四位是行号,
所以比如像这样写:
void OLED_Refresh(void)
{
uint8_t page;
uint8_t cmd;
for( page=0; page<8; page++ )
{
cmd = 0x40; //设置屏幕最顶上一行作为第0行
cmd = 0xB0+page; //设置行起始地址
cmd = 0x10; //设置低列起始地址(高四位)
cmd = 0x00; //设置高列起始地址(低四位)
OLED_WR_CMD( cmd, 4 );
OLED_WR_DAT( OledCache + page*128 , 128 );
}
}
其中0x40也可以放到初始化函数里,就不用每次都发送了。
大明狐 发表于 2025-8-26 13:54
12楼末尾的代码看过了,上面的回复就是根据这个代码推测的。
关于OLED_Refresh函数的修改方法,结构可以 ...
按照版主老师的程序,显示有所改善:不花屏了,但显示不正常,无法定位显示,自己试着修改其它参数仍不能正常,奈何技术水平有限,再次与版主交流。具体描述如下:
程序里所有页都有内容时,显示如下:
第一种情况:
while (1)
{
//<<AICUBE_USER_MAIN_LOOP_BEGIN>>
// 在此添加主函数中用户主循环代码
OLED_ClearScreen(0);
OLED_SetFontHeight(16);
OLED_DrawString(0, 0, " OLED-12864 ", 0);
OLED_DrawString(0, 2, " 文本模式 ", 0);
OLED_SetFontHeight(8);
OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);
}有显示,但显示不全。而且重复显示。
***************************************************
第二种情况:
屏蔽掉
while (1)
{
//<<AICUBE_USER_MAIN_LOOP_BEGIN>>
// 在此添加主函数中用户主循环代码
OLED_ClearScreen(0);
OLED_SetFontHeight(16);
OLED_DrawString(0, 0, " OLED-12864 ", 0);
OLED_DrawString(0, 2, " 文本模式 ", 0);
OLED_SetFontHeight(8);
// OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
//OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
//OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);
}屏幕无显示。
*******************************************************
第三种情况:
屏蔽掉
while (1)
{
//<<AICUBE_USER_MAIN_LOOP_BEGIN>>
// 在此添加主函数中用户主循环代码
OLED_ClearScreen(0);
// OLED_SetFontHeight(16);
// OLED_DrawString(0, 0, " OLED-12864 ", 0);
// OLED_DrawString(0, 2, " 文本模式 ", 0);
OLED_SetFontHeight(8);
OLED_DrawString(0, 4, "OLED Model : SSD1306", 0);
OLED_DrawString(0, 5, "Target MCU : Ai8051U", 0);
OLED_DrawString(0, 6, "Work Freq. : 40.0MHz", 1);
}只显示第6页。只要把第6页去掉,其它再多的内容都不显示了
只要保留第6页,刷屏只能显示偶数页(0、2、4、6页的内容),奇数页显示是偶数页的内容。
*************************************************
试着修改OLED_Refresh()其它参数,都不得要领。
如果想在第0行、0列开始显示内容,结果是空白。根本无法实现随心所欲在任何位置显示。感觉DMA好难理解{:4_167:}。
Tuier 发表于 2025-8-27 11:08
按照版主老师的程序,显示有所改善:不花屏了,但显示不正常,无法定位显示,自己试着修改其它参数仍不能 ...
刚刚拿到了一块ST7567的屏幕,用你的程序试了一下,的确不是速度原因,而是DMA发送数据的问题。
然后发现,上个回复里的OLED_Refresh函数的修改建议里,发送数据的部分写错了,应该是:
void OLED_Refresh(void)
{
uint8_t page;
uint8_t cmd;
for( page=0; page<8; page++ )
{
cmd = 0x40; //设置屏幕最顶上一行作为第0行
cmd = 0xB0+page; //设置行起始地址
cmd = 0x10; //设置低列起始地址(高四位)
cmd = 0x00; //设置高列起始地址(低四位)
OLED_WR_CMD( cmd, 4 );
OLED_WR_DAT( OledCache + page*128, 128 );
}
}
也可以写成
void OLED_Refresh(void)
{
uint8_t page;
uint8_t cmd;
for( page=0; page<8; page++ )
{
cmd = 0xB0+page; //设置行起始地址
cmd = 0x10; //设置低列起始地址(高四位)
cmd = 0x00; //设置高列起始地址(低四位)
OLED_WR_CMD( cmd, 3 );
OLED_WR_DAT( OledCache + page*128, 128 );
}
}
就是把 0x40 指令拿到初始化函数里
static uint8_t code INIT_SEQU[] =
{
0xAE, //关闭显示
0x40, //设置屏幕第一行为起始行
0xA0, //设置列扫描方向从左向右
0xC8, //设置行扫描方向从上向下
0xB0, //设置起始页地址
0x10,0x00, //设置起始列地址
0xA6, //A6-正常显示,A7-反色显示
0xA4, //A4-正常显示,A5-显示全部点阵
0xA2, //设置偏压比
0x26, //调节电阻比,0x20+
0x2F, //打开电源,0x28+
0x81,0x05, //设置对比度(00h~3Fh)
0xAD, //AD-正常模式,AC-睡眠模式
0xF8,0x00, //设置升压倍数
0xAF, //开启显示
};
这样每次就可以少发一个字节了。
======================================================
下面是用修改OLED_Refresh函数后的显示效果
928
大明狐 发表于 2025-8-28 12:25
刚刚拿到了一块ST7567的屏幕,用你的程序试了一下,的确不是速度原因,而是DMA发送数据的问题。
然后发现 ...
非常感谢版主,成功了!对于初学者或技术不硬来说,一点小细节可以让你想破脑袋。再次感谢版主辛苦付出!愿你工作越来越顺利!{:4_196:}
页:
1
[2]