STM32MP157驱动开发——Linux DAC驱动

news2024/12/23 15:02:47

STM32MP157驱动开发——Linux DAC驱动

  • 0.前言
  • 一、DAC 简介
  • 二、驱动源码分析
    • 1.设备树下的 DAC 节点
    • 2.驱动源码分析
      • 1)stm32_dac 结构体
      • 2)stm32_adc_probe 函数
      • 3)stm32_dac_iio_info 结构体
  • 三、驱动开发
    • 1.修改设备树
    • 2.使能DAC驱动
  • 四、 运行测试


0.前言

  上一节对 STM32MP157 内部的 ADC 设备驱动进行了开发,这一节就了解下该芯片内部的 DAC 设备。

一、DAC 简介

  DAC 是数模转换器,负责将 SOC 的数字信号转换为模拟信号。STM32MP157 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。DAC 可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。DAC 模块有 2 个输出通道,每个通道都有独立的转换器。在双 DAC 模式下,2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。DAC 可以通过引脚输入参考电压 Vref+(通 ADC 共用)以获得更精确的转换结果。
其主要特点有:

① 1 个 DAC 接口,最大两个 DAC 输出通道
② 12 位模式下数据左对齐或者右对齐
③ 同步更新功能
④ 噪声波、三角波形生成
⑤ 外部触发
⑥ 双 DAC 通道同时或者分别转换
⑦ 每个通道都有 DMA 功能
⑧ 输入参考电压 VREF+

二、驱动源码分析

1.设备树下的 DAC 节点

在这里插入图片描述
一个 compatible 属性值为“st,stm32h7-dac-core”,对应的 DAC 驱动核心文件为 drivers/iio/dac/stm32-daccore.c。另一个 compatible 属性值“st,stm32-dac”,对应 ADC 驱动文件为 drivers/iio/dac/stm32-dac.c。与 DAV 相关的文档为 Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt。该文档中介绍了如何添加 DAC 设备节点。
DAC 首先需要一个根节点,根节点属性如下:
必要属性:

  • compatible:兼容性属性,必须的,可以设置为“st,stm32h7-dac-core”
  • reg:DAC 控制器寄存器信息
  • clocks:时钟
  • clock-names:时钟名字,必须为“pclk”
  • vref-supply:此属性对应 vref 参考电压句柄
  • address-cells:设置为 1
  • size-cells:设置为 0

可选属性:

  • pinctrl 引脚配置信息
  • resets:复位句柄

STM32MP157 有两个 DAC 通道,每个 DAC 通道对应一个子节点,子节点的属性如下:

  • compatible:兼容性属性,必须的,可以设置为“st,stm32-dac”
  • reg:不同 ADC 控制器寄存器地址偏移信息
  • io-channel-cells:设置为1

2.驱动源码分析

  STM32MP157 DAC 驱动文件也有两个:stm32-dac-core.c 和 stm32-dac.c。stm32-dac-core.c 是 DAC 核心层,主要用于 DAC 时钟、电源等初始化。stm32-adc.c 主体框架是 platform,配合 IIO 驱动框架实现 DAC 驱动。(主要关注此文件)

1)stm32_dac 结构体

struct stm32_dac {
	struct stm32_dac_common *common;
};

相比较于 ADC 的结构体,此结构体简单得多,只有一个 stm32_dac_common 成员变量,其内容如下:

struct stm32_dac_common {
	struct regmap *regmap; /* regmap */
	int vref_mv; /* 参考电压 */
	bool hfsel; /* 高速总线时钟选择 */
};

可以看出,DAC 驱动也采用了 regmap API。

2)stm32_adc_probe 函数

1 static int stm32_dac_probe(struct platform_device *pdev)
2 {
3 		struct device_node *np = pdev->dev.of_node;
4 		struct device *dev = &pdev->dev;
5 		struct iio_dev *indio_dev;
6 		struct stm32_dac *dac;
7 		int ret;
8 
9 		if (!np)
10 			return -ENODEV;
11
12 		indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
13 		if (!indio_dev)
14 			return -ENOMEM;
15 		platform_set_drvdata(pdev, indio_dev);
16
17 		dac = iio_priv(indio_dev);
18 		dac->common = dev_get_drvdata(pdev->dev.parent);
19 		indio_dev->name = dev_name(&pdev->dev);
20 		indio_dev->dev.parent = &pdev->dev;
21 		indio_dev->dev.of_node = pdev->dev.of_node;
22 		indio_dev->info = &stm32_dac_iio_info;
23 		indio_dev->modes = INDIO_DIRECT_MODE;
24
25 		ret = stm32_dac_chan_of_init(indio_dev);
26 		if (ret < 0)
27 			return ret;
......
36 		ret = iio_device_register(indio_dev);
37 		if (ret)
38 			goto err_pm_put;
......
50 		return ret;
51 }

第 12 行,调用 devm_iio_device_alloc 函数申请 iio_dev,这里也连 stm32_dac 内存一起申请了。
第 17 行,调用 iio_priv 函数从 iio_dev 里面的到 stm32_dac 首地址。
第 19~23 行,初始化 iio_dev,重点是第 22 行的 stm32_dac_iio_info,因为用户空间读取或设置 DAC 数据最终就是由 stm32_dac_iio_info 来完成的。
第 25 行,调用 stm32_dac_chan_of_init 函数设置 DAC 通道。
第 36 行,调用 iio_device_register 函数向内核注册 iio_dev。

核心步骤就是初始化 ADC,然后建立 ADC 的 IIO 驱动框架。

3)stm32_dac_iio_info 结构体

1 static const struct iio_info stm32_dac_iio_info = {
2 		.read_raw = stm32_dac_read_raw,
3 		.write_raw = stm32_dac_write_raw,
4 		.debugfs_reg_access = stm32_dac_debugfs_reg_access,
5 };

第 2 行,stm32_dac_read_raw 函数用于读取 DAC 信息,读取 DAC 原始数据值、分辨率等。
第 3 行,stm32_dac_write_raw 函数用于设置 DAC 值。

stm32_dac_read_raw 和 stm32_dac_write_raw 函数内容如下:

1 static int stm32_dac_read_raw(struct iio_dev *indio_dev,
2 								struct iio_chan_spec const *chan,
3 								int *val, int *val2, long mask)
4 {
5 		struct stm32_dac *dac = iio_priv(indio_dev);
6 
7 		switch (mask) {
8 			case IIO_CHAN_INFO_RAW:
9 				return stm32_dac_get_value(dac, chan->channel, val);
10 			case IIO_CHAN_INFO_SCALE:
11 				*val = dac->common->vref_mv;
12 				*val2 = chan->scan_type.realbits;
13 				return IIO_VAL_FRACTIONAL_LOG2;
14 			default:
15 				return -EINVAL;
16 		}
17 }
18
19 static int stm32_dac_write_raw(struct iio_dev *indio_dev,
20 								  struct iio_chan_spec const *chan,
21 								  int val, int val2, long mask)
22 {
23 		struct stm32_dac *dac = iio_priv(indio_dev);
24
25 		switch (mask) {
26 			case IIO_CHAN_INFO_RAW:
27 				return stm32_dac_set_value(dac, chan->channel, val);
28 			default:
29 				return -EINVAL;
30 		}
31 }

第 1~17 行,stm32_dac_read_raw 函数,读取 DAC 的原始值以及分辨率,非常简单。
第 19~31 行,stm32_dac_write_raw 函数,向 DAC 写入原始值,也就是设置 DAC。

可以看出,相较于 ADC 的驱动,DAC 的驱动实现也简单一些。

三、驱动开发

原理图:
在这里插入图片描述
JP2 是一个 3P 的排针,用来设置 ADC 连接可调电位器还是DAC。本节使用 DAC 功能,因此使用跳线帽将 JP2 的 1,2 引脚连接起来。
在这里插入图片描述
正点原子 STM32MP157 开发板使用了 DAC 通道 1,引脚为 PA4。
在开发过程中,可以编写应用程序设置 DAC,然后再使用 ADC 采集回去。

1.修改设备树

DAC 驱动已经由 ST 编写好,只需要修改设备树即可。在 stm32mp15-pinctrl.dtsi 文件中添加 DAC 使用的 PA4 引脚配置信息(原文件中已存在该节点):

dac_ch1_pins_a: dac-ch1 {
	pins {
		pinmux = <STM32_PINMUX('A', 4, ANALOG)>;
	};
};

然后在 stm32mp157d-atk.dts 文件中向根节点添加 v3v3 子节点信息(可以与上节 ADC 中的 vdd 共用):

v3v3: regulator-3p3v {
	compatible = "regulator-fixed";
	regulator-name = "v3v3";
	regulator-min-microvolt = <3300000>;
	regulator-max-microvolt = <3300000>;
	regulator-always-on;
	regulator-boot-on;
};

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

&dac {
	pinctrl-names = "default";
	pinctrl-0 = <&dac_ch1_pins_a>;
	vref-supply = <&vdd>;
	status = "okay";
	dac1: dac@1 {
		status = "okay";
	};
};

①配置 dac 引脚
②设置电压属性(如果与上节的vdd共用,需要修改名称)
③dac1 子节点,设置很简单,直接将 status 属性设置为“okay”即可

2.使能DAC驱动

同样的,使能 Linux 内核中的 ST32MP157 DAC 驱动,在 menuconfig 中选中以下选项:
在这里插入图片描述
然后就可以编译出新的内核镜像与设备树文件,启动开发板。

四、 运行测试

启动开发板后,在 /sys/bus/iio/devices 目录下就会存在与 DAC 对应的 iio 设备:
在这里插入图片描述

  • out_voltage1_powerdown:DAC 输出使能文件,写 0 打开 DAC,写 1 关闭 DAC,默认为 1,也就是关闭 DAC
  • out_voltage1_raw:DAC1 通道 1 原始值文件
  • out_voltage1_scale:DAC1 比例文件(分辨率),单位为 mV。实际输出电压值(mV)=out_voltage1_raw * out_voltage1_scale

ADC1 默认 12 位,因此可设置范围为 0~4095。
先在终端中向 out_voltage1_raw 写入 2000:

echo 0 > /sys/bus/iio/devices/iio:device1/out_voltage1_powerdown #开启 DAC
echo 2000 > /sys/bus/iio/devices/iio:device1/out_voltage1_raw #设置 DAC

此时 DAC 的理论输出电压为 2000*0.805664062≈1611.328mV。使用上一节的 ADC 测试程序,读取该引脚的电压值:
在这里插入图片描述
可以看出,采样到的结果基本一致。

接下来编译一个简单的 DAC 测试 APP,APP 等待用户输入 DAC 原始值,当用户输入以后就调用 ADC 来采集 DAC 输出的电压值,最后将 DAC 理论值与 ADC 采集到的实际值打印出来,看一下是否正确。
dac_app.c:

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>

/* 字符串转数字,将浮点小数字符串转换为浮点数数值 */
#define SENSOR_FLOAT_DATA_GET(ret, index, str, member)\
	ret = file_data_read(file_path[index], str);\
	dev->member = atof(str);\
	
/* 字符串转数字,将整数字符串转换为整数数值 */
#define SENSOR_INT_DATA_GET(ret, index, str, member)\
	ret = file_data_read(file_path[index], str);\
	dev->member = atoi(str);\

/* iio框架对应的文件路径 */
static char *file_path[] = {
	"/sys/bus/iio/devices/iio:device0/in_voltage_scale",
	"/sys/bus/iio/devices/iio:device0/in_voltage19_raw",
	"/sys/bus/iio/devices/iio:device1/out_voltage1_scale",
	"/sys/bus/iio/devices/iio:device1/out_voltage1_raw",
};

/* 文件路径索引,要和file_path里面的文件顺序对应 */
enum path_index {
	IN_VOLTAGE_SCALE = 0,
	IN_VOLTAGE_RAW,
	OUT_VOLTAGE1_SCALE,
	OUT_VOLTAGE1_RAW,
};

/*
 * dac数据设备结构体
 */
struct dac_dev{
	int dac_raw, adc_raw;
	float dac_scale, adc_scale;
	float dac_act, adc_act;
};

struct dac_dev stm32dac;

 /*
 * @description			: 读取指定文件内容
 * @param - filename 	: 要读取的文件路径
 * @param - str 		: 读取到的文件字符串
 * @return 				: 0 成功;其他 失败
 */
static int file_data_read(char *filename, char *str)
{
	int ret = 0;
	FILE *data_stream;

    data_stream = fopen(filename, "r"); /* 只读打开 */
    if(data_stream == NULL) {
		printf("can't open file %s\r\n", filename);
		return -1;
	}

	ret = fscanf(data_stream, "%s", str);
    if(!ret) {
        printf("file read error!\r\n");
    } else if(ret == EOF) {
        /* 读到文件末尾的话将文件指针重新调整到文件头 */
        fseek(data_stream, 0, SEEK_SET);  
    }
	fclose(data_stream);	/* 关闭文件 */	
	return 0;
}

 /*
 * @description	: 获取ADC、DAC数据
 * @param - dev : 设备结构体
 * @return 		: 0 成功;其他 失败
 */
