上位机下位机串口通信设计详解(转载)

直观学PLC • 来源:直观学PLC • 2023-02-21 09:55 • 4233次阅读

串行接口是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件。一般完成这种功能的电路,我们称为串行接口电路。

串口通信结构

串口通信是指外设和计算机间,通过数据信号线 、地线、控制线等,按位进行传输数据的一种通讯方式。这种通信方式使用的数据线少,在远距离通信中可以节约通信成本,但其传输速度比并行传输低。

串口是计算机上一种非常通用的设备通信协议。大多数计算机(不包括笔记本电脑)包含两个基于RS-232的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB兼容的设备也带有RS-232口。同时,串口通信协议也可以用于获取远程采集设备的数据。

RS-232(ANSI/EIA-232标准)是IBM-PC及其兼容机上的串行连接标准。可用于许多用途,比如连接鼠标、打印机或者Modem,同时也可以接工业仪器仪表。用于驱动和连线的改进,实际应用中RS-232的传输长度或者速度常常超过标准的值。RS-232只限于PC串口和设备间点对点的通信。RS-232串口通信最远距离是50英尺。

串口通信

串口通信是在工程应用中很常见。在上位机与下位机通讯过程中常通过有线的串口进行通信,在低速传输模式下串口通信得到广泛使用。在说个之前先来简单解释一下上位机与下位机的概念。

上位机与下位机设计

通常上位机指的是PC,下位机指的是单片机或者带微处理器的系统。下位机一般是将模拟信号经过AD采集将模拟量转换为数字量,下位机再经过数字信号处理以后将数字信号通过串口发送到上位机,相反上位机可以给下位机发送一些指令或者信息。常见的通信串口包括RS232、RS485、RS422等。这些串口只是在电平特性有所不同,在上位机与下位机进行数据通信时可以不考虑电平特性,而且现在在硬件上有各种转接接口,使用起来也很方便。

当然在通常做简单的串口UART实验时我们可以使用各种各样的串口助手小软件,但是这些串口小工具有时候并不能很好满足需求,那就尝试着自己写一套属于自己的串口助手?接下来说说如何使用java实现上位机与下位机之间的RS485串口通信。

step 1:下载支持java串口通信的jar包,这里给出下载地址:

http://files.cnblogs.com/files/Dreamer-1/mfz-rxtx-2.2-20081207-win-x86.zip(32bit 下载地址)

http://files.cnblogs.com/files/Dreamer-1/mfz-rxtx-2.2-20081207-win-x64.zip (64位下载地址)

对以上的版本解释一下,因为本人在这里踩了一个坑,32位或者64位是与ecplise/myecplise一致,要是版本弄错了会报错。

step 2:下载了那个jar包解压后会出现以下内容:

8e8e58cc-b122-11ed-bfe3-dac502259ad0.png

这个文件夹里面需要注意两点:jar包RXTXcomm需要导入到java工程里面去。另外就是需要将rxtxParallel.dll与rxtxSerial.dll复制在安装JDK的bin文件下和jre的bin文件夹下面,这样才能保证能够正常使用这个jar包。以下是将两个dll文件复制的位置:

C:Program Files (x86)Javajdk1.8.0_25in

C:Program Files (x86)Javajdk1.8.0_25jrein12

怎么讲jar包导入java工程里面就是比较简单的操作,可以参考:http://jingyan.baidu.com/arTIcle/ca41422fc76c4a1eae99ed9f.html

step 3:RXTXComm Api如何使用

接下来就是使用该导入jar包进行编码实现串口通信的功能了。在编码之前先来理一理串口通信的主要环节,本人总结主要分为以下几点:

1)计算机首先需要进行硬件check,查找是否有可用的COM端口,并对该对端口进行简要判断,包括这些端口是否是串口,是否正在使用。以下是部分主要代码:

/*类方法 不可改变 不接受继承

* 扫描获取可用的串口

* 将可用串口添加至list并保存至list

*/

public staTIc final ArrayList《String》 uartPortUseAblefind()

