STC实验箱4
IAP15W4K58S4
Keil uVision V5.29.0.0
PK51 Prof.Developers Kit Version:9.60.0.0
DMA控制见【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结
OLED SPI 端口定义
本节引自STM32驱动0.96寸OLED液晶屏(12864液晶屏) —— 小牧同学
两种屏幕的引脚数不一样,左边的有7个引脚,而右边的只有6个。其次,端口的标号也不完全一样,第一个分别标为GND,VCC,D0,D1,RES,DC和CS第二个分别标为GND,VCC,SCL,SDA,RST,D/C。
七针OLED引脚定义
GND — 接地端口
VCC — 接3.3V电源端口
D0 — CLK时钟信号(等同于上面的SCL)
D1 — 数据端口(等同于上面的SDA)
RES — 复位端口(等同于上面的RST)
DC — 数据/命令选择引脚(等同于上面的D/C)
CS — 片选引脚(低电平有效,也就是所需要接低电平,我实际试验过不接该引脚也是可以正常使用的)
六针OLED引脚定义
GND — 接地端口
VCC — 接3.3V电源端口
SCL — CLK时钟信号端口
SDA — MOSI数据端口
RST — 复位端口
D/C — 数据/命令选择引脚
驱动程序
指令解读见【51单片机快速入门指南】4.2: SSD1306 OLED屏(0.96寸、1.3寸)的I2C控制详解
软件SPI程序见【51单片机快速入门指南】5:软件SPI
SPI选择模式1或2均可,实测模式0也行。
51内核单片机所用的stdint.h见【51单片机快速入门指南】1:基础知识和工程创建
oled.c
#include "./SPI_OLED/oled.h"
#include "./SPI_OLED/oledfont.h"
#include "./Soft_SPI/Soft_SPI.h"
#include "./Drivers/delay.h"
sbit OLED_RES = P2 ^ 6;
sbit OLED_DC = P2 ^ 7;
sbit OLED_CS = P2 ^ 4;
//OLED_RST拉高 移植时需修改
void OLED_RST_H()
{
OLED_RES = 1;
}
//OLED_RST拉低 移植时需修改
void OLED_RST_L()
{
OLED_RES = 0;
}
//OLED_DC拉高 移植时需修改
void OLED_DC_H()
{
OLED_DC = 1;
}
//OLED_DC拉低 移植时需修改
void OLED_DC_L()
{
OLED_DC = 0;
}
//OLED_CS拉高 移植时需修改
void OLED_CS_H()
{
OLED_CS = 1;
}
//OLED_CS拉低 移植时需修改
void OLED_CS_L()
{
OLED_CS = 0;
}
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
#if OLED_BUFFER_MODE
uint8_t OLED_GRAM[Max_Row / 8][Max_Column] = {0};
#endif
/**************************************************************************
Function: Refresh the OLED screen
Input : none
Output : none
函数功能:刷新OLED屏幕
入口参数:无
返回 值:无
**************************************************************************/
void OLED_Refresh_Gram(void)
{
#if OLED_BUFFER_MODE
uint16_t i;
OLED_Set_Pos(0, 128);
for (i = 0; i < Max_Row / 8 * Max_Column; i++)
{
OLED_WR_Byte(OLED_GRAM[0][i], OLED_DATA);
}
#endif
}
/**
* @brief 向SSD1306写入一个字节
* @param dat:要写入的数据/命令 cmd:数据/命令标志 0,表示命令;1,表示数据;
* @retval None
*/
void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
OLED_CS_L();
if (cmd)
OLED_DC_H();
else
OLED_DC_L();
SOFT_SPI_RW_MODE2(dat);
OLED_DC_H();
OLED_CS_H();
}
/**************************************************************************
Function: Set the coordinates (position) displayed on the screen.
Input : x, y: starting point coordinates
Output : none
函数功能:设置汉字在屏幕上显示的坐标(位置)
入口参数: x,y :起点坐标
返回 值:无
**************************************************************************/
void OLED_Set_Pos(uint8_t x, uint8_t y)
{
OLED_WR_Byte(0xb0 + y, OLED_CMD);
OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
OLED_WR_Byte((x & 0x0f), OLED_CMD);
}
/**
* @brief 开启OLED显示
* @param None
* @retval None
*/
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14, OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF, OLED_CMD); //DISPLAY ON
}
/**
* @brief 关闭OLED显示
* @param None
* @retval None
*/
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D, OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10, OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE, OLED_CMD); //DISPLAY OFF
}
/**
* @brief 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样
* @param None
* @retval None
*/
void OLED_Clear(void)
{
#if OLED_BUFFER_MODE
uint16_t i;
for (i = 0; i < Max_Row / 8 * Max_Column; i++)
{
OLED_GRAM[0][i] = 0;
}
OLED_Refresh_Gram(); //Update the display //更新显示
#else
uint8_t i, n;
for (i = 0; i<8; i++)
{
OLED_WR_Byte(0xb0 + i, OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte(0x00, OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte(0x10, OLED_CMD); //设置显示位置—列高地址
for (n = 0; n }//更新显示 #endif } /** * @brief 在指定位置显示一个字符,包括部分字符 * @param x:0~127 y:0~63 Is_Reverse:1,反白显示 0,正常显示 charSize:选择字体 16/6 * @retval None */ void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t charSize, uint8_t Is_Reverse) { uint8_t i = 0; chr -= ' '; //得到偏移后的值 if (x > Max_Column - 1) { x = 0; y = y + 2; } #if OLED_BUFFER_MODE if(charSize == 16) { for(i = 0; i < 8; i++) { OLED_GRAM[y][x+i] = Is_Reverse == 0?F8X16[chr][i]:~F8X16[chr][i]; OLED_GRAM[y+1][x+i] = Is_Reverse == 0?F8X16[chr][i+8]:~F8X16[chr][i+8]; } } else if(charSize == 6) { for(i=0; i<6; i++) { OLED_GRAM[y][x+i] = Is_Reverse == 0?F8X6[chr][i]:~F8X6[chr][i]; } } #else if (charSize == 16) { OLED_Set_Pos(x, y); for (i = 0; i<8; i++) OLED_WR_Byte(Is_Reverse == 0?F8X16[chr][i]:~F8X16[chr][i], OLED_DATA); OLED_Set_Pos(x, y + 1); for (i = 0; i<8; i++) OLED_WR_Byte(Is_Reverse == 0?F8X16[chr][i + 8]:~F8X16[chr][i + 8], OLED_DATA); } else if(charSize == 6) { OLED_Set_Pos(x, y); for (i = 0; i<6; i++) OLED_WR_Byte(Is_Reverse == 0?F8X6[chr][i]:~F8X6[chr][i], OLED_DATA); } #endif } /** * @brief m^n函数 * @param None * @retval None */ uint32_t oled_pow(uint8_t m, uint8_t n) { uint32_t result = 1; while (n--)result *= m; return result; } /** * @brief 显示2个数字 * @param x,y :起点坐标 * len :数字的位数,即显示几位有效数字 * Size:字体大小 * mode:模式 0,填充模式;1,叠加模式 * num:数值(0~4294967295); * @retval None */ void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t Size, uint8_t Is_Reverse) { uint8_t t, temp; uint8_t enshow = 0; for (t = 0; t < len; t++) { temp = (num / oled_pow(10, len - t - 1)) % 10; if (enshow == 0 && t < (len - 1)) { if (temp == 0) { OLED_ShowChar(x + 8 * t, y, ' ', Size, Is_Reverse); continue; } else enshow = 1; } OLED_ShowChar(x + 8 * t, y, temp + '0', Size, Is_Reverse); } } /** * @brief 显示一个字符号串 * @param * @retval None */ void OLED_ShowString(uint8_t x, uint8_t y, char *chr, uint8_t charSize, uint8_t Is_Reverse) { uint8_t j = 0; while (chr[j] != '