static int dac_add_dac_read(struct dac_dev *dev)
{
	int ret = 0;
	char str[50];

	/* 1、获取ADC值 */
	SENSOR_FLOAT_DATA_GET(ret, IN_VOLTAGE_SCALE, str, adc_scale);
	SENSOR_INT_DATA_GET(ret, IN_VOLTAGE_RAW, str, adc_raw);

	/* 转换ADC采集到的实际电压值mV */
	dev->adc_act = (dev->adc_scale * dev->adc_raw)/1000.f;

	/* 2、获取DAC值 */
	SENSOR_FLOAT_DATA_GET(ret, OUT_VOLTAGE1_SCALE, str, dac_scale);
	SENSOR_INT_DATA_GET(ret, OUT_VOLTAGE1_RAW, str, dac_raw);

	/* 转换DAC理论电压值mV */
	dev->dac_act = (dev->dac_scale * dev->dac_raw)/1000.f;
	return ret;
}

 /*
 * @description	: 使能DAC
 * @return 		: 无
 */
void dac_enable(void)
{
	system("echo 0 > /sys/bus/iio/devices/iio:device1/out_voltage1_powerdown");
}

/*
 * @description	: 禁止DAC
 * @return 		: 无
 */
void dac_disable(void)
{
	system("echo 1 > /sys/bus/iio/devices/iio:device1/out_voltage1_powerdown");
}

/*
 * @description			: 设置DAC
 * @param - filename	: 要写的文件路径
 * @param - value 		: DAC原始值
 * @return 				: 无
 */
int dac_set(char *filename, int value)
{
	int ret = 0;
	FILE *data_stream;
	char str[10];

	/* 1、将整形变量转换为字符串 */
	sprintf(str, "%d", value);

	/* 2、打开文件流 */
    data_stream = fopen(filename, "w"); /* 只写打开 */
    if(data_stream == NULL) {
		printf("can't open file %s\r\n", filename);
		return -1;
	}

	/* 3、将文件指针重新调整到文件头 */
	fseek(data_stream, 0, SEEK_SET);  

	/* 4、向文件流写入数据 */
	ret = fwrite(str, sizeof(str), 1, data_stream);
    if(!ret) {
        printf("file read error!\r\n");
    } 

	/* 5、关闭文件 */
	fclose(data_stream);		
	return 0;
}

/*
 * @description		: main主程序
 * @param - argc 	: argv数组元素个数
 * @param - argv 	: 具体参数
 * @return 			: 0 成功;其他 失败
 */
int main(int argc, char *argv[])
{
	int ret = 0;
	unsigned int cmd;
	unsigned char str[100];

	if (argc != 1) {
		printf("Error Usage!\r\n");
		return -1;
	}

	dac_enable();	/* 是能DAC */
	while (1) {
		printf("请输入DAC原始值(0~4095):");
		ret = scanf("%d", &cmd);
		if (ret != 1) {				/* 参数输入错误 */
			fgets(str, sizeof(str), stdin);				/* 防止卡死 */
		} else {					/* 参数输入正确 */
			if((cmd < 0) || (cmd > 4095)) {
				printf("输入错误,请正确输入DAC值,范围:0~4095!\r\n");
				continue;
			}
			dac_set(file_path[OUT_VOLTAGE1_RAW], cmd);
			ret = dac_add_dac_read(&stm32dac);
			if(ret == 0) { 			/* 数据读取成功 */
				printf("DAC原始值:%d,理论电压值:%.3fV\r\n", stm32dac.dac_raw, stm32dac.dac_act);
				printf("ADC原始值:%d,实际电压值:%.3fV\r\n", stm32dac.adc_raw, stm32dac.adc_act);
				printf("\r\n");
			}
		}
	}
	return 0;
}

