Linux学习第57天:Linux PWM驱动实验
Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长
本章的思维导图如下:
一、PWM驱动简析
1、设备树下的PWM控制节点
8 路 PWM 都属于 I.MX6ULL 的 AIPS-1 域,分为了两部分, PWM1~PWM4 在一起, PWM5~PWM8 在一起。
本章实验我们使用GPIO1_IO04 这个引脚来完成 PWM 实验,而 GPIO1_IO04 就是 PWM3 的输出引脚。
1 pwm3: pwm@02088000 {
2 compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";/* compatible 属性值有两个“fsl,imx6ul-pwm”和“fsl,imx27-pwm”,所以在整个 Linux
源码里面搜索这两个字符窜即可找到 I.MX6ULL 的 PWM 驱动文件,这个文件就是
drivers/pwm/pwm-imx.c。*/
3 reg = <0x02088000 0x4000>;
4 interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
5 clocks = <&clks IMX6UL_CLK_PWM3>,
6 <&clks IMX6UL_CLK_PWM3>;
7 clock-names = "ipg", "per";
8 #pwm-cells = <2>;
9 };
2、PWM子系统
框架
PWM子系统的核心是 pwm_chip 结构体,定义在文件 include/linux/pwm.h 中,定义如下:
1 struct pwm_chip {
2 struct device *dev;
3 struct list_head list;
4 const struct pwm_ops *ops;/*第 4 行, pwm_ops 结构体就是 PWM 外设的各种操作函数集合,编写 PWM 外设驱动的时
候需要开发人员实现。 */
5 int base;
6 unsigned int npwm;
7 struct pwm_device *pwms;
8 struct pwm_device * (*of_xlate)(struct pwm_chip *pc,
9 const struct of_phandle_args *args);
10 unsigned int of_pwm_n_cells;
11 bool can_sleep;
12 };
pwm_ops 结构体也定义在 pwm.h 头文件中,定义如下:
/*
pwm_ops 中的这些函数不一定全部实现,但是像 config、 enable 和 disable 这些肯定是需要
实现的,否则的话打开/关闭 PWM,设置 PWM 的占空比这些就没操作了。
*/1 struct pwm_ops {
2 int (*request)(struct pwm_chip *chip, //请求 PWM
3 struct pwm_device *pwm);
4 void (*free)(struct pwm_chip *chip, //释放 PWM
5 struct pwm_device *pwm);
6 int (*config)(struct pwm_chip *chip, //配置 PWM 周期和占空比
7 struct pwm_device *pwm,
8 int duty_ns, int period_ns);
9 int (*set_polarity)(struct pwm_chip *chip, //设置 PWM 极性
10 struct pwm_device *pwm,
11 enum pwm_polarity polarity);
12 int (*enable)(struct pwm_chip *chip, //使能 PWM
13 struct pwm_device *pwm);
14 void (*disable)(struct pwm_chip *chip, //关闭 PWM
15 struct pwm_device *pwm);
16 struct module *owner;
17 };
PWM 子系统驱动的核心就是初始化 pwm_chip 结构体各成员变量,然后向内核注册初始化完成以后的 pwm_chip。
int pwmchip_add(struct pwm_chip *chip)/*
chip:要向内核注册的 pwm_chip。
返回值: 0 成功;负数 失败。
*/
卸载 PWM 驱动的时候需要将前面注册的 pwm_chip 从内核移除掉,这里要用到pwmchip_remove 函数,函数原型如下:
int pwmchip_remove(struct pwm_chip *chip)
/*
chip:要移除的 pwm_chip。
返回值: 0 成功;负数 失败。
*/
3、PWM驱动源码分析
1 static const struct of_device_id imx_pwm_dt_ids[] = {
2 { .compatible = "fsl,imx1-pwm", .data = &imx_pwm_data_v1, },
3 { .compatible = "fsl,imx27-pwm", .data = &imx_pwm_data_v2, },
/*
第 3 行,当设备树 PWM 节点的 compatible 属性值为“fsl,imx27-pwm”的话就会匹配此驱
动
后面的.data 为 imx_pwm_data_v2,这是一个 imx_pwm_data 类型的结构体变量,内容
如下:
1 static struct imx_pwm_data imx_pwm_data_v2 = {
2 .config = imx_pwm_config_v2,
3 .set_enable = imx_pwm_set_enable_v2,
4 };imx_pwm_config_v2 函数就是最终操作 I.MX6ULL 的 PWM 外设寄存器,进行实际配置的
函数。 imx_pwm_set_enable_v2 就是具体使能 PWM 的函数。
*/
4 { /* sentinel */ }
5 };
6 7
......
8 9
static struct platform_driver imx_pwm_driver = {
10 .driver = {
11 .name = "imx-pwm",
12 .of_match_table = imx_pwm_dt_ids,
13 },
14 .probe = imx_pwm_probe,/*第 14 行,当设备树节点和驱动匹配以后 imx_pwm_probe 函数就会执行。*/
15 .remove = imx_pwm_remove,
16 };
17
18 module_platform_driver(imx_pwm_driver);
imx_pwm_probe 函数如下(有缩减):
1 static int imx_pwm_probe(struct platform_device *pdev)
2 {
3 const struct of_device_id *of_id =
4 of_match_device(imx_pwm_dt_ids, &pdev->dev);
5 const struct imx_pwm_data *data;
6 struct imx_chip *imx;
7 struct resource *r;
8 int ret = 0;
9
10 if (!of_id)
11 return -ENODEV;
12
13 imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL);
/*
第 13 行, imx 是一个 imx_chip 类型的结构体指针变量,这里为其申请内存。 imx_chip 结
构体有个重要的成员变量 chip, chip 是 pwm_chip 类型的。所以这一行就引出了 PWM 子系统
核心部件 pwm_chip,稍后的重点就是初始化 chip。
*/
14 if (imx == NULL)
15 return -ENOMEM;
......
/*
第 31~35 行,初始化 imx 的 chip 成员变量,也就是初始化 pwm_chip!
*/
31 imx->chip.ops = &imx_pwm_ops;
32 imx->chip.dev = &pdev->dev;
33 imx->chip.base = -1;
34 imx->chip.npwm = 1;
35 imx->chip.can_sleep = true;
36
/*37 和 38 行,从设备树中获取 PWM 节点中关于 PWM 控
制器的地址信息,然后再进行内存映射,这样我们就得到了 PWM 控制器的基地址。
*/
37 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
38 imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
39 if (IS_ERR(imx->mmio_base))
40 return PTR_ERR(imx->mmio_base);
41
42 data = of_id->data;/*第 43 和 44 行,这两行设置 imx 的 config 和 set_enable 这两个成员变量为 data->config 和
data->set_enable,imx_pwm_enable、 imx_pwm_disable 和 imx_pwm_config 这三个函数最终调用就是
imx_pwm_config_v2 和 imx_pwm_set_enable_
*/
43 imx->config = data->config;
44 imx->set_enable = data->set_enable;
45
46 ret = pwmchip_add(&imx->chip);
47 if (ret < 0)
48 return ret;
49
50 platform_set_drvdata(pdev, imx);
51 return 0;
52 }
设置 pwm_chip的 ops 操作集为 imx_pwm_ops, imx_pwm_ops 定义如下:
1 static struct pwm_ops imx_pwm_ops = {
2 .enable = imx_pwm_enable,
3 .disable = imx_pwm_disable,
4 .config = imx_pwm_config,
5 .owner = THIS_MODULE,
6 };
imx_pwm_set_enable_v2:打开或关闭对应的PWM |
1 static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
2 {
3 struct imx_chip *imx = to_imx_chip(chip);
4 u32 val;
5
6 val = readl(imx->mmio_base + MX3_PWMCR);/*第 6 行,读取 PWMCR 寄存器的值。*/
7
8 if (enable)
9 val |= MX3_PWMCR_EN;/*第 9 行,如果 enable 为真,表示使能 PWM,将 PWMCR 寄存器的 bit0 置 1 即可,宏
MX3_PWMCR_EN 为(1<<0)。*/
10 else
11 val &= ~MX3_PWMCR_EN;/*第 11 行,如果 enable 不为真,表示关闭 PWM,将 PWMCR 寄存器的 bit0 清 0 即可。*/
12
13 writel(val, imx->mmio_base + MX3_PWMCR);/*第 13 行,将新的 val 值写入到 PWMCR 寄存器中。*/
14 }
imx_pwm_config_v2 函数用于设置 PWM 的频率和占空比,相关操作如下:
1 static int imx_pwm_config_v2(struct pwm_chip *chip,
2 struct pwm_device *pwm, int duty_ns, int period_ns)
3 {
4 struct imx_chip *imx = to_imx_chip(chip);
5 struct device *dev = chip->dev;
6 unsigned long long c;
7 unsigned long period_cycles, duty_cycles, prescale;
8 unsigned int period_ms;
9 bool enable = test_bit(PWMF_ENABLED, &pwm->flags);
10 int wait_count = 0, fifoav;
11 u32 cr, sr;
12
......
42/*
第43~62行,根据参数duty_ns和period_ns来计算出应该写入到寄存器里面的值 duty_cycles
和 period_cycles。
*/
43 c = clk_get_rate(imx->clk_per);
44 c = c * period_ns;
45 do_div(c, 1000000000);
46 period_cycles = c;
47
48 prescale = period_cycles / 0x10000 + 1;
49
50 period_cycles /= prescale;
51 c = (unsigned long long)period_cycles * duty_ns;
52 do_div(c, period_ns);
53 duty_cycles = c;
54
55 /*
56 * according to imx pwm RM, the real period value should be
57 * PERIOD value in PWMPR plus 2.
58 */
59 if (period_cycles > 2)
60 period_cycles -= 2;
61 else
62 period_cycles = 0;
63
64 writel(duty_cycles, imx->mmio_base + MX3_PWMSAR);/*第 64 行,将计算得到的 duty_cycles 写入到 PWMSAR 寄存器中,设置 PWM 的占空比*/
65 writel(period_cycles, imx->mmio_base + MX3_PWMPR);/*第 65 行,将计算得到的 period_cycles 写入到 PWMPR 寄存器中,设置 PWM 的频率。*/
66
67 cr = MX3_PWMCR_PRESCALER(prescale) |
68 MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN |
69 MX3_PWMCR_DBGEN | MX3_PWMCR_CLKSRC_IPG_HIGH;
70
71 if (enable)
72 cr |= MX3_PWMCR_EN;
73
74 writel(cr, imx->mmio_base + MX3_PWMCR);
75
76 return 0;
77 }
二、PWM驱动编写
1、修改设备树
1)添加 GPIO1_IO04 引脚信息
在 iomuxc 节点下添加 GPIO1_IO04 的引脚信息,如下所示:
1 pinctrl_pwm3: pwm3grp {
2 fsl,pins = <
3 MX6UL_PAD_GPIO1_IO04__PWM3_OUT 0x110b0
4 >;
5 };
2)向 pwm3 节点追加信息
在 imx6ull-alientek-emmc.dts 文件中向 pwm3 节点追加一些内容,在 imx6ull-alientek-emmc.dts 文件中加入如下所示内容:
1 &pwm3 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_pwm3>;/*第 3 行, pinctrl-0 属性指定 PWM3 所使用的输出引脚对应的 pinctrl 节点,*/
4 clocks = <&clks IMX6UL_CLK_PWM3>,/*第 4 和 5 行,设置时钟,第 4 行设置 ipg 时钟,第 5 行设置 per 时钟。*/
5 <&clks IMX6UL_CLK_PWM3>;
6 status = "okay";
7 };
3)屏蔽掉其他复用的 IO
2、使能PWM驱动
-> Device Drivers
-> Pulse-Width Modulation (PWM) Support
-> <*> i.MX PWM support
三、PWM驱动测试
使用新的设备树启动系统,然后将开发板 JP2 排针上的 GPIO_4(GPIO1_IO04)引脚连接到示波器上,通过示波器来查看 PWM 波形图。
直接在用户层来配置 PWM,进入目录/sys/class/pwm 中:
1、调出 pwmchip2 的 pwm0 子目录
echo 0 > /sys/class/pwm/pwmchip2/export
执行完成会在 pwmchip2 目录下生成一个名为“pwm0”的子目录
2、使能 PWM3
echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable
3、设置 PWM3 的频率
echo 50000 > /sys/class/pwm/pwmchip2/pwm0/period
4、设置 PWM3 的占空比
不能直接设置占空比,而是设置的一个周期的 ON 时间,也就是高电平时间:
echo 10000 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
5、PWM背光设置
必要的属性如下:
compatible: 内容必须为“pwm-backlight”,通过这个可以匹配到内核自带的 PWM 背光驱动,驱动文件为 drivers/video/backlight/pwm_bl.c,这里就不去分析驱动源码了。
pwms: 此属性指定背光使用哪一路 PWM,以及 PWM 相关的属性。
brightness-levels: 背光等级数组,范围 0~255,对应占空比为 0%~100%。数组内的值必须从 0 开始,也就是 0%占空比,最后一个值必须是 255,也就是 100%占空比。数组中间值的个数以及值大小可以自行定义。
default-brightness-level: 默认的背光等级,也就是 brightness-levels 属性中第几个值,注意这里是数索引编号,不是具体的数值!
power-supply: 支持的电压,此属性可以不需要。
以正点原子 ALPHA 开发板为例,看一下 PWM 背光节点是如何设置的,打开 imx6ullalientek-emmc.dts,找到如下所示节点内容:
1 backlight {
2 compatible = "pwm-backlight";/*compatible 属性必须为“pwm-backlight”*/
3 pwms = <&pwm1 0 5000000>;
/*
pwms 属性指定背光所使用的 pwm 通道,第一个参数指定使用 pwm1,由于
I.MX6ULL 的 PWM 只有一个通道,因此这里为 0。最后一个参数是 PWM 周期,单位为 ns,这
里 PWM 周期为 5000000ns,频率为 200Hz。
*/
4 brightness-levels = <0 4 8 16 32 64 128 255>;/*第 4 行,背光等级数组,一共 8 个等级,索引编号从 0 到 7。*/
5 default-brightness-level = <7>;/*第 5 行,背光默认处于第 7 等级,也就是 255,为 100%占空比。*/
6 status = "okay";
7 };
本笔记为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,未经允许不得用于商业用途。
相关文章:

Linux学习第57天:Linux PWM驱动实验
Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 本章的思维导图如下: 一、PWM驱动简析 1、设备树下的PWM控制节点 8 路 PWM 都属于 I.MX6ULL 的 AIPS-1 域,分为了两部分, PWM1~P…...

git 远程拉取指定文件
指定操作 git init 创建一个空的文件 git remote add orgin 远程仓库地址链接 表示添加远程库的地址 git config core.sparsecheckout true 打开sparsecheckout功能 注意:如果需要分支内所有文件,这个指令可以直接过忽略,则会拉取对应分支所有的文件…...

【css】 CSS3+JS做一个酷炫的仪表进度条3d进度条
创建一个动态进度环组件 在现代网页设计中,进度环是一种常见的视觉元素,用于展示任务的完成度或加载状态。本文将介绍如何使用Vue.js和Less创建一个动态进度环组件,该组件不仅具有美观的视觉效果,还能够根据用户输入动态改变颜色…...

uniapp小程序全局配置分享到朋友和朋友圈功能的实现
文章目录 1.创建/mixins/share.js插件2.全局配置3.编写share.js4.调用5.分享成功 1.创建/mixins/share.js插件 直接创建 2.全局配置 (1)找到main.js在下面引入share.js文件 (2)使用mixins混入vue中,这样就相当于在每一…...

