U8G2简单应用-动画
目录
1.进度条
1.1 简单的进度条
static void show_progress(u8g2_t *u8g2)
{
#define U8G2_MARGINS (2)
static unsigned int ipx = 0;
#if 1 /* 重复绘制 */
u8g2_DrawFrame(u8g2, 0, 40, u8g2_GetDisplayWidth(u8g2), 15);
if(ipx<(u8g2_GetDisplayWidth(u8g2)-U8G2_MARGINS*2))
u8g2_DrawBox(u8g2, U8G2_MARGINS, 40+U8G2_MARGINS, U8G2_MARGINS+ipx, 15-U8G2_MARGINS*2);
ipx++;
if(ipx>=(u8g2_GetDisplayWidth(u8g2)-U8G2_MARGINS*2))
ipx = 0;
#else /* 只绘制一次 */
if(ipx>=(u8g2_GetDisplayWidth(u8g2)-U8G2_MARGINS*2))
ipx = (u8g2_GetDisplayWidth(u8g2)-U8G2_MARGINS*2);
u8g2_DrawFrame(u8g2, 0, 40, u8g2_GetDisplayWidth(u8g2), 15);
if(ipx<(u8g2_GetDisplayWidth(u8g2)-U8G2_MARGINS*2))
u8g2_DrawBox(u8g2, U8G2_MARGINS, 40+U8G2_MARGINS, U8G2_MARGINS+ipx, 15-U8G2_MARGINS*2);
else
u8g2_DrawBox(u8g2, U8G2_MARGINS, 40+U8G2_MARGINS, ipx, 15-U8G2_MARGINS*2);
ipx++;
#endif
return;
}
u8g2_FirstPage(&u8g2);
do
{
show_progress(&u8g2);
} while (u8g2_NextPage(&u8g2));
显示效果:
1.2 带进度百分比的进度条
说明:
- U8G2_BAR_R之所以定义为0是因为当有角度时,进度%1-%10显示会有问题,这个是可以理解的,当有圆角时,如果宽度太小会显示异常。
- lcdWidth与lcdHeight定义为了浮点类型,因为要参与除法运算。
static void showLoading(u8g2_t *u8g2)
{
#define U8G2_SPACING (2) // 边框到屏幕边沿的间距
#define U8G2_BOX_WIDTH (1) // 边框的宽度
#define U8G2_BOX_HEIGHT (16) // 边框的高度
#define U8G2_BAR_HEITH (12) // 进度条的宽度
#define U8G2_BAR_R (0) // 如果带圆角,进度条的角度
#define U8G2_BAR_MAX (99) // 进度最大值
float lcdWidth = u8g2_GetDisplayWidth(u8g2);
float lcdHeight = u8g2_GetDisplayHeight(u8g2);
static unsigned char progress = 0; //百度比进度
char progressBuf[4] = {0};
float setp = 0; //每百分之一进度显示的宽度
unsigned int barWidth = 0; //进度条的宽度
// 画左上和右上的边框
u8g2_DrawBox(u8g2, U8G2_SPACING, U8G2_SPACING, lcdWidth-U8G2_SPACING*2, U8G2_BOX_WIDTH);
u8g2_DrawBox(u8g2, U8G2_SPACING, U8G2_SPACING, U8G2_BOX_WIDTH, U8G2_BOX_HEIGHT);
u8g2_DrawBox(u8g2, lcdWidth-U8G2_SPACING-U8G2_BOX_WIDTH, U8G2_SPACING, U8G2_BOX_WIDTH, U8G2_BOX_HEIGHT);
// 画左下和右下的边框
u8g2_DrawBox(u8g2, U8G2_SPACING, lcdHeight-U8G2_SPACING-U8G2_BOX_WIDTH, lcdWidth-U8G2_SPACING*2, U8G2_BOX_WIDTH);
u8g2_DrawBox(u8g2, U8G2_SPACING, lcdHeight-U8G2_SPACING-U8G2_BOX_HEIGHT, U8G2_BOX_WIDTH, U8G2_BOX_HEIGHT);
u8g2_DrawBox(u8g2, lcdWidth-U8G2_SPACING-U8G2_BOX_WIDTH, lcdHeight-U8G2_SPACING-U8G2_BOX_HEIGHT,
U8G2_BOX_WIDTH, U8G2_BOX_HEIGHT);
// 显示Loading字符串
u8g2_SetFont(u8g2, u8g2_font_amstrad_cpc_extended_8r);
u8g2_DrawStr(u8g2, (lcdWidth-u8g2_GetStrWidth(u8g2, "Loading"))/2, lcdHeight*1/3, "Loading");
// 画进度条边框
u8g2_DrawRFrame(u8g2, (lcdWidth-(lcdWidth*2/3))/2, (lcdHeight/2)-(U8G2_BAR_HEITH/2), (lcdWidth*2)/3, U8G2_BAR_HEITH, U8G2_BAR_R);
setp = ((lcdWidth*2)/3)/U8G2_BAR_MAX;
barWidth = setp*progress;
if(progress<=U8G2_BAR_MAX)
{
// 显示进度条
u8g2_DrawRBox(u8g2, (lcdWidth-(lcdWidth*2/3))/2, ((lcdHeight/2)-(U8G2_BAR_HEITH/2)),
barWidth, U8G2_BAR_HEITH, U8G2_BAR_R);
//显示进度百分比
snprintf(progressBuf, sizeof(progressBuf), "%2d%s", progress, "%");
u8g2_DrawStr(u8g2, (lcdWidth-u8g2_GetStrWidth(u8g2, progressBuf))/2, lcdHeight*3/4, progressBuf);
progress++;
}
else
{
progress = 0;
}
}
int main(void)
{
unsigned int index;
u8g2_t u8g2;
SysTick_Init(72);
GPIO_Configuration();
u8g2_init(&u8g2);
while (1)
{
index++;
if(index%10000)
PBout(12) = ~ PBin(12);
delay_us(100);
u8g2_FirstPage(&u8g2);
do
{
showLoading(&u8g2);
} while (u8g2_NextPage(&u8g2));
}
}
显示效果:
2. 圆球碰撞反弹
static void random_pattern(u8g2_t *u8g2)
{
#define WIDTH 128
#define HIGH 64
#define R 10
static int Vx=5,Vy=5; // 球移动的步长
static int x=WIDTH/2,y=HIGH/2; // 表示小球的圆心坐标
u8g2_DrawDisc(u8g2, x, y, R, U8G2_DRAW_ALL);
x=x+Vx;
y=y+Vy;
if(x<=R || x>=WIDTH-R)
Vx=-Vx;
if(y<=R || y>=HIGH-R)
Vy=-Vy;
return;
}
说明:代码参考了,https://www.dotcpp.com/course/1182
u8g2_FirstPage(&u8g2);
do
{
random_pattern(&u8g2);
delay_ms(100);
} while (u8g2_NextPage(&u8g2));
显示效果:
3. 在随机位置生成一个图形(测试代码是矩形)
全部代码放在最后。
//random.c
#include "random.h"
#include "stdlib.h"
#include "string.h"
#include "SysTick.h"
extern u32 rand_time_us; //用定时器提供一个动态变量
//=============================================================================
//函数名称:rand_seed
//功能概要:产生随机数
//参数说明:产生min-max之间的随机数
//函数返回:int
//=============================================================================
unsigned int rand_seed(unsigned int min, unsigned int max)
{
unsigned int num;
static char first = 1;
if(first) //只执行一次
{
first = 0;
srand(rand_time_us); //提供随机数种子
}
num = rand() % (max - min + 1) + min;
return num;
}
//main.c
static void random_pattern(u8g2_t *u8g2)
{
unsigned int x, y, w, h;
do{
x = rand_seed(0, 128);
w = rand_seed(0, 128);
}while((x+w)>128);
do{
y = rand_seed(0, 64);
h = rand_seed(0, 64);
}while((y+h)>64);
u8g2_DrawBox(u8g2, x, y, w, h);
}
显示效果:
4. 线段扫描
static void random_pattern(u8g2_t *u8g2)
{
unsigned char setp = 4;
unsigned char x1 = 0, y1 = 0;
static char x2 = 0, y2 = 64;
if(x2<=128)
{
u8g2_DrawLine(u8g2, x1, y1, x2, y2);
x2 = x2+setp;
}
else
{
y2 = y2 -setp;
u8g2_DrawLine(u8g2, x1, y1, x2, y2);
if(y2<=0)
{
x2 = 0;
y2 = 64;
}
}
}
u8g2_FirstPage(&u8g2);
do
{
random_pattern(&u8g2);
delay_ms(50);
} while (u8g2_NextPage(&u8g2));
显示效果:
5. 代码雨
代码参考链接:https://www.jb51.net/article/247902.htm
说明:
- 参考代码是坚着刷新数据的,这里是根据屏横向刷新数据
- 记得修改startup_stm32f10x_hd.s中的栈大小,原来只有620字节(0x400),修改为1440(0x800)。如果不修改栈大小程序跑不起来(这里我找了好久)。
5.1 静态的代码雨
修改栈大小
startup_stm32f10x_hd.s
Stack_Size EQU 0x00000400
修改为
Stack_Size EQU 0x00000800
main.c
static void random_pattern(u8g2_t *u8g2)
{
#define High 64
#define Width 128
#define CharSize 8
int highNum=High/CharSize;
int widthNum=Width/CharSize;
int CharRain[High/CharSize][Width/CharSize];
int RNum[High/CharSize];//每一行的有效字符个数
int i,j,x,y;
char ascii[1] = {0};
for(j=0;j<highNum;j++)
{
for(i=0;i<widthNum;i++)
CharRain[j][i] = 32;
}
for(j=0;j<highNum;j++)//初始化字符矩阵
{
RNum[j] = rand_seed(3, widthNum);//这一行的有效字符个数
for(i=0;i<RNum[j];i++)
CharRain[j][i] = rand_seed(0, 25)+65;//产生A~Z的随机字符
}
u8g2_SetFont(u8g2, u8g2_font_amstrad_cpc_extended_8r);
u8g2_SetFontDirection(u8g2, 0);
for(j=0;j<highNum;j++)//输出整个字符矩阵
{
y=(j+1)*CharSize;//当前字符的y坐标
for(i=0;i<RNum[j];i++)
{
x=i*CharSize;//当前字符的x坐标
memset(ascii, 0, sizeof(ascii));
sprintf(ascii, "%c", CharRain[j][i]);
u8g2_DrawStr(u8g2, x, y, ascii);//输出当前字符
}
}
}
u8g2_FirstPage(&u8g2);
do
{
random_pattern(&u8g2);
delay_ms(500);
} while (u8g2_NextPage(&u8g2));
显示效果:
5.2 动态的代码雨
说明:
- 这里需要一直while循环,所以修改了u8g2的主循环
static void random_pattern(u8g2_t *u8g2)
{
#define High 64
#define Width 128
#define CharSize 8
int highNum=High/CharSize;
int widthNum=Width/CharSize;
int charNotFull;
int CharRain[High/CharSize][Width/CharSize];
int RNum[High/CharSize];//每一行的有效字符个数
int i,j,x,y;
char ascii[1] = {0};
/* 全部重新显示 */
resetShow:
u8g2_ClearBuffer(u8g2);
for(j=0;j<highNum;j++)
{
for(i=0;i<widthNum;i++)
CharRain[j][i] = 32;
}
for(j=0;j<highNum;j++)//初始化字符矩阵
{
RNum[j] = rand_seed(3, widthNum);//这一行的有效字符个数
for(i=0;i<RNum[j];i++)
CharRain[j][i] = rand_seed(0, 25)+65;//产生A~Z的随机字符
}
u8g2_SetFont(u8g2, u8g2_font_amstrad_cpc_extended_8r);
u8g2_SetFontDirection(u8g2, 0);
do
{
/* 还有行没有满,重新填充显示 */
reShow:
delay_ms(500);
for(j=0;j<highNum;j++)//输出整个字符矩阵
{
if(RNum[j]<widthNum)//当这一列字符没有填满时
{
for(i=RNum[j]-1;i>=0; i--)//每个字符向下移动一格
{
CharRain[j][i+1]=CharRain[j][i];
}
CharRain[j][0] = rand_seed(0, 25)+65;//产生A~Z的随机字符
RNum[j]=RNum[j]+1; //这一行的字符数加1
}
}
for(j=0;j<highNum;j++)//输出整个字符矩阵
{
y=(j+1)*CharSize;//当前字符的y坐标
for(i=0;i<RNum[j];i++)
{
x=i*CharSize;//当前字符的x坐标
memset(ascii, 0, sizeof(ascii));
sprintf(ascii, "%c", CharRain[j][i]);
u8g2_DrawStr(u8g2, x, y, ascii);//输出当前字符
}
}
u8g2_SendBuffer(u8g2);
for(j=0;j<highNum;j++) // 判断是否显示满
{
if(RNum[j]<widthNum) // 当这一行字符没有填满时,重新填充显示
{
goto reShow;
}
else
{
if(j==highNum-1) // 当全部行都填满时,重新显示
{
goto resetShow;
break;
}
}
}
}
while (1);
}
int main(void)
{
unsigned int index, x = 0, yn;
u8g2_t u8g2;
uint8_t val = 3;
SysTick_Init(72);
GPIO_Configuration();
u8g2_init(&u8g2);
while (1)
{
index++;
if(index%10000)
PBout(12) = ~ PBin(12);
delay_us(100);
//u8g2_FirstPage(&u8g2);
//do
{
random_pattern(&u8g2);
}
//while (u8g2_NextPage(&u8g2));
}
}
显示效果(从左边填充空白):
5.3 实现代码雨动画(填充空白,并且每行数据下移)
static void random_pattern(u8g2_t *u8g2)
{
#define High 64
#define Width 128
#define CharSize 8
int highNum=High/CharSize;
int widthNum=Width/CharSize;
int charNotFull;
int tmp[Width/CharSize], rTmp;
int CharRain[High/CharSize][Width/CharSize];
int RNum[High/CharSize];//每一行的有效字符个数
int i,j,x,y;
char ascii[1] = {0};
resetShow:
u8g2_ClearBuffer(u8g2);
for(j=0;j<highNum;j++)
{
for(i=0;i<widthNum;i++)
CharRain[j][i] = 32;
}
for(j=0;j<highNum;j++)//初始化字符矩阵
{
RNum[j] = rand_seed(3, widthNum/2);//这一行的有效字符个数
for(i=0;i<RNum[j];i++)
CharRain[j][i] = rand_seed(0, 25)+65;//产生A~Z的随机字符
}
u8g2_SetFont(u8g2, u8g2_font_amstrad_cpc_extended_8r);
u8g2_SetFontDirection(u8g2, 0);
do
{
reShow:
delay_ms(500);
for(j=0;j<highNum;j++)//输出整个字符矩阵
{
if(RNum[j]<widthNum)//当这一列字符没有填满时
{
for(i=RNum[j]-1;i>=0; i--)//每个字符向下移动一格
{
CharRain[j][i+1]=CharRain[j][i];
}
CharRain[j][0] = rand_seed(0, 25)+65;//产生A~Z的随机字符
RNum[j]=RNum[j]+1; //这一行的字符数加1
}
}
for(j=0;j<highNum;j++)//输出整个字符矩阵
{
y=(j+1)*CharSize;//当前字符的y坐标
for(i=0;i<RNum[j];i++)
{
x=i*CharSize;//当前字符的x坐标
memset(ascii, 0, sizeof(ascii));
sprintf(ascii, "%c", CharRain[j][i]);
u8g2_DrawStr(u8g2, x, y, ascii);//输出当前字符
}
}
memset(tmp, 32, sizeof(tmp));
rTmp = 0;
memcpy(tmp, CharRain[highNum-1], sizeof(tmp));
rTmp = RNum[highNum-1];
for(j=highNum-1;j>=0;j--)//输出整个字符矩阵
{
memcpy(CharRain[j], CharRain[j-1], sizeof(CharRain[j-1]));
RNum[j] = RNum[j-1];
}
memcpy(CharRain[0], tmp, sizeof(tmp));
RNum[0] = rTmp;
u8g2_SendBuffer(u8g2);
for(j=0;j<highNum;j++) // 判断是否显示满
{
if(RNum[j]<widthNum) // 当这一列字符没有填满时,重新填充显示
{
goto reShow;
}
else
{
if(j==highNum-1) // 当全部行都填满时,重新显示
{
goto resetShow;
break;
}
}
}
}
while (1);
}
int main(void)
{
unsigned int index, x = 0, yn;
u8g2_t u8g2;
uint8_t val = 3;
SysTick_Init(72);
GPIO_Configuration();
u8g2_init(&u8g2);
while (1)
{
index++;
if(index%10000)
PBout(12) = ~ PBin(12);
delay_us(100);
//u8g2_FirstPage(&u8g2);
//do
{
random_pattern(&u8g2);
}
//while (u8g2_NextPage(&u8g2));
}
}
显示效果:
6. 星空动画
引用自:https://blog.csdn.net/qq_51096702/article/details/130460827
typedef struct START
{
uint16_t x;
uint16_t y;
uint16_t speed;
uint8_t speedcount;
uint8_t isexist;
} Star;
static Star star[128] = {0};
void Sky_Animation_show(u8g2_t *u8g2) // 星空动画
{
uint8_t i = 0;
unsigned int lcdWidth = u8g2_GetDisplayWidth(u8g2);
unsigned int lcdHeight = u8g2_GetDisplayWidth(u8g2);
for (i = 0; i < lcdWidth; i++)
{
if (star[i].isexist == 0)
{
// 设置128个()星星的初始信息
star[i].x = rand_seed(0, lcdWidth); // 随机生成初始x坐标
star[i].y = rand_seed(0, lcdHeight); // 随机生成y的坐标
star[i].speedcount = 0;
star[i].speed = rand_seed(0, 8) + 1; // 1-8的数(长度)
star[i].isexist = 1;
}
}
for (i = 0; i < lcdWidth; i++)
{
// 如果这一个星星已经移动到退出屏幕界面
// 则在最左侧重新生成一颗新星星
if (star[i].isexist == 0)
{
star[i].x = 0;
star[i].y = rand_seed(0, lcdHeight);
star[i].speedcount = 0;
star[i].speed = rand_seed(0, 6) + 1; // 1-6的数(长度)
star[i].isexist = 1;
}
else
{
star[i].speedcount++;
if (star[i].x >= (lcdWidth-4)) // 标记已经退出屏幕
star[i].isexist = 0;
// 清除上一个时刻画的星星(的尾巴) 不管有没有操作 都进行清除操作
u8g2_SetDrawColor(u8g2, 0);
u8g2_DrawLine(u8g2, star[i].x, star[i].y, star[i].x, star[i].y);
u8g2_SetDrawColor(u8g2, 2);
if (star[i].speedcount == star[i].speed) // 运行时间到了一定的长度
{
star[i].speedcount = 0; // 复位运行时间并向右移一格
star[i].x += 1; // 总之星星的结束需要在这经历124次
}
// 只不过有的更快 就能移动更快
// 从头到尾画出整条星星 不管星星是否已经变化
u8g2_DrawLine(u8g2, star[i].x, star[i].y, star[i].x + (6 / star[i].speed), star[i].y);
}
}
}
int main(void)
{
unsigned int index, x = 0, yn;
u8g2_t u8g2;
uint8_t val = 3;
SysTick_Init(72);
GPIO_Configuration();
u8g2_init(&u8g2);
while (1)
{
index++;
if(index%10000)
PBout(12) = ~ PBin(12);
delay_us(100);
u8g2_FirstPage(&u8g2);
do
{
Sky_Animation_show(&u8g2);
}
while (u8g2_NextPage(&u8g2));
}
}
显示效果:
7. 源码
在随机位置生成一个图形(测试代码是矩形)源码:
链接:https://pan.baidu.com/s/1ODQzlX-4O6Z5gBeAOLHorA
提取码:v1ks
文件:spi_lcd_u8g2_v02.zip
视频转gif,或者gif转视频:https://www.zhihuilib.com/general/gifcompress