This repository has been archived on 2024-12-31. You can view files and clone it, but cannot push or open issues or pull requests.
mfps/App/Src/oled.c

634 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "oled.h"
#include "app.h"
#define OLED_ADDRESS 0x78 //电阻焊在了0x3C左移一位得到0x78
// OLED参数
#define OLED_PAGE 8 // OLED页数
#define OLED_ROW 8 * OLED_PAGE // OLED行数
#define OLED_COLUMN 128 // OLED列数
// 显存
uint8_t OLED_GRAM[OLED_PAGE][OLED_COLUMN];
HAL_StatusTypeDef I2CWATCH;
int I2C_ERROR_TIMES = 0,I2C_BUSY_TIMES = 0,I2C_TIMEOUT_TIMES = 0,I2C_OK_TIMES = 0;
HAL_StatusTypeDef OLED_Send(uint8_t *data, uint8_t len)//发送数据 8bit * len
{
I2CWATCH = HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len,2000);//1000
if( I2CWATCH == HAL_ERROR ) I2C_ERROR_TIMES++;
if( I2CWATCH == HAL_BUSY ) I2C_BUSY_TIMES++;
if( I2CWATCH == HAL_TIMEOUT) I2C_TIMEOUT_TIMES++;
if( I2CWATCH == HAL_OK) I2C_OK_TIMES++;
return I2CWATCH;
}
HAL_StatusTypeDef OLED_SendCmd(uint8_t cmd)// [0x00;cmd]
{
static uint8_t sendBuffer[2] = {0};
sendBuffer[1] = cmd;
return OLED_Send(sendBuffer, 2);
}
//OLED初始化
char oled_init_status[27] = {0};
char OLED_Init(void)
{
delay_us(500000);
if(oled_init_status[0] == 0)
{
if(OLED_SendCmd(0xAE) == HAL_OK) oled_init_status[0] = 1;//--display off /1
}
if(oled_init_status[0] == 1)
{
if(OLED_SendCmd(0x00) == HAL_OK) oled_init_status[1] = 2;//--set low column address /2
}
if(oled_init_status[1] == 2)
{
if(OLED_SendCmd(0x10) == HAL_OK) oled_init_status[2] = 3;//--set high column address /3
}
if(oled_init_status[2] == 3)
{
if(OLED_SendCmd(0x40) == HAL_OK) oled_init_status[3] = 4;//--set start line address /4
}
if(oled_init_status[3] == 4)
{
if(OLED_SendCmd(0xB0) == HAL_OK) oled_init_status[4] = 5;//--set page address /5
}
if(oled_init_status[4] == 5)
{
if(OLED_SendCmd(0x81) == HAL_OK) oled_init_status[5] = 6;// contract control /6
}
if(oled_init_status[5] == 6)
{
if(OLED_SendCmd(0xFF) == HAL_OK) oled_init_status[6] = 7;// /7
}
if(oled_init_status[6] == 7)
{
// OLED_SendCmd(0xA1);//set segment re-map 0 to 127
if(OLED_SendCmd(0xA0) == HAL_OK) oled_init_status[7] = 8; //左右翻转 /8
}
if(oled_init_status[7] == 8)
{
if(OLED_SendCmd(0xA6) == HAL_OK) oled_init_status[8] = 9;//set normal display /9
}
if(oled_init_status[8] == 9)
{
if(OLED_SendCmd(0xA8) == HAL_OK) oled_init_status[9] = 10;// /10
}
if(oled_init_status[9] == 10)
{
if(OLED_SendCmd(0x3F) == HAL_OK) oled_init_status[10] = 11;//--1/32 duty /11
}
if(oled_init_status[10] == 11)
{
// OLED_SendCmd(0xC8);//Com scan direction
if(OLED_SendCmd(0xC0) == HAL_OK) oled_init_status[11] = 12;//上下翻转 /12
}
if(oled_init_status[11] == 12)
{
if(OLED_SendCmd(0xD3) == HAL_OK) oled_init_status[12] = 13;//set display offset /13
}
if(oled_init_status[12] == 13)
{
if(OLED_SendCmd(0x00) == HAL_OK) oled_init_status[13] = 14;//no offset /14
}
if(oled_init_status[13] == 14)
{
if(OLED_SendCmd(0xD5) == HAL_OK) oled_init_status[14] = 15;// /15
}
if(oled_init_status[14] == 15)
{
if(OLED_SendCmd(0x80) == HAL_OK) oled_init_status[15] = 16;// /16
}
if(oled_init_status[15] == 16)
{
if(OLED_SendCmd(0xD8) == HAL_OK) oled_init_status[16] = 17;//set area color mode off /17
}
if(oled_init_status[16] == 17)
{
if(OLED_SendCmd(0x05) == HAL_OK) oled_init_status[17] = 18;// /18
}
if(oled_init_status[17] == 18)
{
if(OLED_SendCmd(0xD9) == HAL_OK) oled_init_status[18] = 19;//Set Pre-Charge Period /19
}
if(oled_init_status[18] == 19)
{
if(OLED_SendCmd(0xF1) == HAL_OK) oled_init_status[19] = 20;// /20
}
if(oled_init_status[19] == 20)
{
if(OLED_SendCmd(0xDA) == HAL_OK) oled_init_status[20] = 21;// /21
}
if(oled_init_status[20] == 21)
{
if(OLED_SendCmd(0x12) == HAL_OK) oled_init_status[21] = 22;// /22
}
if(oled_init_status[21] == 22)
{
if(OLED_SendCmd(0xDB) == HAL_OK) oled_init_status[22] = 23;//set Vcomh /23
}
if(oled_init_status[22] == 23)
{
if(OLED_SendCmd(0x30) == HAL_OK) oled_init_status[23] = 24;//0x20,0.77xVcc /24
}
/******************************************************/
if(oled_init_status[23] == 24)
{
if(OLED_SendCmd(0x8D) == HAL_OK) oled_init_status[24] = 25;//set charge pump enable /25
}
if(oled_init_status[24] == 25)
{
if(OLED_SendCmd(0x14) == HAL_OK) oled_init_status[25] = 26;// /26
}
if(oled_init_status[25] == 26)
{
if(OLED_SendCmd(0xAF) == HAL_OK) oled_init_status[26] = 27;//--turn on oled panel /27
}
/******************************************************/
if(oled_init_status[26] == 27)
{
OLED_NewFrame();
return 1;
}
return 0;
}
//开启OLED显示
void OLED_DisPlay_On()
{
OLED_SendCmd(0x8D); // 电荷泵使能
OLED_SendCmd(0x14); // 开启电荷泵
OLED_SendCmd(0xAF); // 点亮屏幕
}
//关闭OLED显示
void OLED_DisPlay_Off()
{
OLED_SendCmd(0x8D); // 电荷泵使能
OLED_SendCmd(0x10); // 关闭电荷泵
OLED_SendCmd(0xAE); // 关闭屏幕
}
//设置颜色模式 黑底白字或白底黑字
//颜色模式COLOR_NORMAL黑底白字 / COLOR_REVERSED白底黑字
void OLED_SetColorMode(OLED_ColorMode mode)
{
if (mode == OLED_COLOR_NORMAL)
{
OLED_SendCmd(0xA6); // 正常显示
}
if (mode == OLED_COLOR_REVERSED)
{
OLED_SendCmd(0xA7); // 反色显示
}
}
/**********************显存操作函数begin*************************/
//清空显存 绘制新的一帧
void OLED_NewFrame()
{
memset(OLED_GRAM, 0, sizeof(OLED_GRAM));
}
uint8_t Lcd_Cnt = 0;
//将当前显存显示到屏幕上
uint8_t sendBuffer[OLED_COLUMN + 1] = {0};
void OLED_ShowFrame()
{
sendBuffer[0] = 0x40;
Lcd_Cnt *= (Lcd_Cnt < OLED_PAGE);
// for (Lcd_Cnt = 0; Lcd_Cnt < OLED_PAGE; Lcd_Cnt++)
// {
OLED_SendCmd(0xB0 + Lcd_Cnt); // 设置页地址
OLED_SendCmd(0x00); // 设置列地址低4位
OLED_SendCmd(0x10); // 设置列地址高4位
memcpy(sendBuffer + 1, OLED_GRAM[Lcd_Cnt], OLED_COLUMN);
OLED_Send(sendBuffer, OLED_COLUMN + 1);
// }
Lcd_Cnt++;
}
//将当前显存显示到屏幕上
uint8_t sendBuffer_page[OLED_COLUMN + 1] = {0};
void OLED_ShowPageFrame(uint8_t page)
{
sendBuffer_page[0] = 0x40;
{
OLED_SendCmd(0xB0 + page); // 设置页地址
OLED_SendCmd(0x00); // 设置列地址低4位
OLED_SendCmd(0x10); // 设置列地址高4位
memcpy(sendBuffer_page + 1, OLED_GRAM[page], OLED_COLUMN);
OLED_Send(sendBuffer_page, OLED_COLUMN + 1);
}
}
/**
* @brief 设置一个像素点
* @param x 横坐标
* @param y 纵坐标
* @param color 颜色
*/
void OLED_SetPixel(uint8_t x, uint8_t y, OLED_ColorMode color)
{
if (x >= OLED_COLUMN || y >= OLED_ROW)
return;
if (!color)
{
OLED_GRAM[y / 8][x] |= 1 << (y % 8);
}
else
{
OLED_GRAM[y / 8][x] &= ~(1 << (y % 8));
}
}
/**
* @brief 设置显存中一字节数据的某几位
* @param page 页地址
* @param column 列地址
* @param data 数据
* @param start 起始位
* @param end 结束位
* @param color 颜色
* @note 此函数将显存中的某一字节的第start位到第end位设置为与data相同
* @note start和end的范围为0-7, start必须小于等于end
* @note 此函数与OLED_SetByte_Fine的区别在于此函数只能设置显存中的某一真实字节
*/
void OLED_SetByte_Fine(uint8_t page, uint8_t column, uint8_t data, uint8_t start, uint8_t end, OLED_ColorMode color)
{
static uint8_t temp;
if (page >= OLED_PAGE || column >= OLED_COLUMN)
return;
if (color)
data = ~data;
temp = data | (0xff << (end + 1)) | (0xff >> (8 - start));
OLED_GRAM[page][column] &= temp;
temp = data & ~(0xff << (end + 1)) & ~(0xff >> (8 - start));
OLED_GRAM[page][column] |= temp;
// 使用OLED_SetPixel实现
// for (uint8_t i = start; i <= end; i++) {
// OLED_SetPixel(column, page * 8 + i, !((data >> i) & 0x01));
// }
}
/**
* @brief 设置显存中的一字节数据
* @param page 页地址
* @param column 列地址
* @param data 数据
* @param color 颜色
* @note 此函数将显存中的某一字节设置为data的值
*/
void OLED_SetByte(uint8_t page, uint8_t column, uint8_t data, OLED_ColorMode color)
{
if (page >= OLED_PAGE || column >= OLED_COLUMN)
return;
if (color)
data = ~data;
OLED_GRAM[page][column] = data;
}
/**
* @brief 设置显存中的一字节数据的某几位
* @param x 横坐标
* @param y 纵坐标
* @param data 数据
* @param len 位数
* @param color 颜色
* @note 此函数将显存中从(x,y)开始向下数len位设置为与data相同
* @note len的范围为1-8
* @note 此函数与OLED_SetByte_Fine的区别在于此函数的横坐标和纵坐标是以像素为单位的, 可能出现跨两个真实字节的情况(跨页)
*/
void OLED_SetBits_Fine(uint8_t x, uint8_t y, uint8_t data, uint8_t len, OLED_ColorMode color)
{
uint8_t page = y / 8;
uint8_t bit = y % 8;
if (bit + len > 8)
{
OLED_SetByte_Fine(page, x, data << bit, bit, 7, color);
OLED_SetByte_Fine(page + 1, x, data >> (8 - bit), 0, len + bit - 1 - 8, color);
}
else
{
OLED_SetByte_Fine(page, x, data << bit, bit, bit + len - 1, color);
}
// 使用OLED_SetPixel实现
// for (uint8_t i = 0; i < len; i++) {
// OLED_SetPixel(x, y + i, !((data >> i) & 0x01));
// }
}
/**
* @brief 设置显存中一字节长度的数据
* @param x 横坐标
* @param y 纵坐标
* @param data 数据
* @param color 颜色
* @note 此函数将显存中从(x,y)开始向下数8位设置为与data相同
* @note 此函数与OLED_SetByte的区别在于此函数的横坐标和纵坐标是以像素为单位的, 可能出现跨两个真实字节的情况(跨页)
*/
void OLED_SetBits(uint8_t x, uint8_t y, uint8_t data, OLED_ColorMode color)
{
uint8_t page = y / 8;
uint8_t bit = y % 8;
OLED_SetByte_Fine(page, x, data << bit, bit, 7, color);
if (bit)
{
OLED_SetByte_Fine(page + 1, x, data >> (8 - bit), 0, bit - 1, color);
}
}
/**
* @brief 设置一块显存区域
* @param x 起始横坐标
* @param y 起始纵坐标
* @param data 数据的起始地址
* @param w 宽度
* @param h 高度
* @param color 颜色
* @note 此函数将显存中从(x,y)开始的w*h个像素设置为data中的数据
* @note data的数据应该采用列行式排列
*/
void OLED_SetBlock(uint8_t x, uint8_t y, const uint8_t *data, uint8_t w, uint8_t h, OLED_ColorMode color)
{
uint8_t fullRow = h / 8; // 完整的行数
uint8_t partBit = h % 8; // 不完整的字节中的有效位数
for (uint8_t i = 0; i < w; i++)
{
for (uint8_t j = 0; j < fullRow; j++)
{
OLED_SetBits(x + i, y + j * 8, data[i + j * w], color);
}
}
if (partBit)
{
uint16_t fullNum = w * fullRow; // 完整的字节数
for (uint8_t i = 0; i < w; i++)
{
OLED_SetBits_Fine(x + i, y + (fullRow * 8), data[fullNum + i], partBit, color);
}
}
// 使用OLED_SetPixel实现
// for (uint8_t i = 0; i < w; i++) {
// for (uint8_t j = 0; j < h; j++) {
// for (uint8_t k = 0; k < 8; k++) {
// if (j * 8 + k >= h) break; // 防止越界(不完整的字节
// OLED_SetPixel(x + i, y + j * 8 + k, !((data[i + j * w] >> k) & 0x01));
// }
// }
// }
}
/**********************显存操作函数end*************************/
// ================================ 文字绘制 ================================
/**
* @brief 绘制一个ASCII字符
* @param x 起始点横坐标
* @param y 起始点纵坐标
* @param ch 字符
* @param font 字体
* @param color 颜色
*/
void OLED_PrintASCIIChar(uint8_t x, uint8_t y, char ch, const ASCIIFont *font, OLED_ColorMode color)
{
OLED_SetBlock(x, y, font->chars + (ch - ' ') * (((font->h + 7) / 8) * font->w), font->w, font->h, color);
}
char lcd_page_flag[8];
/**
* @brief 绘制一个ASCII字符串
* @param x 起始点横坐标
* @param y 起始点纵坐标
* @param str 字符串
* @param font 字体
* @param color 颜色
*/
void OLED_PrintASCIIString(uint8_t x, uint8_t y, char *str, const ASCIIFont *font, OLED_ColorMode color)
{
uint8_t x0 = x;
while (*str)
{
OLED_PrintASCIIChar(x0, y, *str, font, color);
x0 += font->w;
str++;
}
}
/**
* @brief 获取UTF-8编码的字符长度
*/
uint8_t _OLED_GetUTF8Len(char *string)
{
if ((string[0] & 0x80) == 0x00)
{
return 1;
}
else if ((string[0] & 0xE0) == 0xC0)
{
return 2;
}
else if ((string[0] & 0xF0) == 0xE0)
{
return 3;
}
else if ((string[0] & 0xF8) == 0xF0)
{
return 4;
}
return 0;
}
/**
* @brief 绘制字符串
* @param x 起始点横坐标
* @param y 起始点纵坐标
* @param str 字符串
* @param font 字体
* @param color 颜色
*
* @note 为保证字符串中的中文会被自动识别并绘制, 需:
* 1. 编译器字符集设置为UTF-8
* 2. 使用波特律动LED取模工具生成字模(https://led.baud-dance.com)
*/
/**
* @brief 绘制字符串
* @param x 起始点横坐标
* @param y 起始点纵坐标
* @param str 字符串
* @param font 字体
* @param color 颜色
*
* @note 为保证字符串中的中文会被自动识别并绘制, 需:
* 1. 编译器字符集设置为UTF-8
* 2. 使用波特律动LED取模工具生成字模(https://led.baud-dance.com)
*/
void OLED_PrintString(uint8_t x, uint8_t y, char *str, const Font *font, OLED_ColorMode color)
{
uint16_t i = 0; // 字符串索引
uint8_t oneLen = (((font->h + 7) / 8) * font->w) + 4; // 一个字模占多少字节
uint8_t found; // 是否找到字模
uint8_t utf8Len; // UTF-8编码长度
uint8_t *head; // 字模头指针
while (str[i])
{
found = 0;
utf8Len = _OLED_GetUTF8Len(str + i);
if (utf8Len == 0)
break; // 有问题的UTF-8编码
// 寻找字符 TODO 优化查找算法, 二分查找或者hash
for (uint8_t j = 0; j < font->len; j++)
{
head = (uint8_t *)(font->chars) + (j * oneLen);
if (memcmp(str + i, head, utf8Len) == 0)
{
OLED_SetBlock(x, y, head + 4, font->w, font->h, color);
// 移动光标
x += font->w;
i += utf8Len;
found = 1;
break;
}
}
// 若未找到字模,且为ASCII字符, 则缺省显示ASCII字符
if (found == 0)
{
if (utf8Len == 1)
{
OLED_PrintASCIIChar(x, y, str[i], font->ascii, color);
// 移动光标
x += font->ascii->w;
i += utf8Len;
}
else
{
OLED_PrintASCIIChar(x, y, ' ', font->ascii, color);
x += font->ascii->w;
i += utf8Len;
}
}
}
}
char str_print[20] = {0};
char disp_step = 0,temp_cnt = 1;
float Xads_temp[2] = {0},T_temp[2] = {0};
char ocin1_temp[2] = {0},ocin2_temp[2] = {0};
void OLED_Act( void )
{
if(disp_step < 80) //只显示一次
{
OLED_PrintASCIIString(0,0,"Position",&afont16x8, OLED_COLOR_NORMAL);
sprintf(str_print, "%.2f",X_ads1220_prc*100 );
OLED_PrintASCIIString(0,16,str_print,&afont16x8, OLED_COLOR_NORMAL);
// OLED_PrintASCIIString(0,32,"Temperature",&afont12x6, OLED_COLOR_NORMAL);
OLED_PrintASCIIString(48,16,"%",&afont16x8, OLED_COLOR_NORMAL);
OLED_PrintASCIIString(0,32,"ocin1:",&afont16x8, OLED_COLOR_NORMAL);
OLED_PrintASCIIString(64,32,"ocin2:",&afont16x8, OLED_COLOR_NORMAL);
if(ocin1 == 0x00)
{
OLED_PrintASCIIString(0,48,"ERROR",&afont16x8, OLED_COLOR_NORMAL);
}else
{
OLED_PrintASCIIString(16,48,"OK",&afont16x8, OLED_COLOR_NORMAL);
}
if(ocin2 == 0x00)
{
OLED_PrintASCIIString(64,48,"ERROR",&afont16x8, OLED_COLOR_NORMAL);
}else
{
OLED_PrintASCIIString(80,48,"OK",&afont16x8, OLED_COLOR_NORMAL);
}
OLED_ShowFrame(); //显示当前显存内容
disp_step++;
}
if(disp_step == 80) //refresh when changes happen
{
// OLED_DisPlay_On();
Xads_temp[temp_cnt] = X_ads1220_prc;
T_temp[temp_cnt] = TEMP_M1820;
ocin1_temp[temp_cnt] = ocin1;
ocin2_temp[temp_cnt] = ocin2;
if(Xads_temp[temp_cnt] - Xads_temp[!temp_cnt] > 0.01) // refresh when Xads1220 changes
{
OLED_PrintASCIIString(0,16," ",&afont16x8, OLED_COLOR_NORMAL); // clear
sprintf(str_print, "%.2f",Xads_temp[temp_cnt]*100 ); // 电阻尺
OLED_PrintASCIIString(0,16,str_print,&afont16x8, OLED_COLOR_NORMAL);
OLED_ShowPageFrame(2);
OLED_ShowPageFrame(3);
}
if(ocin1_temp[temp_cnt] != ocin1_temp[!temp_cnt]) //refresh when ocin1 changes
{
OLED_PrintASCIIString(0,48," ",&afont16x8, OLED_COLOR_NORMAL); // clear
if(ocin1_temp[temp_cnt] == 0x00)
{
OLED_PrintASCIIString(0,48,"ERROR",&afont16x8, OLED_COLOR_NORMAL);
}else
{
OLED_PrintASCIIString(16,48,"OK",&afont16x8, OLED_COLOR_NORMAL);
}
OLED_ShowPageFrame(6);
OLED_ShowPageFrame(7);
}
if(ocin2_temp[temp_cnt] != ocin2_temp[!temp_cnt]) //refresh when ocin2 changes
{
OLED_PrintASCIIString(64,48," ",&afont16x8, OLED_COLOR_NORMAL); // clear the hole line to refresh
if(ocin2_temp[temp_cnt] == 0x00)
{
OLED_PrintASCIIString(64,48,"ERROR",&afont16x8, OLED_COLOR_NORMAL);
}else
{
OLED_PrintASCIIString(80,48,"OK",&afont16x8, OLED_COLOR_NORMAL);
}
OLED_ShowPageFrame(6);
OLED_ShowPageFrame(7);
}
// OLED_ShowFrame(); //显示当前显存内容
// OLED_ShowPageFrame(2);
// OLED_ShowPageFrame(3);
OLED_ShowPageFrame(6);
// OLED_ShowPageFrame(7);
temp_cnt = !temp_cnt;
}
}