此测试程序是从上一节的 adc_app.c 的基础上修改得到,主要添加了设置 DAC 以及
读取 DAC 数据的内容。
①file_path 为需要操作的文件路径,有 DAC 和 ADC 对应的原始值、分辨率文件
②dac_dev 为 DAC 设备结构体
③dac_add_adc_read 函数读取 ADC 和 DAC 的原始值以及分辨率,并且计算出对应的实际电压值
④dac_enable 函数使能 DAC 输出,本质是向 out_voltage1_powerdown 文件写 0
⑤dac_disable 函数关闭 DAC 输出,本质是向 out_voltage1_powerdown 文件写 1
⑥dac_set 函数用于设置 DAC 原始值。dac_set 的 value 参数就是要设置的 DAC 原始值,这是个整形参数。但是 out_voltage1_raw 文件需要输入字符串,因此先使用 sprintf 函数将整形的 value 值转换为对应的字符串,然后才能调用 fwrite 函数将其写入到 out_voltage1_raw 文件中。

使用以下命令编译测试App:

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

参数的功能主要是使能浮点运算。
测试:
在这里插入图片描述

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

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

相关文章

读书笔记 -公司改造 和 紧迫感

读书笔记 -公司改造 - 三枝匡 读书笔记 -公司改造 - 三枝匡 2022 年夏天的时候在微信读书上读了这本书&#xff0c;这是我们 CSDN 的创始人蒋涛推荐的&#xff0c;当时记了一些笔记如下。 总结&#xff1a; 每个有一定的历史&#xff0c;比较成功、或者尚未非常成功的公司遇…

基于Java+SpringBoot+vue+element实现毕业就业招聘系统

基于JavaSpringBootvueelement实现毕业就业招聘系统 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

用最简单的案例带你掌握C++中各种指针

1、前言 指针&#xff0c;作为C/C中最神秘、功能最强大的语法&#xff0c;着实是难以理解 、难以掌握、难以运用。&#x1f625; 但是&#xff0c;能灵活的使用指针&#xff0c;对利用C/C开发程序将有很大的帮助&#xff0c;让我们一起来了解了解吧。 2、啥是指针&#xff1f…

参加《2022 中国开发者影响力盛典》我的 4 重收获!

感谢 CSDN 邀请&#xff0c;西红柿有幸参加了 2022 中国开发者影响力盛典暨 CSDN 企业生态汇&#xff0c;让我有了一个不虚此行的下午&#xff0c;也跟大家分享一下我在会上的 4 重收获吧~第一重收获&#xff1a;互联网圈大佬 会议聚焦开发者生态建设主题&#xff0c;分享了 CS…

分布式基础篇4 —— 基础篇完结

分类维护一、三级分类后端实现准备工作跨域问题关闭 ESLint 检查前端实现二、分类删除前端完善分类列表后端实现——删除配置发送请求代码片段前端实现——删除三、分类增加前端实现四、分类修改五、拖拽菜单拖拽效果实现拖拽数据收集拖拽功能完成拖拽功能完善六、批量删除品牌…

JS知识补充-JS原型链

概述JS原型链别名&#xff1a;隐式原型链作用&#xff1a;根据一定路径查找属性&#xff08;方法&#xff09;作用举例&#xff1a;我们定义一个构造函数Fn&#xff0c;使用此构造函数创建一个对象fn1&#xff0c;接着使用创建的对象fn1去调用toString方法并打印&#xff0c;我…

【阶段三】Python机器学习03篇:机器学习中的函数、机器学习中的梯度下降、机器学习的数据结构:张量与机器学习概率与统计基础

本篇的思维导图: 机器学习中的函数 函数描述了输入与输出的关系。在函数中,一个事物(输出)随着另一个(或一组)事物(输入)的变化而变化,如下图所示。 输入与输出的关系一般情况下,用x(或x1,x2,x3,…)表示输入,用y表示输出,并把它们叫作变量,…

Java设计模式中的设计原则/开闭原则、里氏代换原则和依赖倒转原则又是什么,怎么用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 3.设计原则 3.1 目的 提高软件系统可维护性与可复用性增加软件可扩展性与灵活性节约开发成本与维护成本 3.2 开闭原则 3.2.1 特点 对扩展开放&#xff0c;对修…

实战干货|自研数据存储迁移MySQL实战

背景 最近公司内部在做某自研数据存储的下线工作&#xff0c;这里我们暂且化名其为DistributeSQL&#xff0c;由于DistributeSQL不再进行服务支持&#xff0c;需要迁移项目中使用到该存储到其他数据存储中。 本篇来聊聊这次在数据存储迁移过程中的方案设计思路、实现的大致细节…

