之前发帖:
【瑞萨RA4系列开发板体验】1. 新建工程+按键控制LED
【瑞萨RA4系列开发板体验】2. KEIL环境搭建+STLINK调试+FreeRTOS使用
【瑞萨RA4系列开发板体验】3. KEIL下UART实现printf与scanf重定向
【瑞萨RA4系列开发板体验】4. PWM驱动LED
前言
瑞萨单片机上有一个IIC接口引出来了,正好可以用来接上一个IIC驱动的OLED,本文将讲解如何使用IIC来驱动OLED屏显示。 本文的试验是基于KEIL5完成,E2上类似。
本文实现如下功能:
- IIC驱动在RASC上配置;
- OLED驱动程序编写;
- 使用取模工具取模汉字;
- 驱动OLED显示汉字。
硬件连接
如下图,我们可以看到板子上自带了一个I2C的接口,连接到了P408与P409。
查看数据手册,也可以知道P408与P409的引脚映射关系。
RASC配置
知道了引脚连接,我们就可以开始进行驱动的配置了,打开RASC,怎么打开不在细说,参考我之前的文章。
本来打算使用IIC的硬件的,但是因为IIC硬件只有两路,为IIC0与IIC1,并且都没有连接到P408与P409,所以只能使用SCI作为IIC的硬件资源使用。
看原理图中的说明,应该是使用SCI3,经过尝试,SCI可以用作为SCL3与SDA3使用。
配置SCI3作为IIC使用
如下图所示,在Pins界面下配置SCI3作为simple I2C使用,会自动选择SCL3为P408,SDA3为P409。
配置IIC资源
在Stacks界面下,新建Stack,如下:
配置IIC属性,修改Channel为3,设置OLED的IIC驱动地址,此处只能设置7Bit,所以设置为0x3C,设置模式为快速模式,可以加快速度。最后设置回调函数。
完成此步骤表明已经设置完成,点击生成,等待生成配置文件。
然后关闭RASC,不然KEIL不能编辑修改。
汉字取模
汉字取模需要使用工具PCtoLCD2002,该工具在网上可以直接百度下载。
取模方式设置
取模有多种方式,最要是根据代码实现不同取模方式不同,本文的代码取模方式为:共阴、逐列式、顺向输出。
如下图:
输入汉字,取模
设置完成之后,输入汉字,然后生成字模,如下图:
将字模代码放到数组中
生成的字符代码放置到数组hz_code中,并且将取模的汉字写在一个数组hz_char中,使用这种方式可以实现调用显示汉字函数时直接输入汉字就可以显示,不用再输入汉字在数组中的索引,使用起来继伟方便。
代码实现
I2C初始化
新建app_hw_i2c.c文件,填写如下内容:
#include "hal_data.h"
#include "app_hw_i2c.h"
i2c_master_event_t i2c_event = I2C_MASTER_EVENT_ABORTED;
void I2c_Init(void)
{
fsp_err_t err;
err = R_SCI_I2C_Open(&g_sci3_i2c_ctrl, &g_sci3_i2c_cfg);
assert(FSP_SUCCESS == err);
}
void sci3_i2c_master_callback(i2c_master_callback_args_t *p_args)
{
i2c_event = I2C_MASTER_EVENT_ABORTED;
if (NULL != p_args)
{
i2c_event = p_args->event;
}
}
新建app_hw_i2c.h文件,填写如下内容:
#ifndef APP_HW_I2C_H_
#define APP_HW_I2C_H_
#include "hal_data.h"
extern i2c_master_event_t i2c_event;
extern void I2c_Init(void);
#endif
OLED驱动代码
新建app_oled.c,填写如下代码,代码是基于我之前的项目修改而来,支持中文显示,并且支持直接输入中文显示。
#include "hal_data.h"
#include "codetab.h"
#include "app_oled.h"
#include "app_hw_i2c.h"
#include <string.h>
#include <stdio.h>
uint8_t OLED_GRAM[128][8];
void OLED_WrDat(unsigned char IIC_Data)
{
fsp_err_t err;
uint32_t timeout_ms = 100;
uint8_t i2c_transmitter[2]={0x40, IIC_Data};
err = R_SCI_I2C_Write(&g_sci3_i2c_ctrl, i2c_transmitter, 0x02, true);
assert(FSP_SUCCESS == err);
while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms>0)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (I2C_MASTER_EVENT_ABORTED == i2c_event)
{
__BKPT(0);
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
}
void OLED_WrCmd(unsigned char IIC_Command)
{
fsp_err_t err;
uint32_t timeout_ms = 100;
uint8_t i2c_transmitter[2]={0x00, IIC_Command};
err = R_SCI_I2C_Write(&g_sci3_i2c_ctrl, i2c_transmitter, 0x02, true);
assert(FSP_SUCCESS == err);
while ((I2C_MASTER_EVENT_TX_COMPLETE != i2c_event) && timeout_ms>0)
{
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (I2C_MASTER_EVENT_ABORTED == i2c_event)
{
__BKPT(0);
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
}
void OLED_OFF(void)
{
OLED_WrCmd(0X8D);
OLED_WrCmd(0X10);
OLED_WrCmd(0XAE);
}
void OLED_ON(void)
{
OLED_WrCmd(0X8D);
OLED_WrCmd(0X14);
OLED_WrCmd(0XAF);
}
void OLED_Fill(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t dot)
{
uint8_t x,y;
for(x=x1;x<=x2;x++)
for(y=y1;y<=y2;y++)
OLED_DrawPoint(x,y,dot);
OLED_Refresh_Gram();
}
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
for(n=0;n<128;n++)
OLED_GRAM[n][i]=0X00;
OLED_Refresh_Gram();
}
void OLED_Init(void)
{
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
OLED_WrCmd(0xAE);
OLED_WrCmd(0xD5);
OLED_WrCmd(80);
OLED_WrCmd(0xA8);
OLED_WrCmd(0X3F);
OLED_WrCmd(0xD3);
OLED_WrCmd(0X00);
OLED_WrCmd(0x40);
OLED_WrCmd(0x8D);
OLED_WrCmd(0x14);
OLED_WrCmd(0x20);
OLED_WrCmd(0x02);
OLED_WrCmd(0xA1);
OLED_WrCmd(0xC0);
OLED_WrCmd(0xDA);
OLED_WrCmd(0x12);
OLED_WrCmd(0x81);
OLED_WrCmd(0xEF);
OLED_WrCmd(0xD9);
OLED_WrCmd(0xf1);
OLED_WrCmd(0xDB);
OLED_WrCmd(0x30);
OLED_WrCmd(0xA4);
OLED_WrCmd(0xA6);
OLED_WrCmd(0xAF);
OLED_Clear();
}
void OLED_Refresh_Gram(void)
{
uint8_t i,n;
for(i=0;i<8;i++)
{
OLED_WrCmd (0xb0+i);
OLED_WrCmd (0x00);
OLED_WrCmd (0x10);
for(n=0;n<128;n++)
OLED_WrDat(OLED_GRAM[n][i]);
}
}
void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t)
{
uint8_t pos,bx,temp=0;
if(x>127||y>63)return;
pos=7-y/8;
bx=y%8;
temp=(uint8_t)(1U<<(7U-bx));
if(t)
OLED_GRAM[x][pos]|=temp;
else
OLED_GRAM[x][pos]&=~temp;
}
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size,uint8_t mode)
{
uint8_t temp,t,t1;
uint8_t y0=y;
uint8_t csize=(size/8+((size%8)?1:0))*(size/2);
chr=chr-' ';
for(t=0;t<csize;t++)
{
if(size==12)temp=asc2_1206[chr][t];
else if(size==16)temp=asc2_1608[chr][t];
else if(size==24)temp=asc2_2412[chr][t];
else return;
for(t1=0;t1<8;t1++)
{
if(temp&0x80)
OLED_DrawPoint(x,y,mode);
else OLED_DrawPoint(x,y,!mode);
temp<<=1;
y++;
if((y-y0)==size)
{
y=y0;
x++;
break;
}
}
}
}
void OLED_ShowString(uint8_t x,uint8_t y,const uint8_t *p,uint8_t size,uint8_t mode)
{
while((*p<='~')&&(*p>=' '))
{
if(x>(128-(size/2))){x=0;y+=size;}
if(y>(64-size)){y=x=0;OLED_Clear();}
OLED_ShowChar(x,y,*p,size,mode);
x+=size/2;
p++;
}
}
uint32_t mypow(uint8_t m, uint8_t n)
{
uint32_t result = 1;
while(n--)
result *= m;
return result;
}
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode)
{
uint8_t t, temp;
uint8_t enshow = 0;
for(t=0; t<len; t++)
{
temp = (num / mypow(10,len-t-1)) % 10;
if((enshow == 0) && (t < (len-1)))
{
if(temp == 0)
{
OLED_ShowChar(x+(size/2)*t,y,'0',size, mode);
continue;
}
else
enshow = 1;
}
OLED_ShowChar(x+(size/2)*t,y,temp+'0',size, mode);
}
}
void OLED_ShowHz(uint8_t x, uint8_t y, const char hz_c[], uint8_t mode)
{
uint8_t temp, t, t1;
uint8_t y0 = y;
uint8_t csize = 32u;
uint8_t chr = 0;
uint8_t flag = 0;
for (t=0; t<(sizeof(hz_char)/sizeof(hz_char[0])); t++)
{
if(strcmp(hz_char[t], hz_c) == 0)
{
chr = t;
flag = 1;
break;
}
}
if(1 == flag)
{
chr <<= 1u;
for(t=0; t<csize; t++)
{
if(16U == t)
chr += 1;
temp=(0 == mode) ? (hz_code[chr][t%16]):(~hz_code[chr][t%16]);
for(t1=0; t1<8; t1++)
{
if(temp & 0x80)
OLED_DrawPoint(x, y, 0);
else
OLED_DrawPoint(x, y, 1);
temp <<= 1;
y++;
if(16U == (y-y0))
{
y = y0;
x++;
break;
}
}
}
}
}
void OLED_ShowHzStringRow(uint8_t x, uint8_t y, const char *hz_s, uint8_t mode)
{
uint8_t i;
char chr[4];
uint8_t len;
len = (uint8_t)strlen(hz_s);
for(i=0; i<(len-1); i+=3)
{
sprintf(chr, "%c%c%c", hz_s[i], hz_s[i+1], hz_s[i+2]);
OLED_ShowHz(x+(uint8_t)((i/3U)<<4U), y, chr, mode);
}
}
void OLED_ShowHzStringColumn(uint8_t x, uint8_t y, const char *hz_s, uint8_t mode)
{
uint8_t i;
char chr[4];
uint8_t len;
len = (uint8_t)strlen(hz_s);
for(i=0; i<(len-1); i+=3)
{
sprintf(chr, "%c%c%c", hz_s[i], hz_s[i+1], hz_s[i+2]);
OLED_ShowHz(x, y+(uint8_t)((i/3U)<<4U), chr, mode);
}
}
void OLED_ShowHzFromIndex(uint8_t x, uint8_t y, uint8_t chr, uint8_t mode)
{
uint8_t temp, t, t1;
uint8_t y0 = y;
uint8_t csize = 32u;
chr <<= 1u;
for(t=0; t<csize; t++)
{
if(16U == t)
chr += 1;
temp=(0 == mode) ? (hz_code[chr][t%16]):(~hz_code[chr][t%16]);
for(t1=0; t1<8; t1++)
{
if(temp & 0x80)
OLED_DrawPoint(x, y, 0);
else
OLED_DrawPoint(x, y, 1);
temp <<= 1;
y++;
if(16U == (y-y0))
{
y = y0;
x++;
break;
}
}
}
}
void OLED_HzStringFromIndex(uint8_t x, uint8_t y, uint8_t chr_S, uint8_t chr_E, uint8_t mode)
{
uint8_t i;
for(i=chr_S; i<=chr_E; i++)
{
OLED_ShowHzFromIndex(x+16*(i-chr_S), y, i, mode);
}
}
新建app_oled.h,填写如下代码:
#ifndef APP_OLED_H_
#define APP_OLED_H_
#include "stdint.h"
#define I2C_SLAVE_OLED_ADDRESS7 0x78
extern void OLED_Init(void);
extern void OLED_Fill(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t dot);
extern void OLED_Clear(void);
extern void OLED_Refresh_Gram(void);
extern void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t);
extern void OLED_ShowHz(uint8_t x, uint8_t y, const char hz_c[], uint8_t mode);
extern void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size,uint8_t mode);
extern void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size, uint8_t mode);
extern void OLED_ShowString(uint8_t x,uint8_t y,const uint8_t *p,uint8_t size,uint8_t mode);
extern void OLED_ShowBMP(uint8_t x,uint8_t y,uint8_t mode,uint8_t bmp[][16],uint32_t len);
extern void OLED_ShowHz(uint8_t x, uint8_t y, const char hz_c[], uint8_t mode);
extern void OLED_ShowHzStringRow(uint8_t x, uint8_t y, const char *hz_s, uint8_t mode);
extern void OLED_ShowHzStringColumn(uint8_t x, uint8_t y, const char *hz_s, uint8_t mode);
extern void OLED_ShowHzFromIndex(uint8_t x, uint8_t y, uint8_t chr, uint8_t mode);
#endif
主函数驱动代码
在main_entry()中填写如下代码。
显示瑞萨单片机的名称;
显示电子发烧友汉字;
显示我的名字。
void hal_entry(void)
{
Uart_Init();
I2c_Init();
OLED_Init();
OLED_ShowString(12, 0, (const uint8_t*)"R7FA4M2AD3CFP", 16, 1);
OLED_ShowHzStringRow(32, 24, (const char*)"电子发烧友", 1);
OLED_ShowString(64, 48, (const uint8_t*)"--hehung", 16, 1);
OLED_Refresh_Gram();
while (1)
{
}
#if BSP_TZ_SECURE_BUILD
R_BSP_NonSecureEnter();
#endif
}
效果展示
如下: