0010动圆
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define LCD_DEV_PATH "/dev/fb0"
int Move_Ball()
{
// 打开显示器设备文件
int lcd = open(LCD_DEV_PATH, O_RDWR);
if (lcd == -1)
{
perror("打开显示器失败!");
return -1;
}
// 映射显示器内存
int *mmap_start_p = (int *)mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd, 0);
if (mmap_start_p == (int *)MAP_FAILED)
{
perror("映射失败!");
return -1;
}
// 打开图片文件
int bmp = open("./a1.bmp", O_RDONLY);
if (bmp == -1)
{
perror("打开图片失败!");
return -1;
}
char rgb[800 * 480 * 3];
lseek(bmp, 54, SEEK_SET);
// 读取图片像素点数据
if (read(bmp, rgb, 800 * 480 * 3) == -1)
{
perror("读取图片像素点失败!");
return -1;
}
int x0 = 400;
int y0 = 240;
int r = 60;
// 控制 x 坐标移动方向的标志
int x_mask = 0;
// 控制 y 坐标移动方向的标志
int y_mask = 0;
while (1)
{
for (int y = 0; y < 480; y++)
{
for (int x = 0; x < 800; x++)
{
// 计算当前像素点在 rgb 数组中的索引
int index = 3 * (800 * (479 - y) + x);
// 判断当前像素点是否在圆内
if ((x - x0) * (x - x0) + (y - y0) * (y - y0) < r * r)
{
// 设置圆内的像素点颜色为浅绿色
*(mmap_start_p + 800 * y + x) = 0x00fff68f;
}
else
{
// 设置圆外的像素点颜色为图片中对应位置的像素点颜色
*(mmap_start_p + 800 * y + x) =
rgb[index] |
rgb[index + 1] << 8 |
rgb[index + 2] << 16;
}
}
}
// 移动圆心
if (y0 + r == 479) // 当圆心到达底部边界时,控制 y 坐标移动方向
y_mask = 0;
if (y0 - r == 0) // 当圆心到达顶部边界时,控制 y 坐标移动方向
y_mask = 1;
if (x0 + r == 799) // 当圆心到达右侧边界时,控制 x 坐标移动方向
x_mask = 0;
if (x0 - r == 0) // 当圆心到达左侧边界时,控制 x 坐标移动方向
x_mask = 1;
y0 += y_mask == 0 ? -1 : 1; // 根据移动方向更新圆心的 y 坐标
x0 += x_mask == 0 ? -1 : 1; // 根据移动方向更新圆心的 x 坐标
// usleep(300); // 延时 0.3 毫秒,但感觉不延时确实好一些
}
if (close(lcd) == -1)
{
perror("关闭显示器失败!");
return -1;
}
if (close(bmp) == -1)
{
perror("关闭图片失败!");
return -1;
}
if (munmap(mmap_start_p, 800 * 480 * 4) == -1)
{
perror("释放映射空间失败!");
return -1;
}
return 0;
}
int main()
{
Move_Ball();
return 0;
}
在开发板上观察到的现象:
看起来掉帧而且还糊,但其实是非常流畅的(GIF就是这样,没啥办法)。
0020图片倍数缩放
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define LCD_DEV_PATH "/dev/fb0"
#define MMAP_OFFSET 0
/**
* 【业务逻辑】:
* 1. 在函数开始处,打开显示器设备。
* 2. 检查打开显示器设备是否成功。
* 3. 进行内存映射,将显示器设备映射到内存中。
* 4. 检查内存映射是否成功,
* 5. 清屏显示,将屏幕上的每个像素点的值设置为0,即黑色。
* 6. 打开图片文件。
* 7. 检查打开图片文件是否成功。
* 8. 读取图片的宽度和高度。
* 9. 检查读取图片宽度和高度是否成功
* 10. 计算图片每行字节对齐的字节数。
* 11. 读取图片像素点数据。
* 12. 检查读取图片像素点数据是否成功。
* 13. 缩放和显示图片。
* 14. 关闭显示器设备、释放内存映射、关闭图片文件。
* 15. 返回0。
*
* 【参数说明】:
* - 参数1:bmp_path,图片文件路径。
* - 参数2:zoomout_times,缩小倍数。
*
* 【注意事项】:
* - 注意事项1:需要确保LCD_DEV_PATH的正确性。
* - 注意事项2:需要确保图片文件存在且可读。
* - 注意事项3:需要确保屏幕的宽度和高度与内存映射的大小一致。
* - 注意事项4:需要确保图片的宽度和高度与缩放倍数的兼容性。
*
* 【总结】:
* 该函数的业务流程包括打开显示器设备、内存映射、清屏显示、打开图片文件、读取图片宽度和高度、
* 计算图片每行字节对齐的字节数、读取图片像素点数据、缩放和显示图片、关闭显示器设备、释放内存映射、关闭图片文件。
*/
int Zoom_Display_Bitmap(const char *bmp_path, int zoomout_times);
int Zoom_Display_Bitmap(const char *bmp_path, int zoomout_times)
{
// 打开显示器设备
int lcd = open(LCD_DEV_PATH, O_RDWR);
if (lcd == -1)
{
perror("打开显示器失败!");
return -1;
}
// 内存映射
int *mmap_start_p = (int *)mmap(NULL,
800 * 480 * 4,
PROT_READ | PROT_WRITE,
MAP_SHARED,
lcd,
MMAP_OFFSET);
if (mmap_start_p == (int *)MAP_FAILED)
{
perror("映射失败!");
return -1;
}
// 清屏显示(黑屏)
for (int i = 0; i < 800 * 480; i++)
{
*(mmap_start_p + i) = 0; // 将每个像素点的值设置为0,即黑色
}
// 打开图片文件
int bmp = open(bmp_path, O_RDONLY);
if (bmp == -1)
{
perror("打开图片失败!");
close(lcd); // 关闭显示器设备
munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
return -1;
}
// 读取图片宽度和高度
int bmp_w, bmp_h;
lseek(bmp, 18, SEEK_SET);
if (read(bmp, &bmp_w, sizeof(int)) == -1 || read(bmp, &bmp_h, sizeof(int)) == -1)
{
perror("读取图片宽度或高度失败!");
close(lcd); // 关闭显示器设备
munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
close(bmp); // 关闭图片文件
return -1;
}
// 计算图片每行字节对齐的字节数
int skip = (bmp_w * 3) % 4 == 0 ? 0 : 4 - (bmp_w * 3) % 4;
// 读取图片像素点数据
char rgb[bmp_w * bmp_h * 3 + skip * bmp_h];
lseek(bmp, 54, SEEK_SET);
if (read(bmp, rgb, bmp_w * bmp_h * 3 + skip * bmp_h) == -1)
{
perror("读取图片像素点失败!");
close(lcd); // 关闭显示器设备
munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
close(bmp); // 关闭图片文件
return -1;
}
// 图片缩放和显示
for (int y = 0, n = 0; y < bmp_h / zoomout_times; y++)
{
for (int x = 0; x < bmp_w / zoomout_times; x++, n += 3 * zoomout_times)
{
// 计算当前像素点在内存映射中的位置
// mmap_start_p 是内存映射的起始地址,类型为 int*,每个像素点占用 4 个字节
// 800 是屏幕的宽度,bmp_h - 1 - y 是当前行在屏幕上的位置,x 是当前列在屏幕上的位置
// rgb[n]、rgb[n + 1] 和 rgb[n + 2] 分别表示当前像素点的 B、G 和 R 分量
// 通过移位操作将 B、G 和 R 分量合并成一个 32 位的像素值,并写入内存映射中的相应位置
*(mmap_start_p + 800 * (bmp_h - 1 - y) + x) = rgb[n] << 0 | rgb[n + 1] << 8 | rgb[n + 2] << 16;
}
// 3 * bmp_w % zoomout_times 计算每行多余的像素点的字节数(跳过缩放的像素)
// 举例:如果是缩小2倍,那么显示一个像素点只需要跳1个像素点
// 其他倍数,缩小n倍,那么显示一个像素点只需要跳n个像素点
n += 3 * bmp_w % zoomout_times;
// skip 是图片每行字节对齐的字节数
// bmp_w * 3 * (zoomout_times - 1) 计算每行缩放后未显示的像素点的字节数(跳过字节对齐的像素)
n += skip + bmp_w * 3 * (zoomout_times - 1);
}
// 关闭文件和释放内存映射
close(lcd); // 关闭显示器设备
munmap(mmap_start_p, 800 * 480 * 4); // 释放内存映射
close(bmp); // 关闭图片文件
return 0;
}
int main(int argc, char const *argv[])
{
if (argc != 3)
{
printf("命令行参数错误!参数不为3\n");
return -1;
}
int zoom_number = atoi(argv[2]);
Zoom_Display_Bitmap(argv[1], zoom_number);
return 0;
}
在开发板上观察到的现象1(缩小2倍):
在开发板上观察到的现象2(缩小4倍):
在开发板上观察到的现象3(缩小3倍),会发现存在问题,事实上,凡是缩小3的倍数都会出现问题,这个有机会再修复:
0030获取显存大小
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
int main(int argc, char const *argv[])
{
// 打开LCD设备文件
int lcd = open("/dev/fb0", O_RDWR);
if (lcd == -1)
{
perror("打开显示器失败!");
return -1;
}
struct fb_fix_screeninfo fix;
// 获取LCD硬件信息
if (ioctl(lcd, FBIOGET_FSCREENINFO, &fix) == -1)
{
perror("获取LCD硬件信息失败!");
return -1;
}
else
{
printf("获取LCD硬件信息成功,其显存大小是:%d字节\n", fix.smem_len);
}
// 关闭LCD设备文件
if (close(lcd) == -1)
{
perror("关闭显示器!");
return -1;
}
return 0;
}
在secureRTC中看到的运行结果:
计算一下,其实相当于3块屏幕,只不过1块是可见区域,另外2块是不可见区域:
0040获取可见区域的高度和宽度
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
int main(int argc, char const *argv[])
{
// 打开LCD设备文件
int lcd = open("/dev/fb0", O_RDWR);
if (lcd == -1)
{
perror("打开显示器失败!");
return -1;
}
struct fb_var_screeninfo var;
// 获取LCD硬件信息
if (ioctl(lcd, FBIOGET_VSCREENINFO, &var) == -1)
{
perror("获取LCD硬件信息失败!");
return -1;
}
else
{
printf("获取LCD硬件信息成功:\nLCD宽:%d\tLCD高:%d\n", var.xres, var.yres);
}
// 关闭LCD设备文件
if (close(lcd) == -1)
{
perror("关闭显示器!");
return -1;
}
return 0;
}
在secureRTC中观察到的运行结果: