U8G2官网:
自己移植的U8g2库,OLED库超好用,自己封装了用户层不需要再去查资料使用,注释写的很多很详细,有示例上手就会,初始化也很简单
个人移植的U8g2库:
超简单的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);
}
}
/*------------------------------------------------------------------------------------------------------------------------------------------------------------------*/