[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-14 SPI MASET发送程序设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1

操作系统:WIN10 64bit

硬件平台:适用安路(Anlogic)FPGA

实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

目录

1 概述

2 程序设计

2.1 系统框图

2.2 驱动源码

3 RTL仿真

3.1 仿真激励文件

3.2 SPI发送驱动代码仿真CPHA=0 CPOL=0

3.3 SPI发送驱动代码仿真CPHA=1 CPOL=0

3.4 SPI发送驱动代码仿真CPHA=0 CPOL=1

3.5 SPI发送驱动代码仿真CPHA=1 CPOL=1


1 概述

SPI的发送器驱动程序主要围绕SPI_MOSI以及SPI_SCLK来设计。通过前面的SPI协议学习,我们这里设计的SPI驱动程序需要支持CPHA=0 CPOL=0; CPHA=1 CPOL=0; CPHA=0 CPOL=1; CPHA=1 CPOL=1四种情况。CPHA用于控制SPI接收器的采样时钟位置,CPOL用于设置SPI_SCLK的初始电平是高电平还是低电平。

程序设计

2.1 系统框图

本次实验设计一个SPI Master(SPI_MOSI)发送驱动,包含SPI的四种工作模式。SPI Master(SPI_MOSI)共有两个模块,分别为顶层模块spi_master_tx和发送驱动模块ui_mspi_tx。我们米联客设计的驱动接口,一般将接口驱动程序和驱动控制程序分开编写,这样的好处可以让代码层次更加清晰,实用维护更加方便。

SPI Master发送驱动器模块:

根据上一节课关于SPI通信原理的学习,我们知道要开始SPI通信,主机必须发送时钟信号,系统时钟一般运行于较高速度,而SPI的SCLK需要基于系统时钟分频后产生,所以首先需要设计一个分频器,并设置CPOL信号控制SCLK的空闲状态。并行数据需要通过MOSI总线发送出去,因此需要一个并串移位模块,将并行数据转成串行数据一位一位发送出去,并设置CPHA信号控制数据的采样时刻。

为了方便SPI Master主控制器可以方便使用该驱动程序,设计数据控制器模块,用来保存要发送的数据。使用I_spi_tx_req以及O_spi_busy用于信号的握手,在以后米联客的代码中,接口之间的握手也会采用类似信号和时序。用户程序通过设置I_spi_tx_req为高,请求发送驱动器发送数据;设置O_spi_busy为1,表示发送总线正忙,这时用户程序需要等待非忙的时候,请求发送数据。

根据以上分析,发送驱动程序包含基本的时钟分频器、数据控制器、并串移位模块、CPOL控制、CPHA控制。

时钟分频器模块

系统时钟一般运行于较高速度,而SPI的SCLK需要基于系统时钟分频后产生,所以首先需要设计一个分频器,用于对SCLK分频,当spi_en拉高代表启动传输,clk_div开始计数,计满清0。

localparam [9:0] SPI_DIV     = CLK_DIV;                             //第二时钟边沿计数器
localparam [9:0] SPI_DIV1    = SPI_DIV/2;                           //第一时钟边沿计数器always@(posedge I_clk)begin                                          //时钟分频器if(spi_en == 1'b0)clk_div <= 10'd0;else if(clk_div < SPI_DIV)clk_div <= clk_div + 1'b1;else clk_div <= 0;
end

SCLK模块:

SCLK可以支持CPOL=0(空闲状态输出低电平)和CPOL=1(空闲状态输出高电平)

首先我们可以设置一个内部参考时钟,这个时钟默认的时钟极性为CPOL=0的情况,当我们设置CPOL=0或者CPOL=1的时候我们只要对时钟采取不取反或者取反操作,最后赋值给O_spi_sclk。

内部的SCLK通过clk_en1和clk_en2的触发时刻来实现电平的输出和切换。

assign      clk_en1     = (clk_div == SPI_DIV1);               //第一内部时钟边沿使能
assign      clk_en2     = (clk_div == SPI_DIV);                 //第二内部时钟边沿使能
assign      O_spi_sclk  = (CPOL == 1'b1) ? ~spi_clk : spi_clk;//设置SPI时钟的初始电平always@(posedge I_clk)begin                                     //生成spi内部时钟if(spi_en == 1'b0)spi_clk <= 1'b0;else if(clk_en2)spi_clk <= 1'b0;                                 //第二时钟边沿else if(clk_en1&&(tx_cnt<4'd8))                     //第一时钟边沿spi_clk <= 1'b1;elsespi_clk <= spi_clk;
end

数据控制器设计

数据控制器是SPI-Master发送驱动器设计中最关键的部分,数据控制器包括驱动控制接口,也包含了SPI数据部分的并串移位模块。

当SPI的控制器部分发送了I_spi_tx_req为高电平后,下一个系统时钟周期数据会被寄存到spi_tx_data_r并且设置spi_en为高电平,之后时钟分频模块、SCLK模块等开始工作。同时设置spi_busy信号为高电平,通知SPI控制器SPI驱动器已经处于工作状态。

assign      clk_end     = (clk_div == SPI_DIV1)&&(tx_cnt==4'd8);
assign      O_spi_mosi  = spi_tx_data_r[7];
assign      O_spi_busy  = spi_en;
……
……//spi发送模块
always@(posedge I_clk)begin                                           //spi发送模块if(I_rstn == 1'b0 || clk_end)beginspi_en <= 1'b0;spi_tx_data_r <= 8'h00;endelse if(I_spi_tx_req&&(spi_en == 1'b0)) begin                    //启用传输spi_en <= 1'b1;spi_tx_data_r <= I_spi_tx_data;endelse if(spi_en)beginspi_tx_data_r[7:0] <= (spi_strobe) ? {spi_tx_data_r[6:0],1'b1} : spi_tx_data_r;end
end  

移位数据的更新通过spi_stroble控制,spi_stroble根据CPHA的设置决定是clk_en1更新数据还是clk_en2更新数据。clk_en1和SCLK的第1个跳变沿同步,clk_en2和SCLK的第2个跳变沿同步。

//当CPHA=0时,数据的第一个SCLK转换边缘被采样,因此数据更新在第二个转换边缘上
//当CPHA=1时,数据的第二个SCLK转换边缘被采样,因此数据更新在第一个转换边缘上assign      spi_strobe  = CPHA ? clk_en1&spi_strobe_en : clk_en2&spi_strobe_en ;always@(posedge I_clk)begin  if(I_rstn == 1'b0)spi_strobe_en <= 1'b0;else if(tx_cnt < 4'd8)beginif(clk_en1)spi_strobe_en <= 1'b1;    elsespi_strobe_en <= spi_strobe_en;end else spi_strobe_en <= 1'b0;        
endalways@(posedge I_clk)begin  if((I_rstn == 1'b0)||(spi_en == 1'b0))tx_cnt <= 4'd0;else if(clk_en1)tx_cnt <= tx_cnt + 1'b1;      
end

SPI Master发送控制器设计

发送控制器设计核心部分在于状态机的设计。M_S状态机只有2个状态,M_S==0状态等待SPI-Master驱动器非忙的情况下,发送数据发送请求信号,并且在M_S==1状态等待数据确认进入忙状态后,再次回到状态0等待空闲,如果总线空闲发送下一个测试数据。

在SPI Master发送控制器的设计中,核心状态机部分首先设置spi_tx_req=1启动一次SPI传输(状态0),发送一次数据,下一个待发送数据计数加1并存储在spi_tx_data,开始传输后进入状态1,spi_busy为高电平时代表正在传输,设置spi_tx_req=0,并且等待spi_busy变为低电平,之后可以进行下一次的数据传输。

2.2 驱动源码

`timescale 1ns / 1ps                                            //定义仿真时间刻度/精度module ui_mspi_tx#
(
parameter CLK_DIV = 100,
parameter CPOL = 1'b0,                                            //时钟极性参数设置
parameter CPHA = 1'b0                                             //时钟相位参数设置
)
(
input       I_clk,                                                 //系统时钟输入
input       I_rstn,                                                //系统复位输入
output      O_spi_mosi,                                            //发送SPI数据
output      O_spi_sclk,                                            //发送SPI时钟
input       I_spi_tx_req,                                         //发送数据请求
input [7:0] I_spi_tx_data,                                        //发送数据  
output      O_spi_busy                                            //发送状态忙,代表正在发送数据 
);localparam [9:0] SPI_DIV     = CLK_DIV;                         //第二时钟边沿计数器
localparam [9:0] SPI_DIV1    = SPI_DIV/2;                       //第一时钟边沿计数器reg [9:0]   clk_div  = 10'd0;   
reg         spi_en   = 1'b0;
reg         spi_clk  = 1'b0;
reg [3:0]   tx_cnt   = 4'd0;
reg [7:0]   spi_tx_data_r=8'd0;
wire        clk_end;
wire        clk_en1;                                           //第一内部时钟边沿使能
wire        clk_en2;                                           //第二内部时钟边沿使能
reg         spi_strobe_en;
wire        spi_strobe;                                        //CPHA=0数据在第一时钟边沿上传输,CPHA=1数据在第二时钟边沿上发送assign      clk_en1     = (clk_div == SPI_DIV1);//第一内部时钟边沿使能
assign      clk_en2     = (clk_div == SPI_DIV);//第二内部时钟边沿使能
assign      clk_end     = (clk_div == SPI_DIV1)&&(tx_cnt==4'd8);
//计数器发送第一个内部时钟0到7次,当计数达到最后8时,不发送时钟//当CPHA=0时,数据的第一个SCLK转换边缘被采样,因此数据更新在第二个转换边缘上
//当CPHA=1时,数据的第二个SCLK转换边缘被采样,因此数据更新在第一个转换边缘上
assign      spi_strobe  = CPHA ? clk_en1&spi_strobe_en : clk_en2&spi_strobe_en ;
assign      O_spi_sclk  = (CPOL == 1'b1) ? ~spi_clk : spi_clk;//设置SPI时钟的初始电平
assign      O_spi_mosi  = spi_tx_data_r[7];
assign      O_spi_busy  = spi_en;always@(posedge I_clk)begin                                   //时钟分频器if(spi_en == 1'b0)clk_div <= 10'd0;else if(clk_div < SPI_DIV)clk_div <= clk_div + 1'b1;else clk_div <= 0;
end
always@(posedge I_clk)begin                                   //生成spi内部时钟if(spi_en == 1'b0)spi_clk <= 1'b0;else if(clk_en2) spi_clk <= 1'b0;                                   //第二时钟边沿else if(clk_en1&&(tx_cnt<4'd8))                       //第一时钟边沿spi_clk <= 1'b1; elsespi_clk <= spi_clk;
endalways@(posedge I_clk)begin  if(I_rstn == 1'b0) spi_strobe_en <= 1'b0;else if(tx_cnt < 4'd8)beginif(clk_en1) spi_strobe_en <= 1'b1;    end else spi_strobe_en <= 1'b0;         
endalways@(posedge I_clk)begin  if((I_rstn == 1'b0)||(spi_en == 1'b0)) tx_cnt <= 4'd0;else if(clk_en1) tx_cnt <= tx_cnt + 1'b1;      
endalways@(posedge I_clk)begin                                           //spi发送模块if(I_rstn == 1'b0 || clk_end)beginspi_en <= 1'b0;spi_tx_data_r <= 8'h00;endelse if(I_spi_tx_req&&(spi_en == 1'b0)) begin                    //启用传输spi_en <= 1'b1;spi_tx_data_r <= I_spi_tx_data;endelse if(spi_en)beginspi_tx_data_r[7:0] <= (spi_strobe) ? {spi_tx_data_r[6:0],1'b1} : spi_tx_data_r;endend   endmodule

SPI Master发送控制器源码

SPI Master的发送控制器根据不同的实际应用需要一次或者多出把一个或者多个数据发送出去,在本实验中,演示了发送连续的加计数器数据的方法。

`timescale 1ns / 1psmodule spi_master_tx#
(
parameter CLK_DIV = 100        
)
(
input  I_clk,                                          //输入时钟
input  I_rstn,                                         //系统复位
output O_spi_sclk,                                     //SPI发送时钟
output O_spi_mosi                                      //SPI发送数据
);wire        spi_busy;                                     //SPI忙信号
reg         spi_tx_req;                                   //SPI发送req信号,有发送需求时拉高
reg [7:0]   spi_tx_data;                                  //待发送数据存储
reg [1:0]   M_S;                                           //状态机//spi send state machine
always @(posedge I_clk) beginif(!I_rstn) begin                                      //拉低复位spi_tx_req  <= 1'b0;spi_tx_data <= 8'd0;M_S <= 2'd0;endelse begincase(M_S)0:if(!spi_busy)begin                            //总线不忙启动传输spi_tx_req  <= 1'b1;                         //req信号拉高,开始传输spi_tx_data <= spi_tx_data + 1'b1;          //测试数据M_S <= 2'd1;end1:if(spi_busy)begin                             //如果spi总线忙,清除spi_tx_reqspi_tx_req  <= 1'b0;M_S <= 2'd0;enddefault:M_S <= 2'd0;endcaseend
end   //例化SPI Master发送驱动器
ui_mspi_tx#
(
.CLK_DIV(CLK_DIV),
.CPOL(1'b0),                                  //CPOL参数设置,可调整
.CPHA(1'b0)                                   //CPHA参数设置,可调整
)
ui_mspi_tx_inst(
.I_clk(I_clk),                              //系统时钟输入
.I_rstn(I_rstn),                            //系统复位输入
.O_spi_mosi(O_spi_mosi),                   //SPI发送数据串行总线
.O_spi_sclk(O_spi_sclk),                   //SPI发送时钟总线
.I_spi_tx_req(spi_tx_req),                  //SPI发送(写)数据请求
.I_spi_tx_data(spi_tx_data),                //SPI发送(写)数据
.O_spi_busy(spi_busy)                        //SPI发送驱动器忙);
endmodule

M_S状态机只有2个状态,M_S==0状态等待SPI-Master驱动器非忙的情况下,发送数据发送请求信号,并且在M_S==1状态等待数据确认进入忙状态后,再次回到状态0等待空闲,如果总线空闲发送下一个测试数据。

3 RTL仿真

3.1 仿真激励文件

Modelsim仿真的创建过程不再重复,如有不清楚的请看前面实验

本实验以仿真的方式演示,仿真激励信号提供一个系统时钟即可

`timescale 1ns / 1ps
module sim_top_tb();
localparam      SYS_TIME   =  'd20;//时钟周期,以ns为单位
reg             I_sysclk;               //系统时钟
reg rstn_i;  
wire spi_sclk_o;
wire spi_mosi_o;spi_master_tx#
(
.CLK_DIV(100)                                    //设置时钟参数,可以减少仿真时间
)
spi_master_tx_inst(
.I_clk(I_sysclk),
.I_rstn(rstn_i),
.O_spi_sclk(spi_sclk_o),
.O_spi_mosi(spi_mosi_o)
);initial beginI_sysclk  = 1'b0;                              //设置时钟基础值rstn_i = 1'b0;                              //低电平复位#100;rstn_i = 1'b1;                             //复位释放#2000000 $finish;
endalways #(SYS_TIME/2) I_sysclk = ~I_sysclk;     //产生主时钟endmodule

以下启动modelsim仿真

3.2 SPI发送驱动代码仿真CPHA=0 CPOL=0

如下图所示,当CPHA=0 CPOL=0,代表SPI的SCLK默认是低电平,SPI接收器在SCLK第1个时钟沿采样。SPI发送驱动器数据在SCLK的第2个时钟沿更新,确保SPI下一个SCLK的第1个时钟沿数据有足够的建立和保持时间。下图以发送8’h02为例。

3.3 SPI发送驱动代码仿真CPHA=1 CPOL=0

如下图所示,当CPHA=1 CPOL=0,代表SPI的SCLK默认是低电平,SPI接收器在SCLK第2个时钟沿采样。SPI发送驱动器数据在下一个SCLK的第1个时钟沿更新,确保SPI下一个SCLK的第2个时钟沿数据有足够的建立和保持时间。下图以发送8’h02为例。

3.4 SPI发送驱动代码仿真CPHA=0 CPOL=1

和CPHA=0 CPOL=0这种设置相比,时钟SCLK取反

3.5 SPI发送驱动代码仿真CPHA=1 CPOL=1

和CPHA=1 CPOL=0这种设置相比,时钟SCLK取反

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库管理-第220期 Oracle的高可用-03(20240715)

数据库管理220期 2024-07-15 数据库管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09;1 AC/TAC2 配置Service3 用户权限4 端口开放总结 数据库管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文…

51单片机10(蜂鸣器介绍)

一、蜂鸣器介绍&#xff1a; 1、蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电&#xff0c;广泛应用于电子产品中作为发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器。 &#xff08;1&#xff09;压电式蜂鸣器&#xff0c;它主要由多谐的一个增胀器…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(八)-通过无人机进行无线接入

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

电脑出现错误——找不到msvcp140.dll无法继续执行代码,有效解决错误dll文件

msvcp140.dll是一个属于 Microsoft Visual C Redistributable for Visual Studio 2015 的 DLL 文件。这个文件是许多Windows应用程序&#xff08;尤其是使用 C 开发的程序&#xff09;所必需的&#xff0c;因为它包含了标准 C 库的函数实现&#xff0c;用于处理数学运算、数据转…

使用shell脚本打印99乘法表

一、简介 前一段时间在旧电脑上安装 antiX 23.1 操作系统&#xff0c;遇到一些问题需要使用shell脚本解决问题&#xff0c;所以专门学习了几天&#xff0c;打印99乘法表是其中的一个练习作业。 二、学习Linux可行的几种方式 虚拟机安装Linux进行学习直接双系统安装在实体电脑…

Ubuntu新系统的使用

1.安装显卡驱动 直接到软件与更新里面&#xff0c;就是一个A字图标的那个软件打开&#xff0c;到附加驱动里选择。要选择“server driver”的&#xff0c;选择后确认即可。 然后输入&#xff1a;nvidia-sim查看 别的方法太复杂&#xff0c;这个方法我亲测了两台电脑&#xff…

MWA(Modern Web App)初学那些事-2-Basic HTML CSS

初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS 目录 初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS前言一、本节学习目标二、HTML基础内容2.1关键元素2.4 Scripts 三、CSS 基础内容3.1 级联样式表-用于设置网页样式和布局3.2 CSS规则语…

springcloud使用微服务的搭建

微服务的搭建 1.配置对应信息 Springboot 、springcloud、springcloud alibaba对应关系 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 2.pom.xml的配置 2.1 总项目pom.xml引入依赖 <parent><groupId>org.sprin…

阿里通义音频生成大模型 FunAudioLLM 开源

简介 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的进步极大地改变了人类与机器的互动方式&#xff0c;特别是在语音处理领域。阿里巴巴通义实验室最近开源了一个名为FunAudioLLM的语音大模型项目&#xff0c;旨在促进人类与大型语言模型&#xff08;LLMs&…

跳妹儿学编程之ScratchJr(9):程序控制积木篇—短跑比赛

跳妹儿学编程之ScratchJr(7)&#xff1a;动作积木篇—爸爸去散步 跳妹儿学编程之ScratchJr(8)&#xff1a;外观积木篇—捉迷藏 跳妹儿学编程之ScratchJr(9)&#xff1a;程序控制积木篇—短跑比赛 引言 在之前的一篇文章中&#xff0c;我们了解了ScratchJr的动作积木和外观积…

阿里云ECS服务器安装jdk并运行jar包,访问成功详解

安装 OpenJDK 8 使用 yum 包管理器安装 OpenJDK 8 sudo yum install -y java-1.8.0-openjdk-devel 验证安装 安装完成后&#xff0c;验证 JDK 是否安装成功&#xff1a; java -version设置 JAVA_HOME 环境变量&#xff1a; 为了确保系统中的其他应用程序可以找到 JDK&…

星火智能体创建指南,星火大模型智能体创建教程

一、什么是星火助手 星火助手是基于讯飞星火认知大模型&#xff0c;面向用户使用场景&#xff0c;打造的高效生产力工具。通过设置结构化的指令模板&#xff0c;用户即可完成助手功能设定&#xff0c;每个助手在对话的模式下能够快速满足场景需求。同时支持助手模板、数据集、…

单链表算法 - 链表的中间节点

. - 力扣&#xff08;LeetCode&#xff09;. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/middle-of-the-linked-list/description/ 思路1: 思路2: 代码: /*** …

【接口自动化_06课_Pytest+Excel+Allure完整框架集成】

一、logging在接口自动化里的应用 1、设置日志的配置&#xff0c;并收集日志文件 日志的设置需要在pytest.ini文件里设置。这个里面尽量不要有中文 2、debug日志的打印 pytest.ini文件的开关一定得是true才能在控制台打印日志 import allure import pytest from P06_PytestFr…

CUDA cuDNN和pytorch(GPU版)的完整安装教程

​ * 说明: 本教程使用wsl-ubuntu20.04, 其他发行版linux的命令可能有所区别. *实测机型: i5-13500HX | RTX 4060 Laptop 一、下载CUDA12.X版本 这里以下载CUDA12.2为例。 前往cuda-12.2下载页, 按照如图方式选择合适的选项&#xff1a; 按照官方给出的命令&#xff0c; 在b…

Trie树的应用

Trie树的应用 题目解题思路代码 题目 维护一个字符串集合&#xff0c;支持两种操作&#xff1a; I x 向集合中插入一个字符串 x x x&#xff1b;Q x 询问一个字符串在集合中出现了多少次。 共有 N N N 个操作&#xff0c;所有输入的字符串总长度不超过 1 0 5 10^5 105&am…

移动应用性能关注分析哪些指标

移动应用常见性能指标 要对应用开展性能测试&#xff0c;首先需要了解需要重点关注哪些指标&#xff1f;指标的参考范围大致是多少&#xff1f;可采用哪些工具收集这些指标&#xff1f;如何收集&#xff1f;如果指标有异常&#xff0c;大致有哪些high level的优化思路。这篇博客…

YoloV8改进策略:卷积篇|Kan行天下之GRAM,KAN遇见Gram多项式V2版本

GRAM(GRAM可能是一个新提出的模型或方法的缩写,这里我们根据上下文进行解释)受到诸如TorchKAN和ChebyKAN等Kolmogorov-Arnold网络(KAN)替代方案的启发。GRAM引入了一种简化的KAN模型,但同时利用了Gram多项式变换的简单性。它与其他替代方案的不同之处在于其独特的离散性特…

【07】分布式事务解决方案

1、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中&#xff0c;一个事务由一组SQL语句组成。事务应该具有ACID四个特性&#xff1a;原子性、一致性、隔离性、持久性。任何事务机制在实现时&#xff0c;都应该考虑事务…

J025_斗地主游戏案例开发(简版)

一、需求描述 完成斗地主游戏的案例开发。 业务&#xff1a;总共有54张牌&#xff1b; 点数&#xff1a;3、4、5、6、7、8、9、10、J、Q、K、A、2 花色&#xff1a;黑桃、红桃、方片、梅花 大小王&#xff1a;大王、小王 点数分别要组合4种花色&#xff0c;大小王各一张。…