首页 > 其他分享 >智慧医疗——Cortex-A53旗舰级科室呼叫管理系统

智慧医疗——Cortex-A53旗舰级科室呼叫管理系统

时间:2024-10-26 09:19:04浏览次数:3  
标签:head ch temp int A53 fd Cortex printf 旗舰级

1.1项目背景及目标

        医疗科室呼号显示屏系统的部署,显著提升了医院门诊部的运营效率,有效地解决了患者排队等候时的拥挤和无序问题,从而显著减少了患者的等待时间,优化了整体的就医体验。这一智能化医疗辅助设施的应用,不仅提高了医院的服务质量,而且改善了医院的整体形象,实现了对医疗资源的高效分配与管理。通过该系统,我们成功实现了以下目标: 1,大幅降低患者排队等候时间,全面提升就医环境质量。以往,在患者数量众多的情况下,就诊过程中患者不得不在诊室门口排队等候,这不仅影响了医生的正常工作秩序,还让患者承受着长时间的等待压力。 2,引入科室呼号显示屏系统后,患者可以轻松地在候诊区的屏幕上查看自己的排队信息,从而避免了在诊室外的无效等待。 3,该系统的投入使用,有效遏制了医疗服务中的混乱现象,如插队、拥挤等,为医院创造了一个安静、有序的就医环境,同时也为医护人员提供了一个更加高效、舒适的工作空间。 换言之,科室呼号显示屏系统的引入,不仅极大地提升了医院的服务水平,还进一步增强了患者对医疗服务的满意度,为医院的现代化管理和智慧医疗服务体系建设奠定了坚实的基础。

1.2程序设计流程图

 1.3程序效果演示

(------------------------------------------------------------------项目视频演示-------------------------------------------------------------)

1.3.1主界面

1.3.2科室选择挂号模块

1.3.3医生信息模块

1.3.4过/叫号模块

1.3.5退出系统模块

1.4核心代码解析

1.4.1主函数

#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 "funtion.h"
#include "font.h"

/*
叫挂界面  callAndHangInterface
界面        interface
科室选择    departmentSelection
退出界面    exit
医生信息    doctorInformation

内科:Internal_Medicine
外科:surgical
急诊:emergency
*/



int main(int argc, char const *argv[])
{
    Scan_Main_face();

    return 0;
}

1.4.2映射函数

// 获取LCD映射地址
void *mmap_lcd()
{
    // 1.打开LCD 设备
    int fd = open("/dev/fb0", O_RDWR);
    if (fd < 0)
    {
        perror("打开LCD失败\n");
        return NULL;
    }

    // 2.映射LCD设备
    void *p = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (p == MAP_FAILED)
    {
        perror("映射失败\n");
        return NULL;
    }
    else
    {
        printf("映射LCD成功\n");
    }

    close(fd);

    return p;
}

// 展示照片
//函数说明: ch 为要展示照片的路径地址
//返回值: 成功返回 0, 失败返回 -1
int show(char *ch)
{
    if (ch == NULL)
    {
        printf("ch 为 NULL\n");
        return -1;
    }

    // 1.打开bmp图片文件
    int fd = open(ch, O_RDWR);
    if (fd < 0)
    {
        perror("打开文件失败\n");
        return -1;
    }

    // 2.读取文件头
    BITMAPFILEHEADER head;
    read(fd, &head, 14);

    // 3.读取文件信息头
    BITMAPINFOHEADER info;
    read(fd, &info, 40);

    // 定义像素缓存区 800      480             24    /  8
    char rgb[info.biWidth * info.biHeight * info.biBitCount / 8];
    // 4.读取图像的像素数据
    read(fd, rgb, sizeof(rgb));

    // 5.内存映射
    int(*lcd)[800] = mmap_lcd();

    // 把char 类型的rgb 转换为 int 类型的color
    int color[info.biHeight][info.biWidth];

    // 指向 rgb 数据
    char *p = rgb;
    for (int y = 0; y < info.biHeight; y++)
    {
        for (int x = 0; x < info.biWidth; x++)
        {
            char b = *p++;
            char g = *p++;
            char r = *p++;
            color[y][x] = b | g << 8 | r << 16 | 0 << 24;
        }
    }

    // 6.把rgb 数据放入 lcd  映射地址
    for (int y = 479; y >= 0; y--)
    {
        for (int x = 0; x < 800; x++)
        {
            lcd[479 - y][x] = color[y][x];
        }
    }

    //关闭映射
    if (munmap(lcd, 800 * 480 * 4) == -1) {
        perror("munmap 失败");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("关闭映射\n");
    }

    
    // 关闭打开后的文件
    close(fd);
    return 0;
}

