目录
前言
这是基于GEC6818开发板实现的点餐系统,是个人结合老师的上课内容自行制作,其中封装好的类和库有一些并不是我自己全部写出来的,更多的是在老师的指导下完成的,分享出来供大家学习讨论。
一、封装各种项目所需要的类
首先给大家看一下我这个项目的目录结构,以免大家编译错误哈
橙色框框都是图片,1.bmp到6.bmp都是大图片(菜品),像素是800*480
MenuUI.bmp这张图片是包含1-6这6张图片的大图片,用作主菜单,
pay.bmp是一个收款码
注意:所有图片必须是bmp格式的,需通过画图工具修改,不能直接改后缀名
下面是各类的具体代码,又需要修改的地方我会说明:
bmp.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/input.h>
//#include <pthread.h>
//#include "touch.h"
#include "word.h"
/*
在板子的x,y坐标处开始显示图片
*/
int *p = NULL;
int flag = -1; //用于暂停循环播放的标志位
void clean(int *plcd)
{
int i,j;
for(i=0;i<480;i++)
{
for(j=0;j<800;j++)
{
*( plcd + 800*i + j ) = 0xffffff;
}
}
}
void clean_Part(int x0,int y0,int x,int y,int* plcd){ //x0 左上角 x 右下角
int i,j;
for(i=y0;i<y;i++)
{
for(j=x0;j<x;j++)
{
*( plcd + 800*i + j ) = 0xffffff;
}
}
}
// void draw_point(int x,int y, int color,int* plcd)
// {
// *(p + 800*y +x) = color;
// }
void show_bmp(char* pathname,int x, int y,int* plcd)
{
//everything is file in linux 打开图片
int fd_bmp = open(pathname,O_RDWR);
if(fd_bmp == -1)
{
perror("open .bmp error\n");
return ;
}
//读取重要信息
int width , height ;
short depth ;
unsigned char buf[4];
//读取宽度
lseek(fd_bmp,0x12,SEEK_SET);
read(fd_bmp,buf,4);
width = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 |buf[0];
//读取高度
lseek(fd_bmp,0x16,SEEK_SET);
read(fd_bmp,buf,4);
height = buf[3]<<24 | buf[2]<<16 | buf[1]<<8 |buf[0];
//读取 色深 每一个像素点所占位数 bit
lseek(fd_bmp,0x1c,SEEK_SET);
read(fd_bmp,buf,2);
depth = buf[1]<<8 |buf[0];
// printf("width = %d height = %d depth = %d\n", width , height , depth );
//读取像素数组
int line_valid_bytes = abs(width) *depth /8 ;//一行有效字节数 bit -> byte
int line_total_bytes ; //一行总字节数
int laizi = 0;
if(line_valid_bytes %4 !=0) //字对齐
{
laizi = 4 - line_valid_bytes%4;
}
line_total_bytes = line_valid_bytes + laizi ;//一行总字节数 = 一行有效字节数 + 赖子
int total_bytes = abs(height) * line_total_bytes;
lseek(fd_bmp,54,SEEK_SET);
unsigned char * piexls = malloc(total_bytes);
read(fd_bmp,piexls,total_bytes);
//把像素数组写到缓存区
//一个像素点由argb组成
unsigned char a ,r,g,b ;
int color ;
int i=0;
int x0,y0;
for(y0=0;y0<abs(height);y0++)
{
for(x0=0;x0<abs(width);x0++)
{
b = piexls[i++];
g = piexls[i++];
r = piexls[i++];
if(depth == 24)//24位没有a
{
a=0;
}
if(depth ==32)
{
a = piexls[i++];
}
color = a<<24 | r<<16 | g<<8 | b ;
draw_point(width >0 ? x+x0 : abs(width)+x-1-x0 , height>0 ? y+height-1-y0 : y+y0 , color,plcd);
//文件像素存储方式有两种 width > 0 左到右保存 width < 0 右到左保存
// height > 0 下到上 <0 上到下
}
i = i+laizi;
}
free(piexls);
close(fd_bmp);
}
int touch_Screen(){ //是否点击了屏幕 是返回1 其他情况 返回-1
// while(1){
// }
}
// //子线程 用于判断屏幕是否点击
// void* thread_Flag(void* para){
// int fd_touch = open("/dev/input/event0",O_RDWR);
// struct input_event e;
// int rflag;
// if(fd_touch == -1){
// perror("open error\n");
// }
// while(1){
// rflag = read(fd_touch,&e,sizeof(struct input_event));
// if(rflag != sizeof(struct input_event)){
// perror("read failed\n");
// continue;
// }
// if(e.type == EV_ABS && e.code == ABS_X){
// flag = -(flag);
// }
// }
// }
// int main()
// {
// //通过路径名打开一个文件 然后判断是否打开成功
// int fd;
// fd =open("/dev/fb0",O_RDWR);
// if(fd== -1)
// {
// perror("open error\n");//能把出错信息打印出来
// return -1;
// }
// printf("open success\n");
// //映射
// p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
// if(p == MAP_FAILED)
// {
// perror("mmap error\n");
// return -2;
// }
// int index = 0;
// show_bmp(pic[index],0,0);
// //创建子线程
// pthread_t thread_flag;
// pthread_create(&thread_flag,NULL,thread_Flag,NULL);
// while(1){
// while(1){
// if(flag != 1){
// show_bmp(pic[index++],0,0);
// if(index>8)
// index = 0;
// sleep(3);
// }
// if(flag==1){
// break;
// }
// }
// // while(1){ //滑动屏幕实现切换
// // if(get_Slide_Dir() == 4){
// // index--;
// // if(index < 0)
// // index = 8;
// // clean();
// // show_bmp(pic[index],0,0);
// // }
// // if(get_Slide_Dir() == 3){
// // index++;
// // if(index > 8)
// // index = 0;
// // clean();
// // show_bmp(pic[index],0,0);
// // }
// // }
// }
// munmap(p,800*480*4);
// }
bmp.h
#ifndef _BMP_H
#define _BMP_H
void show_bmp(char* pathname,int x, int y,int* plcd); //显示图片
void clean(int* plcd); //清空屏幕
void clean_Part(int x0,int y0,int x,int y,int* plcd);
#endif
lcd.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "lcd.h"
int mmap_Init(const char* fileDath,int* fd){
//ͨ · һ ļ Ȼ ж Ƿ ɹ
*fd =open(fileDath,O_RDWR);
if(*fd== -1)
{
perror("open error\n");// ܰѳ Ϣ ӡ
return -1;
}
printf("open bmp success\n");
plcd = mmap(NULL,Width*High*4,PROT_READ | PROT_WRITE,MAP_SHARED,*fd,0);
if(plcd == MAP_FAILED)
{
perror("mmap error\n");
return -2;
}
return 1;
}
void close_LCD_File(int* plcd,int fd){
munmap(plcd,Width*High*4);
close(fd);
}
lcd.h
#ifndef _LCD_H
#define _LCD_H
#define Width 800
#define High 480
int* plcd;
int mmap_Init(const char* fileDath,int* fd);
void close_LCD_File(int* plcd,int fd);
#endif
main.c
#ifndef _LCD_H
#define _LCD_H
#define Width 800
#define High 480
int* plcd;
int mmap_Init(const char* fileDath,int* fd);
void close_LCD_File(int* plcd,int fd);
#endif
touch.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include <linux/input.h>
#include <stdlib.h>
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
int p_x,p_y; //初始点
int x,y; //终止点
void showDir(int D){
if(p_x != -1 && p_y != -1){
if(D == 1){
printf("start %d,%d end %d,%d \n",p_x,p_y,x,y);
printf("MOVE UP\n");
}
else if(D == 2){
printf("start %d,%d end %d,%d \n",p_x,p_y,x,y);
printf("MOVE DOWN\n");
}
else if(D == 3){
printf("start %d,%d end %d,%d \n",p_x,p_y,x,y);
printf("MOVE LEFT\n");
}
else if(D == 4){
printf("start %d,%d end %d,%d \n",p_x,p_y,x,y);
printf("MOVE RIGHT\n");
}
p_x = -1;
p_y = -1; //刷新,允许赋初值
}
}
int get_Slide_Dir(){
int fd_touch = open("/dev/input/event0",O_RDWR);
struct input_event e;
int rflag;
if(fd_touch == -1){
perror("open error\n");
return -1;
}
while(1){
rflag = read(fd_touch,&e,sizeof(struct input_event));
if(rflag != sizeof(struct input_event)){
perror("read failed\n");
//break;
continue;
}
if(e.type == EV_ABS && e.code == ABS_X){
if(p_x == -1)
p_x = e.value;
x = e.value;
}else if(e.type == EV_ABS && e.code == ABS_Y){
if(p_y == -1)
p_y = e.value;
y = e.value;
}else if(e.type == EV_KEY && e.code == BTN_TOUCH && e.value == 0){
int m_x = abs(x-p_x); //X轴移动距离
int m_y = abs(y-p_y); //y轴移动距离
if(m_x - m_y > 30){
if(x > p_x){
showDir(RIGHT);
return RIGHT;
}
showDir(LEFT);
return LEFT;
}
if(m_y - m_x > 30){
if(y > p_y){
showDir(DOWN);
return DOWN;
}
showDir(UP);
return UP;
}
}
}
}
touch.h
#ifndef _TOUCH_H
#define _TOUCH_H
//void showDir(int D); //
int get_Slide_Dir();
#endif
word.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include "word.h"
#include "word_Font.h"
//#include "word_Font.h"
/*
在板子的x,y坐标处开始显示图片
*/
// int *p = NULL;
// int color = 0xfcd116;
// char data[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x1C,0x00,0x0C,0x1C,0x1C,0x00,
// 0xFF,0xFF,0x9C,0x00,0xFF,0xFF,0x9C,0x00,0x0C,0x1C,0x1C,0x00,0x0C,0x1C,0xFF,0xF0,
// 0x0F,0xFC,0xFF,0xF0,0x0F,0xF8,0x1C,0x70,0x01,0xC0,0x1C,0x70,0x3F,0xFE,0x1C,0x70,
// 0x3F,0xFF,0x1C,0x70,0x71,0xC7,0x1C,0x70,0x71,0xC7,0x1C,0x70,0x7F,0xFF,0x1C,0x70,
// 0x3F,0xFE,0x1C,0x70,0x01,0xC0,0x1C,0x70,0x7F,0xFE,0x1C,0x70,0x7F,0xFF,0x38,0x70,
// 0x01,0xC0,0x38,0x70,0x1F,0xFC,0x38,0x70,0x3F,0xFE,0x70,0x70,0x1F,0xFC,0x70,0x70,
// 0x01,0xCE,0x70,0x70,0x01,0xFE,0xE0,0x70,0x7F,0xF9,0xF8,0x70,0xFF,0x03,0xDF,0xE0,
// 0x00,0x01,0x8F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x01,0x80,0x0C,0x1E,0x03,0x80,
// 0x0E,0x0E,0x03,0x80,0x07,0x07,0x07,0x00,0x07,0x87,0x07,0x00,0x03,0x83,0x8E,0x00,
// 0x3F,0xFF,0xFF,0xE0,0x7F,0xFF,0xFF,0xF0,0x70,0x00,0x00,0x70,0x70,0x00,0x00,0x70,
// 0x77,0xFF,0xF8,0x70,0x77,0xFF,0xFC,0xE0,0x70,0x00,0x3C,0xE0,0x00,0x00,0xF8,0x00,
// 0x00,0x03,0xE0,0x00,0x00,0x07,0x80,0x00,0x00,0x07,0x00,0x00,0x3F,0xFF,0xFF,0xF0,
// 0x7F,0xFF,0xFF,0xF8,0x3F,0xFF,0xFF,0xF0,0x00,0x01,0xC0,0x00,0x00,0x00,0xE0,0x00,
// 0x00,0x00,0xE0,0x00,0x00,0x00,0xE0,0x00,0x00,0xC0,0xE0,0x00,0x01,0xE1,0xC0,0x00,
// 0x00,0xFF,0xC0,0x00};
void draw_point(int x,int y, int color,int* p)
{
*(p + 800*y +x) = color;
}
void draw_word(int x0,int y0,int w,int h,char *data,int color,int* plcd)
{
int i,k;
for(i=0;i<w*h/8;i++)
{
for(k=0;k<8;k++)
{
if((data[i]<<k )&0x80)// 1000 0000
{
draw_point(x0+(i*8+k)%w,y0+i/(w/8),color,plcd);
}
}
}
}
void draw_float(int x0,int y0,int w,int h,float showNum,int color,int* plcd){
int arr[100];
int i=-1;
float num = showNum*100;
int temp = (int)num;
// int thnths,percentile;
// qian = (int)i/1000;
// arr[0] = (int)showNum/100%10;
// arr[1] = (int)showNum/10%10;
// arr[2] = (int)showNum/1%10;
// thnths = showNum*10;
// arr[3] = thnths/1%10;
// percentile = showNum*100;
// arr[4] = percentile/1%10;
while((temp/10) != 0){
i++;
arr[i] = temp%10;
temp/=10;
}
i++; //最高有效位进入数组 52.123 即5进入数组
arr[i] = temp;
// if(i==1){ //解决 0.0...
// i++;
// arr[i] = 0;
// }
if(showNum<1){ //解决 0. ... 之类的
i++;
arr[i] = 0;
}
for(int j=0;j<i+1;j++){
if(j==2){
draw_word(x0,y0,w,h,NUM[10],color,plcd);
x0 -= 8;
}
draw_word(x0,y0,w,h,NUM[arr[j]],color,plcd);
x0 -= 8;
}
}
/*
void word_move(int speed){
draw_word(int x0,int y0,int w,int h,char *data,int color);
}
*/
// int main()
// {
// //通过路径名打开一个文件 然后判断是否打开成功
// int fd;
// fd =open("/dev/fb0",O_RDWR);
// if(fd== -1)
// {
// perror("open error\n");//能把出错信息打印出来
// return -1;
// }
// printf("open success\n");
// //映射
// p = mmap(NULL,800*480*4,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
// if(p == MAP_FAILED)
// {
// perror("mmap error\n");
// return -2;
// }
// draw_word(400,230,32,29,data,color);
// munmap(p,800*480*4);
// close(fd);
// }
word.h
#ifndef _WORD_H
#define _WORD_H
void draw_point(int x,int y, int color,int* p);
void draw_word(int x0,int y0,int w,int h,char *data,int color,int* plcd);
void draw_float(int x0,int y0,int w,int h,float showNum,int color,int* plcd);
#endif
word_Font.h
#ifndef _WORD_FONT_H
#define _WORD_FONT_H
//w*h
char NUM[][8*16/8] = {
{0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00}, //0
{0x00,0x00,0x00,0x08,0x38,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3E,0x00,0x00}, //1
{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00}, //2
{0x00,0x00,0x00,0x3C,0x42,0x42,0x02,0x04,0x18,0x04,0x02,0x42,0x42,0x3C,0x00,0x00}, //3
{0x00,0x00,0x00,0x04,0x0C,0x0C,0x14,0x24,0x24,0x44,0x7F,0x04,0x04,0x1F,0x00,0x00}, //4
{0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x78,0x44,0x02,0x02,0x42,0x44,0x38,0x00,0x00}, //5
{0x00,0x00,0x00,0x18,0x24,0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x22,0x1C,0x00,0x00}, //6
{0x00,0x00,0x00,0x7E,0x42,0x04,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x00,0x00}, //7
{0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00}, //8
{0x00,0x00,0x00,0x38,0x44,0x42,0x42,0x42,0x46,0x3A,0x02,0x02,0x24,0x18,0x00,0x00}, //9
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00} //.
};
#endif
main.c
下面这个main.c是需要修改的
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/input.h>
#include <pthread.h>
#include "word.h"
#include "lcd.h"
#include "bmp.h"
#include "touch.h"
//#include "word_Font.h"
//全局变量
int fd;
//int* p;
extern int* plcd;
int x_touch = -1;
int y_touch = -1; //手指触摸屏幕的位置
int flag1 = -1; //循环显示终止标志
pthread_t thread_flag; //循环终止子线程
pthread_t thread_getPos; //获取触摸位置子线程
float total_M = 0.0; //点餐总金额
char pic[][6] = {
"1.bmp",
"2.bmp",
"3.bmp",
"4.bmp",
"5.bmp",
"6.bmp"
};
//菜名价格 和 菜名需要修改成自己图片展示的内容
char* name[6] = { //菜名
"宫保鸡丁 38.88",
"红扒鸡翅 38.88",
"红槽排骨 68.00",
"红烧牛蛙 68.68",
"毛血旺 28.88",
"梅菜扣肉 28.88"
};
float price[6] = {38.88,38.88,68.00,68.88,28.88,28.88};
//子线程 用于判断屏幕是否点击 退出循环播放图片
void* thread_Flag(void* para){
int fd_touch = open("/dev/input/event0",O_RDWR);
struct input_event e;
int rflag;
if(fd_touch == -1){
perror("open error\n");
}
while(1){
rflag = read(fd_touch,&e,sizeof(struct input_event));
if(rflag != sizeof(struct input_event)){
perror("read failed\n");
continue;
}
if(e.type == EV_ABS && e.code == ABS_X){
flag1 = -(flag1);
break;
}
}
close(fd_touch);
}
//子线程 用于获取屏幕点击位置
void* thread_getPosFunction(void* para){
int fd_touch = open("/dev/input/event0",O_RDWR);
struct input_event e;
int rflag;
if(fd_touch == -1){
perror("open error\n");
}
while(1){
rflag = read(fd_touch,&e,sizeof(struct input_event));
if(rflag != sizeof(struct input_event)){
perror("read failed\n");
continue;
}
if(e.type == EV_ABS && e.code == ABS_X){
x_touch = e.value;
}else if(e.type == EV_ABS && e.code == ABS_Y){
y_touch = e.value;
}
// else if(e.type == EV_KEY && e.code == BTN_TOUCH && e.value == 0){
// if(x_touch != -1 && y_touch != -1){}
// //break;
// }
}
}
void pos_Clear(){ //初始化 x_touch y_touch
x_touch = -1;
y_touch = -1;
}
int checkOut(){ //点击结算按钮 返回 0 否 返回 1
if(x_touch>820 && x_touch<1024 && y_touch>500 && y_touch<580){
return 0;
}
if(x_touch == -1 && y_touch == -1){ //首次进入
return 1;
}
// pos_Clear(); //防止坐标未清除一直点菜
return 1;
}
void countPrice(float* totalP){ //计算点餐价格
int tempx ,tempy;
while(1){
if(x_touch != -1 && y_touch != -1)
//
tempx = x_touch;
tempy = y_touch;//防止子线程在判断时修改点击坐标位置
if(tempy<200 && tempy>0 && tempx>10 && tempx<840){
if(tempx>0 && tempx<240){ //1号菜
*totalP += price[0];
printf("%s \n",name[0]);
// printf("x:%d y:%d \n",tempx,tempy); 调式bug 有时候会出现莫名的坐标 x_touch=5;
pos_Clear();
break;
}else if(tempx>240 && tempx<540){ //2号菜
*totalP += price[1];
printf("%s \n",name[1]);
pos_Clear();
break;
}else if(tempx>540 && tempx<840){ //3号菜
*totalP += price[2];
printf("%s \n",name[2]);
pos_Clear();
break;
}
}else if(tempy>280 && tempy<510 && tempx>10 && tempx<840){
if(tempx>0 && tempx<240){ //4号菜
*totalP += price[3];
printf("%s \n",name[3]);
pos_Clear();
break;
}else if(tempx>240 && tempx<540){ //5号菜
*totalP += price[4];
printf("%s \n",name[4]);
pos_Clear();
break;
}else if(tempx>540 && tempx<840){ //6号菜
*totalP += price[5];
printf("%s \n",name[5]);
pos_Clear();
break;
}
}
if(!checkOut()){ //点到了结算按钮,退出
break;
}
}
// pos_Clear();
}
void orderMenu(){ //点餐函数
show_bmp("MenuUI.bmp",0,0,plcd);
while(checkOut()){
countPrice(&total_M); //计算点餐价格
clean_Part(732,421,800,441,plcd); //清除上一次显示的浮点数
draw_float(790,421,8,16,total_M,0xff0000,plcd);
// sleep(1);
}
pos_Clear(); //初始化点击信息,方便后续判断 付款吗
}
int main(void){
int index = 0; //图片数组索引
//创建子线程
pthread_create(&thread_flag,NULL,thread_Flag,NULL);
pthread_create(&thread_getPos,NULL,thread_getPosFunction,NULL);
if(!mmap_Init("/dev/fb0",&fd)){
printf("mmap error \n");
}
clean(plcd); //清空屏幕
while(1){
while(flag1 == -1){
show_bmp(pic[index++],0,0,plcd);
if(index>5)
index = 0;
sleep(2);
}
pos_Clear(); //防止退出循环播放误点餐
clean(plcd); //清空屏幕
orderMenu();
clean(plcd); //清空屏幕
show_bmp("pay.bmp",0,0,plcd); //显示付款码
// printf("x:%d y:%d \n",x_touch,y_touch);
// sleep(3);
while(x_touch == -1){} //未点击屏幕,一直显示付款🐎界面
printf("本单总金额:%.2f\n",total_M);
total_M = 0.0; //点餐完成,清空
}
close_LCD_File(plcd,fd);
}
二、运行步骤
虚拟机上运行的命令为:arm-linux-gcc *.c -pthread
(没有-pthread 会报错)
SercureCRT上面运行的时候,要把图片一张一张传至开发板, rx 1.bmp ....
还要把编译出的文件a.out也传过去,我这个有播放音乐,你有需要需上传音乐至开发板,或者删除音乐那段代码,都是可以的
网上这种项目是很多,但你运行的时候会报很多问题,我这个亲测有效