从零开始手搓一个STM32与机智云的小项目——GPIO的输入输出

news2024/11/25 4:35:04

文章目录

  • 前言
  • GPIO简介
    • GPIO的命名与数量
    • GPIO的功能
    • STM32F1 GPIO的寄存器
  • 库函数开发
    • 搭建库函数的工程
    • 查看原理图
      • WACK_UP输入按键
      • 继电器输出
      • 138控制流水灯
    • 代码编写
      • 库函数简介
      • GPIO输出模式控制继电器
      • 通过138控制led
      • GPIO实现按键输入的操作
      • 编写逻辑代码
    • 实物效果
  • 总结

前言

上一篇中,对整个板子的硬件组成做了一个简单的介绍,本文开始进入程序编写的环节,首先来搞定最简单的GPIO输入输出控制。

GPIO简介

GPIO全称叫做通用输入输出接口,它是单片机内核、片上外设与外部电路连接的桥梁,是单片机与外界进行数据交换的通道。

GPIO的命名与数量

GPIO的端口号是从PA、PB——PI;一共9个端口号,每个端口号上有0-15共16个管脚号,也就是说STM32最多可以有16*9=144个GPIO。但是在实际设计过程中,有很多小项目是用不上这么GPIO口的,所以厂商会对IO口进行裁剪,但是命名规则还是保持不变,只是会裁剪一些组别。
就拿本次使用STM32F103C8T6来说,它的封装一共有48个引脚,但是GPIO的数量只有37个,还有11个引脚不是GPIO。
在这里插入图片描述
如下图中的红色框的电源引脚(9个)、绿色框的复位引脚(1个)、橙色框的BOOT选择(BOOT0 1个)这些引脚是已经定死了功能的,除此之外还有一部分GPIO,如蓝色框的外部时钟引脚,以及BOOT1的PB2这些都是GPIO口,但是又兼顾着外部时钟输入、BOOT选择的功能,一般也不做为GPIO来使用。
在这里插入图片描述
除了上述这些引脚外,还有支持SW下载与JTAG下载调试的GPIO也需要注意,在实际使用过程中需要配置后才可正常使用。
在这里插入图片描述

GPIO的功能

了解了GPIO的命名和数量之后,接下来就需要知道GPIO有哪些功能。
在嵌入式学习笔记——认识STM32的 GPIO口中,我们详细分析了STM32F4的GPIO口的结构以及框图,知道了GPIO有模拟、复用、通用三种大模式,其中模拟功能是专用于处理模拟量的输入;复用模式,主要是配合各类片上外设完成各种输入或者输出的操作;通用模式就是检测输入的高低电平以及控制输出的高低电平。
那么STM32F1的GPIO会有区别吗,首先,从功能来说,几乎一致,只是在具体的配置过程中需要做一点小小的修改,具体的不同之处,在寄存器部分介绍。
在这里插入图片描述

STM32F1 GPIO的寄存器

首先来对比一下F4与F1的GPIO寄存器,对比二者的中文编程手册可以看出来,F1没有F4的端口模式寄存器、端口输出类型寄存器以及端口输出速度寄存器。取而代之的是端口配置低寄存器和端口配置高寄存器。
在这里插入图片描述
那么具体的使用是怎样的呢?
在编程手册中查看一下寄存器的具体描述就可以搞清楚了,如下图所示,原来F1的端口配置寄存器就是将F4中的模式寄存器、输出类型、输出速度寄存器给整合在一起了。每四位控制一个GPIO管脚,低两位控制模式与输出速度,高两位根据输入或者输出模式进一步细化功能。端口配置低寄存器控制管脚0-7,端口配置高寄存器控制管脚8-15。
在这里插入图片描述
然后就是输入数据寄存器与输出数据寄存器的使用,这部分与F4的是一样的,这里不再做赘述,需要了解的可以去上面的嵌入式笔记链接查看。
本文先使用最简单的通用模式完成输入按键的检测以及输出控制LED的操作。

库函数开发

由于在上一个系列中,笔者用的全部是寄存器的开发,为了更加完善整个系列,这个小项目就使用基础库函数来进行开发,库函数开发的优势在于,可以减少开发者翻阅手册的时间,以提高开发效率,但是初学者,建议可以去钻研一下寄存器的开发,通过最底层的寄存器操作会让自己对单片机的整个结构有一个更加清晰的认识,这样对于库函数的使用也有一些帮助,如果直接上库函数的话,总会有一些小地方会让你不明所以,最后搞的自己云里雾里,似懂非懂的。

搭建库函数的工程

这个工程搭建的具体步骤就不做记录了,后面看大家的反馈情况,如果有需要,笔者后面再出一期,其实大致流程与之前的F4那个差不多,只是需要将库的源文件都导入工程。
工程搭建好后,编写一个简单的main.c进行验证,编译结果显示0errors即可。
在这里插入图片描述
关于编译出来的一堆东西,上图中也为大家做了一个简单的介绍,
其中Code 和 RO-data之和表示程序占用 Flash 空间的大小;RW-data 和ZI-data之和表示运行时占用的 RAM 的大小;而我们实际烧录进单片机的数据所占Flash大小则是Code+RO-data+RW-data的大小。上面提到了有关代码段,数据段,在ZI-data中其实还包含有堆和栈的,这部分与C语言中的内存分配有异曲同工,想要了解的同学可以看看下面这几篇的介绍
1.【IoT】STM32 内存分配详解
2.stm32的内存分布
3.keil 编译完 Program Size: Code RO-data RW-data ZI-data 的含义
4.C语言:内存分配—栈区、堆区、全局区、常量区和代码区
好了,上面这个只是一个拓展小知识,感兴趣的可以去了解一下,回归正题,接下来开始代码的编写。

查看原理图

WACK_UP输入按键

还记得这个板子的按键输入与GPIO输出有哪些吗?
看一眼原理图,首先是按键输入,在之前的原理图介绍中提到了,这个五方向按键的上下左右用的是ADC采样来实现,而WACK_UP按键采用的是普通的按键输入模式。
在这里插入图片描述
观察原理图可以发现,WACK_UP没有按下的时候是低电平,当按键按下的时候是高电平,因此对应的PA0需要在配置过程中直接配置为浮空输入即可。

继电器输出

然后来看通用输出模式控制的外设,第一个是继电器模块,这里的继电器使用了一个NMOS来做下半臂的控制,当栅极也就是RELAY没有电压时(输出0),NMOS不导通,继电器线圈不得电,常开触点不吸合,USB口无输出;当RELAY有电压时(输出高),NMOS导通,继电器线圈的电,常开触点吸合,USB口有输出。也就说,PA12需要配置为通用的推挽输出。
在这里插入图片描述

138控制流水灯

除了继电器之外,还有一个电路也是使用到了GOIO的通用推挽输出模式来实现的,那就是失败了一半的74HC138译码器控制LED流水灯的电路。
在这里插入图片描述
138的译码器的管脚介绍如下图所示,A0-A2三个脚输入,控制Y0-Y7的输出,E1、E2为使能脚,低电平有效,E3也是使能脚高电平有效,三个使能脚要同时在有效电平才可以正常工作。
在这里插入图片描述
其真值表如下:
可以看到,当E1、E2、E3分别为001时,随着A0-A2的输入的改变,Y0-Y7的输出会做出对应的更改。
在这里插入图片描述
注意原理图在LED与138之间还有一个芯片叫做74HC245,这个芯片这次主要是提高驱动能力,由于138本身的驱动能力不强,所以加了一个缓冲芯片,它的功能表如下:OE是使能脚,低电平有效,DIR是决定输出方向的,当DIR为低电平时,Bn端是输入,An端的输出等于Bn对应口的输入。当DIR为高电平是,An端为输入,Bn端的输出等于An的输入。
在这里插入图片描述
具体的芯片描述大家去查看一下芯片手册哈。
经过一顿倒腾后,LED的点亮输出控制逻辑如下:
在这里插入图片描述

代码编写

好了,弄清楚了上述模块的原理图后,接下来就是编程实现对应功能了。

库函数简介

当我们拿到库函数后,要怎么进行开发呢?
首先,需要搞清楚库函数的结构,官方按照各个模块进行了底层的初始化库函数的编写,在实际使用过程中,直接在对应模块名的.h文件中查找对应的内容即可,下面以GPIO为例。
打开"stm32f10x_gpio.h",可以发现整.h文件其实就是三大类内容,
一类是各种宏定义,一类是结构体,还有一类是函数的声明。

在这里插入图片描述

1.宏定义往往是各类具体的配置定义, 2.结构体是留给编程人员做配置的接口, 3.函数声明则是具体的功能实现。
库函数的好处就在于,可以减少开发者翻阅手册底层查阅的次数,使用结构体、宏定义、函数接口就可以完成对应模块的使用,而具体的使用步骤笔者大致总结为如下流程:

1、查找对应的初始化结构体,如上图中的GPIO_InitTypeDef
2、根据结构体声明变量,并根据实际的使用需求对结构体的各个成员变量进行赋值(例如:如:配置管脚是GPIO_pin_12);
3、赋值完成后需要调用初始化的函数,将结构体的参数实际写入到底层寄存器中(GPIO_Init);
4、调用相关的功能函数实现想要的功能(GPIO_SetBits)。
下面,就按照上面的步骤来实现一下具体的操作吧。

GPIO输出模式控制继电器

编程思路,根据前面的原理图分析,可以知道,此处的对应的GPIO是PA12,需要通过GPIO输出高低电平来实现继电器的吸合和断开。因此,可以知道GPIOA12需要配置为通用推挽输出模式,按照上一系列的寄存器编程思路,需要去查找对应的寄存器和框图,然后对着框图找到编程流程,最后参考流程以及寄存器描述来进行编写代码,但是,在库函数中就不用这么麻烦了,根据上面总结的初始化流程

1.首先,先将GPIO的初始化结构体来过来做个变量定义。

GPIO_InitTypeDef  GPIO_InitStructure;//定义一个结构体的变量

2根据实际所需对结构体的成员进行配置
结构体中,一共有三个参数,分别是引脚号、速度以及模式。
在这里插入图片描述

这里的结构体变量成员的赋值已经在对应的宏定义组中给出了,实际使用时只需要搜索定位到对应的宏定义组,找到自己所需的参数即可,举个例子吧,现在需要初始化GPIOA12号管脚,那么结构体的赋值中GPIO_Pin的赋值要怎么给定呢,可以看见在成员变量的后面有一个注释“GPIO_pins_define”,选中这个宏名然后查找下一个,找到对应的管脚宏定义组,在组内找到对应的管脚标号即可,由于是GPIOA12所以选择GPIO_Pin_12。
在这里插入图片描述
同样的操作,结构体的第二个第三个参数也是如此操作,当然,对于采用枚举定义参数组,可以直接在注释后面的参数上右键跳转,能跳转过去的就直接选取参数,不能跳转的就使用上面的查找方式来实现。
“GPIO_Speed”右键跳转实现,选择 “GPIO_Speed_2MHz”
在这里插入图片描述
“GPIO_Mode”右键跳转实现,选择 “GPIO_Mode_Out_PP”
在这里插入图片描述
上面的模式选择,与输出端口配置寄存器里面的模式是一一对应的关系。
在这里插入图片描述

将结构体的成员进行如下的初始化。

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//选择对应的引脚号
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//配置输出速度
GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//通用推挽输出

3.调用初始化函数将结构体的数据写入底层。

第二步还只是将参数赋值给了结构体变量,还没有实际生效,还需要将结构体的内容实际写入到寄存器中才行,因此需要调用下方的函数。在
在这里插入图片描述
在对应的.c中有具体的描述,包括了函数的功能以及上面的结构体指针。

GPIO_Init(GPIOA,&GPIO_InitStructure );//初始化GPIOA,将接固体参数写入寄存器中。

其实仔细观察底层的函数操作,就可以看到在寄存器编程中常用的位操作,本质是一样的都是操作寄存器。
在这里插入图片描述

4 调用功能函数,实现具体的功能,在继电器的使用中使用函数来操作GPIO口输出高低电平。

实际使用到的函数是如下两个,一个是对对应位置位写1,另一个是对对应位清除位写0。通过这两个函数就可以实现对指定管脚输出的高低电平控制了。
在这里插入图片描述
但是,完成上面这四步还不能实现控制,因为整个过程中还有很重要的一步没有做,之前在寄存器编程的阶段,提到过,所有的片上外设在使用之前,必做的一步就是开启时钟,这里还没有开启,自然是不可以使用,那么时钟的开启是不是也应该有对应的库函数呢,答案是肯定的,时钟对应的是stm32f10x_rcc.h
在找对应的功能函数之前,还需要找到GPIO所挂接的时钟总线位置,在数据手册的框图位置,通过下图可看见,GPIOA是挂接在AP2上面的,因此只需要在stm32f10x_rcc.h种找到APB2相关的初始化函数就可以了。
在这里插入图片描述
在stm32f10x_rcc.h,找到如下函数,APB2对应上图中的APB2,Periph是外设的意思,ClockCmd时钟控制命令。
在这里插入图片描述
跳转到在stm32f10x_rcc.c中查看具体的函数描述,以及其参数的介绍:通过上方的函数描述,可以知道这个函数的两个形参值该怎么给定。第一个形参选择 “RCC_APB2Periph_GPIOA”,第二形参选择“ENABLE”
在这里插入图片描述
然后将上面的这几句代码稍微封装一下变成一个初始化的函数,同时将输出高低电平用宏定义修饰一下,便于理解和调用。

#define Relay_ON   GPIO_SetBits(GPIOA,GPIO_Pin_12)//GPIO输出高
#define Relay_OFF  GPIO_ResetBits(GPIOA,GPIO_Pin_12)//GPIO输出低
#define Relay_TUN  GPIOA->ODR ^= (1<<12)//异或操作实现翻转


/*********************************
函数名:Relay_Init
函数功能:继电器初始化
形参:void
返回值:void
备注:
Relay-----PA12--------通用推挽输出
**********************************/
void Relay_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;//定义一个结构体的变量
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//初始化GPIOA端口的时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//通用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure );
	
	Relay_OFF;
}

这样继电器的控制就搞定了,在主函数调用初始化,然后在需要应用的地方调用宏执行操作即可。

通过138控制led

至于通过138来控制LED,本质与继电器没啥区别,这里就不做详细介绍了,处理思路和上面一模一样,有一点不同之处在于,实际的输出控制中,笔者使用了位带操作,也就是类似51单片机种P0.0=1输出高,P0.1=0输出低一样的操作,这里实际上就是直接用宏定义操作了ODR的指定位置,与之前的寄存器操作差异不大。感兴趣的同学可以自己根据宏定义去推导一下。
在这里插入图片描述
在这里插入图片描述
这里给出关键代码:


#define ADD0  PAout(4)// PA4
#define ADD1  PAout(5)// PA5
#define ADD2  PAout(6)// PA6
#define EN    PAout(7) //PA7
#define LED1_ON   {ADD0 = 1; ADD1=1;ADD2=1; EN=1;}//111,对应0111 1111 
#define LED2_ON   {ADD0 = 0; ADD1=1;ADD2=1; EN=1;}//110,对应1011 1111 
#define LED3_ON   {ADD0 = 1; ADD1=0;ADD2=1; EN=1;}//101,对应1101 1111
#define LED4_ON   {ADD0 = 0; ADD1=0;ADD2=1; EN=1;}//100,对应1110 1111
/*********************************
函数名:Led_Init
函数功能:led灯初始化
形参:void
返回值:void
备注:74HC138译码器的ADD0-ADD1-ADD2-EN
ADD0-----PB4
ADD1-----PB5
ADD2-----PA6
EN-------PA7
**********************************/
void Led_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;//定义一个结构体的变量
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//初始化GPIOA端口的时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_Out_PP;//通用推挽输出
	GPIO_Init(GPIOA,&GPIO_InitStructure );
}

GPIO实现按键输入的操作

讲完了通用输出,再来看看通用输入的使用,前面的硬件介绍中知道,此时操作的是GPIOA0,配置为输入模式,不需要上下拉的操作,既然遇到了GPIO的初始化,那么自然是需要借用上面初始化GPIO的思路,只是需要在结构体成员的参数配置上修改即可。由于是输入模式,所以结构体中的引脚输出速度这个成员就可以不用配置了。

/*********************************
函数名:Key_Init
函数功能:按键初始化
形参:void
返回值:void
备注:
KEY1(wake up)-----PA0-----高有效
**********************************/
void Key_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;//定义一个结构体的变量
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//初始化GPIOA端口的时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//指定初始化的管脚号
	GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOA,&GPIO_InitStructure );//调用初始化函数写入到寄存器中。
}

关于获取按键的输入状态,自然也是有对应的应用函数:
在这里插入图片描述
根据函数的描述,为了在调用过程中更加易读,与上面的输出操作一样,使用宏定义来优化一下。

#define KEY1   GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_0)

当然,只要使用到按键,就有一个避无可避的问题,按键消抖的问题,这里不在做赘述了,不了解的同学可以去我上一个系列进行学习。
这里也是直接给出代码:


/**************
函数名:KEY_Scanf
函数功能:按键初扫描函数
函数形参:void
函数返回值:u8
备注:
KEY1(wake up)-----PA0-----高有效 ----返回键值1
**************/
u8 KEY_Scanf(void)
{
	u8 key_value = 0;
	//判断按键按下了
	//标志位
	static u8 key_flag = 0;
	if( KEY1==1 && key_flag==0 )  //判断是否按下了按键
	{
		Systick_Delay_ms(10);//消抖
		if(KEY1==1)
		{
		  key_flag = 1;  //按下按键就锁上了
		  key_value=1;
		}
	}
	if( KEY1==0 && key_flag==1 )  //按下了按键之后 是否松手了
	{
		key_flag = 0;  //解锁
	}
	
	return key_value;
}

编写逻辑代码

三个模块的初始化就完成了,接下来就是在主函数中编写逻辑代码进行验证。这里我加了串口和系统滴答来辅助测试,这两个东西在后面会介绍到。最终是可以正常检测按键输入以及实现LED、继电器的控制的。
在这里插入图片描述

实物效果

在这里插入图片描述

总结

关于这个板子最基础的输入输出模块的功能实现就介绍到这,文中如有不足之处欢迎大家批评指正。

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

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

相关文章

Redis学习总结(二)

AOF 为什么是在执行完命令之后记录日志&#xff1f; 关系型数据库&#xff08;如 MySQL&#xff09;通常都是执行命令之前记录日志&#xff08;方便故障恢复&#xff09;&#xff0c;而 Redis AOF 持久化机制是在执行完命令之后再记录日志。AOF 记录日志过程为什么是在执行完命…

如何让GPT不再胡说八道

相信我们大部分人在使用GPT的时候&#xff0c;会发现GPT经常在胡言乱语、回复错误的答案等情况&#xff0c;甚至有的内容牛头不对马嘴&#xff0c;直接开始编造&#xff0c;例如下面案例&#xff1a; 我&#xff1a; 周树人是谁 GPT&#xff1a;周树人 (1897年-1975年) &…

独立开发变现周刊(第90期):自学开发了一个36万美元/年的ChatGPT应用

分享独立开发、产品变现相关内容&#xff0c;每周五发布。 目录 1、ChatGPT-Midjourney: 开源 ChatGPTMidjourney 网页应用2、PLExtension: 一个图床上传浏览器扩展3、EasySpider: 一个可视化爬虫软件4、BibiGPT: 音视频 AI 一键总结 & 对话5、自学的程序员开发了一个36万美…

【i阿极送书——第四期】《ChatGPT时代:ChatGPT全能应用一本通》

系列文章目录 作者&#xff1a;i阿极 作者简介&#xff1a;数据分析领域优质创作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1;评论&#x1f4d2;…

MongoDB集群和安全

目录 副本集-Replica Sets简介副本集的三个角色副本集架构目标副本集的创建主节点副本节点仲裁节点初始化配置副本集和主节点查看副本集的配置内容查看副本集状态添加副本从节点添加仲裁从节点副本集的数据读写操作 主节点的选举原则完整的连接字符串 分片集群-Sharded Cluster…

spring杂记

1、springboot是如何解析yml配置文件中的 tomcat配置&#xff0c;并将其赋值给 tomcat的 重要类 ServerProperties。该类为解析yml文件中的server配置 下面我们主要看看是怎样将 端口号 port 赋值给tomcat的 找到port属性&#xff0c;点击getter方法 发现调用该方法的地方为 …

在弹出框内三个元素做水平显示

最终效果图要求是这样&#xff1a; js代码&#xff1a; // 显示弹出窗口 function showPopup(node) {var popup document.createElement(div);popup.className popup;var inputContainer1 document.createElement(div);/* inputContainer1.className input-container1; */…

Upscayl:开源AI图像放大增强工具 | AIGC实践

连续写了两篇比较理论的文章——一篇行业思考&#xff0c;一篇技术讨论——可能劝退了很多不明真相的人民群众&#xff0c;一看后台数据&#xff0c;好么…… 马上周末了&#xff0c;今天分享一篇轻松小文&#xff0c;介绍一款开源免费、成熟度高、操作简单、效果显著的开源AI图…

记录--开始使用Vue 3时应避免的10个错误

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 Vue 3 稳定已经有一段时间了。许多代码库正在生产中使用它&#xff0c;其他人最终也必须进行迁移。我有机会与它一起工作&#xff0c;并记录了我的错误&#xff0c;这可能是你想避免的。 1.使用响应式…

.Net8罕见的技术:MSIL的机器码简析

前言 一般的只有最终的汇编代码才有机器码表示&#xff0c;然一个偶然的机会发现&#xff0c;MSIL(Microsoft intermediate language)作为一个中间语言表示&#xff0c;居然也有机器码&#xff0c;其实这也难怪&#xff0c;计算机里面万物都是二进制&#xff0c;本篇来看下,以下…

【GitHub探索】用python写web前端之reactpy探索

你有想象过用python来写web前端这种操作么&#xff1f;近期在github-trending上就有这样的一个项目reactpy&#xff0c;可以满足你在python上写web前端的欲望。为此&#xff0c;笔者也决定踩踩坑&#xff0c;看看这个项目的形式到底如何&#xff0c;能不能很方便地实际投产。 …

对比 document.URL 和 location.href

对比 document.URL 和 location.href document.URL 和 location.href 的不同点 document.URL只读 , location.href读写 给 document.URL 赋值, document.URL的值不会改变 给 location.href 赋值, location.href 的值改变了, 并且页面也改变了, 效果和 location.assign()一样…

解数独--难的一批

1题目 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 数…

【MySQL】数据库SQL语句之DML

目录 前言&#xff1a; 一.DML添加数据 1.1给指定字段添加数据 1.2给全部字段添加数据 1.3批量添加数据 二.DML修改数据 三.DML删除数据 四.结尾 前言&#xff1a; 时隔一周&#xff0c;啊苏今天来更新啦&#xff0c;简单说说这周在做些什么吧&#xff0c;上课、看书、…

ubuntu编译安装pcl

环境配置&#xff1a; ubuntu18.04pcl1.11.0 下载源码并解压 tar -zxvf pcl-pcl-1.11.0.tar.gz 进入解压后的文件夹、建立bulid文件夹并进入该文件夹 安装依赖 sudo apt-get update 使用apt-get包管理器安装CMake&#xff1a; sudo apt-get install cmake 使用apt-get包管理…

创新案例 | 新锐品牌Usmile如何借助社媒运营打造爆品成为国产电动牙刷TOP1?

Usmile 是广州星际悦动股份有限公司旗下全面口腔护理品牌。2016 年至今&#xff0c;Usmile共荣获了 16 项国内外设计大奖&#xff0c;2020 年“双十一”期间&#xff0c;入选 2020 年度天猫十大新品牌&#xff0c;销售额超 1 亿&#xff0c;成为国内首个破亿的电动牙刷品牌&…

【立体视觉(一)】之成像原理与相机畸变

【立体视觉&#xff08;一&#xff09;】之成像原理与相机畸变 一、成像原理一&#xff09;针孔模型二&#xff09;坐标系转换1. 世界坐标系到相机坐标系2. 相机坐标系到图像坐标系3. 图像坐标系到像素坐标系4. 相机坐标系到像素坐标系5. 世界坐标系到像素坐标系 二、相机畸变一…

618数码节该如何挑选,推荐几款618值得入手的数码好物

又到了一年一度的618剁手季&#xff0c;各大电商平台都纷纷推出了超级大促活动&#xff0c;激发了无数值友的狂热购物欲望。你是否也已经开始摩拳擦掌&#xff0c;准备掏钱包买买买呢&#xff1f;那么赶快听听小编的建议吧&#xff01;经过自己使用的亲身体验&#xff0c;小编给…

Superset | 地图无法显示的问题

知识目录 一、写在前面二、Superset地图显示不了三、Superset无法加载已更新的MySQL数据库数据 一、写在前面 大家好&#xff01;我是初心&#xff0c;一直在寻找并尝试着适合自己的方向&#xff01; Apache Superset是一款由Python语言为主开发的开源时髦数据探索分析以及可…

高通 Camera HAL3:集成camxoverridesettings.txt到整机版本

camxoverridesettings.txt 是高通提供给开发者临时进行CAMX、CHI-CDK功能调试的一种方式&#xff0c;通过配置各种变量值然后写入到该文件&#xff0c;能控制Log打印、参数配置、数据dump等多种功能 这个文件需要集成在设备目录的vendor/etc/camera/里 因为camxoverridesetti…