RTT&瑞萨高性能 CPK-RA6M4 开发板测评——SPI驱动OLED
[复制链接]
一、硬件
1、OLED引脚介绍
OLED引脚,是7针SPI模式。
1). GND 电源地
2). VCC 电源正(3~5.5V)
3). D0 OLED 的 D0 脚,在 SPI 和 IIC 通信中为时钟管脚
4). D1 OLED 的 D1 脚,在 SPI 和 IIC 通信中为数据管脚
5). RES OLED 的 RES#脚,用来复位(低电平复位)
6). DC OLED 的 D/C#E 脚,数据和命令控制管脚
如图所示:实物引脚。
关于OLED的显示原理就不介绍。
2、接线
1)、VCC接板载3.3V引脚,与板子共地
2)、把SPI0的相应时钟SCLK、数据MOSI关机与OLED的时钟和数据管脚,使用杜邦线连接起来,再使用其他引脚,作为普通管脚,控制OLED的片选CS、复位RES、DC引脚。
二、软件操作
1、RA Smart Configurator操作
1)、使用瑞萨灵活配置软件添加SPI0的复用引脚相关的时钟与MOSI引脚,注意,程序中是软件配置片选,因此SPI0硬件片选引脚CS 配置为普通引脚(P703)。同时设置P406(对应OLED的DC)、P405(对应OLED的RES)为普通输出引脚。
2)、设置三个普通引脚模式为输出模式,并且设置为初始化为高电平
3)、添加SPI的配置,设置SPI0的回调函数为spi0_callback。其他都默认,可以在对应的参数设置中,设置SPI工作模式、速率、相位、极性等。另外也可以直接在RTThread中修改相应的配置。
2、RTThread-Studio操作
1)、添加RTThread对RA6M4支持的SPI驱动。
2)、使能SPI0驱动。
3、代码
1)、OLED驱动代码
/*
* 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[6] = {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[c*16 + i]);
}
OLED_Set_Positon(x,y+1);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16[c*16 + i+8]);
}
}
else
{
OLED_Set_Positon(x,y+1);
for( i =0;i< 6; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F6x8[c]);
}
}
}
/****************************************************************************
* 名 称: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!='\0')
{
OLED_Display_onechar(x,y,str,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[2*Sno]);
adder += 1;
}
OLED_Set_Positon(x,y+1);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk[2*Sno+1]);
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++]);
}
}
}
2)、hal_entry函数
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();
}
}
测试现象
最后,整个代码工程会在最后一篇测评中附上git链接。
|