正点原子嵌入式linux驱动开发——Linux ADC驱动

news2024/12/27 8:19:35

在之前的笔记中,学习了如何给ICM20608编写IIO驱动,ICM20608本质就是ADC,因此纯粹的ADC驱动也是IIO驱动框架的。本章就学习一下如何使用STM32MP1内部的ADC,并且在学习巩固一下IIO驱动

ADC简介

ADC

ADC,Analog to Digital Converter的缩写,中文名称模数转换器。它可以将外部的模拟信号转化成数字信号。对于GPIO口来说高于某个电压值,它读出来的只有高电平,低于就是低电平。假如想知道具体的电压数值就要借助于ADC的帮助,它可以将一个范围内的电压精确的读取出来

ADC有几个比较重要的参数:

  • 测量范围:测量范围对于ADC来说就好比尺子的量程,ADC测量范围决定了外接的设备其信号输出电压范围,不能超过ADC的测量范围。如果所使用的外部传感器输出的电压信号范围和所使用的ADC测量范围不符合,那么就需要自行设计相关电压转换电路。
  • 分辨率:就是尺子上的能量出来的最小测量刻度,假如ADC的测量范围为0-5V,分辨率设置为12位,那么能测出来的最小电压就是 5V除以2的12次方,也就是5/4096=0.00122V。很明显,分辨率越高,采集到的信号越精确,所以分辨率是衡量 ADC 的一个重要指标。
  • 精度:是影响结果准确度的因素之一,比如在厘米尺上能测量出大概多少毫米的尺度但是毫米后一点点我们却不能准确的量出。经过计算ADC在12位分辨率下的最小测量值是0.00122V,但是ADC的精度最高只能到11位也就是0.00244V。也就是ADC测量出0.00244V的结果是要比0.00122V要可靠,也更准确。
  • 采样时间:当ADC在某时刻采集外部电压信号的时候,此时外部的信号应该保持不变,但实际上外部的信号是不停变化的。所以在ADC内部有一个保持电路,保持某一时刻的外部信号,这样ADC就可以稳定采集了,保持这个信号的时间就是采样时间
  • 采样率:也就是在一秒的时间内采集多少次。很明显,采样率越高越好,当采样率不够的时候可能会丢失部分信息,所以ADC采样率是衡量ADC性能的另一个重要指标。

总之,只要是需要模拟信号转为数字信号的场合,那么肯定要用到ADC。很多数字传感器内部会集成ADC,传感器内部使用ADC来处理原始的模拟信号,最终给用户输出数字信号。

STM32MP157 ADC简介

STM32MP157有两个ADC:ADC1和ADC2,ADC1和ADC2紧密耦合,可在双重模式下运行(ADC1为主器件)。每个ADC由一个16位逐次逼近模数转换器组成,每个ADC有20个通道,每个通道支持单次、连续、扫描或不连续采样模式。转换结果存储在一个左对齐或右对
齐的32位数据寄存器中。ADC主要特性如下:

  1. 多达2个ADC,可在双重模式下运行。
  2. 可以配置为16、14、12、10或8位分辨率。
  3. 自校准。
  4. 可独立配置各通道采样时间。
  5. ……

ADC驱动源码简析

设备树下ADC节点

STM32MP157有2个ADC,因此对应2个ADC控制器,所以在设备树里就有2个ADC控制器节点。这2个ADC的设备树节点内容都是一样的,除了reg属性不同(毕竟不同的控制器,其地址范围不同)。本章实验使用PA5这个引脚来完成ADC实验,而PA5就是ADC1_INP19通道引脚,所以这里就以ADC1为例进行讲解,stm32mp151.dtsi文件中的adc节点信息如下:

示例代码 57.2.1.1 adc 节点内容
1  adc: adc@48003000 {
2      compatible = "st,stm32mp1-adc-core";
3      reg = <0x48003000 0x400>;
4      interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
5                  <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
6      clocks = <&rcc ADC12>, <&rcc ADC12_K>;
7      clock-names = "bus", "adc";
8      interrupt-controller;
9      st,syscfg = <&syscfg>;
10     #interrupt-cells = <1>;
11     #address-cells = <1>;
12     #size-cells = <0>;
13     status = "disabled";
14
15     adc1: adc@0 {
16         compatible = "st,stm32mp1-adc";
17         #io-channel-cells = <1>;
18         reg = <0x0>;
19         interrupt-parent = <&adc>;
20         interrupts = <0>;
21         dmas = <&dmamux1 9 0x400 0x80000001>;
22         dma-names = "rx";
23         status = "disabled";
24     };
25
26     adc2: adc@100 {
27         compatible = "st,stm32mp1-adc";
28         #io-channel-cells = <1>;
29         reg = <0x100>;
30         interrupt-parent = <&adc>;
31         interrupts = <1>;
32         dmas = <&dmamux1 10 0x400 0x80000001>;
33         dma-names = "rx";
34         status = "disabled";
35     };
36 };

第2行,compatible属性值为“st,stm32mp1-adc-core”,所以在整个Linux源码里面搜索这个字符串即可找到STM32MP157的ADC驱动核心文件,这个文件就是drivers/iio/adc/stm32-adc-core.c

第16、27行,compatible属性值“st,stm32mp1-adc”,搜索这个字符串,可以找到ADC驱动文件,这个文件就是drivers/iio/adc/stm32-adc.c

关于STM32MP157的ADC节点更为详细的信息请参考对应的绑定文档:Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt。接下来简单分析一下绑定文档,后面需要根据绑定文档修改设备树,使能ADC对应的通道。

ADC首先需要一个根节点,adc根节点属性如下:

1、必要属性

  • compatible:兼容性属性,必须的,可以设置为“st,stm32mp1-adc-core”。
  • reg:ADC控制器寄存器信息。
  • interrupts:中断属性,ADC1和ADC2各对应一个中断信息。
  • clocks:时钟属性。
  • clock-names:时钟名字,可选“adc”或“bus”。
  • interrupt-controller:中断控制器。
  • vdda-supply:此属性对应vdda输入模拟电压句柄。
  • vref-supply:此属性对应vref参考电压句柄。
  • interrupt-cells:设置为1。
  • address-cells:设置为1。
  • size-cells:设置为0。

2、可选属性

  • :pinctrl引脚配置信息。
  • booster-supply:嵌入式booster调节器句柄。
  • vdd-supply:vdd输入电压句柄。
  • st,syscfg:系统配置控制器句柄。
  • st,max-clk-rate-hz:最大时钟。

STM32MP157有两个ADC,每个ADC对应一个子节点,ADC子节点相关属性如下:

1、必要属性

  • compatible:兼容性属性,必须的,可以设置为“st,stm32mp1-adc”。
  • reg:不同ADC控制器寄存器地址偏移信息。
  • interrupts:中断线信息,adc@0为0,adc@100为1。
  • st,adc-channels:ADC通道信息,可以设置0-19,分别对应20个通道。
  • st,adc-diff-channels:ADC差分通道信息,如果使用差分ADC功能的话。
  • io-channel-cells:设置为1。

2、可选属性

  • dmas:DMA 通道句柄。
  • dma-names:dma 名字,必须设置成“rx”。
  • assigned-resolution-bits:ADC分辨率,可以设置为8、10、12,、14或16。
  • st,min-sample-time-nsecs:最小采样时间,单位ns。

ADC驱动源码分析

STM32MP157 ADC驱动文件有两个:stm32-adc-core.c和stm32-adc.cstm32-adc-core.c是ADC核心层,主要用于ADC电源等初始化,需要重点关注的是 stm32-adc.c这个文件。stm32-adc.c主体框架是platform,配合IIO驱动框架实现ADC驱动

stm32_adc结构体

ST自己将ADC外设抽象成了结构体,stm32_adc就相当于自定义的设备结构体。stm32_adc结构体贯穿于整个驱动文件,结构体内容如下:

stm32_adc结构体

stm32_adc_probe函数

接下来看一下stm32_adc_probe函数,内容如下(有省略):

示例代码 57.2.2.2 stm32_adc_probe 函数
1   static int stm32_adc_probe(struct platform_device *pdev)
2   {
3       struct iio_dev *indio_dev;
4       struct device *dev = &pdev->dev;
5       irqreturn_t (*handler)(int irq, void *p) = NULL;
6       struct stm32_adc *adc;
7       int ret;
8 
9       if (!pdev->dev.of_node)
10           return -ENODEV;
11 
12      indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
13      if (!indio_dev)
14          return -ENOMEM;
15 
16      adc = iio_priv(indio_dev);
17      adc->common = dev_get_drvdata(pdev->dev.parent);
18      spin_lock_init(&adc->lock);
19      init_completion(&adc->completion);
20      adc->cfg = (const struct stm32_adc_cfg *)
21          of_match_device(dev->driver->of_match_table, dev)->data;
22 
23      indio_dev->name = dev_name(&pdev->dev);
24      indio_dev->dev.parent = &pdev->dev;
25      indio_dev->dev.of_node = pdev->dev.of_node;
26      indio_dev->info = &stm32_adc_iio_info;
27      indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED;
28 
29      platform_set_drvdata(pdev, adc);
30 
31      ret = of_property_read_u32(pdev->dev.of_node, "reg",
&adc->offset);
32      if (ret != 0) {
33          dev_err(&pdev->dev, "missing reg property\n");
34          return -EINVAL;
35      }
36 
37      adc->irq = platform_get_irq(pdev, 0);
38      if (adc->irq < 0)
39          return adc->irq;
40 
41      ret = devm_request_threaded_irq(&pdev->dev, adc->irq,
stm32_adc_isr,
42                                      stm32_adc_threaded_isr,
43                                      0, pdev->name, adc);
44      if (ret) {
45          dev_err(&pdev->dev, "failed to request IRQ\n");
46          return ret;
47      }
48 
49      adc->clk = devm_clk_get(&pdev->dev, NULL);
50      if (IS_ERR(adc->clk)) {
51          ret = PTR_ERR(adc->clk);
52          if (ret == -ENOENT && !adc->cfg->clk_required) {
53              adc->clk = NULL;
54          } else {
55              dev_err(&pdev->dev, "Can't get clock\n");
56              return ret;
57          }
58      }
59 
60      ret = stm32_adc_of_get_resolution(indio_dev);
61      if (ret < 0)
62          return ret;
63 
64      ret = stm32_adc_chan_of_init(indio_dev);
65      if (ret < 0)
66          return ret;
67 
68      ret = stm32_adc_dma_request(indio_dev);
69      if (ret < 0)
70          return ret;
71 
72      if (!adc->dma_chan)
73          handler = &stm32_adc_trigger_handler;
74 
75      ret = iio_triggered_buffer_setup(indio_dev,
76                     &iio_pollfunc_store_time, handler,
77                     &stm32_adc_buffer_setup_ops);
78      if (ret) {
79          dev_err(&pdev->dev, "buffer setup failed\n");
80          goto err_dma_disable;
81      }
82 
83      /* Get stm32-adc-core PM online */
84      pm_runtime_get_noresume(dev);
85      pm_runtime_set_active(dev);
86      pm_runtime_set_autosuspend_delay(dev,
STM32_ADC_HW_STOP_DELAY_MS);
87      pm_runtime_use_autosuspend(dev);
88      pm_runtime_enable(dev);
89 
90      ret = stm32_adc_hw_start(dev);
91      if (ret)
92          goto err_buffer_cleanup;
93 
94      ret = iio_device_register(indio_dev);
95      if (ret) {
96          dev_err(&pdev->dev, "iio dev register failed\n");
97          goto err_hw_stop;
98      }
......
123     return ret;
124 }

第12行,调用devm_iio_device_alloc函数申请iio_dev,这里也连stm32_adc内存一起申请了。

第16行,调用iio_priv函数从iio_dev里面的到stm32_adc首地址。

第23-27行,初始化iio_dev,重点是第26行的stm32_adc_iio_info,因为用户空间读取ADC数据最终就是由stm32_adc_iio_info来完成的

第37行,调用platform_get_irq获取中断号。

第41行,调用devm_request_threaded_irq函数申请中断,这里使用的是中断线程化。

第60行,调用stm32_adc_of_get_resolution函数获取ADC的分辨率。

第64行,调用stm32_adc_chan_of_init函数初始化ADC通道。

第68行,调用stm32_adc_dma_request函数初始化DMA。

第75行,调用iio_triggered_buffer_setup函数设置IIO触发缓冲区。

第90行,调用stm32_adc_hw_start函数开启ADC。

第94行,调用iio_device_register函数向内核注册iio_dev。

可以看出stm32_adc_probe函数核心就是初始化ADC,然后建立ADC的IIO驱动框架

stm32_adc_iio_info结构体

stm32_adc_iio_info结构体内容如下所示:

stm32_adc_iio_info结构体

重点来看一下第2行的stm32_adc_read_raw函数,因为此函数才是最终向用户空间发送ADC原始数据的,函数内容如下:

stm32_adc_read_raw函数

第9-18行,读取ADC原始数据值,第18行type值为IIO_VOLTAGE,也就是读取电压值。第14行调用stm32_adc_single_conv函数来完成ADC单次读取。stm32_adc_single_conv函数会设置采样率、配置通道、使用硬件触发、开启转换,最后等待转换完成中断发生。

第20-28行,返回ADC对应的分辨率。

第30-36行,返回差分ADC的偏移值。

stm32_adc_read_raw函数内容还是比较简单的,因为只是读取ADC原始值,不像ICM20608那么复杂。关于ADC驱动源码就讲解到这里,接下来学习如何使能ADC,然后编写应用程序读取ADC采集到的值

硬件原理图分析

STM32MP157开发板ADC硬件原理图如下图所示:

ADC原理图

上图中JP2是一个3P的排针,1脚连接到STM32MP157的DAC引脚上(PA4),2脚连
接到ADC引脚上(PA5),3脚连接到VR1这个可调电位器上。本章实验使用STM32MP157的ADC来采集VR1可调电位器的电压,因此要用跳线帽将JP1的2,3脚连接起来,如下图所示:

开发板ADC设置

ADC驱动编写

修改设备树

ADC驱动ST已经编写好了,只需要修改设备树即可。首先在stm32mp15-pinctrl.dtsi文件中添加ADC使用的PA5引脚配置信息:

示例代码 57.4.1.1 PA5 引脚配置信息
1 adc1_in19_pins_a: adc1-in19 {
2     pins {
3         pinmux = <STM32_PINMUX('A', 5, ANALOG)>;
4     };
5 };

接下来在stm32mp157d-atk.dts文件中向根节点添加vdd子节点信息,内容如下:

示例代码 57.4.1.2 vdd 子节点
1 vdd: regulator-vdd {
2     compatible = "regulator-fixed";
3     regulator-name = "vdd";
4     regulator-min-microvolt = <3300000>;
5     regulator-max-microvolt = <3300000>;
6     regulator-always-on;
7     regulator-boot-on;
8 };

最后在stm32mp157d-atk.dts文件中向adc节点追加一些内容,内容如下:

示例代码 57.4.1.3 adc 节点
1  &adc {
2      pinctrl-names = "default";
3      pinctrl-0 = <&adc1_in19_pins_a>;
4      vdd-supply = <&vdd>;
5      vdda-supply = <&vdd>;
6      vref-supply = <&vdd>;
7      status = "okay";
8 
9      adc1: adc@0 {
10         st,adc-channels = <19>;
11         st,min-sample-time-nsecs = <10000>;
12         assigned-resolution-bits = <16>;
13         status = "okay";
14     };
15 };

第3行,配置adc引脚。

第4-6行,设置电压属性。

第9-12行,adc1子节点,第10行st,adc-channels属性设置adc通道为19,第11行st,min-sample-time-nsecs属性设置最小采样时间为10000ns,第12行设置分辨率为16位。

使能ADC驱动

ST官方默认已经使能了ADC驱动,所以不需要修改,但是为了学习,看一下如何使能Linux内核自带的ADC驱动。打开Linux内核配置界面,配置路径如下:

-> Device Drivers
-> Industrial I/O support (IIO [=y])
-> Analog to digital converters
-> STMicroelectronics STM32 adc core (STM32_ADC_CORE [=y])
-> <*>STMicroelectronics STM32 adc //使能 STM32 ADC

如下图所示:

ADC配置项

编写测试APP

编译修改后的设备树,然后使用新的设备树启动系统。进入/sys/bus/iio/devices目录下,此目录下就有ADC对应的iio设备:iio:deviceX,本章例程如下图所示:

ADC iio设备

上图中的“iio:device0”就是ADC设备,因为此时并没有加载其他的IIO设备驱动,只有一个ADC。如果还加载了其他IIO设备驱动,那么就要依次进入iio设备目录,查看一下都对应的是什么设备。

进入“iio:device0”目录,内容如下图所示:

iio:device0目录文件

标准的IIO设备文件目录,只关心三个文件:

  • in_voltage19_raw:ADC1通道19原始值文件。
  • in_voltage_offset:ADC1偏移文件。
  • in_voltage_scale:ADC1比例文件(分辨率),单位为mV。实际电压值(mV)=in_voltage19_raw*in_voltage_scale。

开发板此时in_voltage19_raw和in_voltage_scale这两个文件内容如下:

当前电压

经过计算,上图中实际电压:20779*0.050354003≈1046.3mV,也就是1.0463V。

编写测试APP,其中需要:

新建char数组指针file_path存储iio框架对应文件路径,并enum对应的文件索引。然后欣姐设备结构体,里面存储raw、scale和act就可以了。

编写file_data_read,这个跟之前iio的很类似,就是fopen之后fscanf,到EOF处就fseek把指针调回文件头然后fclose。

之后编写adc_read,里面就是调用file_data_read读出来之后分别atoi和atof转成数字,最后把raw和scale乘起来/1000得到实际值存到adc_dev的结构体指针dev->act之中。

最后是main函数,argc就1个,在while中adc_read然后printf就好了。

运行测试

编译驱动程序和测试APP

由于不需要编写ADC驱动程序,因此也就不需要编译驱动程序。设备树前面已经编译过了,所以这里就只剩下编译测试APP。由于adcApp.c用到了浮点运算,因此编译的时候要使能硬件浮点,输入如下编译adcApp.c 这个测试程序:

arm-none-linux-gnueabihf-gcc -march=armv7-a -mfpu=neon -mfloat-abi=hard adcApp.c -o adcApp

运行测试

注意,在测试之前一定要先按照之前的连接示意图所示,将JP2跳线帽接到左边,也就是将ADC1_CH19通道连接到开发板上的可调电位器上!

输入如下命令,使用adcApp测试程序:

./adcApp

测试APP会不断的读取ADC值并输出到终端,可以通过调节开发板上的电位器来改变电压值,如下图所示:

测试结果

从上图可以看到ADC原始值以及对应的电压值,因为STM32MP157的ADC可采集电压范围为0-3.3V,因此扭动开发板上的电位器的时候,电压会在0-3.3V之间变化。

总结