{

//获取当前所有可用串口

//由CommPorTIdenTIfier类提供方法

Enumeration《CommPortIdentifier》 portList=CommPortIdentifier.getPortIdentifiers();

ArrayList《String》 portNameList=new ArrayList();

//添加并返回ArrayList

while(portList.hasMoreElements())

{

String portName=portList.nextElement().getName();

portNameList.add(portName);

}

return portNameList;

}123456789101112131415161718

以下是测试类的测试实例:

ArrayList《String》 arraylist=UARTParameterSetup.uartPortUseAblefind();

int useAbleLen=arraylist.size();

if(useAbleLen==0)

{

System.out.println(“没有找到可用的串口端口,请check设备!”);

}

else

{

System.out.println(“已查询到该计算机上有以下端口可以使用:”);

for(int index=0;index《arraylist.size();index++)

{

System.out.println(“该COM端口名称:”+arraylist.get(index));

//测试串口配置的相关方法

}

} 123456789101112131415

2)通过计算机对串口的自检后,可以对串口参数进行简单的配置。常见的配置可以从常见的串口助手中得到启发。以下是一个串口助手的人机交换界面:

8eb51570-b122-11ed-bfe3-dac502259ad0.png

以下是对串口设置主要代码:

/*

* 串口常见设置

* 1)打开串口

* 2)设置波特率 根据单板机的需求可以设置为57600 。。。

* 3)判断端口设备是否为串口设备

* 4)端口是否占用

* 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup()

* 6)return:返回一个SerialPort一个实例对象,若判定该com口是串口则进行参数配置

* 若不是则返回SerialPort对象为null

*/

public static final SerialPort portParameterOpen(String portName,int baudrate)

{

SerialPort serialPort=null;

try

{ //通过端口名识别串口

CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

//打开端口并设置端口名字 serialPort和超时时间 2000ms

CommPort commPort=portIdentifier.open(portName,1000);

//进一步判断comm端口是否是串口 instanceof

if(commPort instanceof SerialPort)

{

System.out.println(“该COM端口是串口!”);

//进一步强制类型转换

serialPort=(SerialPort)commPort;

//设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够

//8位数据位

//1位停止位

//无奇偶校验

serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

//串口配制完成 log

System.out.println(“串口参数设置已完成,波特率为”+baudrate+“,数据位8bits,停止位1位,无奇偶校验”);

}

//不是串口

else

{

System.out.println(“该com端口不是串口,请检查设备!”);

//将com端口设置为null 默认是null不需要操作

}

}

catch (NoSuchPortException e)

{

e.printStackTrace();

}

catch (PortInUseException e)

{

e.printStackTrace();

}

catch (UnsupportedCommOperationException e)

{

e.printStackTrace();

}

return serialPort;

}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

以上代码就是返回一个对象,同时也返回了对象属性,因为对象在java里面是属于传值引用。对以上需要说明的是:在实验时需要连接串口才能让计算机检测到才能让程序工作,这里使用的是RS485转接线:

8edf9b24-b122-11ed-bfe3-dac502259ad0.png

3)通过以上两个步骤后基本对串口的设置也完成了,对于串口类型的确认例如:RS232/RS485/RS422等,可以作为进一步确认的条件。RS485可以在gnu.io中找到。

8f15a85e-b122-11ed-bfe3-dac502259ad0.png

接下来就是上位机与下位机之间的双向通信的功能实现了。该部分主要是利用java的输入输出流来实现。以下是主要代码:

/*

* 串口数据发送以及数据传输作为一个类

* 该类做主要实现对数据包的传输至下单板机

*/

class DataTransimit

{

/*

* 上位机往单板机通过串口发送数据

* 串口对象 seriesPort

* 数据帧:dataPackage

* 发送的标志:数据未发送成功抛出一个异常

*/

public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage)

{

OutputStream out=null;

try

{

out=serialPort.getOutputStream();

out.write(dataPackage);

out.flush();

} catch (IOException e)

{

e.printStackTrace();

}finally

{

//关闭输出流

if(out!=null)

{

try

{

out.close();

out=null;

System.out.println(“数据已发送完毕!”);

} catch (IOException e)

{

e.printStackTrace();

}

}

}

}

/*

* 上位机接收数据

* 串口对象seriesPort

* 接收数据buffer

* 返回一个byte数组

*/

public static byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort)

{

byte[] receiveDataPackage=null;

InputStream in=null;

try

{

in=serialPort.getInputStream();

//获取data buffer数据长度

int bufferLength=in.available();

while(bufferLength!=0)

{

receiveDataPackage=new byte[bufferLength];

in.read(receiveDataPackage);

bufferLength=in.available();

}

}

catch (IOException e)

{

e.printStackTrace();

}

return receiveDataPackage;

} 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970

通过以上关于Uart两个基本类实现对底层Uart的功能封装,其中一个类主要负责Uart串口自检和基本设置,另外一个类主要has数据传输的两个方法。接下来以一个实例说一说通过RS485串口通信将系统当前时间发送至单板机系统。

step 4:实现实时系统时间的数据包传输至下位机

这一步可以分为以下两个步骤:首先实现获取系统时间,将时间进行封装成帧;另外就是通过RS485串口将时间数据包发送至单板机系统进行解析。

1) 系统时间的获取

根据java面对对象设计思想,这里将有关系统时间的方法归为一类。

以下是获取当前系统时间代码:

public static String getCurrentDateTime()

{

//单例模式

Calendar calendar=Calendar.getInstance();

int year = calendar.get(Calendar.YEAR);//获取年份

int month=calendar.get(Calendar.MONTH);//获取月份

int day=calendar.get(Calendar.DATE);//获取日期

int minute=calendar.get(Calendar.MINUTE);//分

int hour=calendar.get(Calendar.HOUR);//小时

int second=calendar.get(Calendar.SECOND);//秒

String curerentDateTime = year + “ ” + (month + 1 )+ “ ” + day + “ ”+ (hour+12) + “ ” + minute + “ ” + second + “ ”;

timeCheckSum=year+(month+1)+day+(hour+12)+minute+second;

return curerentDateTime;

}1234567891011121314

java 提供了calender类,该类提供了一些与时间有关方法。至于Calendar.getInstance()使用单例模式获取一个Calendar实例对象,单例模式就是一个类在任何时候只允许有一个实例化对象。获取系统时间除了使用Calendar还可以使用Date类,通过创建对象也可以实现系统当前时间的获取。timeCheckSum作为时间数据的校验和发送至单板机作为自定义协议的一部分。

由于发送的数据包通常是以字节(byte)为单位进行发送和传输的,因此需要将int型的时间转换为byte使用byte[]进行存储,作为一个数据包发送。

/*

* 将以上时间字符串进行隔开用byte[]保存

*/

public static byte[] dateTimeBytesGet(String currenDateTime)

{

//对当前时间参数进行格式判断

//对格式进行判断

int rawDataSize=6;

byte[] dateTimeBytes=new byte[rawDataSize+1];

String[] currentDateTimeSplit=currenDateTime.split(“ ”);

if(currentDateTimeSplit.length==rawDataSize)

{

//时间数据格式正确

//eg 2016 12 23 22 18 26

//使用byte[]进行存储时需要 -128~+127

//对于年份使用两个byte存储

for(int dataIndex=0;dataIndex《rawDataSize;dataIndex++)

{

int dateTemp=Integer.parseInt(currentDateTimeSplit[dataIndex]);

if(dataIndex==0)

{

byte H8bits=(byte)((dateTemp)》》8);

byte L8bits=(byte)((dateTemp)&0xff);

dateTimeBytes[dataIndex]= H8bits;

dateTimeBytes[dataIndex+1]= L8bits;

}

dateTimeBytes[dataIndex+1]=(byte)dateTemp;

}

}else

{

System.out.println(“当前时间获取出现异常数据”);

System.exit(-1);

dateTimeBytes=null;

}

return dateTimeBytes;

}123456789101112131415161718192021222324252627282930313233343536

以上数据可以使用7个byte对时间数据进行存储,因为年份需要使用两个字节来存储,格式为高字节在前,低字节在后,之后依次存放。

将时间数据存放在byte[]数组以后接下来就是添加自己的协议部分了。该部分具有较大的随意性,因为该协议可以根据不同的风格有不同的形式。为了简单起见,只需要在时间数据byte[]之前添加head、CMD、时间数据长度length这三个字节进行补充,时间数据byte[]后面依次添加校验和高低字节以及tail指令即可。以上基本实现了一个简单的时间数据package。以下是本模块的代码:

/*

* 将数组封装成帧

* 每一个数据帧由以下几个部分组成

* 1)数据包头部 head 0X2F

* 2)数据包命令 CMD 0X5A

* 3)数据个数 length of data 7

* 4)校验和 H8/L8 byte of check sum(高字节在前 低字节在后)

* 5)数据结尾标志 tail OX30

* 6)可采用线程进行获取当前时间

*/

public static byte[] makeCurrentDateTimefromStringtoFramePackage(byte[] dateTimeBytes)

{

//在时间byte[]前后添加一些package校验信息

int dataLength=13;

byte[] terimalTimePackage=new byte[dataLength];

//装填信息

//时间数据包之前的信息

terimalTimePackage[0]=0x2F;

terimalTimePackage[1]=0X5A;

terimalTimePackage[2]=7;

//计算校验和

//转化为无符号进行校验

for(int dataIndex=0;dataIndex《dateTimeBytes.length;dataIndex++)

{

terimalTimePackage[dataIndex+3]=dateTimeBytes[dataIndex];

}

//将校验和分为高低字节

byte sumH8bits=(byte)((timeCheckSum)》》8);

byte sumL8bits=(byte)((timeCheckSum)&0xff);

terimalTimePackage[10]=sumH8bits;//高字节在前

terimalTimePackage[11]=sumL8bits;//低字节在后

//数据包结尾

terimalTimePackage[12]=0X30;

return terimalTimePackage;

}1234567891011121314151617181920212223242526272829303132333435

下面给出了将时间数据byte数组进行解析的debug代码,一方面是确定上位机本部分模块的程序可靠性,另外也可以直接移植到下位机对数据包的解析之中。在下位机解析过程中需要注意一点:因为在java中8大基本类型都是带符号,年份时间和时间校验和拆分为高低字节时,低字节是二进制无符号的,但是计算机却是按照有符号数(补码方式)进行读取,例如在2016年转换为二进制数为:11111100000,那么高字节为00000111,低字节为11100000。计算机读取为:高字节为7,低字节为-32。其实由两个byte真实还原的过程应为:7《《8+(低字节二进制数字)=7*256+224=2016,因此在debug解析时间数据包时需要将有符号数字转换为无符号数字。

/*

* 对时间格式进行解析并还原原来的时间格式

* 对数据进行还原

* 仅限于debug使用

*/

public static String dateTimeBytesfromTostring(byte[] currentDateTime)

{

String string=“”;

if(currentDateTime.length==7)

{

string=((currentDateTime[0]《《8)+bytetoUnsigendInt(currentDateTime[1]))+“ ”+currentDateTime[2]+“ ”+

currentDateTime[3]+“ ”+currentDateTime[4]+“ ”+currentDateTime[5]+“ ”+

currentDateTime[6];

}

return string;

}

/*

* 将byte转化为字符串

* 将有符号byte转化为无符号数字

* debug使用

*/

public static int bytetoUnsigendInt(byte aByte)

{

String s=String.valueOf(aByte);

//System.out.println(s);

int bytetoUnsigendInt=0;

for(int i=0;i《s.length();i++)

{

if(s.charAt(i)!=‘0’)

{

bytetoUnsigendInt+=1《《(7-i);

}

}

return bytetoUnsigendInt;

}12345678910111213141516171819202122232425262728293031323334353637

2)将最后的时间数据包通过RS485串口发送至下位机

结合前面的串口程序就可以使用串口发送程序了。在程序debug的前期可以在程序的关键位置输出日志就是打印log的方法可以提高程序调试的效率。以下是主类的测试代码:

//取出第一个COM端口进行测试

SerialPort serialPort=UARTParameterSetup.portParameterOpen(arraylist.get(0), 57600);

//退出程序 后续不需要监测 因为transimit一直需要保证连接状态

//System.exit(0);

DataTransimit.uartSendDatatoSerialPort(serialPort, dataFrame);

String currentDateTime=SystemDateTimeGet.getCurrentDateTime();