Java优化后台分页
第一种情况:先查询出所有记录,再进行分页处理(分页中可以异步处理) 优化前: List<String> list Arrays.asList("1","2","3","4","5","6","…...

<数据集>电梯内人车识别数据集<目标检测>
数据集格式:VOC格式 图片数量:97张 标注数量(xml文件个数):97 标注类别数:3 标注类别名称: [person, motorcycle, bicycle] 序号类别名称图片数框数1person891322motorcycle78793bicycle2222 使用标注工具&#…...

二百五十三、OceanBase——Linux上安装OceanBase数据库(三):OBD页面上部署OceanBase数据库
一、目的 安装OceanBase后,启动obd web,需要在OBD页面上部署OceanBase数据库 二、参考文档 http://t.csdnimg.cn/Qeedq 三、实施步骤 1 在obadmin用户下,启动obd服务,登录页面访问 [obadminhurys23 oceanbase]$ obd web 2 登…...

Redis应用笔记
Redis应用笔记 一、 前言二、 Redis八种常用数据类型2.1 Redis的五种基本数据类型2.2 Redis的三种特殊数据类型 三、发现Redis热Key方案3.1 使用 Redis 自带的 --hotkeys 参数来查找3.2 使用MONITOR 命令3.3 借助开源项目 四、解决 hotkey五、Redis 内存碎片5.1 为何会有Redis …...

html实现好看的塔罗牌、十二星座运势网站源码
文章目录 1.设计来源1.1 十二星座1.2 所有界面效果图 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/deta…...

万字长文带你入门shell编程(超详细)
一、概述 Shell 是计算机操作系统中用户与操作系统内核之间的接口层,它提供了一种方式让用户能够通过命令行界面(CLI)与操作系统交互。Shell 可以被视为一个命令解释器,它接收用户输入的命令,解析这些命令,…...

音质提升秘籍:专业音频剪辑软件汇总
现在欣赏传输音频文件比以前简单多了,这些音频的质量也影响了听众的体验与感受。所以使用一些靠谱的音频剪辑工具处理音频能让你的音频文件呈现更好的效果。 1.福昕音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这是一款电脑端软件。别看…...

idea配置
在我们使用idea的时候会进行配置主要就idea编译器的下载,maven资源管理器,Tomcat服务器 在IntelliJ IDEA的官网进入http://www.jetbrains.com/idea/ 如图如果你是大学生的话一般学校会有相关的激活码直接选择左边的.exe文件下载,直接的就是企…...

将 WinForms 中的 Panel 替换为 WPF 的 WindowsFormsHost 元素
要将 WinForms 中的 Panel 替换为 WPF 的 WindowsFormsHost 元素,你需要执行以下步骤:1. 添加对 WindowsFormsIntegration 的引用:确保你的项目引用了 WindowsFormsIntegration 和 PresentationCore、PresentationFramework 程序集࿰…...

C++ ---- vector的底层原理剖析及其实现
vector 一、定义二、常用接口及模拟实现三、vector迭代器失效问题四、使用memcpy拷贝会出现的问题五、二维数组vector<vector< T >> vv 一、定义 vector 是 C 标准模板库(Standard Template Library, STL)中的一个非常有用的容器。它是一个…...

跑酷视频素材去哪里下载?哪里有跑酷游戏视频素材?
在这个快节奏的视觉时代,跑酷视频因其惊险和动感吸引了众多动作爱好者和视频创作者的目光。如果您正在寻找高质量的跑酷视频素材来丰富您的项目,无论是增强视频的视觉冲击力还是展现跑酷运动的魅力,以下几个推荐的网站将是您的理想选择。 蛙…...

Centos 7配置问题
在VMWare12上面安装Centos 7 Linux虚拟机,在切换到命令界面时,需要登录用户名和密码,但发现输入用户后有字符显示,但是密码没有。 经过一系列查看后,发现这个是Linux的一种机制,即当你输入密码时不显示&…...

浮动IP(Floating IP)计费;OpenStack算力共享;OpenStack实现资源虚拟化;算力调度策略
目录 浮动IP(Floating IP)计费 浮动IP的定义与作用 计费中的浮动IP数据 浮动IP在计费中的作用 OpenStack算力共享 一、OpenStack在算力共享中的角色 二、OpenStack与算力共享的结合方式 三、实际应用案例 算力调度策略 算力计费策略 OpenStack实现资源虚拟化 1.虚…...

Android 源码单独编译Settings模块
一般我们编译源码,只需要在源码的根目录下执行三个命令就行 . build/envsetup.sh 或者source build/envsetup.sh lunch 选择编译目标 make -j60make 不带参数的编译方式是直接编译整个系统,我们也可以使用make带模块名或者使用mmm等命令单独编译某个模块。 首先找到对应模块…...

虚拟机类加载机制
与那些编译时需要进行连接的语言不同,在java语言中,类型的 动态加载:编写一个面向接口的应用程序,可以等到运行时再指定其实现类。 类加载:加载-连接-初始化-使用-卸载 一个类被调用时,会将其class文件从…...

Google Earth Engine(GEE)——逐月筛选影像,并给影像集合添加新的属性
简介 导入影像集合首先,您需要导入您要筛选的影像集合。使用Google Earth Engine的ImageCollection类来导入影像集合。您可以通过ee.ImageCollection()函数传递影像集合的ID或通过一个ee.ImageCollection()对象导入影像集合。 例如,导入Landsat 8卫星每月影像集合的代码如下…...

如何从智联招聘网站快速抓取职位详情?两大技巧揭秘
摘要: 本文将揭秘如何利用Python爬虫技术,高效且合法地从智联招聘网站抓取职位详情信息。通过实战示例,展现两大核心技巧,助你在大数据时代抢占先机,为你的市场分析、人才研究提供强大支持。 一、引言:数据…...

C#知识|ini文件操作
哈喽,你好啊,我是雷工! 本节学习ini文件的操作,之前练习过通过ini文件导出采集模块的配置信息,然后再另一个模块中导入配置信息,如此实现快速配置采集模块,提高效率。 以下为学习笔记。 01 认识ini文件 ini文件是一种文件格式,类似txt,xml等, ini文件在上位机开发中使…...

Linux系统学习之路
一、Linux基础训练 https://mp.weixin.qq.com/mp/appmsgalbum?actiongetalbum&__bizMzUxNjMwMzk4MQ&scene1&album_id3544800080551952390&count3#wechat_redirect...

DNS介绍与部署-Day 01
1. 什么是DNS DNS(Domain Name System)域名系统,是一种采用客户端/服务器机制,负责实现计算机名称与IP地址转换的系统。DNS作为一种重要的网络服务,既是Internet工作的基础,同时在企业内部网络中也得到了广…...

python 图片爬虫记录
感谢大家的点赞。再补充一点。 对于这个 url https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEqB5nighYsMZE7kexaVNJfxy3OkRutNEKatksw9u5f-ckHNROLzFyx2Uty3zYWNEaeOmzsljGr3eARiDWaM9DM8G2hPuPf8uZP0NO3kNUCnM2Cjb3ZKtLhJDBwqeR4ElpJ7ID5_wIHGQ/s200 这个url最…...

本地安装Llama3.1与LobeChat可视化UI界面并实现远程访问大模型实战
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

MSF回弹木马在Ubuntu中测试
1.创建文件 网站地址为192.168.30.129 首先在Ubuntu中use/local/nginx/sbin路径下创建一个PHP文件; 如图所示: 然后进入网页下载PHP文件如图所示: 什么都不显示说明这个没有问题就怕访问失败。 2.使用蚂键连接网站 在蚂键中的URL地址栏中…...

大数据等保测评
在当今数字化浪潮汹涌澎湃的时代,大数据已成为企业和组织创新发展的核心驱动力。然而,随着大数据应用的日益广泛和深入,其安全问题也日益凸显。大数据等保测评作为保障大数据安全的重要手段,具有至关重要的意义。 大数据的特点决定…...

CSS对元素的分类
文章目录 概述置换元素/非置换元素置换元素非置换元素 行内元素/块级元素/行内块级元素行内元素块级元素行内块级元素 概述 CSS从两个维度上将HTML元素进行了分类: 从元素内容的表现形式上,将元素分为:置换元素、非置换元素。从元素自身的显…...

力扣第五十四题——螺旋矩阵
内容介绍 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5]示例 2: 输入:matrix …...