#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <linux/input.h>
#include <pthread.h>
/* 全局变量定义 */
int volume = -25; // 默认音量值
// 12个MP3文件名数组
char mp3_name[12][8] = {"d1.mp3", "d2.mp3", "d3.mp3",
"d4.mp4", "d5.mp3", "d6.mp3",
"d7.mp3", "d8.mp3", "d9.mp3",
"d10.mp3", "d11.mp3", "d12.mp3"};
// 音量显示图片数组
char bmp[12][8] = {"0.bmp", "1.bmp", "2.bmp", "3.bmp", "4.bmp",
"5.bmp", "6.bmp", "7.bmp", "8.bmp", "9.bmp", "10.bmp"};
// 相册图片数组
char album_bmp[4][20] = {"1.bmp", "2.bmp", "3.bmp", "4.bmp"};
int lcd_fd = -1; // LCD文件描述符
int ts_fd = -1; // 触摸屏文件描述符
int *fb_mem = NULL; // 帧缓冲内存映射指针
#define LCD_WIDTH 800 // LCD宽度
#define LCD_HEIGHT 480 // LCD高度
/**
* 显示BMP图片函数
* @param bmpname 图片文件名
* @param w 图片宽度
* @param h 图片高度
* @param x 显示x坐标
* @param y 显示y坐标
* @return 成功返回0,失败返回-1
*/
int showbmp_wh_xy(char *bmpname, int w, int h, int x, int y) {
// 计算每行字节数(考虑4字节对齐)
int row_size = ((w * 24 + 31) / 32) * 4; // 24位BMP每像素3字节
int padding = row_size - w * 3; // 每行填充字节数
// 分配缓冲区
unsigned char *bmp_buf = malloc(row_size * h);
unsigned int *lcd_buf = malloc(w * h * sizeof(unsigned int));
if (!bmp_buf || !lcd_buf) {
printf("内存分配失败\n");
free(bmp_buf);
free(lcd_buf);
return -1;
}
// 打开BMP文件
int bmp = open(bmpname, O_RDONLY);
if (bmp == -1) {
printf("打开%s失败\n", bmpname);
free(bmp_buf);
free(lcd_buf);
return -1;
}
// 跳过BMP文件头和信息头(共54字节)
lseek(bmp, 54, SEEK_SET);
// 读取全部像素数据(包含对齐字节)
read(bmp, bmp_buf, row_size * h);
close(bmp);
// 初始化LCD设备(如果尚未初始化)
if (lcd_fd == -1) {
lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd == -1) {
printf("打开lcd屏幕失败\n");
free(bmp_buf);
free(lcd_buf);
return -1;
}
// 内存映射帧缓冲
fb_mem = mmap(NULL, LCD_WIDTH * LCD_HEIGHT * 4,
PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (fb_mem == (void *)-1) {
printf("mmap失败\n");
close(lcd_fd);
lcd_fd = -1;
free(bmp_buf);
free(lcd_buf);
return -1;
}
}
// BGR -> RGB 转换,并去除对齐字节
int i, j;
for (j = 0; j < h; j++) {
for (i = 0; i < w; i++) {
int bmp_idx = j * row_size + i * 3;
int lcd_idx = j * w + i;
// BGR -> RGB 并转换为32位格式
lcd_buf[lcd_idx] = bmp_buf[bmp_idx] | // Blue
(bmp_buf[bmp_idx + 1] << 8) | // Green
(bmp_buf[bmp_idx + 2] << 16); // Red
}
}
// 显示到LCD(考虑坐标越界)
int display_width = (w < LCD_WIDTH - x) ? w : (LCD_WIDTH - x);
int display_height = (h < LCD_HEIGHT - y) ? h : (LCD_HEIGHT - y);
for (j = 0; j < display_height; j++) {
for (i = 0; i < display_width; i++) {
// 垂直翻转(BMP存储顺序是从下到上)
int src_idx = (h - 1 - j) * w + i;
int dst_idx = (j + y) * LCD_WIDTH + (i + x);
fb_mem[dst_idx] = lcd_buf[src_idx];
}
}
// 释放资源
free(bmp_buf);
free(lcd_buf);
return 0;
}
/**
* 打开LCD设备
* @return 成功返回0,失败返回-1
*/
int lcd_open() {
lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd == -1) {
perror("open lcd failed");
return -1;
}
fb_mem = mmap(NULL, LCD_WIDTH*LCD_HEIGHT*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (fb_mem == (int *)-1) {
perror("mmap failed");
close(lcd_fd);
lcd_fd = -1;
return -1;
}
return 0;
}
/**
* 关闭LCD设备
*/
void lcd_close() {
if (fb_mem) {
munmap(fb_mem, LCD_WIDTH*LCD_HEIGHT*4);
fb_mem = NULL;
}
if (lcd_fd != -1) {
close(lcd_fd);
lcd_fd = -1;
}
}
/**
* 打开触摸屏设备
* @return 成功返回0,失败退出程序
*/
int ts_open() {
ts_fd = open("/dev/input/event0", O_RDWR);
if (ts_fd == -1) {
perror("open ts failed");
exit(1);
}
return 0;
}
/**
* 关闭触摸屏设备
*/
void ts_close() {
if (ts_fd != -1) {
close(ts_fd);
ts_fd = -1;
}
}
/**
* 获取触摸屏坐标
* @param x 返回x坐标
* @param y 返回y坐标
*/
void get_xy(int *x, int *y) {
struct input_event info;
*x = *y = -1;
while (1) {
bzero(&info, sizeof(info));
read(ts_fd, &info, sizeof(info));
if (info.type == EV_ABS) { // 绝对坐标事件
if (info.code == ABS_X) *x = info.value*800/1024; // 转换x坐标
if (info.code == ABS_Y) *y = info.value*480/600; // 转换y坐标
}
// 检测触摸释放事件
if (info.type == EV_KEY && info.code == BTN_TOUCH && info.value == 0) {
if (*x != -1 && *y != -1) break;
}
}
}
/**
* 显示电子钢琴界面
*/
void show_piano() {
showbmp_wh_xy("background.bmp", 800, 480, 0, 0); // 背景
showbmp_wh_xy("bar.bmp", 800, 47, 0, 0); // 顶部栏
// 绘制12个琴键
int a = 10;
for (int i = 0; i < 12; i++) {
showbmp_wh_xy("key_off.bmp", 64, 280, a + (65 * i), 47);
}
showbmp_wh_xy("logo.bmp", 344, 66, 229, 381); // 底部logo
}
/**
* 钢琴按键处理函数
* @param x 触摸x坐标
* @param y 触摸y坐标
* @return 按键编号(1-12:琴键,13:退出,14:音量减,15:音量加,-1:无效区域)
*/
int piano_play(int x, int y) {
if (y >= 47 && y <= 327) { // 琴键区域
return (x - 10) / 65 + 1;
} else if ((x >= 229 && x <= 570) && (y >= 381 && y <= 446)) {
return 13; // 退出钢琴
} else if ((x >= 741 && x <= 800) && (y >= 421 && y <= 480)) {
return 14; // 减小音量
} else if ((x >= 741 && x <= 790) && (y >= 360 && y <= 420)) {
return 15; // 增大音量
} else {
return -1; // 无效区域
}
}
/**
* 电子钢琴主函数
*/
void piano_main() {
int old = -1, new = -1; // 记录新旧按键状态
ts_open(); // 打开触摸屏
show_piano(); // 显示钢琴界面
while (1) {
old = new;
int x = -1, y = -1;
get_xy(&x, &y); // 获取触摸坐标
new = piano_play(x, y); // 转换为按键编号
if (new == 13) { // 退出钢琴
break;
}
// 音量控制
if (new == 14) { // 减小音量
if (volume > -50) {
volume -= 5;
int i = (volume + 50) / 5;
showbmp_wh_xy(bmp[i], 20, 20, 689, 408); // 更新音量显示
}
} else if (new == 15) { // 增大音量
if (volume < 0) {
volume += 5;
int i = (volume + 50) / 5;
showbmp_wh_xy(bmp[i], 20, 20, 689, 408); // 更新音量显示
}
} else if (1 <= new && new <= 12) { // 琴键操作
if (new != old) {
system("killall -9 madplay"); // 停止当前播放
char buf[100] = {0};
int idx = new - 1;
sprintf(buf, "madplay %s &", mp3_name[idx]); // 播放对应音符
system(buf);
// 更新琴键显示状态
if (old != -1) {
showbmp_wh_xy("key_on.bmp", 64, 280, 10 + 65 * (old - 1), 47);
}
showbmp_wh_xy("key_on.bmp", 64, 280, 10 + 65 * (new - 1), 47);
old = new;
}
}
}
ts_close(); // 关闭触摸屏
showbmp_wh_xy("ui.bmp",800,480, 0, 0); // 返回主界面
}
/**
* 加载钢琴声音(示例函数)
*/
void load_piano_sounds() {
printf("进入电子钢琴功能\n");
piano_main();
}
/**
* 自动播放相册
*/
void auto_album() {
for (int i = 0; i < 4; i++) {
showbmp_wh_xy(album_bmp[i], 555, 333, 120, 75);
sleep(2); // 每张图片显示2秒
}
}
/**
* 手动播放相册
*/
void manual_album() {
int i = 0;
while (1) {
showbmp_wh_xy(album_bmp[i], 555, 333, 120, 75);
int x = -1, y = -1;
get_xy(&x, &y);
// 根据触摸位置翻页
if (x >= 0 && x < 300) { // 上翻页
i--;
if (i == -1) i = 3;
} else if (x >= 300 && x < 600) { // 下翻页
i++;
if (i == 4) i = 0;
} else if (x >= 600 && x < 800) { // 退出
break;
}
}
}
int main() {
// 初始化设备
lcd_open();
ts_open();
showbmp_wh_xy("zhu.bmp", 800, 480, 0, 0); // 显示启动画面
sleep(3);
// 主循环
while (1) {
// 显示主界面
showbmp_wh_xy("ui.bmp", 800, 480, 0, 0);
int x = -1, y = -1;
get_xy(&x, &y); // 获取触摸坐标
// 主界面选项处理
if (x > 32 && x < 192 && y > 160 && y < 320) { // 自动播放
auto_album();
} else if (x > 224 && x < 384 && y > 160 && y < 320) { // 手动播放
manual_album();
} else if (x > 416 && x < 576 && y > 160 && y < 320) { // 电子钢琴
load_piano_sounds();
} else if (x > 608 && x < 768 && y > 160 && y < 320) { // 退出
break;
}
}
// 清理资源
lcd_close();
ts_close();
return 0;
}根据上述代码写一份课设报告3000字
最新发布