//展示照片(任意位置)
//函数参数说明: offset_x 和 offset_y 为屏幕上的位置
int show_anywhere(char *ch, int offset_x, int offset_y)
{
    if (ch == NULL)
    {
        printf("ch 为 NULL\n");
        return -1;
    }

    // 1.打开bmp图片文件
    int fd = open(ch, O_RDWR);
    if (fd < 0)
    {
        perror("打开文件失败\n");
        return -1;
    }

    // 2.读取文件头
    BITMAPFILEHEADER head;
    read(fd, &head, 14);

    // 3.读取文件信息头
    BITMAPINFOHEADER info;
    read(fd, &info, 40);

    // 定义像素缓存区 800      480             24    /  8
    char rgb[info.biWidth * info.biHeight * info.biBitCount / 8];

    // 4.读取图像的像素数据
    read(fd, rgb, sizeof(rgb));

    // 5.内存映射
    int(*lcd)[800] = mmap_lcd();

    // 把char 类型的rgb 转换为 int 类型的color
    int color[info.biHeight][info.biWidth];

    // 指向 rgb 数据
    char *p = rgb;
    for (int y = 0; y < info.biHeight; y++)
    {
        for (int x = 0; x < info.biWidth; x++)
        {
            char b = *p++;
            char g = *p++;
            char r = *p++;
            color[y][x] = b | g << 8 | r << 16 | 0 << 24;
        }
    }

    // 6.把rgb 数据放入 lcd  映射地址
    for (int y = offset_y; y < info.biHeight + offset_y; y++)
    {
        for (int x = offset_x; x < info.biWidth + offset_x; x++)
        {
            lcd[y][x] = color[info.biHeight - y + offset_y][x - offset_x];
        }
    }

    //关闭映射
    if (munmap(lcd, 800 * 480 * 4) == -1) {
        perror("munmap 失败");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("关闭映射\n");
    }

    // 关闭打开后的文件
    close(fd);
    return 0;
}

1.4.3获取触摸屏位置数据函数

//获取触摸屏的xy并判断按下松开状态
//函数返回值:成功为 0  失败为 -1
int get_event_data(int *x, int *y)
{
    //打开触摸屏文件
    int fd = open("/dev/input/event0", O_RDWR);
    if (fd < 0)
    {
        perror("open fd error");
        return -1;
    }

    //读取触摸屏中的数据
    while (1)
    {
        struct input_event ev;
        read(fd, &ev, sizeof(ev));
        //获取x的值
        if (ev.type == EV_ABS && ev.code == ABS_X)
        {
            //进行等比例校准
            *x = ev.value * 800 / 1024;
            printf("x = %d  ", *x);
        }
        //获取y的值
        if (ev.type == EV_ABS && ev.code == ABS_Y)
        {
            *y = ev.value * 480 / 600;
            printf("y = %d\n", *y);
        }

        //检测触摸屏的按下和松开(把触摸屏看作一个按钮)
        if (ev.type == EV_KEY)
        {
            //判断按下
            if (ev.value == 1)
            {
                printf("触摸屏按下 %d\n", ev.value);
            }
            if (ev.value == 0)
            {
                printf("触摸屏松开 %d\n", ev.value);
                break;
            }
        }
    }

    close(fd);

    return 0;
}

1.4.4显示文字模块

//显示文字模块
/*函数说明:
test : 要输出的内容
test_size: 字体大小
width: 输出框的宽度
height: 输出框的高度
x,y : 在输出框的起始位置
px, py: 在LCD上的起始位置
color: 颜色数据
maxWidth: 最大宽度, 用于换行
*/
void display_Text(char *text, int test_size, unsigned int width, unsigned int height, int x, int y, int px, int py, unsigned int color, int maxWidth)
{
    // 1.映射LCD 设备
    int(*lcd)[800] = NULL;
    lcd = mmap_lcd();

    // 2.加载字库
    font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");

    // 3.设置字体的大小
    fontSetSize(f, test_size);

    // 4.创建一块输出框
    bitmap *bm = createBitmap(width, height, 4);
    // getColor(A, B, G, R)  设置颜色
    // 5.把汉字放入输出框
    fontPrint(f, bm, x, y, text, color, maxWidth);
    show_font_to_lcd((void *)lcd, px, py, bm);


    //关闭字库
    fontUnload(f);

    //关闭映射
    if (munmap(lcd, 800 * 480 * 4) == -1) {
        perror("munmap 失败");
        exit(EXIT_FAILURE);
    }
    else
    {
        printf("关闭映射\n");
    }
}

1.4.5各个功能实现模块

//科室选择
void department_Selection()
{
    //获取x y 的值
    int x, y;

    //获取内科医生信息
    node *head_Internal = new_department_Internal_Doctors_list();
    node *temp_Internal = head_Internal->next;

    //获取外科医生信息
    node *head_surgical = new_department_surgical_Doctors_list();
    node *temp_surgical = head_surgical->next;

    //获取急诊医生信息
    node *head_emergency = new_department_emergency_Doctors_list();
    node *temp_emergency = head_emergency->next;

    while (1)
    {
        show("/picture/departmentSelection.bmp");
        get_event_data(&x, &y);

        //内科按钮
        if (x >= 220 && x <= 560 && y >= 100 && y <= 170)
        {
            printf("内科响应了\n");
            show("/picture/funtion_1_sourse.bmp");

            department_Selection_Model(head_Internal, temp_Internal);
            continue;
        }

        //外科按钮
        if (x >= 220 && x <= 560 && y >= 215 && y <= 275)
        {
            printf("外科响应了\n");
            show("/picture/funtion_1_sourse.bmp");

            department_Selection_Model(head_surgical, temp_surgical);
            continue;
        }

        //急诊按钮
        if (x >= 220 && x <= 560 && y >= 320 && y <= 400)
        {
            printf("急诊响应了\n");
            show("/picture/funtion_1_sourse.bmp");

            department_Selection_Model(head_emergency, temp_emergency);
            continue;
        }

        //返回首页按钮
        if (x >= 55 && x <= 190 && y >= 370 && y <= 450)
        {
            printf("返回首页响应了\n");
            break;
        }
    }
}