中老年服装电商小程序开发

近年来&#xff0c;随着网络的发展&#xff0c;中老年服装电商小程序开发有了很大的进步。这种平台不仅可以方便用户购买到最新最时尚的产品&#xff0c;而且还能帮助商家提高销售业绩。 1&#xff1a;中老年服装电商小程序开发的优势 中老年人对商品信息需求大、容易接受新鲜…

实验⼀:Windows主机漏洞利⽤攻击实践

永恒之蓝简介 永恒之蓝&#xff08;Eternal Blue&#xff09;爆发于2017年4月14日晚&#xff0c;是一种利用Windows系统的SMB协议漏洞来获取系统的最高权限&#xff0c;以此来控制被入侵的计算机。甚至于2017年5月12日&#xff0c; 不法分子通过改造“永恒之蓝”制作了wannacry…

【ROS】—— ROS重名问题(九)

文章目录前言1. ROS工作空间覆盖2. ROS节点名称重名2.1 rosrun设置命名空间与重映射2.1.1 rosrun设置命名空间2.1.2 rosrun名称重映射2.1.3 rosrun命名空间与名称重映射叠加2.2 launch文件设置命名空间与重映射2.3 编码设置命名空间与重映射2.3.1 重映射2.3.2 C 实现:命名空间3…

Maven基础学习——依赖配置(1):配置同一项目下的三个工程

依赖配置一、前言二、创建第一个工程三、新建第二个工程四、创建第三个工程五、配置1.每个工程的.xml文件2.文件配置六、结语一、前言 在讲述依赖配置时&#xff0c;需要使用实例来说明&#xff0c;在B站黑马课程&#xff08;第12小节&#xff09;中没有讲到如何配置基础的三个…

[Effective Objective] 熟悉Objective-C

了解 Objective-C Objective_C 是一种面向对象的语言。但与jave、C等语言不同&#xff0c;它使用了消息结构&#xff08;messaging structure&#xff09;而非函数调用&#xff08;function calling&#xff09;。Objective-C由Smalltalk演化而来&#xff0c;后者是消息语言的…

React 学习笔记总结(六)

文章目录1. redux 介绍2. redux 工作流程3. redux 的使用4. redux 完整结构补充5. redux的 异步action6. react-redux库 与 redux库7. react-redux库的 实战8. react-redux的connect 最精简写法9. react-redux的 Provider组件作用10. react-redux 整合UI组件 和 容器组件11. re…

webgl图形平移、缩放、旋转

文章目录前言平移图示代码示例缩放图示代码示例旋转公式推导代码示例总结前言 在webgl中将图形进行平移、旋转、缩放的操作称为变换或仿射变换&#xff0c;图形的仿射变换涉及到顶点位置的修改&#xff0c;通过顶点着色器是比较直接的方式。本文通过着色器实现对webgl图形的仿…

ArcGIS基础实验操作100例--实验65按字段调整点符号方向

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验65 按字段调整点符号方向 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff0…

计算机组成原理_总线

计算机组成原理总目录总线概述 1. 总线介绍 我们知道计算机中有CPU、主存、辅存&#xff0c;以及打印机、键盘、鼠标等等的一些外设 那么各个设备之间肯定是要进行数据传输的&#xff0c;这就需要许多线路将它们连接起来 第一种方法&#xff1a;两两相联 外设数量越多&#xf…

35、基于STM32的电子钟(DS1302)

编号&#xff1a;35 基于STM32的电子钟&#xff08;DS1302&#xff09; 功能描述&#xff1a; 本设计由STM32单片机液晶1602按键DS1302时钟组成。 1、采用STM32F103最小系统。 2、利用DS1302芯片提供时钟信号 3、液晶1602实时显示年月日、时分秒、星期等信息。 4、三个按键可…

隐形AR眼镜厂商Mojo Vision裁员75%,专注Micro LED技术

1月7日青亭网报道&#xff0c;隐形AR眼镜厂商Mojo Vision官方宣布了一项重大调整&#xff0c;其中因为产品进展问题&#xff0c;同时还有融资进展受阻等面临大裁员&#xff0c;将进行一系列中心调整&#xff0c;据了解本次裁员比例高达75%。重点关注&#xff1a;1&#xff0c;M…