这一章的学习放在了IIO的驱动后面,所以其实比之前要简单了很多,个人感觉可以先看这个,学一下IIO的驱动框架,然后再去看上一篇笔记,基本的内容都一样,反而上一篇笔记的IIO驱动来搞ICM20608难度大很多

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

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

相关文章

里氏代换原则

package com.jmj.principles.dmeo2.after;/*** 四边形接口*/ public interface Quadrilateral {double getLength();double getWidth();}package com.jmj.principles.dmeo2.after;/*** 长方形类*/ public class Rectangle implements Quadrilateral{private double length;priv…

(附源码)基于SSM旅行社网站-计算机毕设 90030

SSM旅行社网站 摘 要 旅游业是一个信息密集型产业&#xff0c;传统的旅游景点门票售卖受到技术和人力的限制&#xff0c;旅行社网站则可以建立景区与游客之间的有效通道&#xff0c;能更好的满足游客便捷旅游的需求。旅行社网站的设计是基于SSM框架、Mysql数据库、JSP技术、Aja…

立体库堆垛机水平电机输出控制程序功能

###############水平电机输出控制程序################# #############水平变频器输出控制程序################# *******************水平速度曲线建立*********************** 列距离差值&#xff0c;建立与速度的关系式&#xff1a;VX/k MW220为K系数 水平速度控制K系数 列…

EDA实验-----3-8译码器设计(QuartusII)

目录 一. 实验目的 二. 实验仪器 三. 实验原理及内容 1.实验原理 2.实验内容 四&#xff0e;实验步骤 五. 实验报告 六. 注意事项 七. 实验过程 1.创建Verilog文件&#xff0c;写代码 ​编辑 2.波形仿真 3.连接电路图 4.烧录操作 一. 实验目的 学会Verilog HDL的…

AI艺术字比赛;OpenAI GPTs 分享网站;AI项目坟场;农村程序员独立开发者;小红书·大模型与推荐系统 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f251; Alibaba X 堆友「AI造字」主题作品设计大赛 https://d.design/competition/ai-word 堆友 (D.DESIGN) 是一个在线设计平台&#xff0c;…

堆的应用-----Top k 问题

目录 前言 Topk问题 1.问题描述 2.解决方法 3.代码实现&#xff08;C/C&#xff09; 前言 在人工智能算法岗位的面试中&#xff0c;TopK是问得最多的几个问题之一&#xff1a; 到底有几种方法&#xff1f; 这些方案里蕴含的优化思路究竟是怎么样的&#xff1f; 为啥T…

OpenAI发布会,看看GPT又有哪些大动作!2023.11.7【浓缩精华】

ChatGPT GPT-4 Turbo其它applications 北京时间11月7日OpenAI首届开发者大会 GPT-4 Turbo Context length 支持12.8万个上下文contextMore control JSON模式 可复制输出 未来&#xff1a;在API中查看日志Better knowledge 平台启动检索 拥有截至2023年3月的知识New modaliti…

2020年12月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 下面哪个区域是“舞台区”? A:A B:B C:C D:D 答案:B 第2题 下面哪段程序可以随机切换三个背景? A: B: C: D:

2.1 Windows驱动开发:内核链表与结构体

在Windows内核中&#xff0c;为了实现高效的数据结构操作&#xff0c;通常会使用链表和结构体相结合的方式进行数据存储和操作。内核提供了一个专门用于链表操作的数据结构LIST_ENTRY&#xff0c;可以用来描述一个链表中的每一个节点。 使用链表来存储结构体时&#xff0c;需要…

搜狐2023年Q3营收1.45亿美元 宣布最高8000万美元股票回购计划

2023年11月13日&#xff0c;搜狐公司公布2023年第三季度财务报告。财报显示&#xff0c;搜狐公司第三季度总收入为1.45亿美元&#xff0c;其中&#xff0c;品牌广告收入为2200万美元&#xff0c;在线游戏收入为1.17亿美元&#xff1b;同时宣布为期两年&#xff0c;总金额最高为…

Code Former安装及使用

Code Former是南洋理工大学和商汤科技联合研究中心联合开发一款AI人脸修复算法&#xff0c;通过该算法&#xff0c;可以对已经模糊的图片进行人脸修复&#xff0c;找回斑驳的记忆 由于网上对于Code Former的封装&#xff0c;全都是要花钱&#xff0c;或者需要其他什么曲折的方式…

Pyside6/PYQT6如何实现无边框设计,解决无边框窗口无法移动和实现窗口拖拽改变大小的问题

文章目录 💢 问题 💢💯 解决方案 💯🍔 准备工作📚 setWindowFlags、setWindowFlag和setAttribute的区别🐾 操作步骤🐾 窗口无边框🐾 窗口透明🐾 实现窗口可移动🐾 实现窗口拖拽改变大小⚓️ 相关链接 ⚓️💢 问题 💢 有时候我们需要一个无边框的UI设…

转本考前4个月,手把手教你逆袭上岸

现在离转本考试的时间还剩下4个月&#xff0c;绝大多数同学会在之后的寒假期间全力学习&#xff0c;谁在这段时期懈怠&#xff0c;谁就丢掉了一半的分数。 不管是复习了很长一段时间&#xff0c;还是刚起步的同学&#xff0c;都有必要重新规划后面的复习。下面给大家讲讲&…

告别瞎忙+拖延,工作中必不可少的便签工具

在平常的工作中&#xff0c;很多人都会感慨&#xff0c;每天的工作都是在瞎忙&#xff0c;一天忙忙碌碌结束后发现仍旧有许多待完成的任务&#xff0c;也有一些人在工作中碌碌无为&#xff0c;消极怠工拖延时间&#xff0c;瞎忙拖延归根到底是没有提前将工作中的各项工作安排妥…

vscode使用flake8设置单行最长字符限制设置失败的问题

vscode使用flake8设置单行最长字符限制设置失败的问题 问题描述解决方案 问题描述 如图所示&#xff0c;使用flake8单行字数过长&#xff0c;就会有有红色底的波浪线 一般情况下很多教程都会让你在setting.json里面设置 但是我打开我的setting.json&#xff0c;发现我已经进…

List中的迭代器实现【C++】

List中的迭代器实现【C】 一. list的结构二. 迭代器的区别三. 迭代器的实现i. 类的设计ii. 重载iii. !重载iiii. begin()iiiii. end()iiiii. operator* 四.测试五. const迭代器的实现i. 实现5.2 优化实现 一. list的结构 其实按照习惯来说&#xff0c;应该要专门出一篇博客来写…

体验家XMPlus收购NPSMeter,稳固体验管理行业“领头羊”地位

2023年9月30日&#xff0c;体验家XMPlus&#xff08;以下简称“体验家”&#xff09;成功完成了对NPSMeter的收购。此次收购是中国客户体验管理&#xff08;CEM&#xff09;赛道进入快速发展以来的首单收购&#xff0c;标志着体验家在CEM领域的进一步扩张&#xff0c;旨在继续完…

2023亚太杯数学建模C题思路

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

三、机器学习基础知识:Python常用机器学习库(中文文本分析相关库)

文章目录 1、Jieba库1.1 主要函数1.2 词性标注1.3 关键词提取 2、WordCloud库2.1 常见参数2.2 词云绘制 文本分析是指对文本的表示及其特征的提取&#xff0c;它把从文本中提取出来的特征词进行量化来表示文本信息&#xff0c;经常被应用到文本挖掘以及信息检索的过程当中。 1、…

2.2 Windows驱动开发:内核自旋锁结构

提到自旋锁那就必须要说链表&#xff0c;在上一篇《内核中的链表与结构体》文章中简单实用链表结构来存储进程信息列表&#xff0c;相信读者应该已经理解了内核链表的基本使用&#xff0c;本篇文章将讲解自旋锁的简单应用&#xff0c;自旋锁是为了解决内核链表读写时存在线程同…