stm32_ota/HARDWARE/OLED/oled.c

529 lines
22 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "oled.h"
#include "stm32f10x_spi.h"
#include "sysport.h"
/********************************************************************************
* @file oled.c
* @author 晏诚科技 Mr.Wang
* @version V1.0.0
* @date 11-Dec-2018
* @brief 提供1.3英寸OLED显示屏相关驱动。
******************************************************************************
* @attention 1.3英寸显示屏的像素为横向128 纵向64。如果显示大小:12*6的数字/字符一行最多显示
* 16个字符。
*******************************************************************************/
/**************************************************************************************************
* 名 称: void OLED_Init(void)
* 功能说明: 初始化SSD1306
***************************************************************************************************/
void delay(void)
{
u8 t=3;
while(t--);
}
void OLED_Init(void)
{
/* 配置IO */
Gpio_Init(OLED_CS_PORT, OLED_CS_PIN, GPIO_Mode_Out_PP) ; //SPI NSS io口配置
Gpio_Init(OLED_SCLK_PORT, OLED_SCLK_PIN, GPIO_Mode_Out_PP) ; //SPI SCLK io口配置
Gpio_Init(OLED_MISO_PORT, OLED_MISO_PIN, GPIO_Mode_Out_PP) ; //SPI MISO io口配置
Gpio_Init(OLED_MOSI_PORT, OLED_MOSI_PIN, GPIO_Mode_Out_PP) ; //SPI MOSI io口配置
Gpio_Init(OLED_RST_PORT, OLED_RST_PIN , GPIO_Mode_Out_PP) ; //OLED RST io口配置
//SPIxBoardInit() ;
OLED_RST_SET() ;
Wait_For_Nms(100) ;
OLED_RST_CLR() ;
Wait_For_Nms(100) ;
OLED_RST_SET() ;
OledWriteByte(0xAE, OLED_CMD, false) ; //--turn off oled panel
OledWriteByte(0x02, OLED_CMD, false) ; //---set low column address
OledWriteByte(0x10, OLED_CMD, false) ; //---set high column address
OledWriteByte(0x40, OLED_CMD, false) ; //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OledWriteByte(0x81, OLED_CMD, false) ; //--set contrast control register
OledWriteByte(OLED_BRIGHTNESS, OLED_CMD, false) ; // Set SEG Output Current Brightness
OledWriteByte(0xA1, OLED_CMD, false) ; //--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OledWriteByte(0xC8, OLED_CMD, false) ; //Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OledWriteByte(0xA6, OLED_CMD, false) ; //--set normal display
OledWriteByte(0xA8, OLED_CMD, false) ; //--set multiplex ratio(1 to 64)
OledWriteByte(0x3f, OLED_CMD, false) ; //--1/64 duty
OledWriteByte(0xD3, OLED_CMD, false) ; //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OledWriteByte(0x00, OLED_CMD, false) ; //-not offset
OledWriteByte(0xd5, OLED_CMD, false) ; //--set display clock divide ratio/oscillator frequency
OledWriteByte(0x80, OLED_CMD, false) ; //--set divide ratio, Set Clock as 100 Frames/Sec
OledWriteByte(0xD9, OLED_CMD, false) ; //--set pre-charge period
OledWriteByte(0xF1, OLED_CMD, false) ; //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OledWriteByte(0xDA, OLED_CMD, false) ; //--set com pins hardware configuration
OledWriteByte(0x12, OLED_CMD, false) ;
OledWriteByte(0xDB, OLED_CMD, false) ; //--set vcomh
OledWriteByte(0x40, OLED_CMD, false) ; //Set VCOM Deselect Level
OledWriteByte(0x20, OLED_CMD, false) ; //-Set Page Addressing Mode (0x00/0x01/0x02)
OledWriteByte(0x02, OLED_CMD, false) ; //
OledWriteByte(0x8D, OLED_CMD, false) ; //--set Charge Pump enable/disable
OledWriteByte(0x14, OLED_CMD, false) ; //--set(0x10) disable
OledWriteByte(0xA4, OLED_CMD, false) ; // Disable Entire Display On (0xa4/0xa5)
OledWriteByte(0xA6, OLED_CMD, false) ; // Disable Inverse Display On (0xa6/a7)
OledWriteByte(0xAF, OLED_CMD, false) ; //--turn on oled panel
OledWriteByte(0xAF, OLED_CMD, false) ; //display ON
OledClear() ; //清除显示屏
OledSetPos(0, 0) ; //设置显示光标位置
// OledPrintf(LINE_MID, HIGH_16, LINE1, false, "晏 诚 科 技") ; //第一行居中显示“晏 诚 科 技”
}
/**************************************************************************************************
* 名 称: void OledPrintf(ALINEMODE_e eMode, OLEDLINE_e line, char *format, ...)
* 功能说明: OLED显示屏line行按照eMode对齐模式显示可变长字符串
* 入口参数:
* @param1 eMode: ALINEMODE_e枚举类型表示行显示的对齐方式
* @param2 CHARHIGH_e high: CHARHIGH_e结构体表示字符高度
* @param3 line: OLEDLINE_e枚举类型表示内容显示在哪一行
* @param4 char *format 可变参数格式
* @param5 ... : 可变参数
* 注 意: 1、该函数只能显示汉字高为16的字符如果需要显示其他高度的字符需要修改字符码表。
* 2、单行显示字符长度大于X_MAX_WIDTH/high*2则只显示X_MAX_WIDTH/high*2长度字符多余字符不显示
*************************************************************************************************/
void OledPrintf(ALINEMODE_e eMode, CHARHIGH_e high, OLEDLINE_e line, bool reverse, char *format, ...)
{
unsigned int x = 0, i, k, t, y, lineMaxChar = X_MAX_WIDTH/(high/2), n ;
if( high == HIGH_16 )
{
y = line*2 ;
n = (sizeof(sCN16_Msk)/sizeof(FNTGBK16_s)) ;
}
else
{
y = line*2 ;
n = (sizeof(sCN12_Msk)/sizeof(FNTGBK12_s)) ;
}
va_list ap; //ap指向参数的地址
va_start (ap, format); //让ap指针指向可变参数表里的第一个参数
char *buf = portMalloc(lineMaxChar+1) ;
int outLen = vsnprintf(buf, lineMaxChar+1, (const char*)format, ap);
if( (outLen > lineMaxChar) && (*(buf+lineMaxChar-1) > 127)) /*如果单行显示字符长度大于LINE_MAX_CHAR则只显示LINE_MAX_CHAR长度字符多余字符不显示&&最后一个字符为汉字*/
outLen = lineMaxChar-1 ;
else if((outLen > lineMaxChar) ) /*如果单行显示字符长度大于LINE_MAX_CHAR,则只显示LINE_MAX_CHAR长度字符多余字符不显示*/
outLen = lineMaxChar ;
switch( eMode )
{
case LINE_MID :
{
x = (high/2)*((lineMaxChar - outLen)/2) ;
break ;
}
case LINE_RIGHT:
{
x = (high/2)*(lineMaxChar - outLen) ;
break ;
}
default:
{
x = 0 ;
break ;
}
}
if(outLen > 0 ) /*vsnprintf执行OK*/
{
OledClearLine(line) ;
for(k=0; k<outLen; k++) /*轮询str字符串中的每一个字符/汉字*/
{
if(*(buf+k) <= 127) /*小于128是ASCII符号*/
{
OledShowChar(x, y, high, reverse, *(buf+k)); //显示ASCII符号
x += high/2; //填充一个ASCII符号后 x坐标需要右移high/2像素
}
else if(*(buf+k) > 127) /*大于127为汉字前后两个组成汉字内码*/
{
for(i=0; i<n; i++) /*轮询查汉字码表数组*/
{
if( high == HIGH_16 ) /*字高16*/
{
if( (*(buf+k) == sCN16_Msk[i].gbk[0]) && (*(buf+k+1) == sCN16_Msk[i].gbk[1]) ) /*汉字GBK内码一致*/
{
OledSetPos(x, y) ;
for(t=0; t<high; t++)
OledWriteByte(sCN16_Msk[i].msk[t], OLED_DATA, reverse) ; //写入字模
OledSetPos(x, y+1) ;
for(t=high; t<high*2; t++)
OledWriteByte(sCN16_Msk[i].msk[t], OLED_DATA, reverse);
x += high ; //填充一个汉字后 x坐标需要右移16像素
k += 1 ; //汉字占2个字节,跳过一个字节
break ;
}
}
else if(high == HIGH_12) /*字高12*/
{
if( (*(buf+k) == sCN12_Msk[i].gbk[0]) && (*(buf+k+1) == sCN12_Msk[i].gbk[1]) ) /*汉字GBK内码一致*/
{
OledSetPos(x, y) ;
for(t=0; t<high; t++)
OledWriteByte(sCN12_Msk[i].msk[t], OLED_DATA, reverse) ; //写入字模
OledSetPos(x, y+1) ;
for(t=high; t<high*2; t++)
OledWriteByte(sCN12_Msk[i].msk[t], OLED_DATA, reverse);
x += high ; //填充一个汉字后 x坐标需要右移16像素
k += 1 ; //汉字占2个字节,跳过一个字节
break ;
}
}
}
}
}
}
else if( outLen == 0) /*vsnprintf执行后数据长度为0无效字符串*/
{
}
else /*vsnprintf执行失败*/
{
SysErr("") ;
}
va_end(ap) ;
portFree(buf) ;
}
///**************************************************************************************************
//* 名 称: void OledString(OLEDLINE_e line, char *str, char high)
//* 功能说明: 在(x,line)坐标位置显示一个字符串
//* 入口参数:
//* @param1 OLEDLINE_e: 行号
//* @param2 char *str: 需要显示的字符串指针
//***************************************************************************************************/
//void OledString(OLEDLINE_e line, char *str, CHARHIGH_e high)
//{
// OLED_ShowString(0, line, (char *)" ", high);
// OLED_ShowString(0, line, str, high);
//}
/**************************************************************************************************
* 名 称: void OledSetPos(char x, char y)
* 功能说明: 设置显示的坐标起点。
* 入口参数:
* @param1 char x: 横向坐标
* @param2 char y: 纵向坐标
*************************************************************************************************/
void OledSetPos(char x, char y)
{
OledWriteByte(0xb0+y, OLED_CMD, false);
OledWriteByte((((x+2)&0xf0)>>4)|0x10, OLED_CMD, false);
OledWriteByte(((x+2)&0x0f), OLED_CMD, false);
}
/**************************************************************************************************
* 名 称: void OledDisplayOn(void)
* 功能说明: 开启OLED显示
***************************************************************************************************/
void OledDisplayOn(void)
{
OledWriteByte(0X8D, OLED_CMD, false) ; //SET DCDC命令
OledWriteByte(0X14, OLED_CMD, false) ; //DCDC ON
OledWriteByte(0XAF, OLED_CMD, false) ; //DISPLAY ON
}
/**************************************************************************************************
* 名 称: void OledDisplayOff(void)
* 功能说明: 关闭OLED显示
***************************************************************************************************/
void OledDisplayOff(void)
{
OledWriteByte(0X8D, OLED_CMD, false) ; //SET DCDC命令
OledWriteByte(0X10, OLED_CMD, false) ; //DCDC OFF
OledWriteByte(0XAE, OLED_CMD, false) ; //DISPLAY OFF
}
/**************************************************************************************************
* 名 称: void OledClear(void)
* 功能说明: 关闭OLED显示
* 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
***************************************************************************************************/
void OledClear(void)
{
unsigned char i, n ;
for(i=0; i<8; i++)
{
OledWriteByte (0xb0+i, OLED_CMD, false); //设置页地址0~7
OledWriteByte (0x02, OLED_CMD, false); //设置显示位置—列低地址
OledWriteByte (0x10, OLED_CMD, false); //设置显示位置—列高地址
for(n=0; n < 128; n++)
{
OledWriteByte(0, OLED_DATA, false);
}
} //更新显示
}
/**************************************************************************************************
* 名 称: void OledClearLine(OLEDLINE_e line)
* 功能说明: 清空显示屏第line行的内容
***************************************************************************************************/
void OledClearLine(OLEDLINE_e line)
{
OLED_ShowString(0, line*2, false, (char *)" ", HIGH_16);
}
/**************************************************************************************************
* 名 称: void OledWriteByte(char dat, char cmd, bool reserse)
* 功能说明: 向SSD1106写入一个字节。
* 入口参数:
* @param1 char dat: 写入的数据
* @param2 char cmd: 数据/命令标志 0,表示命令;1,表示数据;
* @param3 bool reserse: 写入数据是否“反白”显示
*************************************************************************************************/
void OledWriteByte(char dat, char cmd, bool reserse)
{
char i = 0 ;
if(cmd == OLED_DATA) //写入数据
{
OLED_MISO_SET() ;
}
else //写入命令
{
reserse = false ; //写入命令不存在 反白
OLED_MISO_CLR() ;
}
OLED_CS_CLR() ;
for(i=0; i<8; i++)
{
OLED_SCLK_CLR();
if(reserse == false)
{
if( (dat & 0x80) )
{
OLED_MOSI_SET() ;
}
else
{
OLED_MOSI_CLR() ;
}
}
else
{
if( (dat & 0x80) )
{
OLED_MOSI_CLR() ;
}
else
{
OLED_MOSI_SET() ;
}
}
OLED_SCLK_SET() ;
delay();
dat <<= 1 ;
}
OLED_CS_SET();
OLED_MISO_SET();
}
/**************************************************************************************************
* 名 称: OledShowChar(char x, char y, CHARHIGH_e high, bool reverse, char chr)
* 功能说明: 在(x,y)坐标位置显示一个字符
* 入口参数:
* @param1 char x: 横向坐标0~127
* @param2 char y: 纵向坐标0~63
* @param3 char chr: 需要显示的字符
* @param4 CHARHIGH_e high: CHARHIGH_e结构体表示字符高度
***************************************************************************************************/
void OledShowChar(char x, char y, CHARHIGH_e high, bool reverse, char chr)
{
char c = 0, i = 0 ;
c = chr - ' ' ; //得到偏移后的值
if( x > (X_MAX_WIDTH-1) ) /*如果横向坐标大于最大像素宽度X_MAX_WIDTH执行换行操作*/
{
x = 0 ;
y = y+2 ;
}
switch( high )
{
case HIGH_12: /*显示的字符高度为12*/
{
OledSetPos(x, y+1) ;
for(i=0; i<6; i++)
{
OledWriteByte(ASCII_HIGH12[c][i], OLED_DATA, reverse) ;
}
break ;
}
case HIGH_16: /*显示的字符高度为16*/
{
OledSetPos(x, y) ; //设置起始坐标
for(i=0; i<8; i++)
{
OledWriteByte(ASCII_HIGH16[c][i], OLED_DATA, reverse) ; //显示16字高的上半部分
}
OledSetPos(x, y+1) ;
for(i=0; i<8; i++)
{
OledWriteByte(ASCII_HIGH16[c][i+8], OLED_DATA, reverse) ; //显示16字高的下半部分
}
break ;
}
default:
{
ErrorLogPrintf("No CHARHIGH_e .") ;
break ;
}
}
}
/**************************************************************************************************
* 名 称: void OledShowChar(char x,char y,char *chr)
* 功能说明: 在(x,y)坐标位置显示一个字符串
* 入口参数:
* @param1 char x: 横向坐标0~127
* @param2 char y: 纵向坐标0~63
* @param3 char *chr: 需要显示的字符串指针
* @param4 CHARHIGH_e high: CHARHIGH_e结构体表示字符高度
***************************************************************************************************/
void OLED_ShowString(char x, char y, bool reverse, char *chr, CHARHIGH_e high)
{
char j = 0 ;
while(*(chr+j) != '\0') /*单字节轮询查找直到遇到字符串结尾标识符*/
{
OledShowChar(x, y, high, reverse, *(chr+j)) ; //显示字符串
x += high/2 ; //横坐标偏移high/2像素
if( x > 120 ) //横坐标大于120余下部分不足以显示一个字符时操作换行
{
x = 0 ;
y += 1 ;
// SysErr("OLED_ShowString") ;
}
j++ ;
}
}
/**************************************************************************************************
* 名 称: void OledShowCHinese(char x, char y, const char *buf, CHARHIGH_e high)
* 功能说明: 在(x,y)坐标位置显示一个汉子
* 入口参数:
* @param1 char x: 横向坐标0~127
* @param1 char y: 横向坐标0~63
* @param2 char *buf: 汉字数组
* @param4 CHARHIGH_e high: CHARHIGH_e结构体表示字符高度
***************************************************************************************************/
void OledShowCHinese(char x, char y, bool reverse, const char *buf, CHARHIGH_e high)
{
char t = 0;
unsigned int k = 0 ;
OledSetPos(x, y) ; //设置坐标
switch( high )
{
case HIGH_12:
{
for(k=0; k<strlen(buf); k++) /*轮询str字符串中的每一个字符/汉字*/
{
int sum1=0, sum2 =0 ;
sum1 = sizeof(sCN12_Msk) ;
sum2 = sizeof(FNTGBK12_s) ;
for(unsigned int i=0; i<sum1/sum2; i++) /*轮询查汉字码表数组*/
{
if( (*(buf+k) == sCN12_Msk[i].gbk[0]) && (*(buf+k+1) == sCN12_Msk[i].gbk[1]) ) /*汉字GBK内码一致*/
{
OledSetPos(x, y) ;
for(t=0; t<12; t++)
OledWriteByte(sCN12_Msk[i].msk[t], OLED_DATA, reverse) ;//写入字模
OledSetPos(x, y+1) ;
for(t=12; t<24; t++)
OledWriteByte(sCN12_Msk[i].msk[t], OLED_DATA, reverse);
x += 12 ; //填充一个汉字后 x坐标需要右移16像素
k += 1 ; //汉字占2个字节,跳过一个字节
break ;
}
}
}
break ;
}
case HIGH_16:
{
for(k=0; k<strlen(buf); k++) /*轮询str字符串中的每一个字符/汉字*/
{
for(unsigned int i=0; i<(sizeof(sCN16_Msk)/sizeof(FNTGBK16_s)); i++) /*轮询查汉字码表数组*/
{
if( (*(buf+k) == sCN16_Msk[i].gbk[0]) && (*(buf+k+1) == sCN16_Msk[i].gbk[1]) ) /*汉字GBK内码一致*/
{
OledSetPos(x, y) ;
for(t=0; t<16; t++)
OledWriteByte(sCN16_Msk[i].msk[t], OLED_DATA, reverse) ;//写入字模
OledSetPos(x, y+1) ;
for(t=16; t<32; t++)
OledWriteByte(sCN16_Msk[i].msk[t], OLED_DATA, reverse);
x += 16 ; //填充一个汉字后 x坐标需要右移16像素
k += 1 ; //汉字占2个字节,跳过一个字节
break ;
}
}
}
break ;
}
default:
{
ErrorLogPrintf("No CHARHIGH_e .") ;
break ;
}
}
}
/***********功能描述显示显示BMP图片128×64起始点坐标(x,y),x的范围0127y为页的范围07*****************/
/**************************************************************************************************
* 名 称: void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1, const unsigned char BMP[])
* 功能说明: 在(x0,y0)坐标位置显示一张图片
* 入口参数:
* @param1 unsigned char x0: 横向坐标0~127
* @param1 unsigned char y0: 横向坐标0~7
* @param2 unsigned char x1: 图片宽度(单位:像素)
* @param4 unsigned char y1: 图片高度单位8像素
***************************************************************************************************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char width, unsigned char high, bool reverse, const unsigned char BMP[])
{
unsigned int i = 0 ;
unsigned char x, y, line8 ;
if( high%8 == 0 ) /*像素高度是8的整数倍*/
line8 = high/8 ;
else /*像素高度不是8的整数倍*/
line8 = high/8+1 ;
for(y=y0; y<line8; y++)
{
OledSetPos(x0, y) ;
for(x=x0; x<width+x0; x++)
{
OledWriteByte(BMP[i++],OLED_DATA, reverse) ;
}
}
}
/**************************************************************************************************
* 名 称: void SPIxBoardInit(void)
* 功能说明: SPI功能块初始化
*************************************************************************************************/
void SPIxBoardInit(void)
{
/* 配置SPI 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE) ;
/* 配置SPI IO */
Gpio_Init(OLED_MISO_PORT, OLED_MISO_PIN, GPIO_Mode_IN_FLOATING) ; //SPI MISO io口配置
Gpio_Init(OLED_SCLK_PORT, OLED_SCLK_PIN, GPIO_Mode_AF_PP) ; //SPI SCLK io口配置
Gpio_Init(OLED_MOSI_PORT, OLED_MOSI_PIN, GPIO_Mode_AF_PP) ; //SPI MOSI io口配置
Gpio_Init(OLED_CS_PORT, OLED_CS_PIN, GPIO_Mode_Out_PP) ; //SPI NSS io口配置
/* 配置SPI模式 */
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* 打开SPI1 */
SPI_Cmd(SPI1, ENABLE);
}