System.out.println(currentDateTime);

byte[] bytes=SystemDateTimeGet.dateTimeBytesGet(currentDateTime);

//System.out.println(Arrays.toString(bytes));

String str=SystemDateTimeGet.dateTimeBytesfromTostring(bytes);

System.out.println(str);

//System.out.println(SystemDateTimeGet.bytetoUnsigendInt((byte) -32));

byte[] terimalTimeByte=SystemDateTimeGet.makeCurrentDateTimefromStringtoFramePackage(bytes);

System.out.println(Arrays.toString(terimalTimeByte));

DataTransimit.uartSendDatatoSerialPort(serialPort, terimalTimeByte);123456789101112131415

以下是测试结果:

当没有串口设备接入计算机时控制台打印一条信息:

没有找到可用的串口端口,请check设备!

12

当RS485设备接入计算机时,控制台打印消息如下:

8f35a974-b122-11ed-bfe3-dac502259ad0.png

通过以上几个步骤基本实现了上位机与下位机串口通信的功能,接下来还可以对程序进行改进:

1)添加界面,可以类比串口助手界面根据自身需要设计独具风格的人机交互界面。

2) 在程序中添加线程,在以上程序中对于系统时间的获取可以通过线程的方式进行获取,这样上位机就可以一直往下位机发送数据包,而不是仅仅发一次。

3)对于上位机数据接收,除了以上最基本的接收功能外,还可以使用JDBC与mysql等数据进行存储,并绘画数据曲线实现特性分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/170462.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能AI 全栈体系(十三)

第二章 计算机是如何学会下棋的 人类棋手在下棋时,会根据自己的经验只考虑在当前棋局下最重要的几个可能的走法,但是计算机没有这种经验。 知识太复杂了,需要考虑很多具体的情况,一旦知识总结的不到位,可能就会出现大…

【寒武纪(14)】硬件系统由标量指令、向量指令、张量指令、访存指令构成

我们在文档《Cambricon-BANG-C-Developer-Guide-EN-v4.5.1》的build-in function 发现,存在三种计算:矩阵乘法、标量类型、向量。 查阅《Cambricon-BANG-C-CProgramming-Guide-CN-v1.5.0.pdf》可知,硬件系统由标量指令、向量指令、张量指令、…

提升工作效率,使用AnyTXT Searcher实现远程办公速查公司电脑文件——“cpolar内网穿透”

文章目录 前言1. AnyTXT Searcher1.1 下载安装AnyTXT Searcher 2. 下载安装注册cpolar3. AnyTXT Searcher设置和操作3.1 AnyTXT结合cpolar—公网访问搜索神器3.2 公网访问测试 4. 固定连接公网地址 前言 你是否遇到过这种情况,异地办公或者不在公司,想找…

STM32 Flash

FLASH简介 Flash是常用的用于存储数据的半导体器件,它具有容量大,可重复擦写,按“扇区/块”擦除、掉电后数据可继续保存的特性。 常见的FLASH主要有NOR FLASH和NAND FLASH两种类型。NOR和NAND是两种数字门电路,可以简单地认为FL…

计算机毕业设计python企业员工人事管理系统vue

管理员: 1.员工资料管理:查看员工列表,添加职工,修改信息(搜索员工使用模糊查询) 2.部门管理:查看部门列表,修改信息,添加新部门 3.职工考勤管理:添加&#x…

你知道如何实现游戏中的透视效果吗?

引言 游戏中的透视效果可以合理运用CtrlCV实现。 不知道大家有没有这样一段经历:在做Cocos项目时需要一些特定的Shader去做一些特定的效果,例如透视、高光、滤镜等等,想自己写吧,不怎么会啊,网上又找不到&#xff0c…

EtherCAT从站EEPROM分类附加信息详解:RXPDO(输入过程数据对象)

0 工具准备 1.EtherCAT从站EEPROM数据(本文使用DE3E-556步进电机驱动器)1 分类附加信息——RXPDO(输入过程数据对象) 1.1 分类附加信息规范 在EEPROM字64开始的区域存储的是分类附加信息,这里存储了包括设备信息、SM配置、FMMU配置在内的诸多信息。每个信息在一段连续的…