//医生信息模块
void doctor_Information_Module(node *head, node *temp)
{
    int x, y;

    while (1)
    {
        //打印医生信息
        show(temp->data);
        display_Text_profile(temp->profile);
        display_Text_professionalExcellence(temp->professionalExcellence);

        //获取坐标值
        get_event_data(&x, &y);

        //检测 “上一张” 按钮
        if (x >= 35 && x <= 160 && y >= 380 && y <= 425)
        {
            if (temp->prev == head)
            {
                printf("已经到顶啦\n");
                display_Test_prompt("           已经到顶啦");
                if (check_Ok_Button(x, y))
                {
                    temp = head->next; // 始终指向第一个节点
                    continue;
                }
            }
            else
            {
                temp = temp->prev;
            }
            printf("上一张响应\n");
        }

        //检测 “返回主页” 按钮
        if (x >= 300 && x <= 470 && y >= 380 && y <= 425)
        {
            printf("返回主页响应\n");
            break;
        }

        //检测 “下一张” 按钮
        if (x >= 600 && x <= 750 && y >= 380 && y <= 425)
        {
            if (temp->next == head)
            {
                printf("已经到底啦\n");
                display_Test_prompt("           已经到底啦");
                if (check_Ok_Button(x, y))
                {
                    continue;
                }
            }
            else
            {
                temp = temp->next;
            }
            printf("下一张响应\n");
        }
    }
}
//呼/挂号模块
void call_And_Hang_Interface(node *head_patients, node **temp_patients, queue *m, char **ch_ok, char **ch_pass)
{
    //监控页面控件
    while (1)
    {
        printf("这是第三个按钮\n");
        show("/picture/callAndHangInterface.bmp"); //展示框架
        // show_anywhere("/picture/surgical_01.bmp", 53, 63); //头像
        // display_Name("华佗", 120, 267);                    //展示名字
        // display_Doctor_Department("外科", 120, 297);       //展示科室

        //展示等待人员信息
        show_Information_Waiting_People(m);

        //展示正在就诊和过号人员
        display_Name_chang_size(*ch_ok, 35, 330, 128);
        display_Name_chang_size((*temp_patients)->name, 35, 330, 295);

        //监控页面按钮
        int key_num = check_call_And_Hang_Interface_button();

        //返回首页 按钮响应
        if (key_num == 1)
        {
            printf("返回首页响应\n");
            break;
        }

        //过 按钮响应
        if (key_num == 2)
        {
            printf(" 过 响应\n");
            *ch_pass = pop(m);

            if (*ch_pass == NULL)
            {
                // *ch_pass = " ";
                // display_Name_chang_size(*ch_pass, 35, 330, 295);
                continue;
            }
            else
            {
                //尾插到链表中
                *temp_patients = new_Node(NULL, NULL, NULL, *ch_pass, NULL);
                insert_end(head_patients, *temp_patients);
                // //过号患者
                // display_Name_chang_size(temp_patients->name, 35, 330, 295);
            }
        }

        //勾 按钮响应
        if (key_num == 3)
        {
            printf(" 勾 响应\n");
            *ch_ok = pop(m);

            if (*ch_ok == NULL)
            {
                *ch_ok = " ";
                display_Name_chang_size(*ch_ok, 35, 330, 128);
            }
            else
            {
                //正在就诊
                display_Name_chang_size(*ch_ok, 35, 330, 128);
            }
        }

        //上一位  按钮响应
        if (key_num == 4)
        {
            printf(" 上一位 响应\n");
            //到顶了
            if ((*temp_patients)->prev == head_patients)
            {
                printf("已经到顶啦\n");
                display_Test_prompt("           已经到顶啦");
                if (check_Ok_Button())
                {
                    (*temp_patients) = head_patients->next; // 始终指向第一个节点
                    continue;
                }
            }

            //展示上一位过号患者
            (*temp_patients) = (*temp_patients)->prev;
        }

        //下一位  按钮响应
        if (key_num == 5)
        {
            printf(" 下一位 响应\n");
            //到顶了
            if ((*temp_patients)->next == head_patients)
            {
                printf("已经到底啦\n");
                display_Test_prompt("           已经到底啦");
                if (check_Ok_Button())
                {
                    continue;
                }
            }

            //展示上一位过号患者
            (*temp_patients) = (*temp_patients)->next;
        }
    }
}

/*
退出系统模块
确认退出  返回  1
取消退出  返回  2
*/
int exit_funtion()
{
    printf("这是第四个按钮\n");

    display_Test_prompt_two_button("确定退出吗");
    int key_num = check_Ok_Button_two_button();

    //确认退出
    if (key_num == 1)
    {
        show("/picture/exit.bmp");
        return 1;
    }

    //取消退出
    if (key_num == 2)
    {
        return 2;
    }
}

1.5难点总结

  • 内存映射是一个重大难点,要通过open函数打开LCD设备,调用mmap函数映射LCD设备,再通过强制类型转换把映射地址强制转换为 int (*)[800]
  • 图像处理也是一大重大难点,本次项目我主要处理的是bmp图像,并且bmp图片 = 文件头(14)个字节 + 位图信息头(40)个字节 + 像素数据,不过在网上或者GPT都可以获得图像处理的接口,最后把图像显示在LCD屏就大功告成了
  • 触摸屏的处理同样也是一大难点,通过open函数打开触摸屏文件,通过read函数读取触摸屏中的数据,其中要注意读取到的数据要与LCD屏幕进行比例匹配
  • 最后的就是医生信息的存储、文字库的运用以及各种的图片素材的存储,这些都是文件IO的基本功,难点还是可以接受的

1.6开源项目代码分享

标签:head,ch,temp,int,A53,fd,Cortex,printf,旗舰级
From: https://blog.csdn.net/weixin_72119871/article/details/143192989

