当前位置: 首页 > news >正文

养老院自助饮水机(字符设备驱动)

目录

1、项目背景

2、驱动程序

2.1 三层架构

2.2 驱动三要素

2.3 字符设备驱动

 2.3.1 驱动模块

2.3.2 应用层

3、设计实现

3.1 项目设计

3.2 项目实现

3.2.1 驱动模块代码

3.2.2 用户层代码 

4、功能特性

5、技术分析 

6. 总结与未来展望


1、项目背景

        养老院的老人在生活中难免有所不方便,为了便捷老年人的生活,使用字符设备驱动编写了一个自助饮水机项目。该饮水机与普通饮水机的区别在于拥有更复杂的功能;饮水机拥有可以自行输入金额,然后程序开始运行。运行期间常亮绿灯,可以点击按钮暂停,灯颜色改变;一直到余额不足,然后蜂鸣器提示用户。

        提示:该项目的基础是在”系统移植“之上,对于系统移植步骤及说明:

        http://t.csdnimg.cn/O1uMi

 

2、驱动程序

2.1 三层架构

图2-1 结构框图

         对于三层的说明,想必大家都不陌生。内核层既需要去通过转换地址映射到内核,使得内核可以通过虚拟地址去操作底层的硬件设备;也需要使用虚拟文件系统向上层提供一个用户能够操作的文件设备。内核层作为中间枢纽,能提供如此的功能,归功于驱动程序,见图2-2。

 

2.2 驱动三要素

//驱动模块三要素 入口、出口、许可证
#include <linux/init.h>
#include <linux/module.h>
//入口
static int hello_init(void)
{return 0;
}
//出口
static void hello_exit(void)
{
}
module_init(hello_init);
module_exit(hello_exit);
//许可证
MODULE_LICENSE("GPL");//一个最简单、最基本的驱动程序

 

2.3 字符设备驱动

图2-2 字符设备驱动框图

 

 2.3.1 驱动模块

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
unsigned int major=0;
#define CNAME "hello"
ssize_t mycdev_read (struct file *file, char __user *ch, size_t len, loff_t *lodd)
{printk("this is read\n");return 0;
}
ssize_t mycdev_write (struct file *file, const char __user *buf, size_t len, loff_t *lodd)
{printk("this is write\n");return 0;
}
int mycdev_open (struct inode *ino, struct file *file)
{printk("this is open\n");return 0;
}
int mycdev_release (struct inode *ino, struct file *file)
{printk("this is close\n");return 0;
}
const struct file_operations fops=
{.read=mycdev_read,.write=mycdev_write,.open=mycdev_open,.release=mycdev_release,
};//该结构体主要用于像上层的用户层,提供调用的接口函数
static int __init hello_init(void)
{major=register_chrdev(major,CNAME,&fops);//注册一个字符设备驱动if(major<0){printk("register chrdev error\n");return major;}return 0;
}
static void __exit hello_exit(void)
{unregister_chrdev(major,CNAME);printk("bai bai\n");
}
module_init(hello_init);//入口
module_exit(hello_exit);//出口
MODULE_LICENSE("GPL");//返回值

 

2.3.2 应用层

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
char buf[128]={0};
int main(int argc,const char *argv[])
{int fd;fd=open("./hello",O_RDWR);if(fd==-1){perror("open error");return -1;}write(fd,buf,sizeof(buf));//对应着设备驱动模块的mycdev_write read(fd,buf,sizeof(buf));//对应着设备驱动模块的mycdev_readclose(fd);return 0;
}

         所以,具体应用层所能干的,就是调用接口,而接口函数里面做的事情,则由我们驱动开发人员去编写,当然,此驱动模块还没有去操作实际的硬件设备,对于想要操作底层的硬件设备,则需要去看板子的原理图,查看外设的地址映射等。(以上驱动模块并未自动创建设备文件,执行完还需自行mknod,命令格式如下:sudo mknod hello c/b(c 代表字符设备 b代表块设备)主设备号 次设备号)

3、设计实现

3.1 项目设计

        对于该项目组成,同样是上述组成,不过更加复杂,具体的我就不再引出了。如果有任何问题,可以联系博主。

图3-1 驱动模块的作用

3.2 项目实现

3.2.1 驱动模块代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>#define CNAME "NEW_C"
unsigned int major=0;
struct class *cls;
struct device *dvs;
char kbuf[64]={0};
int money=0;
int devlen=0;#define RED_BASE 0xC001A000
#define GRE_BASE 0xC001E000
#define BLU_BASE 0xC001B000
#define BEEP_BASE 0xC001C000
unsigned int *red_base=NULL;
unsigned int *gre_base=NULL;
unsigned int *blu_base=NULL;
unsigned int *beep_base=NULL;#define GPIONO(m,n) m*32+n  //计算gpio号
#define GPIO_B8  (GPIONO(1,8))//计算按键gpio号
#define GPIO_B16  (GPIONO(1,16)) //计算gpio号
struct timer_list mytimer;//声明结构体
struct timer_list mytimer1;
struct timer_list mytimer2;
int gpiono[] = {GPIO_B8,GPIO_B16};//数组内存入两个按键的软中断号
char *irqname[] = {"interrupt-b8","interrupt-b16"};//中断的名字
void key_irq_timer_handle(unsigned long data)//定时器中断处理函数
{int status_b8  = gpio_get_value(GPIO_B8);//读取gpiob8数值int status_b16 = gpio_get_value(GPIO_B16);//读取gpiob16数值if(status_b8 == 0){//如果等于0表示按下,执行打印函数*blu_base |= 1<<12;mod_timer(&mytimer1,jiffies+1000);printk("left  button down............\n");}if(status_b16 == 0){//如果等于0表示按下,执行打印函数*blu_base &= ~(1<<12);del_timer(&mytimer1);printk("right button down#############\n");}
}void key_irq_timer_handle1(unsigned long data)//定时器中断处理函数
{kbuf[11]=kbuf[11]-1;if(kbuf[11]=='/'){kbuf[10]=kbuf[10]-1;kbuf[11]=kbuf[11]+10;}mod_timer(&mytimer1, jiffies + 1000);
}void key_irq_timer_handle2(unsigned long data)//定时器中断处理函数
{*beep_base &= ~(1<<14);
}
irqreturn_t farsight_irq_handle(int num, void *dev)//按键产生的中断处理函数
{mod_timer(&mytimer,jiffies+10);//开启定时器。只要触发就重新赋值,用来消抖return IRQ_HANDLED; 
}ssize_t my_dev_read(struct file *file, char __user *ubuf, size_t len, loff_t *loff)
{if(len >sizeof(kbuf)){len =sizeof(kbuf);}printk("%c %c\n",kbuf[10],kbuf[11]);devlen = copy_to_user(ubuf,kbuf,len);if(devlen){printk("copy to user is err\n");return devlen;}return 0;
}ssize_t my_dev_write(struct file *file, const char __user *ubuf, size_t len, loff_t *loff)
{if(len > sizeof (kbuf)){len=sizeof(kbuf);}devlen = copy_from_user(kbuf,ubuf,len);if(devlen){printk("copy from user is err\n");return devlen;}money=(kbuf[10]-48)*10+(kbuf[11]-48);printk("This is my char_dev_write %d\n",money);return 0;
}int my_dev_open(struct inode *inode, struct file *file)
{return 0;
}int my_dev_release(struct inode *inode, struct file *file)
{*beep_base |= 1<<14;mod_timer(&mytimer2, jiffies + 1000);return 0;
}const struct file_operations fops=
{.read=my_dev_read,.write=my_dev_write,.open=my_dev_open,.release=my_dev_release,// .unlocked_ioctl=my_unlocked_ioctl,
};static int __init hello_init(void)
{major=register_chrdev(major,CNAME,&fops);if(major<0){printk("register_chrdev is error\n");return major;}red_base=ioremap(RED_BASE,36);gre_base=ioremap(GRE_BASE,36);blu_base=ioremap(BLU_BASE,36);beep_base=ioremap(BEEP_BASE,36);if(red_base==NULL || gre_base==NULL){printk("ioremap is err\n");return -ENOMEM;}*red_base &=~(1<<28);*(red_base+1) |=1<<28;*(red_base+9) &=~(3<<24);*gre_base &= ~(1<<13);*(gre_base+1) |= (1<<13);*(gre_base+8) &=~(3<<26);*(blu_base+1) |= 1<<12;*(blu_base+8) |=(2<<24);*beep_base &= ~(1<<14);*(beep_base+1) |= 1<<14;*(beep_base+8) &= ~(1<<29);*(beep_base+8) |= 1<<28;cls = class_create(THIS_MODULE, CNAME);if(IS_ERR(cls)){printk("class create is err\n");return PTR_ERR(cls);}dvs=device_create(cls, NULL, MKDEV(major,0), NULL, CNAME);if(IS_ERR(dvs)){printk("device create is err\n");return PTR_ERR(dvs);}int ret,i;mytimer.expires = jiffies + 10;//时间mytimer.function = key_irq_timer_handle;//定时器中断处理函数mytimer.data = 0;//参数init_timer(&mytimer);//将定时器信息写入进行初始化add_timer(&mytimer);//开启一次定时器mytimer1.expires = jiffies + 1000;//时间mytimer1.function = key_irq_timer_handle1;//定时器中断处理函数mytimer1.data = 0;//参数init_timer(&mytimer1);//将定时器信息写入进行初始化add_timer(&mytimer1);//开启一次定时器mytimer2.expires = jiffies + 1000;//时间mytimer2.function = key_irq_timer_handle2;//定时器中断处理函数mytimer2.data = 0;//参数init_timer(&mytimer2);//将定时器信息写入进行初始化add_timer(&mytimer2);//开启一次定时器for(i=0;i<ARRAY_SIZE(gpiono); i++){//这里用for主要目的之申请两个中断ret = request_irq(gpio_to_irq(gpiono[i]),farsight_irq_handle,IRQF_TRIGGER_FALLING,irqname[i],NULL);//中断申请 参数:软中断号  中断执行函数  下降沿触发 中断的名字if(ret){printk("request irq%d error\n",gpio_to_irq(gpiono[i]));//申请失败提示return ret;}}return 0;
}static void __exit hello_exit(void)
{int i;for(i=0;i<ARRAY_SIZE(gpiono); i++){//注销掉中断free_irq(gpio_to_irq(gpiono[i]),NULL);}del_timer(&mytimer);//注销掉定时器del_timer(&mytimer1);//注销掉定时器del_timer(&mytimer2);//注销掉定时器class_destroy(cls);device_destroy(cls,MKDEV(major,0));iounmap(red_base);iounmap(gre_base);iounmap(blu_base);iounmap(beep_base);unregister_chrdev(major,CNAME);}module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

3.2.2 用户层代码 

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <time.h>#include "head.h"char buf[64] ={0};
char buff[128]={0};
struct tm *tp;
time_t t;
int main(int argc, char *argv[])
{int fd = open("/dev/NEW_C", O_RDWR);if (fd < 0){perror("open NEW_C err\n");return -1;}int fds=open("./history.txt",O_APPEND|O_CREAT|O_WRONLY,0666);if(fds<0){perror("open history err\n");return -1;}sprintf(buf,"0X55%s%s0XFF",argv[1],argv[2]);write(fd,buf,sizeof(buf));int readlen=0;while(1){time(&t);tp = localtime(&t);if((buf[10]=='0') && buf[11]=='0'){goto loop;}readlen = read(fd,buf,sizeof(buf));sprintf(buff,"%4d-%02d-%02d %02d:%02d:%02d : 账户:%c%c\t剩余金额:%c%c\n",tp->tm_year+1900,tp->tm_mon+1,tp->tm_mday,tp->tm_hour,tp->tm_min,tp->tm_sec,buf[6],buf[7],buf[10],buf[11]);write(fds,buff,strlen(buff));printf("账户:%c%c\t剩余金额:%c%c\n",buf[6],buf[7],buf[10],buf[11]);sleep(1);}
loop:close(fd);return 0;
}

 

4、功能特性

上述项目的功能大体如下:

        用户可自行输入金额。

        金额定时减少,出水时亮绿灯

        用户可点击按钮实现暂停接水,并且余额不会减少。

        余额归零,代表出水完毕,蜂鸣器响提示用户。

        本地日志会记录用户的购买记录及详细信息。

 

5、技术分析 

        字符设备驱动编写:向上提供接口,向下控制硬件。

        定时器使用:按键消抖,水量控制,蜂鸣器控制。

        中断使用:按键触发中断。

        文件io:保存用户消费日志。

 

6. 总结与未来展望

        字符设备驱动是操作系统中的一种设备驱动程序,用于管理和控制字符设备。在Linux系统中,字符设备驱动通常使用字符设备接口进行开发。驱动程序需要定义设备结构体、注册设备、实现文件操作函数等,以提供稳定高效的设备访问接口。除了基本的功能,驱动程序还可以实现多个进程访问同一个设备、内存映射、虚拟文件系统、设备驱动模块化、调试信息输出等特性。

        字符设备驱动技术在计算机领域有着重要的意义和影响。首先,它为应用程序提供了访问字符设备的标准接口,使得应用程序能够方便地与设备进行数据交互,从而促进了各种应用软件的开发和推广。其次,字符设备驱动技术也支持多种设备类型和多种操作系统平台,使得设备之间的互通性得到了提升,为设备互联和智能化提供了先决条件。

        未来,随着物联网技术的不断发展和普及,字符设备驱动技术将会得到更广泛的应用和推广。特别是在智能家居、工业自动化、医疗健康等领域,字符设备驱动技术将发挥更大的作用和贡献。同时,随着技术的不断进步和创新,字符设备驱动技术也将会不断完善和优化,以满足日益增长的设备互联需求和应用场景。

        感谢大家的阅读,欢迎留言指教。

相关文章:

养老院自助饮水机(字符设备驱动)

目录 1、项目背景 2、驱动程序 2.1 三层架构 2.2 驱动三要素 2.3 字符设备驱动 2.3.1 驱动模块 2.3.2 应用层 3、设计实现 3.1 项目设计 3.2 项目实现 3.2.1 驱动模块代码 3.2.2 用户层代码 4、功能特性 5、技术分析 6. 总结与未来展望 1、项目背景 养老院的老人…...

Jenkins 构建触发器指南

目录 触发远程构建 (例如&#xff0c;使用脚本) 描述 配置步骤 安全令牌 在其他项目构建完成后触发构建 描述 配置步骤 定时触发构建 描述 配置步骤 GitHub钩子触发GITScm轮询 描述 配置步骤 Poll SCM - 轮询版本控制系统 描述 触发远程构建 (例如&#xff0c;使…...

通用的java中部分方式实现List<自定义对象>转为List<Map>

自定义类 /*** date 2023/12/19 11:20*/ public class Person {private String name;private String sex;public Person() {}public Person(String name, String sex) {this.name name;this.sex sex;}public String getName() {return name;}public String getSex() {return…...

Python---静态Web服务器-返回固定页面数据

1. 开发自己的静态Web服务器 实现步骤: 编写一个TCP服务端程序获取浏览器发送的http请求报文数据读取固定页面数据&#xff0c;把页面数据组装成HTTP响应报文数据发送给浏览器。HTTP响应报文数据发送完成以后&#xff0c;关闭服务于客户端的套接字。 2. 静态Web服务器-返回固…...

react v-18父组件调用子组件的方法和数据

版本 "react": "^18.1.0", "react-dom": "^18.1.0", 父组件 import React, { useState, useRef, memo, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Card } from &q…...

Linux——缓冲区

我在上篇博客留下了一个问题&#xff0c;那个问题就是关于缓冲区的问题&#xff0c;我们发现 文件有缓冲区&#xff0c;语言有用户级缓冲区&#xff0c;那么缓冲区到底是什么&#xff1f;&#xff0c;或者该怎 么认识缓冲区&#xff1f;这篇文章或许会让你有所认识&#xff0c;…...

Mac 生成Android签名证书 .keystore文件

工具下载地址 https://www.oracle.com/java/technologies/downloads/#jdk21-mac1. 找到安装jdk的路径&#xff0c;并进入bin目录下 1.1 查找JDK命令 /usr/libexec/java_home -v结果为: java_home: option requires an argument -- v /Library/Java/JavaVirtualMachines/jdk…...

电商数仓项目----笔记六(数仓ODS层)

ODS层的设计要点如下&#xff1a; &#xff08;1&#xff09;ODS层的表结构设计依托于从业务系统同步过来的数据结构。 &#xff08;2&#xff09;ODS层要保存全部历史数据&#xff0c;故其压缩格式应选择压缩比较高的&#xff0c;此处选择gzip。 &#xff08;3&#xff09;…...

rtsp视频在使用unity三维融合播放后的修正

1 rtsp 接入 我们使用unity UE 等三维渲染引擎中使用c编写插件来接入rtsp 视频。同时做融合的时候&#xff0c;和背景的三维颜色要一致&#xff0c;这就要使用视频融合修正技术。包括亮度&#xff0c;对比度&#xff0c;饱和度的修正。在单纯颜色上的修正可以简单使用rgb->…...

【已解决】解决Springboot项目访问本地图片等静态资源无法访问的问题

今天在开发一个招聘系统的时候&#xff0c;有投递简历功能&#xff0c;有投递就会有随之而来的查看简历对吧&#xff0c;我投递过的简历&#xff0c;另存为一个文件夹&#xff0c;就是说本地磁盘(或者服务器)有一个专门存放投递过的简历的文件夹&#xff0c;用于存放PDF&#x…...

运维笔记之centos部署Go-FastDfs

安装Go-FastDfs 当前最新版本为1.4.5&#xff0c;但发布的最新版本为1.4.4 # 下载文件 wget --no-check-certificate https://github.com/sjqzhang/go-fastdfs/releases/download/v1.4.4/fileserver -O fileserver # 赋权限 chmod x fileserver # 运行 ./fileserver server服…...

C#基础——线程(线程池、线程锁、线程抢占、多线程)

线程 进程&#xff08;Process&#xff09;是由操作系统分配资源并执行的一个独立的程序实&#xff0c;属于Windows的概念&#xff0c;进程结束就表示程序关闭了。 线程&#xff08;Thread&#xff09;是程序中执行的最小单位。一个线程代表了一个独立的执行流&#xff0c;可…...

C# WPF上位机开发(QT vs WPF)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 最近经常收到朋友们的私信&#xff0c;他们对C# WPF开发很感兴趣&#xff0c;但是呢&#xff0c;正当准备学习的时候&#xff0c;又有人告诉他们应…...

2-高可用-负载均衡、反向代理

负载均衡、反向代理 upstream server即上游服务器&#xff0c;指Nginx负载均衡到的处理业务的服务器&#xff0c;也可以称之为real server,即真实处理业务的服务器。 对于负载均衡我们要关心的几个方面如下&#xff1a; 上游服务器配置&#xff1a;使用upstream server配置上…...

STM32 使用ARM仿真器设置

STM32单片机程序下载到单片机芯片中有两种方式&#xff0c;①编译生成HEX&#xff0c;使用程序烧录软件刷到单片机芯片里。②使用ARM仿真器下载程序。使用ARM仿真器的优势是&#xff0c;在工程编译没问题直接在Keil软件里就可以将程序下载到单片机里&#xff0c;并且程序可以在…...

【Java】spring

一、spring spring是一个很大的生态圈&#xff0c;里面有很多技术。 其中最基础的是spring framework&#xff0c;主要的技术 是springboot以及springcloud。 1、spring framework spring framework是spring生态圈中最基础的项目&#xff0c;是其他项目的基础。 1.1、核心…...

C语言中关于操作符的理解

本篇文章只会列出大家在生活中经常使用的操作符 算术操作符 在算数操作符中常用的有&#xff0c;&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;% &#xff0c;我们重点讲一讲 / (除) 和 % (模) " / "运算 #include <stdio.h>int main() {int a5/2;fl…...

Flutter本地化(国际化)之App名称

文章目录 Android国际化IOS国际化 Flutter开发的App&#xff0c;如果名称想要跟随着系统的语言自动改变&#xff0c;则必须同时配置Android和IOS原生。 Android国际化 打开android\app\src\main\res\values 创建strings.xml 在values上右键&#xff0c;选择New>Values Res…...

Redis哨兵源码分析

在Redis server启动过程中&#xff0c;实现了实例化和初始化 1、哨兵实例化过程&#xff0c;采用redis sentinel指令实例化还是redis server下的参数实例化--sentinel。 // 检查服务器是否以 Sentinel 模式启动 server.sentinel_mode checkForSentinelMode(argc,argv);/* Re…...

安装Neo4j

jdk1.8对应的neo4j的版本是3.5 自行下载3.5版本的zip文件 地址 解压添加环境变量 变量名&#xff1a;NEO4J_HOME 变量值&#xff1a;D:\neo4j-community-3.5.0 &#xff08;你自己的地址&#xff09; PATH添加&#xff1a; %NEO4J_HOME%\bin (如果是挨着的注意前后英…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

Springboot社区养老保险系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;社区养老保险系统小程序被用户普遍使用&#xff0c;为方…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...