前言
本项目是我经过学习C语言,文件IO,数据结构后,独立开发实现的。模拟的是自助开发机系统功能:
语音提醒,
可以实现购买商品,
加减要购买商品的数量,
模拟付款,
左右翻页,
加入购物车,
管理员登陆,
管理员四大权限(上架商品,下架商品,修改商品,查询商品信息).
一、开发环境
VScode、wsL(windows下的linux系统)
二、开发工具
GEC6818开发板 800*480
交叉编译工具:arm-linux-gnueabi-5.4.0.tar.xz
串口:secure CRT
传输:tftp技术
三、技术要点
C语言 ,文件IO ,数据结构
四、实现思维导图
五、基础代码
1、显示任意大小图片
//显示任意大小图片
int show_anybmp(int w,int h,int x,int y,char *bmpname, LCD* lcd)
{
int bmpfd;
int lcdfd;
int i,j;
//定义int类型的指针指向lcd在显存中的首地址
int *lcdmem;
//定义数组存放像素点的RGB
char bmpbuf[w*h*3];
//定义数组存放转换得到的ARGB
int lcdbuf[w*h]; // int占4字节
int tempbuf[w*h];
//打开你要显示的bmp图片 w*h
bmpfd=open(bmpname,O_RDWR);
if(bmpfd==-1)
{
perror("打开图片");
return -1;
}
// //打开lcd的驱动
// lcdfd=open("/dev/fb0",O_RDWR);
// if(lcdfd==-1)
// {
// perror("打开lcd");
// return -1;
// }
// //映射得到lcd在显存中对应的首地址
// lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
// if(lcdmem==NULL)
// {
// perror("映射lcd");
// return -1;
// }
//跳过前面没有用的54字节
lseek(bmpfd,54,SEEK_SET);
//判断bmp图片的宽所占的字节数能否被4整除
if((w*3)%4!=0)
{
for(i=0; i<h; i++)
{
read(bmpfd,&bmpbuf[i*w*3],w*3);
lseek(bmpfd,4-(w*3)%4,SEEK_CUR); //跳过填充的垃圾数据
}
}
else
//从55字节读取bmp的像素点颜色值
read(bmpfd,bmpbuf,w*h*3); //bmpbuf[0] B bmpbuf[1] G bmpbuf[2] R 一个像素点的RGB
//bmpbuf[3] bmpbuf[4] bmpbuf[5]
//3字节的RGB-->4字节的ARGB 位运算+左移操作
for(i=0; i<w*h; i++)
lcdbuf[i]=bmpbuf[3*i]|bmpbuf[3*i+1]<<8|bmpbuf[3*i+2]<<16|0x00<<24;
//00[2][1][0]
for(i=0; i<w; i++)
for(j=0; j<h; j++)
//*(lcdmem+(y+j)*800+x+i)=lcdbuf[j*w+i]; 图片颠倒
*(lcd->mp+(y+j)*800+x+i)=lcdbuf[(h-1-j)*w+i];
//关闭
close(bmpfd);
return 0;
}
2、链表基本操作
#include "myhead.h"
#define SIZE 100
//头节点初始化
Product* init_head(char* name, int amount, float price, char* pathname)
{
Product *head = (Product*)malloc(sizeof(Product));
strcpy(head->name, name);
head->amount = amount;
head->price = price;
strcpy(head->pathname, pathname);
head->next = head;
head->prev = head;
if(strcmp(name,"田园薯片") == 0)//最开始头节点数据写入记事本
{
//写入记事本
int fd = open("production/production.txt", O_RDWR|O_CREAT|O_TRUNC);
if(fd == -1)
{
perror("打开production.txt");
}
char buf[100] = "田园薯片@20@5@photo/tysp.bmp\n";
write(fd, buf, strlen(buf));
close(fd);
}
return head;
}
//节点初始化
Product* init_node(char* name, int amount, float price, char* pathname)
{
Product *head = (Product*)malloc(sizeof(Product));
strcpy(head->name, name);
head->amount = amount;
head->price = price;
strcpy(head->pathname, pathname);
head->next = NULL;
head->prev = NULL;
return head;
}
//尾插入节点
void insert_node_tail(Product *head, char* name, int amount, float price, char* pathname)
{
Product* node = head;
Product* newnode = init_node(name, amount, price, pathname);
while(node->next != head)
node = node->next;
newnode->prev = node;
node->next->prev = newnode;
newnode->next = node->next;
node->next = newnode;
printf("插入成功!\n");
}
//删除节点
void delete_node(Product* head, char* name)
{
Product* node = head;
if (node == NULL)
{
printf("链表为空\n");
return;
}
if(strcpy(node->name, name) == 0)//排除头节点
{
node->next->prev = node->prev;
node->prev->next = node->next;
free(node);
printf("删除成功\n");
}
while (node->next != head)
{
node = node->next;
if (strcmp(name, node->name) == 0)
break;
}
if(node->next==head && strcmp(name, node->name)!=0)
{
printf("没有找到要删除的结点\n");
return;
}
node->next->prev = node->prev;
node->prev->next = node->next;
free(node);
printf("删除成功\n");
}
//修改结点数据
void link_updata(Product* head, char* oldname, char* name, int amount, float price, char* pathname)
{
Product* node = head;
while(node->next != head)
{
if(strcmp(node->name, oldname) == 0)
break;
node = node->next;
}
if(node->next==head && strcmp(oldname, node->name)!=0)
{
printf("没有找到要修改的结点\n");
return;
}
strcpy(node->name, name);
node->amount = amount;
node->price = price;
strcpy(node->pathname, pathname);
printf("修改成功!\n");
}
//查找结点数据
Product* find_data(Product* head, char* name)
{
Product* node = head;
while(node->next != head)
{
if(strcmp(node->name, name)==0)
{
return node;
}
node = node->next;
}
if(node->next==head && strcmp(node->name, name)==0)
{
printf("没有找到要修改的结点\n");
return node;
}
return NULL;//不存在
}
//打印双向循环链表
void printf_link(Product* head)
{
Product* node = head;
do
{
node = node->next;
printf("%s %d %.1f %s\n",node->name, node->amount, node->price, node->pathname);
}while(node != head);
}
//释放链表
void clearList(Product* head)
{
// 检查链表是否为空
if (head->next == head)
{
printf("链表为空\n");
return;
}
Product* current = head->next; // 从第一个数据节点开始
Product* temp;
// 遍历链表并释放每个节点
while (current != head) // 当达到头节点时停止
{
temp = current; // 保存当前节点
current = current->next; // 移动到下一个节点
free(temp); // 释放当前节点
}
head->next = head;
head->prev = head;
}
//记事本初始化
void txt_init()
{
char buf[SIZE][SIZE]={
"呀!土豆@20@10@photo/ytd.bmp\n",
"芬达@40@5@photo/fd.bmp\n",
"果汁泥@50@1@photo/gzn.bmp\n",
"花生酥@40@3@photo/hss.bmp\n",
"菊珍@48@5@photo/jz.bmp\n",
"可口可乐@40@4@photo/kkkl.bmp\n",
"曲奇饼@30@4@photo/qq.bmp\n",
"吐司面包@1@3@photo/tsmb.bmp\n",
"雪碧@30@5@photo/xb.bmp\n",
"方便面@34@4@photo/fbm.bmp\n",
""
};//记事本内容初始化
int fd = open("production/production.txt", O_RDWR|O_APPEND);
if(fd == -1)
{
perror("打开production.txt");
return;
}
for(int i=0; strlen(buf[i])>0; i++)
{
write(fd, buf[i], strlen(buf[i]));
}
close(fd);
}
//商品信息链表存储初始化
void production_init(Product* head)
{
char buf[SIZE];//存储商品全部信息
char name[SIZE];
int amount;
float price;
char pathname[SIZE];
int flag_p=0;
Product* node = head;
FILE* myfile = fopen("production/production.txt", "r+");
if(myfile == NULL)
{
perror("打开production.txt");
return;
}
while(1)
{
bzero(buf, SIZE);
char* addr = fgets(buf, SIZE, myfile);
if(addr == NULL)
break;
if(flag_p)
{
sscanf(buf, "%[^@]@%d@%f@%s", name, &amount, &price, pathname);
insert_node_tail(node, name, amount, price, pathname);
}
flag_p=1;
}
fclose(myfile);//关闭文件
}
3、触摸屏
#include "myhead.h"
//获取坐标
int get_xy(LCD* lcd)
{
//printf("%d\n",sizeof(enum function));
int count;//记录指针移动次数
flag_buy = 0;
int cur_x, cur_y;
int tsfd;
//定义一个结构体存放触摸屏的坐标
struct input_event myevent;
//第一步;打开触摸屏的驱动
tsfd=open("/dev/input/event0",O_RDWR);
if(tsfd == -1)
{
perror("打开触摸屏失败\n");
}
while(1)
{
//读取触摸屏点击的坐标位置
read(tsfd,&myevent,sizeof(myevent));
//判断事件类型
if(myevent.type==EV_ABS) //说明是触摸屏的驱动
{
//判断是x坐标,还是y坐标
if(myevent.code==ABS_X) //说明读取的x坐标
{
printf("x坐标是: %d\n",(myevent.value*800)/1024);
cur_x = (myevent.value*800)/1024;
}
if(myevent.code==ABS_Y) //说明读取的y坐标
{
printf("y坐标是: %d\n",(myevent.value*480)/600);
cur_y = (myevent.value*480)/600;
}
//判断在哪个区域,从而执行哪个功能函数
switch (fun_select)
{
case main_fun:
if((0<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=480))//开始界面
{
return main_click;
}
break;
case buy_fun:
if((0<=cur_x&&cur_x<=180) && (395<=cur_y&&cur_y<=480))//向前翻页
{
return prev;
}
else if((630<=cur_x&&cur_x<=800) && (395<=cur_y&&cur_y<=480))//向后翻页
{
return next;
}
//点击任何一个图片
else if( ((100<=cur_x&&cur_x<=200) && (60<=cur_y&&cur_y<=240)) || ((266<=cur_x&&cur_x<=366) && (60<=cur_y&&cur_y<=240)) || ((432<=cur_x&&cur_x<=532) && (60<=cur_y&&cur_y<=240)) || ((598<=cur_x&&cur_x<=698) && (60<=cur_y&&cur_y<=240)))
{
flag_buy = 1;
show_character_jt("", lcd, 638, 240);
show_character_jt("", lcd, 472, 240);
show_character_jt("", lcd, 306, 240);
show_character_jt("", lcd, 140, 240);
if((100<=cur_x&&cur_x<=200) && (60<=cur_y&&cur_y<=240))//判断点击哪张照片
{
show_character_jt("^", lcd, 140, 240);
count = 8;
}
else if((266<=cur_x&&cur_x<=366) && (60<=cur_y&&cur_y<=240))
{
show_character_jt("^", lcd, 306, 240);
count = 7;
}
else if((432<=cur_x&&cur_x<=532) && (60<=cur_y&&cur_y<=240))
{
show_character_jt("^", lcd, 472, 240);
count = 6;
}
else if((598<=cur_x&&cur_x<=698) && (60<=cur_y&&cur_y<=240))
{
show_character_jt("^", lcd, 638, 240);
count = 5;
}
while(count > 0)
{
cur_node = cur_node->prev;
//car_node = car_node->prev;
count--;
}
}
else if((210<=cur_x&&cur_x<=390) && (390<=cur_y&&cur_y<=480) && flag_buy)//再点击购买
{
return buy;
}
else if((410<=cur_x&&cur_x<=590) && (390<=cur_y&&cur_y<=480) && flag_buy)//加入购物车
{
return put_car;
}
//不点击图片就点击购买或者加入购物车,提示:请选择要购买的商品
else if( ( ((410<=cur_x&&cur_x<=590) && (390<=cur_y&&cur_y<=480)) || ((210<=cur_x&&cur_x<=390) && (390<=cur_y&&cur_y<=480)) ) && !flag_buy )
{
return buy_select;
}
else if((750<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=50))//管理员登陆界面
{
return login_face;
}
else if((730<=cur_x&&cur_x<=800) && (310<=cur_y&&cur_y<=380))//进入购物车
{
return into_car;
}
break;
case buy_count_fun:
//加数量
if((250<=cur_x&&cur_x<=350) && (380<=cur_y&&cur_y<=480))
{
return add;
}
//减数量
else if((450<=cur_x&&cur_x<=550) && (380<=cur_y&&cur_y<=480))
{
return sub;
}
//购买结算界面返回
else if((700<=cur_x&&cur_x<=800) && (380<=cur_y&&cur_y<=480))
{
return buy_back;
}
else if((0<=cur_x&&cur_x<=190) && (390<=cur_y&&cur_y<=480))//结算界面付款
{
return buy_count_buy;
}
else if((750<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=50))//管理员登陆界面
{
return login_face;
}
break;
case money_way_fun:
if((0<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=480))//支付方式
{
return money_way_face;
}
break;
case login_fun:
if((738<=cur_x&&cur_x<=788) && (65<=cur_y&&cur_y<=115))//登陆界面返回
{
return login_root_back;
}
else if((254<=cur_x&&cur_x<=537) && (185<=cur_y&&cur_y<=227))//输入用户名
{
return login_name;
}
else if((254<=cur_x&&cur_x<=537) && (246<=cur_y&&cur_y<=287))//输入用户密码
{
return login_passward;
}
else if((409<=cur_x&&cur_x<=536) && (315<=cur_y&&cur_y<=355))//点击登陆
{
return login_button;
}
break;
case root_fun:
if((750<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=50))//登陆界面返回
{
return login_root_back;
}
else if((40<=cur_x&&cur_x<=190) && (120<=cur_y&&cur_y<=270))//上架商品
{
return add_goods;
}
else if((230<=cur_x&&cur_x<=380) && (120<=cur_y&&cur_y<=270))//修改商品
{
return change_goods;
}
else if((420<=cur_x&&cur_x<=570) && (120<=cur_y&&cur_y<=270))//下架商品
{
return sub_goods;
}
else if((610<=cur_x&&cur_x<=760) && (120<=cur_y&&cur_y<=270))//查询商品
{
return find_goods;
}
break;
case find_goods_fun:
if((740<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=70))//返回管理员界面
{
return login_root_back;
}
else if((74<=cur_x&&cur_x<=638) && (177<=cur_y&&cur_y<=255))//用户输入查询的商品名字
{
return find_input;
}
else if((644<=cur_x&&cur_x<=725) && (177<=cur_y&&cur_y<=255))//点击搜索
{
return find_find;
}
break;
case sub_goods_fun:
if((363<=cur_x&&cur_x<=530) && (167<=cur_y&&cur_y<=190))//下架商品名字
{
return sub_goods_name;
}
else if((363<=cur_x&&cur_x<=530) && (204<=cur_y&&cur_y<=227))//商品价格
{
return sub_goods_price;
}
else if((363<=cur_x&&cur_x<=530) && (243<=cur_y&&cur_y<=266))//商品数量
{
return sub_goods_amount;
}
else if((365<=cur_x&&cur_x<=426) && (280<=cur_y&&cur_y<=308))//按钮
{
return sub_button;
}
else if((740<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=70))//返回管理员界面
{
return login_root_back;
}
break;
case change_goods_fun:
if((363<=cur_x&&cur_x<=530) && (167<=cur_y&&cur_y<=190))//修改商品名字
{
return change_goods_name;
}
else if((363<=cur_x&&cur_x<=530) && (204<=cur_y&&cur_y<=227))//修改商品价格
{
return change_goods_price;
}
else if((363<=cur_x&&cur_x<=530) && (243<=cur_y&&cur_y<=266))//修改商品数量
{
return change_goods_amount;
}
else if((365<=cur_x&&cur_x<=426) && (280<=cur_y&&cur_y<=308))//修改按钮
{
return change_button;
}
else if((740<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=70))//返回管理员界面
{
return login_root_back;
}
break;
case add_goods_fun:
if((363<=cur_x&&cur_x<=530) && (167<=cur_y&&cur_y<=190))//上架商品名字
{
return add_goods_name;
}
else if((363<=cur_x&&cur_x<=530) && (204<=cur_y&&cur_y<=227))//商品价格
{
return add_goods_price;
}
else if((363<=cur_x&&cur_x<=530) && (243<=cur_y&&cur_y<=266))//商品数量
{
return add_goods_amount;
}
else if((365<=cur_x&&cur_x<=426) && (280<=cur_y&&cur_y<=308))//按钮
{
return add_button;
}
else if((740<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=70))//返回管理员界面
{
return login_root_back;
}
break;
case into_goods_car_fun:
if((300<=cur_x&&cur_x<=450) && (330<=cur_y&&cur_y<=480))//清空购物车
{
return car_delete;
}
else if((0<=cur_x&&cur_x<=190) && (390<=cur_y&&cur_y<=480))//结算界面付款
{
return car_buy_count;
}
else if((750<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=50))//管理员登陆界面
{
return login_face;
}
else if((650<=cur_x&&cur_x<=800) && (350<=cur_y&&cur_y<=480))//返回购买界面
{
return buy_back;
}
else if((0<=cur_x&&cur_x<=800) && (0<=cur_y&&cur_y<=480))//支付方式点击
{
return money_way_face;
}
break;
}
}
}
//关闭
//free(change_signal);
close(tsfd);
}
4、液晶屏
#include "myhead.h"
//lcd初始化
LCD* lcd_init(char* pathname)
{
LCD* lcd = (LCD*)malloc(sizeof(LCD));
if(lcd == NULL)
{
perror("Lcd空间申请失败!\n");
return NULL;
}
lcd->fd = open(pathname,O_RDWR);
if(lcd->fd == -1)
{
perror("打开lcd失败!\n");
return NULL;
}
lcd->mp = mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd->fd, 0);
return lcd;
}
//显示汉字(arm-linux-gcc编译才有用)
void show_character(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 25); //字体大小30,可以人为修改
//创建一个画板(点阵图)宽是120个像素,高是30个像素
bitmap *bm = createBitmapWithInit(120,30,4,getColor(0,255,255,255)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板的左上角显示
fontPrint(f,bm,0,0,disname,getColor(0,0,0,0),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示数量
void show_character_amount(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 30); //字体大小30,可以人为修改
//创建一个画板(点阵图)宽是80个像素,高是60个像素
bitmap *bm = createBitmapWithInit(120,40,4,getColor(0,0,128,255)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板的左上角显示
fontPrint(f,bm,0,0,disname,getColor(0,0,0,0),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示箭头
void show_character_jt(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 30); //字体大小30,可以人为修改
//创建一个画板(点阵图)宽是15个像素,高是12个像素
bitmap *bm = createBitmapWithInit(12,18,4,getColor(0,64,128,255)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板的左上角显示
fontPrint(f,bm,0,0,disname,getColor(0,0,0,255),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示总金额
void show_character_sum_price(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 40); //字体大小30,可以人为修改
//创建一个画板(点阵图)宽是74个像素,高是55个像素
bitmap *bm = createBitmapWithInit(72,52,4,getColor(0,76,177,34)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板10,3显示
fontPrint(f,bm,1,6,disname,getColor(0,0,0,255),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示用户名、密码
void show_character_np(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 20); //字体大小10,可以人为修改
//创建一个画板(点阵图)宽是74个像素,高是42个像素
bitmap *bm = createBitmapWithInit(200,40,4,getColor(0,255,255,255)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板0,0显示
fontPrint(f,bm,0,11,disname,getColor(0,0,0,0),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示应用名字
void show_character_application(char* disname, LCD* lcd_name, int x, int y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, 40); //字体大小10,可以人为修改
//创建一个画板(点阵图)宽是150个像素,高是40个像素
bitmap *bm = createBitmapWithInit(150,40,4,getColor(0,255,255,255)); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板0,0显示
fontPrint(f,bm,10,0,disname,getColor(0,0,0,0),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示任意大小文字、画板、位置
void show_character_any(char* disname, LCD* lcd_name, int x, int y, int font_size, int board_high, int board_width, int* font_color, int* board_color, int font_x, int font_y)
{
//打开字体
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
//字体大小的设置
fontSetSize(f, font_size); //字体大小font_size,可以人为修改
//创建一个画板(点阵图)宽是board_width个像素,高是board_high个像素
bitmap *bm = createBitmapWithInit(board_width,board_high,4,getColor(0,board_color[2],board_color[1],board_color[0])); //也可使用createBitmapWithInit函数,改变画板颜色
//bitmap *bm = createBitmap(288, 100, 4);
//将字体写到点阵图上 0,0表示汉字在画板0,0显示
fontPrint(f,bm,10,0,disname,getColor(0,font_color[2],font_color[1],font_color[0]),0);
// A B G R
//把字体框输出到LCD屏幕上 参数x,y表示画板显示的坐标位置
show_font_to_lcd(lcd_name->mp,x,y,bm);
//关闭字体,关闭画板
fontUnload(f);
destroyBitmap(bm);
}
//显示任意大小图片
int show_anybmp(int w,int h,int x,int y,char *bmpname, LCD* lcd)
{
int bmpfd;
int lcdfd;
int i,j;
//定义int类型的指针指向lcd在显存中的首地址
int *lcdmem;
//定义数组存放像素点的RGB
char bmpbuf[w*h*3];
//定义数组存放转换得到的ARGB
int lcdbuf[w*h]; // int占4字节
int tempbuf[w*h];
//打开你要显示的bmp图片 w*h
bmpfd=open(bmpname,O_RDWR);
if(bmpfd==-1)
{
perror("打开图片");
return -1;
}
// //打开lcd的驱动
// lcdfd=open("/dev/fb0",O_RDWR);
// if(lcdfd==-1)
// {
// perror("打开lcd");
// return -1;
// }
// //映射得到lcd在显存中对应的首地址
// lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
// if(lcdmem==NULL)
// {
// perror("映射lcd");
// return -1;
// }
//跳过前面没有用的54字节
lseek(bmpfd,54,SEEK_SET);
//判断bmp图片的宽所占的字节数能否被4整除
if((w*3)%4!=0)
{
for(i=0; i<h; i++)
{
read(bmpfd,&bmpbuf[i*w*3],w*3);
lseek(bmpfd,4-(w*3)%4,SEEK_CUR); //跳过填充的垃圾数据
}
}
else
//从55字节读取bmp的像素点颜色值
read(bmpfd,bmpbuf,w*h*3); //bmpbuf[0] B bmpbuf[1] G bmpbuf[2] R 一个像素点的RGB
//bmpbuf[3] bmpbuf[4] bmpbuf[5]
//3字节的RGB-->4字节的ARGB 位运算+左移操作
for(i=0; i<w*h; i++)
lcdbuf[i]=bmpbuf[3*i]|bmpbuf[3*i+1]<<8|bmpbuf[3*i+2]<<16|0x00<<24;
//00[2][1][0]
for(i=0; i<w; i++)
for(j=0; j<h; j++)
//*(lcdmem+(y+j)*800+x+i)=lcdbuf[j*w+i]; 图片颠倒
*(lcd->mp+(y+j)*800+x+i)=lcdbuf[(h-1-j)*w+i];
//关闭
close(bmpfd);
return 0;
}
//保存当前图像
void save_current_image(int w,int h,int x,int y,int *prev_image, LCD* lcd)
{
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
prev_image[j * w + i] = *(lcd->mp + (y + j) * w + (x + i));
}
}
}
//显示上一次图像
int show_lastbmp(int w,int h,int x,int y,int *prev_image, LCD* lcd)
{
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
*(lcd->mp+ (y + j) * w + (x + i)) = prev_image[j * w + i];
}
}
return 0;
}
六、功能代码
1.开始界面
图示:
代码:
void main_into(LCD* lcd)
{
int change_signal_fun;
//播放欢迎音频
system("madplay mp3/main.mp3 &");
//显示界面
show_anybmp(800, 480, 0, 0, "photo/main.bmp", lcd);
change_signal_fun = get_xy(lcd);//获取下一步操作
if(change_signal_fun == main_click)
{
fun_select = buy_fun;
}
}
2.购买界面
图示:
代码:
void buy_goods(LCD* lcd, Product* head, Product* car_head)
{
int change_signal_fun = next;
int prev_image[GROUND_HIGH*GROUND_WIDTH];
char buf[3][100];
int cnt;//计数让指针移动的次数
Product* node = head;
int buf_x[4] = {100, 266, 432, 598};//存储零食图片开始x坐标
int buf_y = 60;//存储零食图片开始y坐标
memset(buf, 0, sizeof(buf));
//显示购买界面背景
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/buy_ground.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示购物车
show_anybmp(70, 70, 720, 310, "photo/car_car.bmp", lcd);
// //显示翻页
show_anybmp(180, 85, 0, 395, "photo/up.bmp", lcd);
show_anybmp(180, 85, 620, 395, "photo/down.bmp", lcd);
// //显示购买
show_anybmp(180, 90, 210, 390, "photo/buy.bmp", lcd);
// //显示加入购物车
show_anybmp(180, 90, 410, 390, "photo/car.bmp", lcd);
//显示指示框
show_character_jt("", lcd, 638, 240);
show_character_jt("", lcd, 472, 240);
show_character_jt("", lcd, 306, 240);
show_character_jt("", lcd, 140, 240);
while(1)
{
if(change_signal_fun == next)//下一页
{
cnt = 0;
while(cnt<4)//显示下面四张图片
{
//显示前四个零食图片
show_anybmp(PHOTO_WIDTH, PHOTO_HIGH, buf_x[cnt], buf_y, node->pathname, lcd);
//显示四个零食的名称、数量、价格
//显示姓名
sprintf(buf[0], "姓名: %s", node->name);
show_character(buf[0], lcd, buf_x[cnt]-10, buf_y+20+PHOTO_HIGH);
//显示数量
sprintf(buf[1], "数量: %d", node->amount);
show_character(buf[1], lcd, buf_x[cnt]-10, buf_y+20+25+PHOTO_HIGH);
//显示价格
sprintf(buf[2], "价格: %.1f¥", node->price); // 将浮点数转换为字符串,保留两位小数
show_character(buf[2], lcd, buf_x[cnt]-10, buf_y+20+50+PHOTO_HIGH);
node = node->next;
cnt++;
}
cur_node = node;
car_node = node;
}
else if(change_signal_fun == prev)//上一页
{
cnt = 8;
while(cnt>0)//指针往前移动cnt个
{
node = node->prev;
cnt--;
}
while(cnt<4)//显示下面四张图片
{
//显示前四个零食图片
show_anybmp(PHOTO_WIDTH, PHOTO_HIGH, buf_x[cnt], buf_y, node->pathname, lcd);
//显示四个零食的名称、数量、价格
//显示姓名
sprintf(buf[0], "姓名: %s", node->name);
show_character(buf[0], lcd, buf_x[cnt]-10, buf_y+20+PHOTO_HIGH);
//显示数量
sprintf(buf[1], "数量: %d", node->amount);
show_character(buf[1], lcd, buf_x[cnt]-10, buf_y+20+25+PHOTO_HIGH);
//显示价格
sprintf(buf[2], "价格: %.1f", node->price); // 将浮点数转换为字符串,保留两位小数
show_character(buf[2], lcd, buf_x[cnt]-10, buf_y+20+50+PHOTO_HIGH);
node = node->next;
cnt++;
}
cur_node = node;
car_node = node;
}
else if(change_signal_fun == buy_select)//提示选择商品
{
//显示提示
system("madplay mp3/select_goods.mp3 &");
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(500, 165, 130, 105, "photo/buy_tip.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
}
else if(change_signal_fun == put_car)//加入购物车
{
//printf("%s %d %.1f %s\n",cur_node->name, cur_node->amount, cur_node->price, cur_node->pathname);
if(car_goods_amount<4)//购物车没满就插入
{
insert_node_tail(car_head, car_node->name, car_node->amount, car_node->price, car_node->pathname);
}
car_goods_amount++;
//显示购物数量
switch(car_goods_amount)
{
case 1:
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(40, 40, 481, 343, "photo/1.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
break;
case 2:
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(40, 40, 481, 343, "photo/2.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
break;
case 3:
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(40, 40, 481, 343, "photo/3.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
break;
case 4:
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(40, 40, 481, 343, "photo/4.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
break;
default://购物车满了
system("madplay mp3/car_full.mp3 &");
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(500, 165, 130, 105, "photo/car_full.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
break;
}
flag_buy = 0;
}
else if(change_signal_fun == buy)//点击购买
{
//printf("%s %d %.1f %s\n",cur_node->name, cur_node->amount, cur_node->price, cur_node->pathname);
//printf("购买成功!\n");
flag_buy = 0;
fun_select = buy_count_fun;
break;
}
else if(change_signal_fun == login_face)
{
//printf("进入登陆界面成功\n");
fun_select = login_fun;
break;
}
else if(change_signal_fun == into_car)//进入购物车
{
printf("进入购物车成功!\n");
fun_select = into_goods_car_fun;
break;
}
else if(change_signal_fun == login_face)//登陆界面
{
//printf("进入成功!\n");
fun_select = login_fun;
break;
}
change_signal_fun = get_xy(lcd);//获取下一步操作
}
}
3.购买结算
图示:
代码:
void buy_count_give(LCD* lcd)
{
sum_price = 0;
int prev_image[GROUND_HIGH*GROUND_WIDTH];
int goods_amount=0;
float goods_price_sum=0;
int change_signal_fun;
char buf[5][100]={0};
//printf("购买成功!\n");
//显示结算支付界面
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/buy_count_ground_big.bmp", lcd);
show_anybmp(200, 200, 4, 70, "photo/buy_count_ground_small.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示购买
show_anybmp(190, 90, 0, 390, "photo/count_buy.bmp", lcd);
//显示返回
show_anybmp(100, 100, 700, 380, "photo/back.bmp", lcd);
//显示加减数量
show_anybmp(100, 100, 250, 380, "photo/add.bmp", lcd);
show_anybmp(100, 100, 480, 380, "photo/sub.bmp", lcd);
while(1)
{
//显示商品信息
show_anybmp(PHOTO_WIDTH, PHOTO_HIGH, 322, 40, cur_node->pathname, lcd);
//显示零食的名称、数量、价格
//显示姓名
sprintf(buf[0], "姓名:%s", cur_node->name);
show_character(buf[0], lcd, 310, 32+15+PHOTO_HIGH);
//显示数量
sprintf(buf[1], "数量:%d", cur_node->amount);
show_character(buf[1], lcd, 310, 32+15+25+PHOTO_HIGH);
//显示价格
sprintf(buf[2], "价格:%.1f¥", cur_node->price); // 将浮点数转换为字符串,保留一位小数
show_character(buf[2], lcd, 310, 32+15+50+PHOTO_HIGH);
//显示购买数量
sprintf(buf[3], "数量: %d", goods_amount);
show_character_amount(buf[3], lcd, 356, 395);
//显示购买价格
sprintf(buf[4], "价格: %.1f", goods_price_sum);
show_character_amount(buf[4], lcd, 356, 400+30);
//printf("%d\n",goods_amount);
change_signal_fun = get_xy(lcd);//获取下一步操作
//改变显示的数字
if(change_signal_fun == add && goods_amount>=0 && cur_node->amount>0)//商品正常数量,加数量
{
goods_amount++;
goods_price_sum += cur_node->price;
cur_node->amount--;
}
else if((change_signal_fun == add && cur_node->amount==0) || (change_signal_fun == sub && cur_node->amount==0 && goods_amount==0) ||(change_signal_fun == buy_count_buy && cur_node->amount==0 && goods_amount==0))//商品卖完
{
//显示提示:商品卖完
system("madplay mp3/goods_out.mp3 &");
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(500, 165, 130, 105, "photo/buy_over .bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
}
else if(change_signal_fun == sub && goods_amount>0)//减去数量
{
goods_amount--;
goods_price_sum -= cur_node->price;
cur_node->amount++;
}
else if(change_signal_fun == buy_count_buy && goods_amount)//结算界面购买
{
sum_price = goods_price_sum;
fun_select = money_way_fun;
break;
}
else if(change_signal_fun == buy_back)//返回
{
fun_select = buy_fun;
break;
}
else if(change_signal_fun == login_face)//登陆界面
{
printf("进入成功!\n");
fun_select = login_fun;
break;
}
}
}
4.购物车
图示:
代码:
void goods_car(Product* head, LCD* lcd)
{
printf("购物车信息:\n");
printf_link(head);
int change_signal_fun;
float price_sum = 0;
char buf[3][100] = {""};
int buf_x[4] = {100, 266, 432, 598};//存储零食图片开始x坐标
int buf_y = 60;//存储零食图片开始y坐标
Product* node = head;
node = node->next;
int cnt = 0;
if(head->next != head)
{
//显示购物车界面
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/car_ground.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示返回
show_anybmp(100, 100, 700, 380, "photo/back.bmp", lcd);
//显示结账
show_anybmp(190, 90, 0, 390, "photo/count_buy.bmp", lcd);
//显示清空
show_anybmp(100, 100, 350, 380, "photo/car_delete.bmp", lcd);
}
else
{
//显示清空的背景
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/car_delete_ground.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示返回
show_anybmp(100, 100, 700, 380, "photo/back.bmp", lcd);
}
//显示商品
while(node!=NULL && node!=head)
{
//显示零食图片
show_anybmp(PHOTO_WIDTH, PHOTO_HIGH, buf_x[cnt], buf_y, node->pathname, lcd);
//显示四个零食的名称、数量、价格
//显示姓名
sprintf(buf[0], "姓名: %s", node->name);
show_character(buf[0], lcd, buf_x[cnt]-10, buf_y+20+PHOTO_HIGH);
//显示数量
int food_amount = 1;
sprintf(buf[1], "数量: %d", food_amount);
show_character(buf[1], lcd, buf_x[cnt]-10, buf_y+20+25+PHOTO_HIGH);
//显示价格
sprintf(buf[2], "价格: %.1f¥", node->price); // 将浮点数转换为字符串,保留两位小数
show_character(buf[2], lcd, buf_x[cnt]-10, buf_y+20+50+PHOTO_HIGH);
price_sum += node->price;
node = node->next;
cnt++;
}
while(1)
{
change_signal_fun = get_xy(lcd);//获取下一步操作
//清空购物车
if(change_signal_fun == car_delete)
{
//显示清空的背景
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/car_delete_ground.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示返回
show_anybmp(100, 100, 700, 380, "photo/back.bmp", lcd);
//清空链表
clearList(head);
price_sum = 0;
car_goods_amount = 0;
}
//结账
else if(change_signal_fun == car_buy_count)
{
char buf[100];
int change_signal_fun;
show_anybmp(800, 480, 0, 0, "photo/money_way.bmp", lcd);
change_signal_fun = get_xy(lcd);
if(change_signal_fun == money_way_face)
{
system("madplay mp3/buy_s.mp3 &");
show_anybmp(800, 480, 0, 0, "photo/money_ground.bmp", lcd);
show_anybmp(150, 150, 650, 0, "photo/love.bmp", lcd);
sprintf(buf, "%.lf", price_sum);
show_character_sum_price(buf, lcd, 470, 351);
show_anybmp(300, 300, 225, 31, "photo/succeful_money.bmp", lcd);
sleep(5);
//显示清空的背景
show_anybmp(GROUND_WIDTH, GROUND_HIGH, 0, 0, "photo/car_delete_ground.bmp", lcd);
//显示管理员登陆
show_anybmp(50, 50, 750, 0, "photo/root.bmp", lcd);
//显示返回
show_anybmp(100, 100, 700, 380, "photo/back.bmp", lcd);
}
//清空链表
clearList(head);
price_sum = 0;
car_goods_amount = 0;
}
//进入登陆界面
else if(change_signal_fun == login_face)
{
//printf("进入登陆界面成功\n");
fun_select = login_fun;
break;
}
//返回
else if(change_signal_fun == buy_back)//返回
{
fun_select = buy_fun;
break;
}
}
}
5.管理员登录
图示:
代码:
void login(LCD* lcd)
{
int prev_image[GROUND_HIGH*GROUND_WIDTH];
int flag=0;
//人工
char buf_man_name[100]={""};
char buf_man_passward[100]={""};
//pc端
char buf_name[100]={" "};//保存用户名
char buf_passward[100]={" "};//保存用户密码
int change_signal_fun;//记录触摸屏下一步操作`
//显示登陆界面
show_anybmp(800, 480, 0, 0, "photo/login_face.bmp", lcd);
show_anybmp(50, 50, 738, 65, "photo/login_root_back.bmp", lcd);
while(1)
{
change_signal_fun = get_xy(lcd);//下一步操作
if(change_signal_fun == login_root_back )//登陆界面返回,返回购买界面
{
fun_select = buy_fun;
break;
}
else if(change_signal_fun == login_name)//输入用户名
{
strcmp(buf_man_name, "");
while(strlen(buf_man_name) < 1)
{
printf("请输入用户名:\n");
scanf("%s",buf_man_name);
if(strcmp(buf_man_name, "ysx") != 0)
{
//输入用户名
sprintf(buf_name, ": %s", buf_man_name);
show_character_np(buf_name, lcd, 306, 187);
//显示用户名输入不正确,重新输入图片
//显示提示
system("madplay mp3/name_error.mp3 &");
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(500, 165, 130, 105, "photo/name_error.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
strcpy(buf_man_name, "");
sprintf(buf_name, "%s", buf_man_name);
show_character_np(buf_name, lcd, 306, 187);
}
else
{
//输入用户名
sprintf(buf_name, ": %s", buf_man_name);
show_character_np(buf_name, lcd, 306, 187);
}
}
flag++;
}
else if(change_signal_fun == login_passward && flag==1)//输入用户密码
{
strcmp(buf_man_passward, "");
while(strlen(buf_man_passward) < 1)
{
printf("请输入密码:\n");
scanf("%s",buf_man_passward);
if(strcmp(buf_man_passward, "123456") != 0)
{
//显示密码
sprintf(buf_passward, ": %s", buf_man_passward);
show_character_np(buf_passward, lcd, 306, 247);
//显示密码输入不正确,重新输入,图片
system("madplay mp3/passward_error.mp3 &");
save_current_image(800, 480, 0, 0, prev_image, lcd);
show_anybmp(500, 165, 130, 105, "photo/passward_error.bmp", lcd);
sleep(1);
show_lastbmp(800, 480, 0, 0, prev_image, lcd);
strcpy(buf_man_passward, "");
sprintf(buf_passward, "%s", buf_man_passward);
show_character_np(buf_passward, lcd, 306, 247);
}
else
{
//输入用户名
sprintf(buf_passward, ": %s", buf_man_passward);
show_character_np(buf_passward, lcd, 306, 247);
}
}
flag++;
}
else if(change_signal_fun == login_button && flag==2) //点击登陆
{
printf("进入管理员界面成功\n");
//显示登陆成功
system("madplay mp3/login_s.mp3 &");
show_anybmp(500, 200, 150, 116, "photo/login_s.bmp", lcd);
sleep(2);
flag=0;
fun_select = root_fun;
break;
}
}
}
6.管理员权限
图示:
代码:
void root(LCD* lcd)
{
int change_signal_fun;//记录触摸屏下一步操作
//显示管理员界面
show_anybmp(800, 480, 0, 0, "photo/root_face.bmp", lcd);
show_anybmp(50, 50, 750, 0, "photo/login_root_back.bmp", lcd);
//显示四个操作
//上架商品
show_anybmp(150, 150, 40, 120, "photo/add_goods.bmp", lcd);
show_character_application("上架商品", lcd, 40, 280);
//修改商品(数量,价格)
show_anybmp(150, 150, 230, 120, "photo/change_goods.bmp", lcd);
show_character_application("修改商品", lcd, 230, 280);
//下架商品
show_anybmp(150, 150, 420, 120, "photo/delete.bmp", lcd);
show_character_application("下架商品", lcd, 420, 280);
//查询商品
show_anybmp(150, 150, 610, 120, "photo/find_goods.bmp", lcd);
show_character_application("查询商品", lcd, 610, 280);
while(1)
{
change_signal_fun = get_xy(lcd);//获取下一步操作
if(change_signal_fun == add_goods)//上架商品
{
fun_select = add_goods_fun;
break;
}
else if(change_signal_fun == change_goods)//修改商品(数量或者价格)
{
fun_select = change_goods_fun;
break;
}
else if(change_signal_fun == sub_goods)//下架商品
{
fun_select = sub_goods_fun;
break;
}
else if(change_signal_fun == find_goods)//查询商品
{
fun_select = find_goods_fun;
break;
}
else if(change_signal_fun == login_root_back)//返回登陆界面
{
fun_select = login_fun;
break;
}
}
}
总结
这个项目总共花费四天的时间完成,以前不能这么快的,可不可以完成都是一个问题。通过这次项目呢。最主要的感悟就是我们老师上课说的一句话:做项目要步步为营。我在这次项目中是深有感悟,我主要是没写一个功能都要验证有没有问题,警告也不能出现,所以我的项目很少出现逻辑错误,最多的就是粗心的语法错误。所以我觉得这句话是很好的,诸君共勉。
项目视频: