目录
自己移植的U8g2库,OLED库超好用,自己封装了用户层不需要再去查资料使用,注释写的很多很详细,有示例上手就会,初始化也很简单
超简单的stm32 U8g2移植
大家可以自己去官网移植,也可以用我的 U8G2官网
很多大家都可以举一反三
一、小球在 OLED 屏幕平面内运动并碰撞反弹的效果
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// 小球结构体,包含位置、速度等信息
typedef struct {
int16_t x;
int16_t y;
int16_t vx; // x方向速度
int16_t vy; // y方向速度
uint8_t radius; // 小球半径
} Ball;
// 初始化小球的位置和速度
void init_ball(Ball *ball) {
ball->x = 10;
ball->y = 10;
ball->vx = 2;
ball->vy = 2;
ball->radius = 5;
}
// 更新小球的位置,处理边界碰撞
void update_ball_position(Ball *ball, u8g2_uint_t screen_width, u8g2_uint_t screen_height) {
// 更新x坐标
ball->x += ball->vx;
// 检查是否碰到左右边界,碰到则反弹
if (ball->x <= ball->radius || ball->x >= screen_width - ball->radius) {
ball->vx = -ball->vx;
}
// 更新y坐标
ball->y += ball->vy;
// 检查是否碰到上下边界,碰到则反弹
if (ball->y <= ball->radius || ball->y >= screen_height - ball->radius) {
ball->vy = -ball->vy;
}
}
// 在OLED屏幕上绘制小球
void draw_ball(Ball ball) {
WU_OLED_U8G2_DrawDisc(ball.x, ball.y, ball.radius, U8G2_DRAW_ALL);
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
OLED_WUStartTask04(void *argument)
{
Ball my_ball;
init_ball(&my_ball);
while(1)
{
//Wu_oled_Proc();
// 清空缓冲区
WU_OLED_U8G2_ClearBuffer();
// 获取屏幕宽度和高度
u8g2_uint_t screen_width = WU_OLED_U8G2_GetDisplayWidth();
u8g2_uint_t screen_height = WU_OLED_U8G2_GetDisplayHeight();
// 更新小球位置
update_ball_position(&my_ball, screen_width, screen_height);
// 绘制小球
draw_ball(my_ball);
// 刷新缓冲区,显示内容到OLED屏幕
WU_OLED_U8G2_SendBuffer();
//osDelay(50);
}
}
二、 简单的波形生成和显示程序:
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include "../../WU/OLED_U8g2/U8g2/WU_U8g2_Init.h"
#include "USER_OLED.h"
#include "../../WU/OLED_U8g2/U8g2/u8g2.h"
// 定义屏幕的宽度和高度
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// 定义波形参数
#define WAVE_AMPLITUDE 20 // 波形的振幅
#define WAVE_FREQUENCY 0.2 // 波形的频率(加快频率)
// 初始化波形数据
void InitWave(void) {
// 无需初始化,因为每次都会重新计算正弦波
}
// 更新波形数据(生成正弦波)
void UpdateWave(uint8_t *waveData, float time) {
for (int i = 0; i < SCREEN_WIDTH; i++) {
// 计算正弦波的值,并将其映射到屏幕范围内
float value = WAVE_AMPLITUDE * sin(WAVE_FREQUENCY * (i + time));
waveData[i] = SCREEN_HEIGHT / 2 + (uint8_t)value;
}
}
// 绘制波形
void DrawWave(uint8_t *waveData) {
// 清空屏幕
WU_OLED_U8G2_ClearBuffer();
// 绘制波形
for (int i = 0; i < SCREEN_WIDTH; i++) {
// 确保波形在屏幕范围内
if (waveData[i] < SCREEN_HEIGHT) {
WU_OLED_U8G2_DrawPixel(i, waveData[i]);
}
}
// 刷新发送缓冲区
WU_OLED_U8G2_SendBuffer();
}
// 主函数
int main(void) {
uint8_t waveData[SCREEN_WIDTH]; // 存储每个像素点的Y坐标
float time = 0; // 时间变量,用于生成动态波形
// 初始化OLED
WU_OLED_U8G2_Init();
// 主循环
while (1) {
// 更新波形数据
UpdateWave(waveData, time);
// 绘制波形
DrawWave(waveData);
// 更新时间(加快波形移动速度)
time += 1.0;
// 延时一段时间,控制波形刷新速度(减少延时时间)
// 这里假设有一个延时函数 delay_ms
//delay_ms(20); // 将延时时间从50ms减少到20ms
}
return 0;
}
三、三维三角形旋转展示
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// 定义更大的三角形在三维空间中的三个顶点坐标
float triangleVertices[3][3] = {
{-15, -15, 0}, // 第一个顶点,调整了坐标使三角形更大
{15, -15, 0}, // 第二个顶点
{0, 15, 0} // 第三个顶点
};
// 用于记录绕X、Y、Z轴旋转的角度
float angleX = 0;
float angleY = 0;
float angleZ = 0;
// 旋转角度的增量,这里固定一个合适的速度,可按需调整
const float angleIncrement = 0.03;
// 投影平面距离视点(类似相机到投影平面的距离,影响投影效果,可调整)
const float projectionPlaneDistance = 8;
// 转换三维坐标到二维屏幕坐标(简单的正投影示例,实际可替换为更复杂的投影算法比如透视投影等)
void project3DTo2D(float point3D[3], float* x2D, float* y2D) {
// 先绕X轴旋转
float rotatedX = point3D[0];
float rotatedY = point3D[1] * cos(angleX) - point3D[2] * sin(angleX);
float rotatedZ = point3D[1] * sin(angleX) + point3D[2] * cos(angleX);
// 再绕Y轴旋转
rotatedX = rotatedX * cos(angleY) + rotatedZ * sin(angleY);
rotatedZ = -rotatedX * sin(angleY) + rotatedZ * cos(angleY);
// 接着绕Z轴旋转
rotatedX = rotatedX * cos(angleZ) - rotatedY * sin(angleZ);
rotatedY = rotatedX * sin(angleZ) + rotatedY * cos(angleZ);
// 进行正投影,将三维坐标投影到二维平面(这里假设投影平面平行于XY平面,且在Z轴固定位置)
*x2D = rotatedX * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
*y2D = rotatedY * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
// 转换坐标到屏幕坐标系(以屏幕中心为原点,根据屏幕尺寸进行偏移等调整)
*x2D += 64; // 这里假设屏幕宽度为128像素,取一半作为中心原点的X偏移量,可根据实际屏幕宽度调整
*y2D += 32; // 这里假设屏幕高度为64像素,取一半作为中心原点的Y偏移量,可根据实际屏幕高度调整
}
// 绘制旋转后的空心三角形
void drawRotatedTriangle() {
float x1, y1, x2, y2, x3, y3;
// 对三角形的三个顶点分别进行投影转换
project3DTo2D(triangleVertices[0], &x1, &y1);
project3DTo2D(triangleVertices[1], &x2, &y2);
project3DTo2D(triangleVertices[2], &x3, &y3);
// 绘制空心三角形(使用绘制线的函数来连接三个顶点形成三角形)
WU_OLED_U8G2_DrawLine(x1, y1, x2, y2);
WU_OLED_U8G2_DrawLine(x2, y2, x3, y3);
WU_OLED_U8G2_DrawLine(x3, y3, x1, y1);
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
OLED_WUStartTask04(void *argument)
{
while(1)
{
//Wu_oled_Proc();
// 清空发送缓冲区
WU_OLED_U8G2_ClearBuffer();
// 绘制旋转后的空心三角形
drawRotatedTriangle();
// 更新旋转角度(分别绕X、Y、Z轴增加一定角度,实现旋转效果)
angleX += angleIncrement;
angleY += angleIncrement;
angleZ += angleIncrement;
if (angleX >= 2 * M_PI) angleX -= 2 * M_PI;
if (angleY >= 2 * M_PI) angleY -= 2 * M_PI;
if (angleZ >= 2 * M_PI) angleZ -= 2 * M_PI;
// 刷新发送缓冲区,将绘制内容显示到屏幕上
WU_OLED_U8G2_SendBuffer();
// 可以添加适当延时,控制动画速度,这里简单示意,实际可根据需求调整延时时间
//osDelay(50);
}
}
四、正方形平面内顺时针旋转
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// 定义正方形在三维空间中的四个顶点坐标,调整大小使其适配屏幕
float squareVertices[4][3] = {
{-20, -20, 0}, // 左下角顶点
{20, -20, 0}, // 右下角顶点
{20, 20, 0}, // 右上角顶点
{-20, 20, 0} // 左上角顶点
};
// 用于记录绕 Z 轴旋转的角度(仅绕 Z 轴旋转可实现平面内顺时针旋转)
float angleZ = 0;
// 旋转角度的增量,用于控制旋转速度,可根据实际需求调整
const float angleIncrement = 0.05;
// 投影平面距离视点(类似相机到投影平面的距离,影响投影效果,可调整)
const float projectionPlaneDistance = 5;
// 转换三维坐标到二维屏幕坐标(简单的正投影示例,实际可替换为更复杂的投影算法比如透视投影等)
void project3DTo2D(float point3D[3], float* x2D, float* y2D) {
// 先绕 Z 轴旋转
float rotatedX = point3D[0] * cos(angleZ) - point3D[1] * sin(angleZ);
float rotatedY = point3D[0] * sin(angleZ) + point3D[1] * cos(angleZ);
float rotatedZ = point3D[2];
// 进行正投影,将三维坐标投影到二维平面(这里假设投影平面平行于XY平面,且在Z轴固定位置)
*x2D = rotatedX * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
*y2D = rotatedY * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
// 转换坐标到屏幕坐标系(以屏幕中心为原点,根据屏幕尺寸进行偏移等调整)
*x2D += 64; // 这里假设屏幕宽度为128像素,取一半作为中心原点的X偏移量,可根据实际屏幕宽度调整
*y2D += 32; // 这里假设屏幕高度为64像素,取一半作为中心原点的Y偏移量,可根据实际屏幕高度调整
}
// 绘制旋转后的正方形
void drawRotatedSquare() {
float x1, y1, x2, y2, x3, y3, x4, y4;
// 对正方形的四个顶点分别进行投影转换
project3DTo2D(squareVertices[0], &x1, &y1);
project3DTo2D(squareVertices[1], &x2, &y2);
project3DTo2D(squareVertices[2], &x3, &y3);
project3DTo2D(squareVertices[3], &x4, &y4);
// 绘制正方形的四条边
WU_OLED_U8G2_DrawLine(x1, y1, x2, y2);
WU_OLED_U8G2_DrawLine(x2, y2, x3, y3);
WU_OLED_U8G2_DrawLine(x3, y3, x4, y4);
WU_OLED_U8G2_DrawLine(x4, y4, x1, y1);
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
OLED_WUStartTask04(void *argument)
{
while(1)
{
//Wu_oled_Proc();
// 清空发送缓冲区
WU_OLED_U8G2_ClearBuffer();
// 绘制旋转后的正方形
drawRotatedSquare();
// 更新旋转角度(绕 Z 轴增加一定角度,实现顺时针旋转效果)
angleZ += angleIncrement;
if (angleZ >= 2 * M_PI) angleZ -= 2 * M_PI;
// 刷新发送缓冲区,将绘制内容显示到屏幕上
WU_OLED_U8G2_SendBuffer();
// 可以添加适当延时,控制动画速度,这里简单示意,实际可根据需求调整延时时间
//osDelay(50);
}
}
五、带有旋转点的空心圆圈应用
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// 定义大空心圆圈的圆心坐标及半径
float bigCircleCenter[2] = {0, 0};
float bigCircleRadius = 25;
// 定义实心小圆圈的初始坐标
float smallSolidCircle[3];
// 用于记录实心小圆圈绕大空心圆圈旋转的角度
float circleAngle = 0;
const float circleAngleIncrement = 0.03;
// 投影平面距离视点(类似相机到投影平面的距离,影响投影效果,可调整)
const float projectionPlaneDistance = 5;
// 转换三维坐标到二维屏幕坐标(简单的正投影示例,实际可替换为更复杂的投影算法比如透视投影等)
void project3DTo2D(float point3D[3], float* x2D, float* y2D) {
// 先绕 Z 轴旋转(针对实心小圆圈所在平面内旋转)
float rotatedX = point3D[0];
float rotatedY = point3D[1];
float rotatedZ = point3D[2];
// 进行正投影,将三维坐标投影到二维平面(这里假设投影平面平行于XY平面,且在Z轴固定位置)
*x2D = rotatedX * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
*y2D = rotatedY * projectionPlaneDistance / (rotatedZ + projectionPlaneDistance);
// 转换坐标到屏幕坐标系(以屏幕中心为原点,根据屏幕尺寸进行偏移等调整)
*x2D += WU_OLED_U8G2_GetDisplayWidth() / 2;
*y2D += WU_OLED_U8G2_GetDisplayHeight() / 2;
}
// 绘制大空心圆圈
void drawBigHollowCircle() {
float centerX, centerY;
project3DTo2D(bigCircleCenter, ¢erX, ¢erY);
WU_OLED_U8G2_DrawCircle(centerX, centerY, bigCircleRadius, U8G2_DRAW_ALL);
}
// 绘制实心小圆圈并更新其位置(绕大空心圆圈旋转)
void drawRotatingSmallSolidCircle() {
float x, y;
// 根据旋转角度更新实心小圆圈的坐标
smallSolidCircle[0] = bigCircleRadius * cos(circleAngle);
smallSolidCircle[1] = bigCircleRadius * sin(circleAngle);
project3DTo2D(smallSolidCircle, &x, &y);
WU_OLED_U8G2_DrawDisc(x, y, 5, U8G2_DRAW_ALL);
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
OLED_WUStartTask04(void *argument)
{
// 初始化实心小圆圈的坐标
smallSolidCircle[0] = bigCircleRadius;
smallSolidCircle[1] = 0;
smallSolidCircle[2] = 0;
while(1)
{
//Wu_oled_Proc();
// 清空发送缓冲区
WU_OLED_U8G2_ClearBuffer();
// 绘制大空心圆圈
drawBigHollowCircle();
// 绘制绕大空心圆圈旋转的实心小圆圈
drawRotatingSmallSolidCircle();
// 更新实心小圆圈绕大空心圆圈的旋转角度
circleAngle += circleAngleIncrement;
if (circleAngle >= 2 * M_PI) circleAngle -= 2 * M_PI;
// 刷新发送缓冲区,将绘制内容显示到屏幕上
WU_OLED_U8G2_SendBuffer();
// 可以添加适当延时,控制动画速度,这里简单示意,实际可根据需求调整延时时间
//osDelay(50);
}
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
六、字幕滚动效果
void OLED_WUStartTask04(void *argument)
{
const char* message = "祝大家新年快乐,恭喜发财!"; // 祝福语
int messageWidth = WU_OLED_U8G2_GetUTF8Width(message); // 获取祝福语的宽度
int x = WU_OLED_U8G2_GetDisplayWidth(); // 获取屏幕宽度,初始x坐标为屏幕最右侧
while (1)
{
// 清空显示缓冲区
WU_OLED_U8G2_ClearBuffer();
// 绘制祝福语,x坐标逐渐减小,实现从右往左滚动效果
WU_OLED_U8G2_SetFont(u8g2_font_wqy13_t_gb2312a); // 设置字体,支持中文
WU_OLED_U8G2_DrawUTF8(x, 32, message); // 在指定位置绘制祝福语
// 刷新显示
WU_OLED_U8G2_SendBuffer();
// 更新x坐标,实现滚动效果
x--;
// 如果祝福语完全滚出屏幕,重置x坐标
if (x < -messageWidth) {
x = WU_OLED_U8G2_GetDisplayWidth();
}
// 控制滚动速度,避免过快或过慢
//osDelay(20); // 20ms的延时,可以根据实际效果调整
}
}
七、下雪动画效果
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
// 定义屏幕的宽度和高度,你可根据实际OLED屏幕尺寸修改
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// 雪花结构体,用于表示每个雪花的属性
typedef struct Snowflake {
int x; // x坐标
int y; // y坐标
int speed; // 下落速度
} Snowflake;
// 最大雪花数量,可以根据想要的下雪密度调整
#define MAX_SNOWFLAKES 50
Snowflake snowflakes[MAX_SNOWFLAKES];
// 初始化雪花的位置和速度
void initSnowflakes() {
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
snowflakes[i].x = rand() % SCREEN_WIDTH;
snowflakes[i].y = rand() % SCREEN_HEIGHT;
snowflakes[i].speed = rand() % 3 + 1; // 速度在1到3之间随机
}
}
// 更新雪花的位置,实现下落效果,超出屏幕底部则重新回到顶部
void updateSnowflakes() {
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
snowflakes[i].y += snowflakes[i].speed;
if (snowflakes[i].y > SCREEN_HEIGHT) {
snowflakes[i].y = 0;
snowflakes[i].x = rand() % SCREEN_WIDTH;
}
}
}
// 在OLED屏幕上绘制雪花(白色像素点)
void drawSnowflakes() {
WU_OLED_U8G2_SetDrawColor(1); // 设置为白色,用于绘制雪花
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
WU_OLED_U8G2_DrawPoint(snowflakes[i].x, snowflakes[i].y);
}
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
OLED_WUStartTask04(void *argument)
{
initSnowflakes();
while(1)
{
//Wu_oled_Proc();
WU_OLED_U8G2_ClearBuffer(); // 清空缓冲区
updateSnowflakes();
drawSnowflakes();
WU_OLED_U8G2_SendBuffer(); // 刷新缓冲区,将绘制内容显示到屏幕上
// 可以添加适当延时,控制动画速度,这里简单示意,实际可根据需求调整延时时间
//osDelay(50);
}
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
八、进度条动画效果
OLED_WUStartTask04(void *argument)
{
int dat;
while(1)
{
//Wu_oled_Proc();
while(dat<101)
{
WU_OLED_U8G2_ClearBuffer();
WU_OLED_U8G2_SetFont(u8g2_font_wqy13_t_gb2312a);//选择字库
WU_OLED_U8G2_Printf(25,18,CHINA,"WU-有点东");
WU_OLED_U8G2_DrawButtonUTF8(65, 35, U8G2_BTN_SHADOW1|U8G2_BTN_HCENTER|U8G2_BTN_BW2, 0, 2, 2, "请等待初始化完成" );
WU_OLED_U8G2_Printf(101,60,CHINA,"%d%%",dat);
WU_OLED_U8G2_DrawRFrame(0, 50, 100,10,4);
WU_OLED_U8G2_DrawRBox(0, 50, dat,10,4);
WU_OLED_U8G2_SendBuffer();
dat+=2;
}
WU_OLED_U8G2_DrawButtonUTF8(65, 35, U8G2_BTN_SHADOW1|U8G2_BTN_HCENTER|U8G2_BTN_BW2|U8G2_BTN_INV, 0, 2, 2, "请等待初始化完成" );
WU_OLED_U8G2_SendBuffer();
dat=0;
//osDelay(50);
}
}