[ ST NUCLEO-U575ZI-Q 测评] 优化OLED显示
<div class='showpostmsg'><p><a href="https://bbs.eeworld.com.cn/thread-1229117-1-1.html">[ ST NUCLEO-U575ZI-Q 测评] HAL移植U8G2 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)</a></p><p><a href="https://bbs.eeworld.com.cn/thread-1229192-1-1.html">[ ST NUCLEO-U575ZI-Q 测评] 时钟——U8g2 - stm32/stm8 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>
<p>上面的帖子是用u8g2实现OLED的显示,为了更进一步的熟悉ssd1306的使用,以及对hal库i2c的数据发送,这段时间又继续研究了ssd1306的数据发送。</p>
<p>STM32U575的HAL_I2C库的输出操作函数有两种模式,一种是阻塞模式,另一种是非阻塞模式。</p>
<p><strong>阻塞模式</strong>:在轮询模式下执行通信。所有数据处理的状态由同一函数返回完成转移后。</p>
<p><strong>无阻塞模式</strong>:使用中断进行通信或DMA。这些函数返回传输启动的状态。数据处理的结束将通过</p>
<p> </p>
<p>阻塞模式功能发送有:</p>
<p>HAL_I2C_Master_Transmit()</p>
<p>HAL_I2C_Slave_Transmit()</p>
<p>HAL_I2C_Mem_Write()</p>
<p>带中断的无阻塞模式发送有:</p>
<p>HAL_I2C_Master_Transmit_IT()</p>
<p>HAL_I2C_Slave_Transmit_IT()</p>
<p>HAL_I2C_Mem_Write_IT()</p>
<p>DMA无阻塞模式功能:</p>
<p>HAL_I2C_Master_Transmit_DMA()</p>
<p>HAL_I2C_Slave_Transmit_DMA()</p>
<p>HAL_I2C_Mem_Write_DMA()</p>
<p>因为ssd1306的驱动没有做读取函数,所以只需要用到发送即可。</p>
<p>1、首先创建一个ssd1306的缓存,屏幕总共有128*8 = 1024字节,所以建立一个u8 OLED_GRAM;的缓存,用于存放显存数据。</p>
<p>2、把缓存数据发送给ssd1306的第一版函数:</p>
<pre>
<code>//更新显存到OLED
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
for(n=0;n<128;n++)
{
OLED_WR_Byte(OLED_GRAM,OLED_DATA);
}
}
}</code></pre>
<p>这样的话,总共要执行设置行起始地址、设置低列起始地址、设置高列起始地址8次,执行写入从机地址、数据位、位数8*128次。等待超时时间8*3+8*128次。</p>
<p>3、优化为发送数据128位时用一个函数来发送:</p>
<pre>
<code>//更新显存到OLED
void OLED_Refresh(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
//for(n=0;n<128;n++)
//{
// OLED_WR_Byte(OLED_GRAM,OLED_DATA);
//}
修改为一次发送128数据,减少了127个发送从机地址、命令位的时间。
HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM, 128, 100);
}
}</code></pre>
<p>这样的话就优化到少了8*127次发送从机地址+数据位命令的时间。</p>
<p>4、优化页写入命令,将所有数据做一次发送:</p>
<pre>
<code>//在OLED初始化中修改页面寻址方式
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
//OLED_WR_Byte(0x02,OLED_CMD);//把页地址修改为水平方式(页地址0x02,水平0x00,垂直0x01)
OLED_WR_Byte(0x00,OLED_CMD);//
//更新显存到OLED
void OLED_Refresh(void)
{
/*
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址
OLED_WR_Byte(0x10,OLED_CMD); //设置高列起始地址
//for(n=0;n<128;n++)
//{
// OLED_WR_Byte(OLED_GRAM,OLED_DATA);
//}
修改为一次发送128数据,减少了127个发送从机地址、命令位的时间。
HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM, 128, 100);
}
*/
//修改为一次发送1024数据。减少了8*4个地址位发送时间+8*4个数据位令发送时间。
HAL_I2C_Mem_Write(&hi2c1, oled_addr, 0x00,1, &OLED_GRAM, 128, 100);
}</code></pre>
<p>这样的话更进一步少了发送时间。</p>
<p>5、上面为阻塞式发送数据,下面修改为中断发送,首先在stm32cubeMax下配置为中断事件。</p>
<p> 然后修改发送函数为:</p>
<pre>
<code>//更新显存到OLED
void OLED_Refresh(void)
{
HAL_I2C_Mem_Write_IT(&hi2c1, oled_addr, 0x40,1, &OLED_GRAM, 1024);
}</code></pre>
<p>6、更换为DMA发送模式:</p>
<p> 配置好后修改发送函数为:</p>
<pre>
<code>//更新显存到OLED
void OLED_Refresh(void)
{
HAL_I2C_Mem_Write_DMA(&hi2c1, oled_addr, 0x40,1, &OLED_GRAM, 1024);
}
</code></pre>
<p>【总结】经过以上的估化,刷新速度明显提高,而且代码量也变得少了。</p>
<p>
<p> </p>
</p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> <p>测评汇总:免费申请|ST NUCLEO-U575ZI-Q https://bbs.eeworld.com.cn/thread-1228653-1-1.html</p>
页:
[1]