会议剪影 | 思腾合力受邀出席第四届长三角文博会并作主题演讲

以“担当新使命:长三角文化产业的力量”为主题的「第四届长三角国际文化产业博览会」于2023年11月16日-19日在国家会展中心(上海)成功举办。思腾合力作为行业领先的人工智能基础架构解决方案商出席本次盛会。 此次展会的面积首次超过10万平米&#xff0c…

BUUCTF [BJDCTF2020]一叶障目 1

BUUCTF:https://buuoj.cn/challenges 题目描述: 得到的 flag 请包上 flag{} 提交。来源:https://github.com/BjdsecCA/BJDCTF2020 密文: 下载附件,解压得到一张.png图片。 解题思路: 1、在010 Editor中打开&#x…

【六祎 - Dubbo】Dubbo 应用 XML配置分析;Dubbo 配置篇;Dubbo参考手册

Dubbo 应用 XML配置分析 演示案例:提供者代码xml配置消费者代码xml配置 参考地址: 手动配置 https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/config/overview/ 配置说明 xml配置 https://cn.dubbo.apache.org/zh-cn/ov…

Haclon简介及数据类型

Haclon简介 HALCON是由德国MVtec公司开发的机器视觉算法包,它由一千多个各自独立的函数(算子)构成,其中除了包含各类滤波、色彩以及几何、数学转换、形态学计算分析、图像校正,目标分类辨识、形状搜寻等基本的图像处理…

Linux常用命令——builtin命令

在线Linux命令查询工具 builtin 执行shell内部命令 补充说明 builtin命令用于执行指定的shell内部命令,并返回内部命令的返回值。builtin命令在使用时,将不能够再使用Linux中的外部命令。当系统中定义了与shell内部命令相同的函数时,使用…

基于Python实现用于实时监控和分析 MySQL 服务器的性能指标和相关信息工具源码

MySQL命令行监控工具 - mysqlstat 介绍 mysqlstat 是一个命令行工具,用于实时监控和分析 MySQL 服务器的性能指标和相关信息。 它可以帮助 DBA(数据库管理员)和开发人员定位和解决数据库性能问题。 以下是 mysqlstat 工具的主要功能&#…

007 OpenCV霍夫变换

目录 一、环境 二、霍夫变换原理 三、代码 一、环境 本文使用环境为: Windows10Python 3.9.17opencv-python 4.8.0.74 二、霍夫变换原理 OpenCV中的霍夫变换是一种用于检测图像中直线和圆的算法。它基于图像中像素的分布情况,通过统计像素点之间的…

纯CSS实现炫酷文本时钟

如图所示这是一个纯本文时钟效果,和传统的时钟不一样,没有表盘,也没有完整到每一分钟的数字表示当前时刻。 在这个时钟中,当前时间通过文本显示,显示的文本时间误差为+/- 4分钟,以明亮的颜色突出显示当前时间,而其余字母则较暗。 实际上这是一个实现很复杂的时钟,因为…

python刷题笔记1(42例题)

1. split()函数 str.split([sep [, maxsplit]]) 分割字符串,返回一个数组 2. 判断子串 # 判断子串是否在主串里面,是则输出“Yes”,否则输出“No” str1 input("子串:") str2 input("主串:") if str1 in s…

Python如何将项目直接打包为一键整合包

目录 一、准备项目 二、创建打包文件 三、创建安装脚本 四、执行安装 五、测试安装 六、常见问题与解决方案 总结 Python项目打包成一键整合包是一个比较复杂的任务,需要考虑到项目的各个方面,包括依赖项、配置文件、静态文件、数据库等等。下面是…

Flask Web开发:数据库

目录 在虚拟环境中安装Flask-SQLAlchemy: 一、配置 数据库配置示例: 二、定义模型 Role 和 User 模型代码: (1)常用的 SQLAlchemy 列类型:​编辑 (2)常用的 SQLAlchemy 列选项…

基于springboot实现冬奥会科普平台系统【项目源码+论文说明】计算机毕业设计

基于SpringBoot实现冬奥会科普平台系统演示 摘要 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理平台应运而生&…