RTT&瑞萨高性能 CPK-RA6M4 开发板测评——SPI驱动OLED
<h1 id="rttandamp瑞萨高性能-cpk-ra6m4-开发板测评spi驱动oled">一、硬件</h1><h3 id="1、oled引脚介绍">1、OLED引脚介绍</h3>
<p>OLED引脚,是7针SPI模式。</p>
<p>1). GND 电源地</p>
<p>2). VCC 电源正(3~5.5V)</p>
<p>3). D0 OLED 的 D0 脚,在 SPI 和 IIC 通信中为时钟管脚</p>
<p>4). D1 OLED 的 D1 脚,在 SPI 和 IIC 通信中为数据管脚</p>
<p>5). RES OLED 的 RES#脚,用来复位(低电平复位)</p>
<p>6). DC OLED 的 D/C#E 脚,数据和命令控制管脚</p>
<p>如图所示:实物引脚。</p>
<p></p>
<p>关于OLED的显示原理就不介绍。</p>
<h3 id="2、接线">2、接线</h3>
<p>1)、VCC接板载3.3V引脚,与板子共地</p>
<p>2)、把SPI0的相应时钟SCLK、数据MOSI关机与OLED的时钟和数据管脚,使用杜邦线连接起来,再使用其他引脚,作为普通管脚,控制OLED的片选CS、复位RES、DC引脚。</p>
<h2 id="二、软件操作">二、软件操作</h2>
<h3 id="1、ra-smart-configurator操作">1、RA Smart Configurator操作</h3>
<p>1)、使用瑞萨灵活配置软件添加SPI0的复用引脚相关的时钟与MOSI引脚,注意,程序中是软件配置片选,因此SPI0硬件片选引脚CS 配置为普通引脚(P703)。同时设置P406(对应OLED的DC)、P405(对应OLED的RES)为普通输出引脚。</p>
<p></p>
<p>2)、设置三个普通引脚模式为输出模式,并且设置为初始化为高电平</p>
<p></p>
<p>3)、添加SPI的配置,设置SPI0的回调函数为spi0_callback。其他都默认,可以在对应的参数设置中,设置SPI工作模式、速率、相位、极性等。另外也可以直接在RTThread中修改相应的配置。</p>
<p></p>
<h3 id="2、rtthread-studio操作">2、RTThread-Studio操作</h3>
<p>1)、添加RTThread对RA6M4支持的SPI驱动。</p>
<p></p>
<p>2)、使能SPI0驱动。</p>
<p></p>
<h3 id="3、代码">3、代码</h3>
<p>1)、OLED驱动代码</p>
<pre>
<code>/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-05-01 LD the first version
*/
#include "OLED.h"
#include "oledfont.h"
#include <rtthread.h>
#include <stdio.h>
#include <drv_spi.h>
//static struct rt_spi_device spi_dev_lcd;
/*OLED段码分布
正常
(page0) SEG0-SEG128
COM0
|
COM7
反置
(page0) SEG128-SEG0
COM63
|
COM56
写命令,其实是写寄存器
*/
static struct rt_spi_device spi_dev_oled;
static int rt_hw_oled_config(void)
{
char user_data[] = {1};
if (rt_spi_bus_attach_device(&spi_dev_oled, "oled", "spi0", user_data) != RT_EOK)
return -RT_ERROR;
/* config spi */
{
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
cfg.max_hz = 5 * 1000 * 1000; /* 42M,SPI max 42MHz,lcd 4-wire spi */
rt_spi_configure(&spi_dev_oled, &cfg);
}
rt_pin_mode(OLED_DC, PIN_MODE_OUTPUT);
rt_pin_mode(OLED_RES, PIN_MODE_OUTPUT);
return RT_EOK;
}
/****************************************************************************
* 名 称:void OLED_Init(void)
* 功 能:OLED初始化
* 入口参数:无
* 出口参数:无
* 说 明:参照上电序列初始化(24/40)
****************************************************************************/
int OLED_Init(void)
{
rt_hw_oled_config();
OLED_CS_High;
//复位OLED
OLED_RST_High;
rt_thread_mdelay(200);
OLED_RST_Low;
rt_thread_mdelay(200);
OLED_RST_High;
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置列低位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置列高位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //设置起始行地址及映射RAM显示起始行 (0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0xB0); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x81); //对比度设置
OLED_Write_Operate(OLED_Mode_Cmd,0xCF); //Set SEG Output Current Brightness
OLED_Write_Operate(OLED_Mode_Cmd,0xA1); //Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //
OLED_Write_Operate(OLED_Mode_Cmd,0xA8); //设置驱动路数(1 to 64)
OLED_Write_Operate(OLED_Mode_Cmd,0x3F); //*duty = 1/64*/
OLED_Write_Operate(OLED_Mode_Cmd,0xC8); //0xc0上下反置 0xc8正常
OLED_Write_Operate(OLED_Mode_Cmd,0xD3); //设置显示偏移(0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //not offset
OLED_Write_Operate(OLED_Mode_Cmd,0xD5); //--set Display clock divide ratio/oscillator frequency
OLED_Write_Operate(OLED_Mode_Cmd,0x80); //--set divide ratio, Set Clock as 100 Frames/Sec
OLED_Write_Operate(OLED_Mode_Cmd,0xD9); //*set pre-charge period*/
OLED_Write_Operate(OLED_Mode_Cmd,0Xf1); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_Write_Operate(OLED_Mode_Cmd,0xDA); //*set COM pins*/
OLED_Write_Operate(OLED_Mode_Cmd,0x12); //
OLED_Write_Operate(OLED_Mode_Cmd,0xdb); //*set vcomh*/
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //Set VCOM Deselect Level
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0x20); //设置存储模式(0x00,0x02,0x01)
OLED_Write_Operate(OLED_Mode_Cmd,0x02); //页地址模式
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //*set charge pump disable*/
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //--set(0x10) disable
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0xA4); //显示开启(A4,显示,A5无显示)
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //背景正反向显示(0xa6,正显,0xa7,反显)
OLED_Display_Clear(); //清屏
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开显示
return 0;
}
INIT_COMPONENT_EXPORT(OLED_Init);
/****************************************************************************
* 名 称:u8 SPI1_WriteReadByte(u8 Data)
* 功 能:SPI1读写一个字节
* 入口参数:无
* 出口参数:接收的数据
* 返回值:0,发送接收超时,1成功
* 说 明:无
****************************************************************************/
uint8_t g_master_rx_buff = {0};
static rt_err_t SPI0_WriteReadByte(const rt_uint8_t Data)
{
rt_size_t len = 0;
rt_spi_transfer(&spi_dev_oled, (const void *)&Data, NULL, 1);
if (len != 1)
{
LOG_I("ssd1306_write_data error. %d", len);
return -RT_ERROR;
}
else
{
return RT_EOK;
}
return RT_EOK;
}
/****************************************************************************
* 名 称:u8 OLED_Write_Byte(u8 data)
* 功 能:OLED写一个字节
* 入口参数:无
* 出口参数:接收的数据
* 返回值:0失败,1成功
* 说 明:无
****************************************************************************/
u8 OLED_Write_Byte(u8 data)
{
if(SPI0_WriteReadByte(data))
return 0;
else
return 1;
}
/****************************************************************************
* 名 称:void OLED_Write_Operate(u8 mode,u8 data)
* 功 能:OLED写操作
* 入口参数:模式,数据
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Write_Operate(u8 mode,u8 data)
{
OLED_CS_Low;
if(mode)
{
OLED_Write_Data;
}
else
{
OLED_Write_Cmd;
}
OLED_Write_Byte(data);
OLED_CS_High;
}
/****************************************************************************
* 名 称:void OLED_Display_Clear(void)
* 功 能:OLED清屏
* 入口参数:无
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_Clear(void)
{
u8 page = 0;
u8 i=0;
OLED_CS_Low;
for(page=0;page < 8; page++)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0+page);//设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置显示位置-列低地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置显示位置-列高地址
for(i = 0;i< 128; i++)
{
OLED_Write_Operate(OLED_Mode_Data,0x00);//清屏
}
}
}
/****************************************************************************
* 名 称:void OLED_Set_Positon(void)
* 功 能:设置显示坐标
* 入口参数:x,y
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Set_Positon(u8 x,u8 y)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0 + y); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,((x & 0xf0) >>4 ) | 0x10); //设置列高四位地址
OLED_Write_Operate(OLED_Mode_Cmd,(x & 0x0f) | 0x01); //设置列低四位地址
}
/****************************************************************************
* 名 称:void OLED_Display_on(void)
* 功 能:显示打开
* 入口参数:无
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_on(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //打开充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_offvoid)
* 功 能:显示关闭
* 入口参数:无
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_off(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //关闭充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_onechar(u8 x,u8 y,u8 character,u8 size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
character 字符
size 字号大小
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_onechar(u8 x,u8 y,u8 character,u8 size)
{
u8 c=0,i=0;
c = character-' ';
if(x > MAX_COLUMN - 1)
{
x= 0;
if(size == SIZE8)
{
y = y+1;
}
if(size == SIZE16)
{
y = y+2;
}
}
if(size == SIZE16)
{
OLED_Set_Positon(x,y);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16);
}
OLED_Set_Positon(x,y+1);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16);
}
}
else
{
OLED_Set_Positon(x,y+1);
for( i =0;i< 6; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F6x8<i>);
}
}
}
/****************************************************************************
* 名 称:void OLED_Display_string(u8 x,u8 y,u8 *str,u8 size)
* 功 能:显示字符串
* 入口参数:
x ,y坐标位置
str 字符串
size 字号大小
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_string(u8 x,u8 y,u8 *str,u8 size)
{
u8 i=0;
while(str<i>!='\0')
{
OLED_Display_onechar(x,y,str<i>,size);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
i++;
}
}
/****************************************************************************
* 名 称:void OLED_Display_Chinese(u8 x,u8 y,u8 Sno)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_Chinese(u8 x,u8 y,u8 Sno)
{
u8 adder=0,i=0;
OLED_Set_Positon(x,y);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk<i>);
adder += 1;
}
OLED_Set_Positon(x,y+1);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk<i>);
adder += 1;
}
}
/****************************************************************************
* 名 称:u32 OLED_POW(u8 m, u8 n)
* 功 能:m的n次方
* 入口参数:
m为底数,n为指数
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
u32 OLED_POW(u8 m, u8 n)
{
u32 result=1;
while(n--)
{
result *= m;
}
return result;
}
/****************************************************************************
* 名 称:void OLED_Display_Num(u8 x,u8 y,u32 num, u8 Len,u8 size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_Num(u8 x,u8 y,u32 num, u8 len,u8 size)
{
u8 i=0;
u8 endisplay=0;
u8 temp=0;
for(i = 0;i < len;i++)
{
temp = (num / (OLED_POW(10,len-i-1)))%10;
if(endisplay == 0 && i < len-1)
{
if(temp == 0)
{
OLED_Display_onechar(x + (size / 2) * i,y,' ',size);
continue;
}
else
{
endisplay = 1;
}
}
OLED_Display_onechar(x + (size / 2) * i,y,temp + '0',size);
}
}
/****************************************************************************
* 名 称:void OLED_Display_Picture(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[])
* 功 能:显示一张图片
* 入口参数:
x0 ,y0,x1,y1图片的大小
BMP[] 图片的码
* 出口参数:无
* 返回值:无
* 说 明:无
****************************************************************************/
void OLED_Display_Picture(u8 x0, u8 y0, u8 x1, u8 y1, u8 BMP[])
{
u8 i=0;
u8 x,y;
if(y1 == 8)
{
y= y1/ 8;
}
else
{
y = y1/ 8 + 1;
}
for(y = y0;y < y1;y++)
{
OLED_Set_Positon(x0,y);
for(x = x0;x< x1; x++)
{
OLED_Write_Operate(OLED_Mode_Data,BMP);
}
}
}
</i></i></i></i></i></code></pre>
<p><i><i><i> </i></i></i></p>
<p><i><i><i>2)、hal_entry函数</i></i></i></p>
<pre>
<i><i><i>
<code>void hal_entry(void)
{
rt_kprintf("\nHello RT-Thread!\n");
OLED_Display_string(0,0,"CPK-RA6M4 Board Evaluation",SIZE8);
while (1)
{
rt_thread_mdelay(50);
breathing_light();
}
}</code></i></i></i></pre>
<p><i><i><i>测试现象</i></i></i></p>
<p><i><i><i></i></i></i></p>
<p><i><i><i>最后,整个代码工程会在最后一篇测评中附上git链接。</i></i></i></p>
<p>全是代码,谢谢分享!</p>
<p>要是现在已经上传了,可以单独给出这个工程师文件夹链接</p>
页:
[1]