相关文章

  • Cortex-A53高端智能影音融合播放系统
    1.1项目背景及目标        随着信息技术的飞速发展,多媒体数据已成为人们日常生活和工作的重要组成部分,用户对于音视频播放软件的需求日益增长。然而,目前市面上的多媒体播放器在功能、性能、用户体验等方面存在较大差异,许多播放器无法满足用户多样化的播放需求。为了填......
  • Cortex-M3及以上32单片机使用内核DWT实现微秒级延时
    目录一、什么是DWT二、为什么要使用DWT实现延时2.1延时方法2.2上述两种方案的缺点三、如何实现DWT延时 3.1DEMCR寄存器3.2DWT_CTRL寄存器与DWT_CYCCNT寄存器四、代码实现五、验证延时函数一、什么是DWT        在Cortex-M3及以上的内核中有一个外设......
  • 大疆Osmo Action 5 Pro深度评测:旗舰级运动相机画质再升级
    大疆自去年夏天推出OsmoAction4运动相机以来,凭借其出色的稳定性和优质的影像表现在极限运动用户和Vlog创作者中赢得了极高的评价,成为了许多人拍摄运动场景和日常生活的首选设备。而如今,经过几代产品的积累,大疆OsmoAction运动相机系列终于推出了全新的旗舰级产品——OsmoAction......
  • ARM Cortex-M3/M4内核架构:中断处理过程
    目录一、概述1.保存现场?什么是现场?现场包括什么?2.怎么处理异常?我们先来简单介绍下。3.又怎么恢复现场?4.异常进入流程(核心流程)二、保存现场三、恢复现场1、EXC_RETURN2、恢复现场四、异常处理优化1、末尾连锁2、延时到达3、出栈抢占五、总结一、概述中断......
  • Cortex-M3/M4/M7 芯片 Fault 分析原理与实战
    目录一、简介1、异常类型2、异常优先级3、同步异步问题4、异常具体类型二、Faultexceptionregisters1、Controlregisters1.1CCR1.2SHP1.3SHCSR2、Statusandaddressregisters2.1HardFaultStatusRegister——HSFR2.2ConfigurableFaultStatusRegister——......
  • PY32 link仿真器,支持PY32系列ARM-Cortex内核单片机的调试烧录
    PY32系列32位单片机基于Arm®Cortex®-M处理器,包括M0+和M4系列产品。集高性能、实时操作、数字信号处理、低功耗性能、高性价比等特性于一身,同时还保持了系统简单、易于开发的特点,符合消费市场的基本设计需求,受到广大开发者的喜爱。PY32系列单片机适用于消费类、工业类,数字控制等......
  • Cortex-A7 MPCore 架构
    Cortex-A7MPCore架构 1)Cortex-A7MPCore简介Cortex-A7MPcore处理器支持1~4核,通常是和Cortex-A15组成big.LITTLE架构的,Cortex-A15作为大核负责高性能运算,比如玩游戏啥的,Cortex-A7负责普通应用,因为CortexA7省电。Cortex-A7本身性能也不弱,不要看它叫做Cortex-......
  • Hi3559A/C V100 集成了双核 A73 和双核 A53,支持 8K30/4K120 视频录制
    1.1概述Hi3559AV100是专业的8KUltraHDMobileCameraSOC,它提供了8K30/4K120广播级图像质量的数字视频录制,支持多路Sensor输入,支持H.265编码输出或影视级的RAW数据输出,并集成高性能ISP处理,同时采用先进低功耗工艺和低功耗架构设计......
  • Cortex-A7的GIC(通用中断控制器):边沿触发和电平触发中断的区别
    0资料ARM®GenericInterruptControllerArchitectureversion2.0ArchitectureSpecification1边沿触发和电平触发中断的区别1.1边沿触发和电平触发中断官方解释边沿触发(Edge-triggered)Thisisaninterruptthatisassertedondetectionofarisingedge......
  • Cortex-A7的GIC(通用中断控制器):边沿触发和电平触发中断处理流程
    0资料ARM®GenericInterruptControllerArchitectureversion2.0ArchitectureSpecification1边沿触发和电平触发中断处理流程1.0边沿触发和电平触发的区别边沿触发(Edge-triggered)Thisisaninterruptthatisassertedondetectionofarisingedgeofa......