-
【常用模块】HC-05蓝牙串口通信模块使用详解(实例:手机蓝牙控制STM32单片机)
2018-05-19 16:09:54HC-05蓝牙串口通信模块应该是使用最广泛的一种蓝牙模块之一了。为什么呢? 因为HC05模块是一款高性能主从一体蓝牙串口模块,可以不用知道太多蓝牙相关知识就可以很好的上手。说白了,只是个蓝牙转串口的设备,你...HC-05蓝牙串口通信模块应该是使用最广泛的一种蓝牙模块之一了。为什么呢?
因为HC05模块是一款高性能主从一体蓝牙串口模块,可以不用知道太多蓝牙相关知识就可以很好的上手。说白了,只是个蓝牙转串口的设备,你只要知道串口怎么编程使用,就可以了,实现了所谓的透明传输。
但是就是这么一个很常见的模块,网上很多的博客写的都是错的,或者都是很不详细的。
所以本文就介绍一下这款蓝牙通信模块的使用,包括蓝牙模块的调试、手机与蓝牙模块之间的传输、手机蓝牙控制STM32单片机,应该是逐渐深入的一个过程。但是这仅仅是使用,以后有时间应该会对蓝牙有一个稍微深度的学习,而不能仅仅是浮于表面,只会用。
模块名称:HC-05蓝牙串口通信模块
参考资料:HC-05蓝牙串口通信模块官方资料包
其他模块:USB转TTL模块、手机蓝牙串口助手app
手机蓝牙串口助手软件,可以点击链接下载:蓝牙串口。因为这是我见过所有手机端界面最好看的了,其他的界面都有点太糟糕了。
蓝牙模块的调试
准备工作
USB转TTL模块与HC-05蓝牙模块的接线:
两模块共地,两模块共VCC(VCC取5V);蓝牙模块的RX接转换模块的TX,蓝牙模块的TX接转换模块的RX。如下图所示:
这个时候就要将转换模块连接到电脑上,然后利用串口调试助手进行蓝牙模块的调试。
附可能会用到的驱动:链接:https://pan.baidu.com/s/1bpYLfCr 密码:yabv
蓝牙模块的调试
HC-05蓝牙串口通讯模块具有两种工作模式:命令响应工作模式和自动连接工作模式。在自动连接工作模式下模块又可分为主(Master)、从(Slave)和回环(Loopback)三种工作角色。
- 当模块处于自动连接工作模式时,将自动根据事先设定的方式连接的数据传输;
- 当模块处于命令响应工作模式时能执行AT命令,用户可向模块发送各种AT 指令,为模块设定控制参数或发布控制命令。
怎么进入命令响应工作模式?
进入命令响应工作模式有两种方法:
- 模块上电,未配对情况下就是AT模式,波特率为模块本身的波特率,默认:9600,发送一次AT指令时需要置高一次PIO11;
- PIO11 置高电平后,再给模块上电,此时模块进入AT 模式,波特率固定为:38400,可以直接发送AT指令。
什么叫做置高一次PIO11?
在蓝牙模块中有一个小按键,按一下就置高一次PIO11。也就是说,第一种方法需要每发送一次AT指令按一次;而第二种方式是长按的过程中上电,之后就无需再管了,直接发送AT命令即可。
需要注意一下,两种进入命令响应工作模式的方式使用的波特率是不一样的,建议使用第二种方式。
怎么区分进了命令响应工作模式呢?
在蓝牙模块上有灯,当灯快闪的时候,就是自动连接工作模式;当灯慢闪的时候,就是命令响应工作模式。
AT命令
进入到命令响应工作模式之后,就可以使用串口调试助手进行蓝牙调试了。
首先有一点,AT指令不区分大小写,均以回车、换行结尾。下面介绍常用的AT指令:
常用AT指令 指令名 响应 含义 AT OK 测试指令 AT+RESET OK 模块复位 AT+VERSION? +VERSION:<Param> OK 获得软件版本号 AT+ORGL OK 恢复默认状态 AT+ADDR? +ADDR:<Param> OK 获得蓝牙模块地址 AT+NAME=<Param> OK 设置设备名称 AT+NAME? +NAME:<Param> OK 获得设备名称 AT+PSWD=<Param> OK 设置模块密码 AT+PSWD? +PSWD:<Param> OK 获得模块密码 AT+UART=<Param1>,<Param2>,<Param3> OK 设置串口参数 AT+UART? +UART:<Param1>,<Param2>,<Param3> OK 获得串口参数 对于AT指令,有几点注意:
- AT+NAME?:获得设备名称,这个AT指令有很大可能性是没有返回的,因为我也看到了很多的例子……,但是其他的指令都是没有问题的,直接设置设备名称就行了;
- AT+UART?:获得串口参数,串口的参数一共有三个,波特率、停止位、检验位。其取值如下:
串口参数 参数名称 取值 波特率 2400、4800、9600、19200、38400、5760、
115200、230400、460800、921600、1382400
停止位 0:1位
1:2位
校验位 0:NONE 1:Odd 2:Even 其默认值为:9600,0,0。
例子:
本文中,蓝牙串口的波特率设置成115200。之后的内容,就会采用这个波特率来进行通讯了。
手机与蓝牙模块之间的传输
直接将蓝牙模块与转换模块连接,再讲其连接到电脑上,蓝牙模块直接进入自动连接工作模式。
此时手机打开蓝牙串口调试应用,用其来连接蓝牙模块。手机蓝牙串口助手软件,可以点击链接下载:蓝牙串口。万分推荐这款,因为界面脱离了那种黑不溜秋的感觉,比较简洁、清爽。
这个软件的使用:点击界面右下角蓝牙的标志,选择蓝牙进行连接。
然后在电脑上的调试助手和手机的蓝牙串口调试应用之间就可以相互传输了,比如:
可以清楚的看到:电脑向手机发送了“hello you”,手机向电脑发送了“hello world”。
手机蓝牙控制STM32单片机
之前的两个例子都是相比较而言比较简单的,这个例子将会涉及到程序的内容了。
实现功能:手机通过蓝牙,向STM32单片机发送消息,STM32接收到消息之后原封不动的返回给手机。当然如果掌握了这个例子,也可以修改成,手机发送特定的消息,然后,STM32单片机做出相对应的动作。比如:点亮LED等、发动电机等等。
连接说明
使用USART1进行试验,也就是说STM32选取PA9、PA10来和HC-05进行连接。同时手机通过蓝牙来和HC-05进行连接。
原理就是:手机通过蓝牙传输到HC-05上,再通过串口通信和STM32通信;而之前一般都是电脑上通过USB线转串口的方式,通过串口和STM32通信。本质上没有区别的。
这个时候就应该更加深刻地体会到了本文开篇的一句话:说白了,只是个蓝牙转串口的设备,你只要知道串口怎么编程使用,就可以了,实现了所谓的透明传输。蓝牙的相关一切都被封装起来了,都不需要接触到。
STM32控制程序
#include "stm32f10x.h" void My_USART1_Init(void) { GPIO_InitTypeDef GPIO_InitStrue; USART_InitTypeDef USART_InitStrue; NVIC_InitTypeDef NVIC_InitStrue; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIO端口使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口端口使能 GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStrue.GPIO_Pin=GPIO_Pin_9; GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz; GPIO_Init(GPIOA,&GPIO_InitStrue); GPIO_InitStrue.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitStrue.GPIO_Pin=GPIO_Pin_10; GPIO_InitStrue.GPIO_Speed=GPIO_Speed_10MHz; GPIO_Init(GPIOA,&GPIO_InitStrue); USART_InitStrue.USART_BaudRate=115200; USART_InitStrue.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USART_InitStrue.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; USART_InitStrue.USART_Parity=USART_Parity_No; USART_InitStrue.USART_StopBits=USART_StopBits_1; USART_InitStrue.USART_WordLength=USART_WordLength_8b; USART_Init(USART1,&USART_InitStrue); USART_Cmd(USART1,ENABLE);//使能串口1 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启接收中断 NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn; NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStrue.NVIC_IRQChannelSubPriority=1; NVIC_Init(&NVIC_InitStrue); } void USART1_IRQHandler(void) { u8 res; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { res= USART_ReceiveData(USART1); USART_SendData(USART1,res); } } int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); My_USART1_Init(); while(1); }
这段程序和【STM32】串口相关配置寄存器、库函数(UART一般步骤)中的程序一模一样,几乎没有什么改动。
区别就是,在UART实验中,USART1是和USB转串口模块连接在一起的,然后与电脑上的串口调试助手进行通信;现在改成USART1是和蓝牙模块连接在一起的,然后和手机上的蓝牙串口调试助手进行通信。
-
Arduino使用HC05蓝牙模块与手机连接
2017-09-18 10:32:16进入 At 模式进行蓝牙基本参数设置想要使用 Arduino 的蓝牙模块,首先要对蓝牙模块进行基本参数设置。基本参数设置主要包含:蓝牙名称、模式以及匹配密码等。设置蓝牙模块可以使用 USB-TTL 连接电脑使用串口调试软通过本文,可以了解到以下内容:
- 进入 AT 模式进行蓝牙基本参数设置
- Arduino 蓝牙控制 LED 电路设计以及代码编写
- 利用 Andorid 蓝牙串口调试软件测试功能
进入 At 模式进行蓝牙基本参数设置
想要使用 Arduino 的蓝牙模块,首先要对蓝牙模块进行基本参数设置。基本参数设置主要包含:蓝牙名称、模式以及匹配密码等。设置蓝牙模块可以使用 USB-TTL 连接电脑使用串口调试软件进入 AT 模式进行设置,也可以使用 Arduino 连接蓝牙模块进行设置,本文主要介绍后一种方法。
注意事项
在连接蓝牙的时候,要注意线的连接是否正确,检查清楚再进行通电,除此之外,还要主要不要让针脚短路,我在首次使用蓝牙模块的时候,因为没注意接线,导致一个蓝牙模块损坏了,只能发信息不能收信息,所以为了避免不必要的损失,这里要注意。
Arduino HC05 AT模式接线
进入 AT 模式设置蓝牙的接线如下:
Arduino 5V - VCC
Arduino GND - GND
Arduino Pin10 - TXD
Arduino Pin11 - RXD
在通电前检查接线是否正确连接
Arduino 进入 AT 模式代码
接下来,我们需要为使用 Arduino 设置蓝牙模块 AT 模式编写程序,这个程序是让我们可以通过 Arduino IDE 提供的
串口监视器
来设置蓝牙模块。详细的 Arduino 代码如下:#include <SoftwareSerial.h> // Pin10为RX,接HC05的TXD // Pin11为TX,接HC05的RXD SoftwareSerial BT(10, 11); char val; void setup() { Serial.begin(38400); Serial.println("BT is ready!"); // HC-05默认,38400 BT.begin(38400); } void loop() { if (Serial.available()) { val = Serial.read(); BT.print(val); } if (BT.available()) { val = BT.read(); Serial.print(val); } }
利用 Arduino IDE 串口监视器进行调试
首先,将 Arduino 断电,然后按着蓝牙模块上的黑色按钮,再让 Arduino 通电,如果蓝牙模块指示灯按2秒的频率闪烁,表明蓝牙模块已经正确进入 AT 模式。
打开 Arduino IDE 的串口监视器,选择正确的端口,将输出格式设置为Both: NL & CR
,波特率设置为38400
,可以看到串口监视器中显示BT is ready!
的信息。
然后,输入AT
,如果一切正常,串口显示器会显示OK
。
接下来,我们即可对蓝牙模块进行设置,常用 AT 命令如下:AT+ORGL # 恢复出厂模式 AT+NAME=<Name> # 设置蓝牙名称 AT+ROLE=0 # 设置蓝牙为从模式 AT+CMODE=1 # 设置蓝牙为任意设备连接模式 AT+PSWD=<Pwd> # 设置蓝牙匹配密码
正常情况下,命令发送后,会返回
OK
,如果没有返回任何信息,请检查接线是否正确,蓝牙模块是否已经进入 AT 模式,如果上述两点都没有问题,可能是蓝牙模块的问题,可以找蓝牙模块供应商咨询。
设置完毕后,断开电源,再次通电,这是,蓝牙模块指示灯会快速闪烁,这表明蓝牙已经进入正常工作模式。利用 Andorid 手机连接 Arduino 并控制 LED灯开关
我们完成了对蓝牙模块的设置后,我们将做一个可以通过手机蓝牙连接,控制 Arduino 开关 LED 灯的小实验。
Arduino 电路设计
这里的电路设计比较简单,主要是两部分:
- Arduino 与 HC05 模块连接
- Arduino 与 LED 连接
这里有两点需要注意,Arduino 上的 TXD 应与 HC05 模块上的 RXD 端连接,Arduino 上的 RXD 应与 HC05 模块上的 TXD 连接。
在下面的图例中,我的 LED 是直接连接在 Arduino Pin13 上,而实际电路连接中,因根据连接的 Led 灯的设计考虑是否需要串联电阻。
Arduino 蓝牙控制 LED 灯 程序设计
Arduino 程序代码如下:
void setup() { // 设置波特率为 38400 Serial.begin(38400); pinMode(13, OUTPUT); } void loop() { while(Serial.available()) { char c=Serial.read(); if(c=='1') { Serial.println("BT is ready!"); // 返回到手机调试程序上 Serial.write("Serial--13--high"); digitalWrite(13, HIGH); } if(c=='2') { Serial.write("Serial--13--low"); digitalWrite(13, LOW); } } }
Android 手机端调试
在 Android 端上进行调试,需要下载蓝牙串口调试 APP,可以根据喜好在各大应用商场搜索下载。
下载安装完成 APP 后,我们先打开手机的蓝牙设置,搜索并匹配好我们的蓝牙模块。然后打开蓝牙串口调试APP
,让 APP 连接上蓝牙模块,然后我们可以在 APP 中输入1
,接下来可以看到 LED 等亮了,并且能在 APP 中看到Serial--13--high
的返回(有些 APP 返回值可能不是返回在同一行)。我们再在 APP 中输入 2,可以看到 LED 熄灭, APP 中返回Serial--13--low
。小结
在这篇文章中,我们了解了在 Arduino 中使用 HC05 蓝牙模块的两个主要步骤,首先是进入
AT模式
对蓝牙模块进行设置,这里要注意接线的正确性,设置完成后,就可以将蓝牙模块的TX
与Arduino RX
连接,RX
与Arduino TX
连接,再通过 Arduino 程序中的Serial
来实现数据的传输与读取。最后,在通过 Android 上的蓝牙串口调试APP,来测试我们的试验是否成功。参考资料
蓝牙模块HC05
Arduino Bluetooth Basic Tutorial
本文为原创内容,由同一作者于早前发表于简书,Arduino使用HC05蓝牙模块与手机连接
-
Python-collections模块
2020-09-27 10:29:34collections模块 这个模块实现了特定目标的容器,以提供Python标准内建容器 dict、list、set、tuple 的替代选择。 Counter:字典的子类,提供了可哈希对象的计数功能 defaultdict:字典的子类,提供了一个工厂函数...collections模块
这个模块实现了特定目标的容器,以提供Python标准内建容器 dict、list、set、tuple 的替代选择。
- Counter:字典的子类,提供了可哈希对象的计数功能
- defaultdict:字典的子类,提供了一个工厂函数,为字典查询提供了默认值
- OrderedDict:字典的子类,保留了他们被添加的顺序
- namedtuple:创建命名元组子类的工厂函数
- deque:类似列表容器,实现了在两端快速添加(append)和弹出(pop)
- ChainMap:类似字典的容器类,将多个映射集合到一个视图里面
Counter
Counter是一个dict子类,主要是用来对你访问的对象的频率进行计数。
>>> import collections >>> # 统计字符出现的次数 ... collections.Counter('hello world') Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1}) >>> # 统计单词个数 ... collections.Counter('hello world hello lucy'.split()) Counter({'hello': 2, 'world': 1, 'lucy': 1})
常用方法:
-
elements():返回一个迭代器,每个元素重复计算的个数,如果一个元素的计数小于1,就会被忽略
-
most_common([n]):返回一个列表,提供n个访问频率最高的元素和计数
-
subtract([iterable-or-mapping]):从迭代对象中减去元素,输入输出可以是0或者负数
-
update([iterable-or-mapping]):从迭代对象计数元素或者从另一个 映射对象 (或计数器) 添加
>>> c = collections.Counter('hello world hello lucy'.split()) >>> c Counter({'hello': 2, 'world': 1, 'lucy': 1}) >>> # 获取指定对象的访问次数,也可以使用get方法 ... c['hello'] 2 >>> # 查看元素 ... list(c.elements()) ['hello', 'hello', 'world', 'lucy'] >>> c1 = collections.Counter('hello world'.split()) >>> c2 = collections.Counter('hello lucy'.split()) >>> c1 Counter({'hello': 1, 'world': 1}) >>> c2 Counter({'hello': 1, 'lucy': 1}) >>> # 追加对象,+或者c1.update(c2) ... c1+c2 Counter({'hello': 2, 'world': 1, 'lucy': 1}) >>> # 减少对象,-或者c1.subtract(c2) ... c1-c2 Counter({'world': 1}) >>> # 清除 ... c.clear() >>> c Counter()
defaultdict
返回一个新的类似字典的对象。
defaultdict
是内置dict
类的子类。class collections.defaultdict([default_factory[, ...]])
>>> d = collections.defaultdict() >>> d defaultdict(None, {}) >>> e = collections.defaultdict(str) >>> e defaultdict(<class 'str'>, {})
例子
defaultdict的一个典型用法是使用其中一种内置类型(如str、int、list或dict等)作为默认工厂,这些内置类型在没有参数调用时返回空类型。
>>> e = collections.defaultdict(str) >>> e defaultdict(<class 'str'>, {}) >>> e['hello'] '' >>> e defaultdict(<class 'str'>, {'hello': ''}) >>> # 普通字典调用不存在的键时,报错 ... e1 = {} >>> e1['hello'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'hello'
使用
int
作为default_factory
>>> fruit = collections.defaultdict(int) >>> fruit['apple'] = 2 >>> fruit defaultdict(<class 'int'>, {'apple': 2}) >>> fruit['banana'] # 没有对象时,返回0 0 >>> fruit defaultdict(<class 'int'>, {'apple': 2, 'banana': 0})
使用
list
作为default_factory
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] >>> d = collections.defaultdict(list) >>> for k,v in s: ... d[k].append(v) ... >>> d defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]}) >>> d.items() dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])]) >>> sorted(d.items()) [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
使用
dict
作为default_factory
>>> nums = collections.defaultdict(dict) >>> nums[1] = {'one':1} >>> nums defaultdict(<class 'dict'>, {1: {'one': 1}}) >>> nums[2] {} >>> nums defaultdict(<class 'dict'>, {1: {'one': 1}, 2: {}})
使用
set
作为default_factory
>>> types = collections.defaultdict(set) >>> types['手机'].add('华为') >>> types['手机'].add('小米') >>> types['显示器'].add('AOC') >>> types defaultdict(<class 'set'>, {'手机': {'华为', '小米'}, '显示器': {'AOC'}})
OrderedDict
Python字典中的键的顺序是任意的,它们不受添加的顺序的控制。
collections.OrderedDict
类提供了保留他们添加顺序的字典对象>>> o = collections.OrderedDict() >>> o['k1'] = 'v1' >>> o['k3'] = 'v3' >>> o['k2'] = 'v2' >>> o OrderedDict([('k1', 'v1'), ('k3', 'v3'), ('k2', 'v2')])
如果在已经存在的 key 上添加新的值,将会保留原来的 key 的位置,然后覆盖 value 值。
>>> o['k1'] = 666 >>> o OrderedDict([('k1', 666), ('k3', 'v3'), ('k2', 'v2')]) >>> dict(o) {'k1': 666, 'k3': 'v3', 'k2': 'v2'}
namedtuple
三种定义命名元组的方法:第一个参数是命名元组的构造器(如下的:Person1,Person2,Person3)
>>> P1 = collections.namedtuple('Person1',['name','age','height']) >>> P2 = collections.namedtuple('Person2','name,age,height') >>> P3 = collections.namedtuple('Person3','name age height')
实例化命名元组
>>> lucy = P1('lucy',23,180) >>> lucy Person1(name='lucy', age=23, height=180) >>> jack = P2('jack',20,190) >>> jack Person2(name='jack', age=20, height=190) >>> lucy.name # 直接通过 实例名.属性 来调用 'lucy' >>> lucy.age 23
deque
collections.deque
返回一个新的双向队列对象,从左到右初始化(用方法 append()),从 iterable(迭代对象)数据创建。如果 iterable 没有指定,新队列为空。
collections.deque
队列支持线程安全,对于从两端添加(append)或者弹出(pop),复杂度O(1)。
虽然list
对象也支持类似操作,但是这里优化了定长操作(pop(0)、insert(0,v))的开销。
如果 maxlen 没有指定或者是 None ,deque 可以增长到任意长度。否则,deque 就限定到指定最大长度。一旦限定长度的 deque 满了,当新项加入时,同样数量的项就从另一端弹出。支持的方法:
- append(x):添加x到右端
- appendleft(x):添加x到左端
- clear():清除所有元素,长度变为0
- copy():创建一份浅拷贝
- count(x):计算队列中个数等于x的元素
- extend(iterable):在队列右侧添加iterable中的元素
- extendleft(iterable):在队列左侧添加iterable中的元素,注:在左侧添加时,iterable参数的顺序将会反过来添加
- index(x[,start[,stop]]):返回第 x 个元素(从 start 开始计算,在 stop 之前)。返回第一个匹配,如果没找到的话,升起 ValueError 。
- insert(i,x):在位置 i 插入 x 。注:如果插入会导致一个限长deque超出长度 maxlen 的话,就升起一个 IndexError 。
- pop():移除最右侧的元素
- popleft():移除最左侧的元素
- remove(value):移去找到的第一个 value。没有抛出ValueError
- reverse():将deque逆序排列。返回 None 。
- maxlen:队列的最大长度,没有限定则为None。
>>> d = collections.deque(maxlen=10) >>> d deque([], maxlen=10) >>> d.extend('python') >>> [i.upper() for i in d] ['P', 'Y', 'T', 'H', 'O', 'N'] >>> d.append('e') >>> d.appendleft('f') >>> d.appendleft('g') >>> d.appendleft('h') >>> d deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'e'], maxlen=10) >>> d.appendleft('i') >>> d deque(['i', 'h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n'], maxlen=10) >>> d.append('m') >>> d deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'm'], maxlen=10)
ChainMap
问题背景是我们有多个字典或者映射,想把它们合并成为一个单独的映射,有人说可以用update进行合并,这样做的问题就是新建了一个数据结构以致于当我们对原来的字典进行更改的时候不会同步。如果想建立一个同步的查询方法,可以使用 ChainMap
可以用来合并两个或者更多个字典,当查询的时候,从前往后依次查询。简单使用:
>>> d1 = {'apple':1,'banana':2} >>> d2 = {'orange':2,'apple':3,'pike':1} >>> combined1 = collections.ChainMap(d1,d2) >>> combined2 = collections.ChainMap(d2,d1) >>> combined1 ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1}) >>> combined2 ChainMap({'orange': 2, 'apple': 3, 'pike': 1}, {'apple': 1, 'banana': 2}) >>> for k,v in combined1.items(): ... print(k,v) ... orange 2 apple 1 pike 1 banana 2 >>> for k,v in combined2.items(): ... print(k,v) ... apple 3 banana 2 orange 2 pike 1
有一个注意点就是当对ChainMap进行修改的时候总是只会对第一个字典进行修改,如果第一个字典不存在该键,会添加。
>>> d1 = {'apple':1,'banana':2} >>> d2 = {'orange':2,'apple':3,'pike':1} >>> c = collections.ChainMap(d1,d2) >>> c ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1}) >>> c['apple'] 1 >>> c['apple'] = 2 >>> c ChainMap({'apple': 2, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1}) >>> c['pike'] 1 >>> c['pike'] = 3 >>> c ChainMap({'apple': 2, 'banana': 2, 'pike': 3}, {'orange': 2, 'apple': 3, 'pike': 1})
从原理上面讲,ChainMap 实际上是把放入的字典存储在一个队列中,当进行字典的增加删除等操作只会在第一个字典上进行,当进行查找的时候会依次查找,new_child() 方法实质上是在列表的第一个元素前放入一个字典,默认是{},而 parents 是去掉了列表开头的元素
>>> a = collections.ChainMap() >>> a['x'] = 1 >>> a ChainMap({'x': 1}) >>> b = a.new_child() >>> b ChainMap({}, {'x': 1}) >>> b['x'] = 2 >>> b ChainMap({'x': 2}, {'x': 1}) >>> b['y'] = 3 >>> b ChainMap({'x': 2, 'y': 3}, {'x': 1}) >>> a ChainMap({'x': 1}) >>> c = a.new_child() >>> c ChainMap({}, {'x': 1}) >>> c['x'] = 1 >>> c['y'] = 1 >>> c ChainMap({'x': 1, 'y': 1}, {'x': 1}) >>> d = c.parents >>> d ChainMap({'x': 1}) >>> d is a False >>> d == a True
>>> a = {'x':1,'z':3} >>> b = {'y':2,'z':4} >>> c = collections.ChainMap(a,b) >>> c ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4}) >>> c.maps [{'x': 1, 'z': 3}, {'y': 2, 'z': 4}] >>> c.parents ChainMap({'y': 2, 'z': 4}) >>> c.parents.maps [{'y': 2, 'z': 4}] >>> c.parents.parents ChainMap({}) >>> c.parents.parents.parents ChainMap({})
-
Springboot构建多模块项目
2020-06-08 15:12:34首先新建一个springboot父项目 这里不选择其他的,直接next就好了,后续需要再添加。...继续创建2个module,分别为module和server,至此多模块springboot项目创建完成。建立完成后的项目结构: 父pom文.首先新建一个springboot父项目
这里不选择其他的,直接next就好了,后续需要再添加。
建立完成后项目结构如下,但是这是一个父项目,做版本控制,什么都不需要,所以我们要删除如下的东西。
选中的全部删除
然后开始建立子模块
注意这里需要选中springboot-dubbo然后右键
选择其中的quickstart
继续创建2个module,分别为module和server,至此多模块springboot项目创建完成。建立完成后的项目结构:
父pom文件:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> <modules> <module>module</module> <module>server</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>parent</artifactId> <version>0.0.1-SNAPSHOT</version> <name>parent</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
测试
model工程是我们放实体类和xml实现的地方,我们首先创建一个测试实体类user。
public class User { private String name; private Integer age; //省略get set方法 }
server是我们逻辑处理和controller存放的地方,首先我们在父pom中添加web依赖,即springboot-dubbo的pom:
<!--引入SpringBoot-WEB模块--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
然后创建测试用的启动类,及controller,结构如下:
SpringbootApplication:
@SpringBootApplication public class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); } }
@Controller @RequestMapping("user") public class HelloController { @RequestMapping("/printUser") @ResponseBody public User printUser(User user) { return user; } }
这里可以我们会报错,引入不了User这个类,因为我们要设置server依赖于工程model,server工程右键
然后apply,这时我们就可以导入User这个类了
但是因为我们是maven项目这种设置我们下次启动还是回丢失对Model的引用,所以我们需要在pom中引入对model的依赖
在server pom中添加如下依赖(可以根据提示,自动导入也是可以的)<dependency> <groupId>com.example</groupId> <artifactId>module</artifactId> <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency>
然后我们开始启动测试,启动 SpringbootApplication,然后看见控制台输出:
可以看到端口号配置生效
然后再浏览器访问:http://localhost:8083/user/printUser?name=‘你好’&age=666
浏览器显示:
至此多模块springboot项目构建完成。
-
安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯
2018-08-28 15:56:19(1)安卓手机与蓝牙模块联合调试(一)——蓝牙模块的串口通讯 (2)安卓手机与蓝牙模块联合调试(二)—— 单片机蓝牙控制LED灯亮灭(上) (3)安卓手机与蓝牙模块联合调试(三)—— 单片机蓝牙控制LED灯亮灭... -
工程模块
2020-04-19 12:29:21工程模块 1. 模块划分 项目共分为7大模块,分别如下: –start: 启动模块 –infrastructure:基础设施层 –query:查询层 –application: 应用层 –**domain:领域层–shared:共享层 –api:对外服务接口 ** 2. ... -
Python中几个非常有趣的模块
2019-10-24 12:16:05最近学习Python,发现了许多有趣的模块。感觉开启了新世界的大门,因为我也不是对所有模块都熟悉,所以今天不是讲代码。 1、ItChat 这是一个微信自动回复的模块,因为我微信一直无法登陆,所以也没有测试这个模块的... -
创翼错误118 pppoe拨号模块损坏
2019-04-20 16:21:58创翼错误118 pppope拨号模块损坏 . 1809版本、创翼的bug 一、新建一个.txt文件 二、复制下面代码到.txt文件里并保存 Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\... -
Python进阶(四十二)-windows 64位安装Pillow模块替换PIL模块
2017-04-19 19:42:27Python进阶(四十二)-windows 64位安装Pillow模块替换PIL模块 在利用Python做图像配准时,需要安装PIL(Python Image Lib)模块。而PIL官网提示信息为:“The current free version is PIL 1.1.7. This release ... -
调用自定义模块出现ModuleNotFoundError: No module named ‘XXX‘的解决方案
2019-03-08 16:07:45问题:确保将调用的模块与被调用的模块放在同一目录下,但仍出现ModuleNotFoundError: No module named ‘XXX’。 Python会在以下路径中搜索它想要寻找的模块: 程序所在的文件夹 标准库的安装路径 操作系统... -
Gradle多模块之父子模块
2019-07-22 09:57:56目录一:新建一个gradle工程二:修改工程三:新建子模块四:修改父模块setting.gradle五:修改gradle插件六:测试 利用gradle进行多模块架构,用于代码解耦 一:新建一个gradle工程 以springboot为例 选择gradle... -
Python 模块
2020-02-03 20:48:23Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。 模块让你能够有逻辑地组织你的 Python 代码段。 把相关的代码分配到一个模块里能让你的代码更好用,更易懂。 模块... -
IDEA多模块maven项目子模块无法引用父模块依赖
2020-05-27 23:14:35IDEA多模块maven项目子模块无法引用父模块依赖第一节 问题第二节 解决方案 第一节 问题 当在IDEA创建一个maven项目后,并在该项目下新建一个moudle后,使得前一个maven项目作为父模块,配置信息如下: MybatisDemo... -
VBA中窗体模块、标准模块和类模块的区别
2019-03-04 22:05:26VBA中窗体模块、标准模块和类模块的区别 -
AngularJS进阶(四十)创建模块、服务
2016-06-15 21:11:24AngularJS进阶(四十)创建模块、服务学习要点 使用模块构架应用 创建和使用服务 为什么要使用和创建服务与模块? 服务允许你打包可重用的功能,使之能在此应用中使用。 模块允许你打包可重用的功能,使之能跨应用使用... -
perl模块(创建模块,加载模块详解)
2017-02-22 18:38:27如何创建和加载perl模块,深入理解perl模块如何创建和加载perl模块深入理解perl模块 加载模块 1 编译阶段加载模块使用use 2 运行阶段加载模块使用require 3 使用no 创建模块 1 命名规则 2 创建传统模块 3 创建面向... -
python自定义模块与模块调用
2018-09-07 14:27:53在python中,一个.py文件就是一个模块,程序复杂的情况下,将代码做成一个个模块,然后调用,就能把大问题分解成一个个小问题。 使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同... -
隔离模块介绍-隔离电源模块
2018-09-14 10:07:29这里将隔离模块分为隔离电源模块和隔离信号模块部分,分别以隔离电源模块和光耦为目标进行介绍,大部分数据都来自相应的数据手册,侵删! 隔离模块介绍-隔离电源模块 1.介绍 DC-DC隔离电源,定压输入、非... -
Python的os模块简介
2018-01-14 12:52:28一、什么是os模块 os模块提供了多数操作系统的功能接口函数。当os模块被导入后,它会自适应于不同的操作系统平台,根据不同的平台进行相应的操作,在python编程时,经常和文件、目录打交道,这时就离不了os模块,... -
pycharm 之模块与模块引用
2017-10-11 12:09:09首先在pycharm,创建文件的快捷键...其次函数的模块调用规则如下图 模块引用并指导源文件函数:按住CTRL,点击函数即可 判断是否是主文件:name if name==’main’ 当前文件路径:file 当前文件描述:doc -
python serial模块
2012-06-06 15:16:34开发python串口的模块,简洁方便。在开发前,请确保安装此模块。 -
Python学习笔记(十六):关于模块和加载模块
2021-02-16 17:28:08Python学习笔记(十六):关于模块 模块的相关操作Python学习笔记(十六):关于模块一.导入模块importfrom...import二.自定义模块说明文档三.加载模块环境变量默认的模块加载路径四.__all__变量 一.导入模块 import... -
pyperclip模块
2018-05-06 18:44:54用 pyperclip 模块拷贝粘贴字符串pyperclip 模块有 copy()和 paste()函数, 可以向计算机的剪贴板发送文本, 或从它接收文本。将程序的输出发送到剪贴板, 使它很容易粘贴到邮件、文字处理程序或其他软件中。 ... -
python基础(十九):模块
2020-05-12 13:25:31文章目录一、模块介绍二、模块的使用1、import语句(1)基本用法(2)三种模块2、from ... import ... 语句(1)基本用法(2)from 模块名 import *3、其他导入语法(as别名)4、循环导入问题(1)测试一(采用执行... -
python导入模块import与常见的模块
2018-08-30 00:44:300.什么是python模块?干什么的用的? Java中如果使用abs()函数,则需要需要导入Math包,同样python也是封装的,因为python提供的函数太多,所以根据函数的功能将其封装在不同的module模块中。就这样的话,pthon... -
蓝牙模块的配置(HC05):修改密码、修改模块名字、修改波特率。
2018-11-24 11:31:29蓝牙模块是电子开发经常使用的模块,通常使用串口协议的方式与蓝牙通信, 从而完成数据的传输,串口通信很常见,用起来也很简单,几乎所有的单片机都配有串口通信功能。 蓝牙模块用于小数据量的无线传输,使用很... -
ImportError: No module named matplotlib.pyplot安装模块python
2017-09-19 10:31:21原文:https://my.oschina.net/letiantian/blog/339901http://www.cnblogs.com/sincoolvip/p/5966696.html环境...用上面的环境,测试一个曲线拟合的demo测试的时候,运行出错,原因是我的python没有安装模块。错误: I -
Python模块及不同目录下导入模块方法
2019-06-17 09:41:32一、模块 在实际程序开发过程中,随着我们代码越写越多,文件中代码越来越长,最终导致越来越难以维护。为了编写可维护代码,我们可以把很多函数分组,分别放到不同文件里。在Python中,一个 .py 文件就称为一个... -
python函数及常用模块
2017-03-06 18:37:39这一部分主要介绍了函数的概念和使用,以及生成器,迭代器,装饰器等python特性的学习,另外还有一些常用模块的介绍,包括time模块,os模块,re模块,logging模块,json&pickle;模块等等。这一部分内容涵盖了...
-
情感励志类短视频素材
-
hcsa day4
-
hebing
-
信息安全风险评估与风险管理.ppt
-
软件开发的7大原则
-
PPT大神之路高清教程
-
MySQL 高可用(DRBD + heartbeat)
-
2021.3.1blog
-
友邦.rar电气设备选型资料大全 (适合刚刚入行的电气工程师对设备进行选型规划)详解
-
尚观教育嵌入式4个月培训课堂笔记
-
Win10 Dolby Atmos Speaker System 杜比全景声(Dolby Atmos)扬声器系统.zip
-
VMware vSphere ESXi 7 精讲/VCSA/VSAN
-
Git&GitHub入门(MAC)
-
将Anaconda3创建的虚拟环境打包成Docker环境
-
MySQL Router 实现高可用、负载均衡、读写分离
-
唯恩.rar电气设备选型资料大全 (适合刚刚入行的电气工程师对设备进行选型规划)详解 报价
-
NFS 实现高可用(DRBD + heartbeat)
-
ML 方案 .pdf
-
Zheng方案.pdf
-
MySQL 多实例安装 及配置主从复制实验环境