2021-08-01

基于ARM嵌入式开发板的电梯显示系统

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/input.h>
#include <stdbool.h>
#include <stdlib.h>
int now_floor;//电梯当前的楼层int run_flag;//0表示电梯暂停,1表示上行,-1表示下行
int now_voice;//当前到达楼层的声音//BMP文件头(14字节)
struct bitmap_header
{ int16_t type;// 位图文件的类型,必须为BM(1-2字节)
int32_t size;// 位图文件的大小,以字节为单位(3-6字节)
int16_t reserved1;// 位图文件保留字,必须为0(7-8字节)
int16_t reserved2;// 位图文件保留字,必须为0(9-10字节)
int32_t offbits;// 位图数据的起始位置,以相对于位图(11-14字节) // 文件头的偏移量表示,以字节为单位
}attribute((packed));//位图信息头(40字节)
struct bitmap_info{ int32_t size;// 本结构所占用字节数(15-18字节)
int32_t width;// 位图的宽度,以像素为单位(19-22字节)
int32_t height;// 位图的高度,以像素为单位(23-26字节)
int16_t planes;// 目标设备的级别,必须为1(27-28字节)
int16_t bit_count;// 每个像素所需的位数,必须是1(双色),(29-30字节) // 4(16色),8(256色)或24(真彩色)之一 int32_t compression;// 位图压缩类型,必须是 0(不压缩),(31-34字节) // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 int32_t size_img;// 位图的大小,以字节为单位(35-38字节) int32_t X_pel;// 位图水平分辨率,每米像素数(39-42字节) int32_t Y_pel;// 位图垂直分辨率,每米像素数(43-46字节) int32_t clrused;// 位图实际使用的颜色表中的颜色数(47-50字节) int32_t clrImportant;// 位图显示过程中重要的颜色数(51-54字节)}attribute((packed));//表示触摸事件的坐标信息struct coordinate{ int x; int y;};//节点结构体声明struct Node{ int num;//数据域 struct Node next;//指针域};//函数声明int show_bmp(char filename, int x_offset, int y_offset);int read_ts(struct coordinate coor_p);int btn_floor();void show_btn(int n, int flag);bool update_node(struct Node head, int old_num, int new_num);void clear_link(struct Node head);bool delete_node(struct Node head, int num);struct Node find_node(struct Node head, int num);void display(struct Node head);void insert_node(struct Node head, struct Node new);struct Node creat_node(int num);struct Node init_link();/ 触摸屏坐标读取的线程/void tc_pthread_func(void arg){ //将链表表头传入线程任务函数 struct Node mylist = (struct Node )arg; printf(“触摸屏线程进入\n”); int tc_floor = -1;//表示按到的楼层号 while(1) { //等待读取按钮按下的楼层 if(tc_floor = btn_floor()) { printf(“按到按钮为:%d楼\n”, tc_floor); } else { printf(“按下无效\n”); continue; } //判断电梯状态 //暂停 if (run_flag == 0) { if (tc_floor > now_floor) { run_flag = 1;//将电梯设置为向上运行 show_bmp("/hcp/picture/up.bmp", 480, 110); insert_node(mylist, creat_node(tc_floor)); //显示按钮按下效果 show_btn(tc_floor, 1); } else if (tc_floor < now_floor) { run_flag = -1;//将电梯设置为向下运行 show_bmp("/hcp/picture/down.bmp", 480, 220); insert_node(mylist, creat_node(tc_floor)); //显示按钮按下效果 show_btn(tc_floor, 1); } else {} } //上行 else if(run_flag == 1) { if (tc_floor > now_floor) { insert_node(mylist, creat_node(tc_floor)); //显示按钮按下效果 show_btn(tc_floor, 1); } } //下行 else if (run_flag == -1) { if (tc_floor < now_floor) { insert_node(mylist, creat_node(tc_floor)); //显示按钮按下效果 show_btn(tc_floor, 1); } } }}/ 广告循环显示的线程/void bc_pthread_func(void arg){ printf(“广告播放线程进入\n”); while(1) { show_bmp("/hcp/picture/ad1.bmp", 0, 0); sleep(3); show_bmp("/hcp/picture/ad2.bmp", 0, 0); sleep(3); }}int main(int argc, char const argv[]){ //1.系统初始化 struct Node mylist = init_link();//初始化链表:用来存放电梯运行过程中待到达的目标楼层 now_floor = 1;//当前楼层默认在1楼 run_flag = 0;//电梯当前是暂停的 char now_floor_pic[][100] = {//这个数组用来表示每个当前楼层显示的图片文件名 “/hcp/picture/1.bmp”, “/hcp/picture/2.bmp”, “/hcp/picture/3.bmp”, “/hcp/picture/4.bmp”, “/hcp/picture/5.bmp”, “/hcp/picture/6.bmp”, “/hcp/picture/7.bmp”, “/hcp/picture/8.bmp”, “/hcp/picture/9.bmp”, “/hcp/picture/0010.bmp”, }; char now_voice_mu[][100] = {//这个数组用来表示每个当前楼层显示的图片 “madplay /hcp/mp3/01.mp3 &”, “madplay /hcp/mp3/02.mp3 &”, “madplay /hcp/mp3/03.mp3 &”, “madplay /hcp/mp3/04.mp3 &”, “madplay /hcp/mp3/05.mp3 &”, “madplay /hcp/mp3/06.mp3 &”, “madplay /hcp/mp3/07.mp3 &”, “madplay /hcp/mp3/08.mp3 &”, “madplay /hcp/mp3/09.mp3 &”, “madplay /hcp/mp3/10.mp3 &”, }; printf("==初始化完成=\n"); //2.显示登陆界面 printf(“登陆界面显示\n”); show_bmp("/hcp/picture/main.bmp", 0, 0); printf(“系统进入的语音播放\n”); system(“madplay /hcp/mp3/1.mp3 &”); sleep(3); //3.主界面,默认当前的楼层为1楼 printf(“显示主界面\n”); now_floor = 1; show_bmp("/hcp/picture/elevatorinterface.bmp", 0, 0); show_bmp("/hcp/picture/1.bmp", 200, 140); //4.创建2个子线程 pthread_t tc_tid; pthread_t bc_tid; pthread_create(&tc_tid, NULL, tc_pthread_func, (void )mylist);//触摸屏坐标读取 pthread_create(&bc_tid, NULL, bc_pthread_func, NULL);//广告播放 //主线程:电梯运行控制 printf(“主线程电梯运行管理\n”); while(1) { sleep(2);//用两秒的演示来模拟电梯运行的速度 //暂停 if (run_flag == 0) {} //上行 else if(run_flag == 1) { now_floor++; } //下行 else if (run_flag == -1) { now_floor–; } show_bmp(now_floor_pic[now_floor-1], 200, 140); // printf(“判断当前楼层是否是需要到达的目标楼层\n”); //查找节点的方式,查找now_floor是不是链表中的节点 if (find_node(mylist, now_floor))//如果是 { delete_node(mylist, now_floor);//删除节点 show_btn(now_floor, 0);//将按下状态的图标显示为没有按下的效果 printf(“播放楼层语音\n”); system(now_voice_mu[now_floor-1]); printf(“开门\n”); sleep(3); printf(“关门\n”); //如果链表变成空的,电梯就停止运行,做一些恢复 if (mylist->next == NULL) { if (run_flag == 1) { show_bmp("/hcp/picture/restore_pic1.bmp", 480, 110); } else if(run_flag == -1) { show_bmp("/hcp/picture/restore_pic2.bmp", 480, 220); } run_flag = 0;//电梯停止运行 } } } return 0;}/**函数实现将某个指定文件,显示到液晶屏的指定位置参数:filename:待显示的图片文件名 x_offset:显示位置相对液晶屏的x偏移 y_offset:显示位置相对液晶屏的y偏移/int show_bmp(char filename, int x_offset, int y_offset){ // (1)打开图片文件、液晶屏设备文件 open int lcd_fd = open("/dev/fb0", O_RDWR); int bmp_fd = open(filename, O_RDONLY); if (lcd_fd == -1 || bmp_fd == -1) { perror(“open”); return -1; } // (2)读取文件头信息 struct bitmap_header head;//存放文件头 read(bmp_fd, &head, 14); struct bitmap_info info;//位图信息头 read(bmp_fd, &info, 40); int w = info.width; int h = info.height; // printf(“width:%d, height:%d\n”, w, h); // (3)读取RGB图像数据 read char RGB[wh3]; read(bmp_fd, RGB, wh3); // (4)RGB转成ARGB数据 unsigned int ARGB[wh]; for (int i = 0; i < wh; ++i) { ARGB[i] = RGB[i3+2]<<16|RGB[i3+1]<<8|RGB[i3+0]<<0; } // y坐标翻转 unsigned int w_data[wh]; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { w_data[(y)w+x] = ARGB[(h-1-y)w+x]; } } // (5)用显存映射的方式显示图片 // ①申请映射区 unsigned int FB = mmap(NULL, 8004804, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0); if (FB == MAP_FAILED) { perror(“mmap”); return -1; } // ②内存拷贝 : 显示 for (int i = 0; i < h; ++i) { //一行一行做内存拷贝 memcpy(FB+(y_offset+i)800+(x_offset), w_data+wi, w4); } // ③解除映射 munmap(FB, 8004804); // (6)关闭图片文件和液晶屏设备文件 close(lcd_fd); close(bmp_fd); return 0;}/触摸屏事件读取,获取坐标信息 参数:用来存放坐标信息的地址 返回值:0表示成功,-1表示失败/int read_ts(struct coordinate coor_p){ //定义两个变量表示x和y是否读到 bool x_ready = false; bool y_ready = false; int touch = -1; //1.打开触摸屏 int ts_fd = open("/dev/input/event0", O_RDONLY); if(ts_fd == -1) { perror(“open touchscreen”); return -1; } //2.读取输入事件信息 struct input_event event_info; while(1) { //产生阻塞,当有触摸屏输入事件的时候,继续运行 read(ts_fd, &event_info, sizeof(event_info)); switch(event_info.type)//判断是哪种输入事件 { // case EV_SYN:printf("----------SYN----------\n");break; case EV_KEY:if (event_info.code == BTN_TOUCH) { // printf(“touch:%d\n”, event_info.value); touch = event_info.value; } break; case EV_ABS://绝对位移事件 if (event_info.code == ABS_X) { // printf(“x = %d\n”, event_info.value); coor_p->x = event_info.value; x_ready = true; } else if (event_info.code == ABS_Y) { // printf(“y = %d\n”, event_info.value); coor_p->y = event_info.value; y_ready = true; } else if (event_info.code == ABS_PRESSURE) { // printf(“p = %d\n”, event_info.value); } break; default:break; } //一次坐标事件读取完成 if (x_ready && y_ready && touch == 0) { break; } } //3.关闭设备文件 close(ts_fd); return 0;}/*获取按钮按下对应的楼层号/int btn_floor(){ //(1)读坐标 struct coordinate coor; read_ts(&coor); //黑色屏需要 /coor.x = coor.x800/1024; coor.y = coor.y480/600;/ //(2)判断坐标对应的楼层号,并返回 if (coor.x>600 && coor.x<700 && coor.y>384 && coor.y<480) return 1; else if (coor.x>700 && coor.x<800 && coor.y>384 && coor.y<480) return 2; else if (coor.x>600 && coor.x<700 && coor.y>288 && coor.y<384) return 3; else if (coor.x>700 && coor.x<800 && coor.y>288 && coor.y<384) return 4; else if (coor.x>600 && coor.x<700 && coor.y>192 && coor.y<288) return 5; else if (coor.x>700 && coor.x<800 && coor.y>192 && coor.y<288) return 6; else if (coor.x>600 && coor.x<700 && coor.y>96 && coor.y<192) return 7; else if (coor.x>700 && coor.x<800 && coor.y>96 && coor.y<192) return 8; else if (coor.x>600 && coor.x<700 && coor.y>0 && coor.y<96) return 9; else if (coor.x>700 && coor.x<800 && coor.y>0 && coor.y<96) return 10; else return 0;}/**显示对应楼层号为按下参数:n表示楼层号* flag:1表示按下,0表示放开*/void show_btn(int n, int flag){ if (flag == 1) { switch(n) { case 1:show_bmp("/hcp/picture/001.bmp", 600-1, 384-1);break;//384-480 case 2:show_bmp("/hcp/picture/002.bmp", 700-1, 384-1);break; case 3:show_bmp("/hcp/picture/003.bmp", 600-1, 288-1);break;//288-384 case 4:show_bmp("/hcp/picture/004.bmp", 700-1, 288-1);break; case 5:show_bmp("/hcp/picture/005.bmp", 600-1, 192-1);break;//192-288 case 6:show_bmp("/hcp/picture/006.bmp", 700-1, 192-1);break; case 7:show_bmp("/hcp/picture/007.bmp", 600-1, 96-1);break;//96-192 case 8:show_bmp("/hcp/picture/008.bmp", 700-1, 96-1);break; case 9:show_bmp("/hcp/picture/009.bmp", 600-1, 0);break;//0-95 case 10:show_bmp("/hcp/picture/010.bmp", 700-1, 0);break; default:break; } } else if (flag == 0) { switch(n) { case 1:show_bmp("/hcp/picture/01.bmp", 600-1, 384-1);break;//384-480 case 2:show_bmp("/hcp/picture/02.bmp", 700-1, 384-1);break; case 3:show_bmp("/hcp/picture/03.bmp", 600-1, 288-1);break;//288-384 case 4:show_bmp("/hcp/picture/04.bmp", 700-1, 288-1);break; case 5:show_bmp("/hcp/picture/05.bmp", 600-1, 192-1);break;//192-288 case 6:show_bmp("/hcp/picture/06.bmp", 700-1, 192-1);break; case 7:show_bmp("/hcp/picture/07.bmp", 600-1, 96-1);break;//96-192 case 8:show_bmp("/hcps/picture/08.bmp", 700-1, 96-1);break; case 9:show_bmp("/hcp/picture/09.bmp", 600-1, 0);break;//0-95 case 10:show_bmp("/hcp/picture/10.bmp", 700-1, 0);break; default:break; } }}/2.初始化空链表 返回:创建好的头节点的地址*/struct Node init_link(){ //(1)申请头节点空间 struct Node head = malloc(sizeof(struct Node)); //(2)初始化头节点 // head->num = 0; head->next = NULL; return head;}/3.创建节点参数:int num:表示新建节点的数据返回:新建好的节点的地址/struct Node creat_node(int num){ //(1)申请新节点的空间 struct Node new = malloc(sizeof(struct Node)); //(2)初始化新节点 new->num = num; new->next = NULL; return new;}/4.插入节点参数:head表示链表头节点 new表示节点/void insert_node(struct Node *head, struct Node new){ //(1)找到链表尾部 struct Node p = head; while(p->next != NULL) { p = p->next; } //(2)将新节点插入到原来尾部节点的后边 p->next = new;}//5.遍历整个链表void display(struct Node head){ struct Node p = head; while(p->next != NULL) { p = p->next; printf("%d “, p->num); } printf(”\n");}/6.查找节点参数:head:待查找的链表 num:想要找的数据返回值:成功:找到的节点的地址 失败:返回NULL/struct Node *find_node(struct Node head, int num){ struct Node p = head; while(p->next != NULL) { p = p->next; if (p->num == num) { return p; } } return NULL;}/7.删除节点参数:head:链表头 num:待删节点的数据/bool delete_node(struct Node *head, int num){ //(1)找到待删节点的前面节点 struct Node prev = head; while(prev->next != NULL) { //找到了待删节点的前面节点 prev if (prev->next->num == num) { //(2)删除节点 struct Node delete = prev->next; //将prev的next成员赋值为待删节点的后面节点的地址 prev->next = delete->next; //释放空间 free(delete); //退出 return true; } //如果prev不是待删节点的前面节点 prev = prev->next; } return false;}//8.清空链表void clear_link(struct Node head){ while(head->next != NULL) { struct Node first = head->next; head->next = first->next; free(first); }}/9.更新节点参数:head:链表头节点 old_num:想要更新的节点原来的数据 new_num:更新过后的数据 返回值:成功返回true,失败返回false/bool update_node(struct Node *head, int old_num, int new_num){ //(1)找到节点 struct Node *node = find_node(head, old_num); if (node == NULL) { return false; } //(2)更新数据 node->num = new_num; return true;}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值