电子工程师成长之路

让更多人少走弯路,更快成长


  • 首页

  • 归档

  • 搜索

搭在Ubuntu中安装eclipse图文详解“

发表于 2019-11-21

1.首先得先下载JDK和eclipse

jdk下载网址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

eclipse下载网址:http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/heliossr1/

2.安装JDK
2.1解压JDK
将JDK解压到/opt/jvm文件夹下,所以得先在/opt下新建一个jvm文件夹,而要在opt文件夹下新建文件夹需要获取root权限,所以需要sudo指令。在/opt下新建文件夹jvm的指令:

1
sudo mkdir /opt/jvm

输入指令之后,需要输入密码才能够执行,输入密码的过程是不会显示出来的,直接输入密码按回车就可以了
2.2 创建完文件夹之后,需要将JDK复制到jvm文件夹下
采用的指令为:

1
mv jdk-8u151-linux-x64.tar.gz /opt/jvm (得先用su指令进入root权限)

2.3 解压JDK到/opt/jvm目录下.
首先得先进入到/opt/jvm目录下,通过指令:

1
cd /opt/jvm

然后解压文件:

1
tar zxvf jdk-8u121-linux-x64.tar.gz -C /opt

4.配置JDK的环境变量。
(1)打开 /etc/profile,打开指令:sudo vi /etc/profile。通过这条指令之后,会进入vim编辑器,要在vim编辑器里面插入数据需要使用i指令,vim的常用指令如下:
光标运动: h,j , k, l (上/下/左/右)
删除字符: x
删除行 : dd
模式退出 : Esc,Insert(或者i)
退出编辑器 : q
强制退出不保存: q!
运行shell命令 :sh(使用exit返回vi编辑器)
保存文件 :w
文本查找 : /
(2)打开文件后,在文件末尾加入以下语句,每条语句之间要空一行

export JAVA_HOME=/opt/jvm/jdk1.8.0_191

export JRE_HOME=${JAVA_HOME}/jre

export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:CLASSPATH

export PATH=${JAVA_HOME}/bin:$PATH

输入这个内容后需要先按ESC,再按“:”,最后输入wq回车,就能够退出保存
(3)查看JDK是否安装成功
先输入 source /etc/profile
然后输入 java -version
安装成功后会显示jdk版本

3.安装eclipse
3.1将eclipse解压到/opt文件夹下
首先,用su获取root权限,然后将eclipse剪切到/opt文件夹下

然后,解压eclipse到/opt文件夹下,指令为:sudo tar zxvf eclipse-inst-linux64.tar.gz -C /opt/

3.2创建eclipse桌面快捷图标
首先输入指令: cd /usr/share/applications
然后输入指令: sudo vim eclipse.desktop

最后将下面的代码复制到文件中:

1
2
3
4
5
6
7
8
9
10
[Desktop Entry]
Encoding=UTF-8
Name=Eclipse
Comment=Eclipse
Exec=/opt/eclipse-installer/eclipse-inst
Icon=/opt/eclipse-installer/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Application;Development;

其中“Exec=”后面为eclipse安装目录下的eclipse程序的位置路径,“Icon=”后面为eclipse安装目录下的图标图片的路径

3.3将eclipse变为可执行文件
指令为:sudo chmod u+x eclipse.desktop

3.4 在/usr/share/applications目录下将Eclipse图标复制到桌面

3.5点击图标下载相关的eclipse版本
————————————————
版权声明:本文为CSDN博主「spenglu」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013216156/article/details/78677740

搭建 ESP32 开发环境 —— Hello World

发表于 2019-11-21

这里以 Ubuntu 为例,其它系统请参考中文文档:

file:///home/work/esp/esp-idf-doc-zh/docs/_build/html/get-started/linux-setup.html

【安装依赖包】

整个 ESP-IDF 环境需要用到很多软件,例如 git makepython等,因此我们需要先将这些软件预装好。

1
sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial

虽然需要用到这么多软件,但是只需要这样一条简单的命令,系统自动就会帮我们装好,多方便啊,这就是 Linux 对我的魅力之所在。想一想,如果 windows 需要安装这么多软件,是不是烦都烦死了。

【安装工具链】

64 位操系统和 32 位操作系统所使用的工具链不相同,所以请根据你自己对系统选择对应的方法。

可从Espressif网站下载适用于Linux的ESP32工具链:

  • 对于64位Linux:

    https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

  • 对于32位Linux:

    https://dl.espressif.com/dl/xtensa-esp32-elf-linux32-1.22.0-80-g6c4433a-5.2.0.tar.gz

  1. 下载此文件,然后将其解压缩到~/esp目录中:
1
2
3
mkdir -p ~/esp
cd ~/esp
tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz

解压后的工具链位于路径~/esp/xtensa-esp32-elf下面。该目录下面的bin目录就是我们用来编译 ESP-IDF 工程所需的可执行程序。如果要使系统直接能够这些程序,需要将这个bin文件夹路径添加到系统的环境变量PATH中去。这里直接使用echo命令将其添加到脚本文件~/.bashrc中(系统每次启动刚时都会执行这个脚本)。

1
2
echo "export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin" >> ~/.bashrc
source ~/.bashrc

第一次添加后需要对该脚本执行source ~/.bashrc操作,让该脚本立即生效。今后重启系统后不需要再执行该操作。

【下载ESP-IDF(即SDK)】

ESP-IDF 的全称是 Espressif IoT Development Framework(乐鑫 IoT 开发框架),即我们通常所说的 SDK,它里面提供了丰富的可供我们调用的库和API。

我们直接使用 git 进行 clone:

1
2
cd ~/esp
git clone --recursive https://github.com/espressif/esp-idf.git

最新版的SDK下载方式:

1
2
cd ~/esp
git clone -b v3.3 --recursive https://github.com/espressif/esp-idf.git

注意 clone 后面的参数–recursive,它表示递归克隆该仓库的子仓库,这是一种在开源界非常流行的做法,可以方便地对多个仓库进行控制。如果你是‘老鸟’,在 clone 时没看到这个参数(说明你还只是半老鸟,^_^),也可以使用下面的命令来手动更新该仓库的子模块:

1
git submodule update --init

ESP-IDF 下载完成后,我们还需要导出环境变量IDF_PATH —— 我们今后在编译自己的工程代码时会使用这个变量来查找 ESP-IDF 所在路径。同样使用echo命令将其追加到脚本文件~/.bashrc的默认(完成后不要忘记执行source ~/.bashrc命令哦)。

1
echo "export IDF_PATH=~/esp/esp-idf" >> ~/.bashrc

另外,多花几分钟看看 ESP-IDF 目录下的各文件都是干嘛的吧

【编译 Hello world】

ESP-IDF 为我们提供了丰富的 demo 程序,位于路径examples下面。我们这里先试试经典款hello world。进入 hello world 所在目录,然后编译:

1
2
cd examples/get-started/hello_world/
make

如果是第一次执行make命令,系统会弹出一个图形配置界面,如下图所示。

我们可以通过键盘上的tab键在下面的菜单中进行跳转。当光标跳转到菜单后,按下回车键,退出配置菜单,然后系统会自动编译 ESP-IDF 目录下的各个组件以及 hello world 目录下的源码。

编译完成后,我们可以在 hello wolrd 工程所在目录下生成一个 build 文件,用于存放编译过程中生成的临时文件以及最终可以直接烧写到开发板的.bin 文件。此外,系统还会直接在 hello world 工程所在目录生成一个配置文件 sdkconfig,它存放了我们在配置界面所配置的各种值(我们这里没有修改,所以是默认值)。

【烧写程序】
然后用 USB 将开发板与 PC 连接在一起,系统会识别到设备/dev/ttyUSB0。

如果你用的是虚拟机,需要在虚拟机上面将该设备从 win 移动到虚拟机中。

我们先修改该设备的权限,然后烧写并监视串口输出:

1
2
sudo chmod 777 /det/ttyUSB0
make flash monitor

当然,你也可以根据自己的喜好使用选择串口工具,例如 minicom 等。

然后就看到系统启动消息了,大功告成!!!

单片机工程师工作有哪些适合入门和了解行业的书籍、视频

发表于 2019-08-10

单片机工程师需要具备哪些条件呢?

搜索了数十条招聘信息后,如下:

img

img

img

总结说来:

1.会C/C++语言编程;

2.熟练或精通一款单片机(不限于51/AVT/STM32)

3.熟悉外围电路(模拟电子和数字电子部分),

4.熟悉I2C,SPI,UART等协议

5.能独立完成原理图设计(会PADS/DXP/protel等软件)

现在按各个的能力和需求提供书籍和视频

1、C语言学习

书籍:C primer plus

img

视频:这里推荐网易公开课的老师的视屏

img

​ http://open.163.com/movie/2019/2/9/0/ME7HONPPN_ME7HP0U90.html

2.单片机学习

单片机学习和入门大力推荐:“手把手教你学单片机程序框架 ”

(新手看有难度,建议先看视频了解后再学)

http://bbs.elecfans.com/jishu_406259_1_1.htmlwww.zhihu.com![图标](https://zhstatic.zhihu.com/assets/zhihu/editor/zhihu-card-default.svg)

视频就用“10天学会51单片机—郭天祥”

B站有他的视频

img

https://www.bilibili.com/video/av7781436/www.bilibili.com

3.模电数电部分

清华大学这个版比较多人用,推荐这个。

img

视屏:模拟电子技术基础 清华大学 华成英主讲

https://www.bilibili.com/video/av26225883?from=search&seid=3820332834176087459www.bilibili.com

数字电子技术基础 清华大学 王红主讲

https://www.bilibili.com/video/av23487060?from=search&seid=3223420955061265422www.bilibili.com

4.I2C,SPI,UART等协议

这个就需要自己在实践中学习 了。

单片机怎么入门

发表于 2019-08-09

单片机入门摘要

•了解单片机基础知识,形成对单片机较为深刻的认识,掌握单片机最小系统电路;

•C语言中常用的基础知识;

•学习使用51单片机的开发环境及下载过程;

•编写流水灯、蜂鸣器、继电器实验程序,熟练掌握单片I/O口的操作及延时方法。

什么是单片机

​ 在一块芯片上集成了:CPU、振荡电路、ROM和RAM存储器、定时/计数器和并行/串行I/O接口等,具有一定能功能的计算机称为单片微型计算机,简称单片机。 如图所示的就是单片机,不过由于技术的发展,单片机变得越来越小,种类越来越多,像合泰,松翰,STC,新唐,中颖等国产单片机也在市场上发挥了重要作用。

1565333482756

我最近用到的单片机封装是这样的(我用的是第二个),封装很小了,但是感觉还是太大了。

1565333880265

单片机里面是这样的:

1565334383398

现代的工艺把各种寄存器集成到一起,就成了我们所谓的“单片机”。

什么是单片机最小系统?

最小系统可以理解为让单片机工作的最简单的线路,其实单片机的最小系统可分为三部分:1-电源部分;2-晶振部分;3-复位部分。如图就是单片机最小系统。能工作,能运行的系统。

1565335825598

学单片机到底学什么 ?

•1、通过I/O口来控制外围的器件

•2、通过I/O口接受外围模块的电压

•3、保证在恰当的时间作出正确的动作

以下是我以前学习用的开发板的电路集合,大部分项目只用到下面的一个或几个功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	8只3mm LED灯,共4种颜色,可以学习流水灯,跑马灯基础编程。
 1只0.5寸共阳数码管,方便学习数码管显示的基本原理和使用数码管显示数据。
 8位0.36寸共阴数码管,2个74HC573锁存,通过控制段锁存和位锁存可进行数码管的静态显示与动态扫描显示的工作。
 1只1.9mm红色8x8点阵,2个74HC573锁存。用于练习使用LED屏显示图形、字符。
 LCD1602插座,10K电位器调节比度,即插即用。可以实现多种模式的显示,如移动显示、滚动显示、反白显示、光标显示闪烁等。
 LCD12864液晶标准插座,10K电位器调节比度,可以连接多款并口液晶,也可以直接插接我们配套的彩屏,练习使用写入用户自编图形或者字符,显示图片,显示数字等。
 8个独立按键,人机接口输入部分重要模块,按键可以自由配置,可进行外部中断控制实验、数据的增减控制、继电器开关控制等
 4x4标准矩阵键盘,带有中断信号输入接口,可以学习行列扫描、反转扫描、定时扫描、中断扫描等。
 高精度热敏电阻,通过AD采集转换可以测量环境温度变化等。
 高精度光敏电阻,通过AD采集转换可以测量光照度变化等。
 2路独立的18B20温度传感器接口,预留扩展插针,自由度更高,可以实验温度采集,超温报警和温度上下限设置等
 蜂鸣器,可播放音乐,可进行多种声音模拟,如警笛、消防车声、电子琴等 时钟芯片DS1302,32.768KHz时钟源晶振,另配备用电源CR1220纽扣电池,可编写日历时钟的编程显示、上位机在线更新时钟等程序
 EEPROM存储器24c02,IIC总线接口。使用方便灵活,可实现单字节、多字节数据的存储,掉电保护数据、开机次数记忆等。
 串行信号转并行信号芯片74HC164,通过模拟串口信号输入,输出8位并口信号,多用于扩展单片机本身端口。
 反向器CD4069,可以做门电路基础实验,信号组合试验等
 PCF8591芯片,8位数模/模数转换芯片,提供4路AD输入,和1路DA输出。4路输入接口分别连接到2个电位器的电平测试引脚,电平调节值范围0-VCC,端口也可自行外接;DA端口连接到一只LED灯,端口也可外接。
 优质隔离性光耦,通过控制光耦的1、2引脚的开关来隔离控制3、4引脚的通断(开发板3、4引脚的通断用一只红色led反映)。
 2路红外避障电路,使用触发器CD40106振荡出38K基波调制信号,单片机只要控制芯片使能脚即可发出38K红外载波信号;1路高灵敏度,宽范围一体化红外接收头,可以做避障、通讯功能等实验。使用我们的配套遥控器可以实现遥控解码控制等。
 MAX232串口电平转换,2路串口(DB9公口和母口),可以使用串口进行程序下载、与上位机之间串口通信等。
 PL2303为USB转换下载芯片,通过一根USB线与电脑进行程序下载,数据交换通信。
 RS485芯片,学习485硬件控制原理。可以提高串口的通信距离。
 PS/2接口,可以连接PS/2标准输入设备,学习PS/2协议原理和技术。
 标准AT-ISP接口,选购标准AT下载器可以进行AT89s系列51芯片和Atmega公司的AVR芯片下载和使用

​ 所以学习单片机一定要对硬件有一定的基础,I/O(输入/输出引脚)涉及到很多相关的知识,比如按键需要上拉或者下拉,晶振的准确性影响大部分时钟的准确性,还有I2C,SPI,CAN等各种协议。如果没有一定的基础,贸然直接学习可能会受到很大的挫折,打击学习的积极性。

C语言中常用的基础知识

大部分的单片机都可以通过C语言来编程了,在编程的时候用到的知识有:

1.了解基本的C语言结构和相关的关键字,比如sbit,data,code ;

2.会基本的参数声明,赋值、初始化;

3.会用基本的if-else编程,知道主函数的mian();

4.了解ASCII,知道二进制、十进制、十六进制之间的转换。

其实只要稍微学习一下C语言就可以着手编写自己的程序了。

单片机的开发环境及下载过程教程

内容太多,请参考这篇文章

https://zhuanlan.zhihu.com/p/77376751

学单片机可以做什么 ?

•秒表

•循迹小车

•数字台灯

•智能仪表

•游戏机

•冰箱、彩电、洗衣机控制电路

具体的源码和程序我已经放到我的github空间了,大家放心下载。

https://github.com/mmdanielmm/Project-update-weekly

怎样才能学好单片机?

•孰能生巧,一定要多动手写一些程序,不能仅仅局限在视频上,杜绝眼高手低;

•多去动手焊一些外围模块、最小系统,这样可以增加对电路的认识;

•多去查一些数据手册,学会看数据手册,不能完全依赖与百度。

KEIL / MDK生成BIN文件的两种方式

发表于 2019-08-03

KEIL / MDK生成BIN文件的两种方式

1 KEIL工程配置入口

点击“魔术棒”图标(Option for Target)

在After Build/Rebuild选项卡中,勾选 “Run # 1”,在后面输入框写入bin文件生成方式,见2.1、2.2

2 输出Bin文件配置

​ KEIL生成bin文件,根据输入命令的相对\绝对路径来分,有两种方式,都是通过自带的fromelf.exe来生成

2.1 绝对路径方式

绝对路径方式,如果更换电脑等,需要手动修改MDK工具链(formelf.exe)所在路径与项目文件名(例如test_app)

1
"D:\Program Files\MDK516\ARM\ARMCC\bin\fromelf.exe" --bin -o ./obj/test_app.bin ./obj/test_app.axf"

2.2 相对路径方式

使用相对路径生成,则不需要任何修改

1
$K\ARM\ARMCC\bin\fromelf.exe --bin --output=@L.bin !L

编译后,Build Out框可以看到:
After Build - User command #1: D:\Program Files\MDK516\ARM\ARMCC\bin\fromelf.exe –bin –output=test1.bin .\obj\test1.axf

上述操作后,在xxx.uvprojx当前目录下,可看到一个test1.bin

如果希望生成.bin文件输出在当前工程下的指定目录,比如Bin文件夹,可如下操作:

1
$K\ARM\ARMCC\bin\fromelf.exe --bin --output=Bin\@L.bin !L

编译后,Build Out框可以看到:
After Build - User command #1: D:\Program Files\MDK516\ARM\ARMCC\bin\fromelf.exe –bin –output=Bin\test1.bin .\obj\test1.axf

上述操作后,在xxx.uvprojx当前目录下,可看到一个新生成的Bin文件夹,里面是test1.bin

​

符号代号(Key Code)
$ 扩展为 指定文件的路径名
@ 表示 Output -> Name of Exectable:定义的工程名,比如test1build工程后,最终生成的bin文件名称将是test1.bin
! 当前目录下的扩展路径 !L编译(Build)后,就是 .\obj\xx.axf文件
文件代号(File Code)
K keil develop chaintool 工具链(fromelf.exe)
L Linker output fileL.bin 编译后,生成的就是最终的xx.bin文件

​

3 参考资料

1.原文链接(Keil官方):Key Sequence for Tool Parameters
http://www.keil.com/support/man/docs/uv4/uv4_ut_keysequence.htm

2.https://blog.csdn.net/veabol/article/details/52318694

3.https://blog.csdn.net/nich2009/article/details/81124691

电子烟控制板功能说明

发表于 2019-07-26

※ 组件结构尺寸

EGO电子烟控制板由主控板组件和红黑蓝三条/四条导线组成,主控板尺寸为9.8mm*11mm,板厚0.8mm±0.1,按键高度2.5mm

导线规格可按客户要求定制。

​

※ 电气参数(实际应用差异影响以下参数)

表2 参数表

参数项 典型值 单位
工作范围电压 1.6~5.0 V
工作额定电压 3.2~4.2 V
雾化器电阻值 1.0~3.5 Ohm
待机模式电流 ≤1.0 uA
LED灯电流 (LED灯电压可以支持到3V) 10 mA
雾化器输出是PWM方式 3.7 V
充电输入电压范围 4.2V~5.5V V
恒流充电电流(Icc) 400/600 mA
终止充电电流(Iterm) 0.1*Icc mA
工作温度 -20~80 ℃

※ 使用功能说明

3.1 上电IC自检,LED连闪2次(200ms ON,200ms OFF)进入待机模式。

3.2 待机模式下,在2秒内连续接按键5次后,锁机;锁机时,2秒内连续按按键5次后,回到待机模式;而且在充电中可支持吸烟的场景中,依然支持此锁机和解锁模式。

3.3 输出电压方式是PWM,当电池电压>4.1V时PWM占空比90%(空载),当电池电压3.9V~4.1V时PWM占空比93%(空载),当电池电压3.7V~3.9V时PWM占空比97%(空载),当电池电压3.3V~3.7V时PWM占空比100%(空载)。

3.4 在待机模式下,用户按键, LED灯亮;电池电压低于3.2V后,LED灯连闪15次(200ms ON,200ms OFF),继续待机。

3.5 在待机模式下,吸烟时需按住按键开关,启动雾化器, 开始吸烟;停止吸烟时,需把按键放开,关闭雾化器。 按键按住超过10秒,LED闪3次(200ms ON,200ms OFF),雾化器停止工作。

3.6 雾化器短路后,用户按键,LED闪3次(200ms ON,200ms OFF),处于短路保护状态。吸烟时雾化器短路LED闪3次(200ms ON,200ms OFF),处于大电流保护状态。

※ 充电说明

4.1 烟杆接上充电,LED闪烁5次(200ms ON,200ms OFF)后LED常亮,处于充电状态。在电池电压低于2.8V时,为涓流充电,电流40mA;大于2.8V时,开始以恒流充电;电压充到4.2V(±0.05V),且充电电流下降到充电电流的1/10后,LED灯灭,充电截止;拔出充电器LED闪2次。如果在未充满电的情况下,而此时电池电压已经达到或超过4.1V(±0.07V),再充电时LED闪烁5次后LED灯灭,充电截止。

4.2 充电输入电压范围

充电输入电压4.2V~5.5V。

※**产品外观**

CT811QM4是一款可充电电子烟专用咪头,产品主体直径6mm,高度2.7mm,外接四条导线,LED灯色和线材规格可按客户要求定制。

黑线 GND 连接电池负极 注:LED灯色和线材长度根据客户要求定制
红线 VDD 连接电池正极
蓝线 OUT 连接输出正极
黄线 CHG 连接充电正极

※**电气参数(外围线路影响以下参数)**

参数项 最小值 典型值 最大值 单位
工作范围电压 1.7 5 V
工作额定电压 3.2 4.2 V
雾化器电阻值 1.35 Ω
吸烟开关功率MOS Rds-on 100 mΩ
待机电流 5 uA
吸烟启动时间 30 100 mS
LED电流 5 mA
LED闪灯周期 0.4 S
吸烟中LED灯渐亮时间 0.5 S
吸烟中LED灯渐灭时间 1 S
雾化器输出电压PWM方式 3.7 V
稳压电源充电电压 4.2 5.5 V
恒流充电电流(Icc) 200 mA
终止充电电流(Iterm) 20 mA
电容检测变化开关阀值 1.6 %
工作温度 -20 80 ℃

※ 主要功能

No. 功能 说明
1 电池电压 3.2V~4.2V(标配电池:3.7V锂电池 )。
2 省电电流 睡眠模式下小于5uA。
3 吸烟超时 一次吸烟超过10秒关闭输出同时LED灯闪3次,然后进入待机状态
4 上电提示 芯片上电IC自检,LED连闪2次后进入待机模式。
5 开机/解锁 在1.5秒内连续吸烟3次为开锁机切换,LED灯闪2次提示。 如在锁机状态下充电,可解除锁定即回到开机状态。
6 吸烟提示 芯片在吸烟过程中,LED有渐亮、渐灭功能。渐亮时间为0.5s,渐灭时间为1s;当LED灯亮时雾化器发热并有烟雾产生,当LED灯灭时,雾化器不发热,无烟雾产生。
7 输出电压 输出恒压3.7V 误差±0.05V
8 大电流保护 雾化器电流在3A或以上,LED闪3次,处于大电流保护状态
9 短路保护 发热丝低于1.35欧单片机判定为短路,吸烟时按键灯和电量灯闪3次提示。
10 低压提示 BAT<3.20±0.1V(空载),吸烟时按键灯闪10次提示,无电压输出。
11 充电 1.烟杆接上充电,LED常亮,处于充电状态。在电池电压低于2.8V时,为涓流充电,电流20mA;大于2.8V时,开始以恒流200mA充电;电压充到4.2V(±0.05V),且充电电流下降到20mA后,LED灯灭,充电截止;拔出充电器LED闪2次。如果在未充满电的情况下,而此时电池电压已经达到或超过4.1V(±0.07V),再充电时LED灯灭,充电截止。 2.充电输入电压范围 充电输入电压为4.3V~5.5V。

※**产品外观**

CT811QM是一款可充电电子烟专用咪头,产品主体直径6mm,高度2.7mm,外接三条导线,LED灯色和线材规格可按客户要求定制。

引线功能
黑线 GND 电源负极 注:灯色和线材长度根据客户要求定制
红线 VDD 电源正极
蓝线 OUT 输出正极

※**电气参数(外围线路影响以下参数)**

参数项 最小值 典型值 最大值 单位
工作范围电压 1.7 5 V
工作额定电压 3.2 4.2 V
雾化器电阻值 1.35 Ω
吸烟开关功率MOS Rds-on 100 mΩ
待机电流 5 uA
吸烟启动时间 30 100 mS
LED电流 5 mA
LED闪灯周期 0.4 S
吸烟中LED灯渐亮时间 0.5 S
吸烟中LED灯渐灭时间 1 S
雾化器输出电压PWM方式 3.7 V
稳压电源充电电压 4.2 5.5 V
恒流充电电流(Icc) 200 mA
终止充电电流(Iterm) 20 mA
电容检测变化开关阀值 1.6 %
工作温度 -20 80 ℃

※ 主要功能

No. 功能 说明
1 电池电压 3.2V~4.2V(标配电池:3.7V锂电池 )。
2 省电电流 睡眠模式下小于5uA。
3 吸烟超时 一次吸烟超过10秒关闭输出同时LED灯闪3次,然后进入待机状态
4 上电提示 芯片上电IC自检,LED连闪2次后进入待机模式。
5 开机/解锁 在1.5秒内连续吸烟3次为开锁机切换,LED灯闪2次提示。 如在锁机状态下充电,可解除锁定即回到开机状态。
6 吸烟提示 芯片在吸烟过程中,LED有渐亮、渐灭功能。渐亮时间为0.5s,渐灭时间为1s;当LED灯亮时雾化器发热并有烟雾产生,当LED灯灭时,雾化器不发热,无烟雾产生。
7 输出电压 输出恒压3.7V 误差±0.05V
8 大电流保护 雾化器电流在3A或以上,LED闪3次,处于大电流保护状态
9 短路保护 发热丝低于1.35欧单片机判定为短路,吸烟时按键灯和电量灯闪3次提示。
10 低压提示 BAT<3.20±0.1V(空载),吸烟时按键灯闪10次提示,无电压输出。
11 充电 1.烟杆接上充电,LED常亮,处于充电状态。在电池电压低于2.8V时,为涓流充电,电流20mA;大于2.8V时,开始以恒流200mA充电;电压充到4.2V(±0.05V),且充电电流下降到20mA后,LED灯灭,充电截止;拔出充电器LED闪2次。如果在未充满电的情况下,而此时电池电压已经达到或超过4.1V(±0.07V),再充电时LED灯灭,充电截止。 2.充电输入电压范围 充电输入电压为4.3V~5.5V。

※**产品外观**

CT815是一款可充电电子烟专用咪头,产品主体直径6mm,高度2.7mm,外接五条导线,LED灯色和线材规格可按客户要求定制。

黑线① GND 连接电池负极&输出负极 注:LED灯色和线材长度根据客户要求定制
红线 VDD 连接电池正极
蓝线 OUT 连接输出正极
黄线 CHG 连接充电正极
黑线② GND 连接充电负极

※**电气参数(外围线路影响以下参数)**

参数项 最小值 典型值 最大值 单位
工作范围电压 1.7 5 V
工作额定电压 3.2 4.2 V
雾化器电阻值 1.35 Ω
吸烟开关功率MOS Rds-on 100 mΩ
待机电流 5 uA
吸烟启动时间 30 100 mS
LED电流 5 mA
LED闪灯周期 0.4 S
吸烟中LED灯渐亮时间 0.5 S
吸烟中LED灯渐灭时间 1 S
雾化器输出电压PWM方式 3.7 V
稳压电源充电电压 4.2 5.5 V
恒流充电电流(Icc) 200 230 mA
终止充电电流(Iterm) 20 mA
电容检测变化开关阀值 1.6 %
工作温度 -20 80 ℃

※ 主要功能

No. 功能 说明
1 电池电压 3.2V~4.2V(标配电池:3.7V锂电池 )。
2 省电电流 睡眠模式下小于5uA。
3 吸烟超时 一次吸烟超过10秒关闭输出同时LED灯闪3次,然后进入待机状态
4 上电提示 芯片上电IC自检,LED连闪2次后进入待机模式。
5 吸烟提示 芯片在吸烟过程中,LED有渐亮、渐灭功能。渐亮时间为0.5s,渐灭时间为1s;当LED灯亮时雾化器发热并有烟雾产生,当LED灯灭时,雾化器不发热,无烟雾产生。
6 输出电压 输出恒压3.7V 误差±0.05V
7 大电流保护 雾化器电流在3A或以上,LED闪3次,处于大电流保护状态
8 短路保护 发热丝低于1.35欧单片机判定为短路,吸烟时按键灯和电量灯闪3次提示。
9 低压提示 BAT<3.20±0.1V(空载),吸烟时按键灯闪10次提示,无电压输出。
10 充电 1.可连接单独的充电口,LED常亮,处于充电状态。在电池电压低于2.8V时,为涓流充电,电流20mA;大于2.8V时,开始以恒流200~230mA充电;电压充到4.2V(±0.05V),且充电电流下降到20mA后,LED灯灭,充电截止;拔出充电器LED闪2次。如果在未充满电的情况下,而此时电池电压已经达到或超过4.1V(±0.07V),再充电时LED灯灭,充电截止。 2.充电输入电压范围 充电输入电压为4.3V~5.5V。

※**产品规格**

1.咪头主体尺寸规格

尺寸规格 直径 高度 LED 灵敏度
咪头主体 6.0mm±0.1 2.7mm±0.1 客户指定 -400Pa以内

​

  1. 咪头外接三条导线,导线规格可根据客户要求定制。

※ 主要功能

1.1输出电流在2.5A(±0.5A)或以上,LED闪1次,处于大电流保护状态。

1.2吸烟一口时长超过12秒(误差±30%)LED灭,输出自动截止。

1.3吸烟过程中,LED灯有渐亮、渐灭效果。

※ 电气参数(外围线路影响以下参数)

参数项 典型值 单位
工作范围电压 1.8~5.5 V
工作额定电压 1.8~4.2 V
待机电流 <5.0 μA
雾化器输出电压 同电池电压 V
工作温度 -20~85 ℃

※ 使用功能说明

3.1芯片上电IC自检,LED闪1次再进入待机模式。5

3.2当加上雾化器做吸烟动作时,IC输出导通来启动雾化器工作。

3.3吸烟工作过程中,LED渐亮、渐灭,同时在LED灯亮时雾化器发热并有烟雾产生,即LED灯灭时,雾化器不发热,无烟雾产生。

3.4吸烟过程中,吸烟一口时长超过12秒(误差±30%),LED灯灭,同时雾化器不发热,烟雾自动停止。

3.5当电池电压低于1.8V时,芯片不工作。

※ 原理图

如何使用虚拟机(vmware workstation)安装Ubuntu系统

发表于 2019-06-13

本文只使用最简单的方式去安装虚拟机(vmware workstation)和ubuntu。

1.下载360安全卫士,在360软件管家搜索“虚拟机”,如下图

2.找到“vmware workstation”,随后点击下载安装。

如需注册码请到官方网站购买或者在下方评论中找

3.安装完成之后到Ubuntu官方下载Ubuntu系统.

我用的是ubuntu-16.04.5-desktop-amd64版本,目前最低版本是18.04,直接点击download,如下图

4.下载完成后,打开Vmware workstation软件,打开“文件->新建虚拟机”

5.然后使用典型安装,

6.找到下载好的光盘镜像文件

7.输入名字和密码,密码一定要记住,后面开机和编程时获取权限用的到;

8.填入虚拟机名字,设置安装ubuntu的位置,这个光盘最好有20G以上空间。

9.为Ubuntu分配空间,一般20G就够用了。

10.点击完成就等待Ubuntu安装了,看机子的配置,一般20多分钟就可以搞定。

11.看,正在安装!

输入密码,大功告成了!

下一步,配置ESP32编译环境!

搭建基于Ubuntu的 ESP32 开发环境

发表于 2019-06-13

本人使用ubuntu系统来开发ESP32也有一年多了,为给后人提供经验,故写下自己的经验,让后人少走弯路。

Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于DebianGNU/Linux,支持x86、amd64(即x64)和ppc架构,由全球化的专业开发团队(Canonical Ltd)打造的。 使用linux编译的好处是相比于windows系统,Linux更快,更方便。

1.如何使用虚拟机安装Ubuntu系统

基于stm32f030的模拟I2C与博世BMI160六轴传感器通信

发表于 2019-05-29 | 更新于 2019-05-31

博世BMI160简介

​

​ Bosch Sensortec公司推出的最新BMI160惯性测量单元将最顶尖的16位3轴重力加速度计和超低功耗3轴陀螺仪集成于单一封装。采用14管脚LGA封装,尺寸为2.5×3.0×0.8mm3。当加速度计和陀螺仪在全速模式下运行时,耗电典型值低至950µA,仅为市场上同类产品耗电量的50%或者更低。

BMI160是一款高度集成的低功耗惯性测量单元(IMU),可提供精确的加速度和角速率(陀螺 仪)测量。


主要特点

 高性能加速度计和陀螺仪(硬件同步)
 功耗极低:典型值。 920μA(全功能加速度计和陀螺仪)
 符合Android Kitkat:重要的运动和步进检测器/步进计数器(每个5μA)
 占地面积2.5 x 3.0 mm2,高度0.83 mm
 内置电源管理单元(PMU),用于高级电源管理
 具有快速启动陀螺仪模式的省电功能
 宽电源范围:1.71V …… 3.6V
 可分配的1024字节FIFO缓冲区(能够处理外部传感器数据)
 硬件传感器时间戳,用于精确的传感器数据融合
 集成中断,用于增强自主运动检测
 灵活的数字主接口,通过I2C或SPI连接主机
 扩展I2C模式,时钟频率高达1 MHz
 用于OIS应用的附加二级高速接口
 能够处理外部传感器数据 (例如Bosch Sensortec的地磁或气压传感器)


下载地址

BMI160的中文Datasheet的下载连接如下: [点击此处进入下载网页]

官方英文Datasheet下载地址

官方参考驱动代码下载地址

主接口I2C / SPI协议选择

bmi160flow1

​ 从上面的框图中,我们可以看到,BMI160与外部进行双向数据传输的方式有两种:SPI和I2C。下面,我们来看下通过I2C与外部进行通信的方式。当BMI160通过I2C与外部进行通信的时候,BMI160将作为I2C从设备挂到主控芯片(主设备)的I2C总线上,所以,主控芯片在配置其对应的I2C驱动时就需要知道BMI160的从设备地址。

​ 上电后,根据芯片选择CSB引脚行为自动选择协议。复位/上电时,BMI160处于I2C模式。 如果CSB在上电期间连接到VDDIO且未更改,则传感器接口 在I2C模式下工作。 对于使用I2C,建议将CSB线硬连线到VDDIO。 由于上电复位仅在VDD和 VDDIO都建立时执行,因此不存在由于上电顺序而导致协议检测错误的风险。

​ 如果CSB在上电后看到上升沿,则BMI160接口切换到SPI直到复位或下一次上电。 因此,在启 动SPI之前需要CSB上升沿通讯。

​ 因此,建议在实际通信之前对ADDRESS 0x7F执行SPI单读访问,以便使用SPI接口。 如果没有数据,则无法切换CSB位通信时,寄存器(0x70)NV_CONF中还有spi_en位,可用于将 主接口永久设置为SPI,而无需在每次上电或复位时切换CSB引脚。

本文采用的是I2C接口

I2C接口

如果SDO引脚被拉至’GND‘,器件的I²C地址为0b1101000(0x68)。

如果SDO引脚被拉至VDDIO‘,器件的I²C地址为0b1101001(0x69)。

I2C时序图

下图给出的I²C时序的定义

I²C协议的工作原理如下:

START: 总线上的数据传输从SDA线上的高电平到低电平转换开始,而SCL保持高电平(I²C总 线主机指示的启动条件(S))。 一旦主机传输START信号,总线就会被认为是忙碌的。

STOP: 每个数据传输应由主机产生的停止信号(P)终止。 STOP条件是SDA线上的低电平到高 电平转换,而SCL保持高电平。

ACKS: 必须确认传输的每个数据字节。 它由接收器发送的确认位指示。 发送器必须在应答脉冲 期间释放SDA线(无下拉),而接收器必须将SDA线拉低,以便在应答时钟周期的高电平期间保 持稳定的低电平。

I²C写数据

I²C写访问可用于在一个序列中写入数据字节。 该序列以主机产生的启动条件开始,后跟7位从机地址和写入位(RW = 0)。 从器件发送一个应 答位(ACKS = 0)并释放总线。 然后主机发送一个字节的寄存器地址。 从机再次确认传输并等 待8位数据,这些数据应写入指定的寄存器地址。 从机确认数据字节后,主机产生停止信号并终 止写入协议。I²C写访问的示例:

I²C读数据

I²C读访问也可用于在一个序列中读取一个或多个数据字节。
I²C读访问也可用于在一个序列中读取一个或多个数据字节。
读序列由一个字节的I²C写阶段和I C读阶段组成。变速器的两个部分必须通过重复启动条件(S)分开。 I²C写入阶段寻址从器件并发送要读取的寄存器地址。从机确认发送后,主机再次产生一个起始条件,并将从机地址与读取位(RW = 1)一起发送。然后主机释放总线并等待从从机读出数据字节。在每个数据字节之后,主机必须生成应答位(ACKS = 0)以启用进一步的数据传输。
来自主设备的NACKM(ACKS = 1)停止从从设备传输的数据。从器件释放总线,以便主器件可以生成STOP条件并终止传输。
寄存器地址自动递增,因此可以顺序读出多个字节。一旦新的数据读取传输开始,起始地址将被设置为自最新的I²C写入命令以来指定的寄存器地址。默认情况下,起始地址设置为0x00。以这种方式,可以从相同的起始地址重复多字节读取。

I²C读访问示例(读取陀螺仪数据):

I²C读写初始化程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**************************实现函数********************************************
*函数原型: void IIC_Start(void)
*功  能: 产生IIC起始信号
*******************************************************************************/
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA_1;
IIC_SCL_1;

delay_us(5);
IIC_SDA_0;//START:when CLK is high,DATA change form high to low

delay_us(5);
IIC_SCL_0;//钳住I2C总线,准备发送或接收数据
}

/**************************实现函数********************************************
*函数原型: void IIC_Stop(void)
*功  能: //产生IIC停止信号
*******************************************************************************/
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL_0;
IIC_SDA_0;//STOP:when CLK is high DATA change form low to high

delay_us(5);
IIC_SCL_1;
IIC_SDA_1;//发送I2C总线结束信号

delay_us(5);
}

/**************************实现函数********************************************
*函数原型: u8 IIC_Wait_Ack(void)
*功  能: 等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
*******************************************************************************/
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA_1;
delay_us(5);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>50)
{
IIC_Stop();
return 1;
}
delay_us(5);
}
IIC_SCL_1;
delay_us(5);
IIC_SCL_0;//时钟输出0
return 0;
}

/**************************实现函数********************************************
*函数原型: void IIC_Ack(void)
*功  能: 产生ACK应答
*******************************************************************************/
void IIC_Ack(void)
{
IIC_SCL_0;
SDA_OUT();
IIC_SDA_0;
delay_us(5);
IIC_SCL_1;
delay_us(5);
IIC_SCL_0;
}

/**************************实现函数********************************************
*函数原型: void IIC_NAck(void)
*功  能: 产生NACK应答
*******************************************************************************/
void IIC_NAck(void)
{
IIC_SCL_0;
SDA_OUT();
IIC_SDA_1;
delay_us(5);
IIC_SCL_1;
delay_us(5);
IIC_SCL_0;
}

/**************************实现函数********************************************
*函数原型: void IIC_Send_Byte(u8 txd)
*功  能: IIC发送一个字节
*******************************************************************************/
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL_0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if(txd&0x80)
IIC_SDA_1; //IIC_SDA=1;
else
IIC_SDA_0; //IIC_SDA=0;
txd<<=1;
delay_us(2);
IIC_SCL_1;
delay_us(5);
IIC_SCL_0;
delay_us(3);
}
}

/**************************实现函数********************************************
*函数原型: u8 IIC_Read_Byte(unsigned char ack)
*功  能: //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
*******************************************************************************/
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL_0;

delay_us(5);
IIC_SCL_1;
receive<<=1;
if(READ_SDA)receive++;
delay_us(5);
}
if (ack)
IIC_Ack(); //发送ACK
else
IIC_NAck();//发送nACK
return receive;
}

/**************************实现函数********************************************
*功  能: 读取指定设备 指定寄存器的 length个值
输入 dev 目标设备地址
reg 寄存器地址
length 要读的字节数
*data 读出的数据将要存放的指针
返回 读出来的字节数量
*******************************************************************************/

u8 IICreadBytes(u8 dev, u8 reg, u8 *data , uint16_t length)
{
u8 count = 0;

IIC_Start();
IIC_Send_Byte(dev<<1); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); //发送地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte((dev<<1)+1); //进入接收模式
IIC_Wait_Ack();

for(count=0;count<length;count++){

if(count!=length-1)data[count]=IIC_Read_Byte(1); //带ACK的读数据
else data[count]=IIC_Read_Byte(0); //最后一个字节NACK
}
IIC_Stop();//产生一个停止条件
return 0;
}

/**************************实现函数********************************************
*功  能: 将多个字节写入指定设备 指定寄存器
输入 dev 目标设备地址
reg 寄存器地址
length 要写的字节数
*data 将要写的数据的首地址
返回 返回是否成功
*******************************************************************************/
u8 IICwriteBytes(u8 dev, u8 reg, u8 *data , uint16_t length)
{
u8 count = 0;
IIC_Start();
IIC_Send_Byte(dev<<1); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); //发送地址
IIC_Wait_Ack();
for(count=0;count<length;count++){
IIC_Send_Byte(data[count]);
IIC_Wait_Ack();
}
IIC_Stop();//产生一个停止条件

return 0; //status == 0;

}

初始化完成之后,就可以结合官方库区读取数据了。

首先对BMI160初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct bmi160_dev bmi160sensor ;
void mybmi160_init(void)//BMI160初始化
{
// struct bmi160_dev bmi160sensor;
int8_t rslt = BMI160_OK;
bmi160sensor.id = BMI160_I2C_ADDR;
bmi160sensor.interface = BMI160_I2C_INTF;
bmi160sensor.read = IICreadBytes;
bmi160sensor.write = IICwriteBytes;
bmi160sensor.delay_ms = delay_ms;
bmi160sensor.chip_id=0;
IICreadBytes(BMI160_I2C_ADDR,BMI160_CHIP_ID_ADDR, &bmi160sensor.chip_id, 1);
printf("bmi_id=%d\n",bmi160sensor.chip_id);
// bmi160_get_regs2(BMI160_CHIP_ID_ADDR, &bmi160sensor.chip_id, 1, dev);
rslt = bmi160_init(&bmi160sensor);
/* Select the Output data rate, range of accelerometer bmi160sensor */
bmi160sensor.accel_cfg.odr = BMI160_ACCEL_ODR_800HZ;
bmi160sensor.accel_cfg.range = BMI160_ACCEL_RANGE_4G;
bmi160sensor.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;

/* Select the power mode of accelerometer bmi160sensor */
bmi160sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;

/* Select the Output data rate, range of Gyroscope bmi160sensor */
bmi160sensor.gyro_cfg.odr = BMI160_GYRO_ODR_800HZ;
bmi160sensor.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS;
bmi160sensor.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;

/* Select the power mode of Gyroscope bmi160sensor */
bmi160sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;

/* Set the bmi160sensor configuration */
rslt = bmi160_set_sens_conf(&bmi160sensor);
/* After the above function call, accel and gyro parameters in the device structure
are set with default values, found in the datasheet of the bmi160sensor */
}

获取陀螺仪和加速度数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//获取数据
void get_accel_gyro_data2(void)
{
uint8_t data_array[15] = {0};
uint8_t lsb;
uint8_t msb;
int16_t msblsb;
int16_t gx,gy,gz,ax,ay,az;

IICreadBytes(BMI160_I2C_ADDR,BMI160_GYRO_DATA_ADDR,data_array,15);//获取陀螺仪的数据

lsb = data_array[0];
msb = data_array[1];
msblsb = (int16_t)((msb << 8) | lsb);
gx = msblsb; /* gyro X axis data */

lsb = data_array[2];
msb = data_array[3];
msblsb = (int16_t)((msb << 8) | lsb);
gy = msblsb; /* gyro Y axis data */

lsb = data_array[4];
msb = data_array[5];
msblsb = (int16_t)((msb << 8) | lsb);
gz = msblsb; /* gyro Z axis data */

/* Accel Data */
lsb = data_array[6];
msb = data_array[7];
msblsb = (int16_t)((msb << 8) | lsb);
ax = (int16_t)msblsb; /* accel X axis data */

lsb = data_array[8];
msb = data_array[9];
msblsb = (int16_t)((msb << 8) | lsb);
ay = (int16_t)msblsb; /* accel Y axis data */

lsb = data_array[10];
msb = data_array[11];
msblsb = (int16_t)((msb << 8) | lsb);
az = (int16_t)msblsb; /* accel Z axis data */
printf("gyro->x=%d,y=%d,z=%d,accel->x=%d,y=%d,z=%d \n",gx,gy,gz,ax,ay,az);
}

设置为任意方向中断,这样可以通过示波器查看,当摇晃BMI160时,观察中断通道1是否有高电平产生了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void bmi160_Interrupt(void)//设置任意方向中断
{
struct bmi160_int_settg int_config;
int8_t rslt = BMI160_OK;
/* Select the Interrupt channel/pin */
int_config.int_channel = BMI160_INT_CHANNEL_1;// Interrupt channel/pin 1

/* Select the Interrupt type */
int_config.int_type = BMI160_ACC_ANY_MOTION_INT;// Choosing Any motion interrupt
/* Select the interrupt channel/pin settings */
int_config.int_pin_settg.output_en = BMI160_ENABLE;// Enabling interrupt pins to act as output pin
int_config.int_pin_settg.output_mode = BMI160_DISABLE;// Choosing push-pull mode for interrupt pin
int_config.int_pin_settg.output_type = BMI160_ENABLE;// Choosing active low output
int_config.int_pin_settg.edge_ctrl = BMI160_ENABLE;// Choosing edge triggered output
int_config.int_pin_settg.input_en = BMI160_DISABLE;// Disabling interrupt pin to act as input
int_config.int_pin_settg.latch_dur = BMI160_LATCH_DUR_40_MILLI_SEC;// non-latched output

/* Select the Any-motion interrupt parameters */
int_config.int_type_cfg.acc_any_motion_int.anymotion_en = BMI160_ENABLE;// 1- Enable the any-motion, 0- disable any-motion
int_config.int_type_cfg.acc_any_motion_int.anymotion_x = BMI160_ENABLE;// Enabling x-axis for any motion interrupt
int_config.int_type_cfg.acc_any_motion_int.anymotion_y = BMI160_ENABLE;// Enabling y-axis for any motion interrupt
int_config.int_type_cfg.acc_any_motion_int.anymotion_z = BMI160_ENABLE;// Enabling z-axis for any motion interrupt
int_config.int_type_cfg.acc_any_motion_int.anymotion_dur = 0;// any-motion duration
int_config.int_type_cfg.acc_any_motion_int.anymotion_thr = 100;
/* Set the Any-motion interrupt */
rslt=bmi160_set_int_config(&int_config, &bmi160sensor); /* bmi160sensor is an instance of the structure bmi160_dev */
}

更多其他详细程序请到我的公众号或者github查找。

美信DS28E05单总线EEPROM通信方式详解(以STM32F030为例)

发表于 2019-05-27 | 更新于 2019-05-30

概述

​ DS28E05是一款112字节用户可编程EEPROM芯片,分为7页,每页16字节。存储器页通过保护字节可单独设置为写保护或者EPROM仿真模式。每个器件都带有唯一的64位ROM注册码(ROM ID),由工厂刻入器件。DS28E05通过Maxim Integrated单触点1-Wire®接口高速通信,在多点1-Wire网络中,ROM ID作为节点地址。

关键特性

单触点1-Wire接口

112字节用户EEPROM,具有1K次写循环

用户存储器可编程为写保护以及OTP EPROM仿真模式

唯一、工厂编程的64位ROM ID

与主机通信速率高达76.9kbps (仅高速模式)

工作范围:3.3V ±10%, -40°C至+85°C

IO引脚具有±8kV HBM ESD保护(典型值)

3引脚SOT23和6引脚TSOC封装

应用

配件/PCB识别

消费品的售后管理

模拟感应器校准

医用传感器校准数据存储

通信方式与程序

​ DS28E05是通过单总线协议连接的,根据文档显示,标准的单总线协议是不行的,只能使用快速的单总线协议(Overdrive Speed)才行。

如图为读写周期的时间,最短的读写周期仅有2个微秒,注意读的时候不要超过2个微秒,否则就读不出数据了。

整个周期

复位时序图

复位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/******************************************
1-Wire器件复位, 并检查应答;有应答返回0, 无应答返回1
*******************************************/
unsigned char Reset( void )
{
unsigned char testCount = 50;
GPIO_DS28E05_Out_Mode();
DS28E05_Write_1();
DS28E05_Write_0();
delay_us(60); //复位60us低脉冲保持
DS28E05_Write_1(); //释放总线后9us读应答
GPIO_DS28E05_Input_Mode();
while(testCount--)
{
if( 0 == DS28E05_ReadBit() )
{
delay_us(2);
return 0;
}
}
return 1;
}

写数据时序图

写时序

写数据程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/******************************************
写数据位1
*******************************************/
void WriteBit_1( void )
{
DS28E05_Write_1();
DS28E05_Write_0(); //拉低总线保持1us
delay_us(1);
DS28E05_Write_1(); //释放总线延时大于12us
delay_us(20);//20us
}
/******************************************
写数据位0
*******************************************/
void WriteBit_0( void )
{

DS28E05_Write_1();
DS28E05_Write_0(); //拉低总线保持8-16us
delay_us(12); //9-10us
DS28E05_Write_1(); //释放总线延时6us
delay_us(9);
}

读数据程序

读时序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/******************************************
读数据位
*******************************************/
unsigned char value1;
static unsigned char Read_Bit( void )
{
GPIO_DS28E05_Out_Mode();
DS28E05_Write_1();
DS28E05_Write_0(); //拉低总线保持1us
delay_us(1);
DS28E05_Write_1();
DS28e05_IO_IN();//最重要的一步,一定要用寄存器操作,否则会错过读取的时间,经检测,整个读取周期为2-3微妙
value1 = DS28E05_ReadBit();
delay_us(2);
return value1;
}

写一个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/******************************************
写字节
*******************************************/
static void Write_Byte( unsigned char value )
{
unsigned char i;
GPIO_DS28E05_Out_Mode();
for( i = 0; i < 8; i++ )
{
if( value & 0x01 )
{
WriteBit_1();
}
else
{
WriteBit_0();
}
value = value >> 1;
}
}

读一个字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/******************************************
读字节
*******************************************/
static unsigned char Read_Byte( void )
{
int i, value;
value = 0;
for( i = 0; i < 8; i++ )
{
value >>= 1;
if( Read_Bit() )
value |= 0x80;
}
return value;
}

读写ROM和flash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/******************************************
功能:读8位家族码;48位序列号;8位CRC码;读取成功返回0
参数:*id--读取的数据存放地址
返回:0--操作成功;1--总线不可用;
*******************************************/
unsigned char DS28E05_ReadRom( unsigned char *id )
{
unsigned char i,j;
while(Reset());
Write_Byte( Rom_Read_Cmd ); //写命令
for( i = 0; i < 8; i++ )
{
j= Read_Byte();
*id++ = j;
}
return ( 0 );
}
/******************************************
功能: 读EPROM
参数: tgaddr--目标地址;
len--要读取的字节数;
*buffer--存放地址
返回:0--操作成功;1--总线不可用;
*******************************************/
unsigned char DS28E05_ReadMemory( unsigned char tgaddr, unsigned char len, unsigned char * buffer )
{
unsigned char i;
if( Reset() != 0 )
return ( 1 );
Write_Byte( Rom_Skip_Cmd ); //写命令
Write_Byte( Memory_Read_Cmd ); //写命令
Write_Byte( tgaddr ); //写地址低字节
Write_Byte( 0 ); //写地址高字节
for( i = 0; i < len; i++ )
{
buffer[ i ] = Read_Byte();
}
Reset();
return ( 0 );
}
//写eeprom

int ds28e05WriteMemory(uint8_t address, char *buffer, int length)
{
uint8_t a,b;
uint8_t sf,ef;
uint8_t sb[2]={0};
uint8_t eb[2]={0};
uint8_t spage, epage, npage, wpage;
uint8_t nseg, wseg=0;
uint8_t wBytes=0, rBytes=0, wAddr = 0;

// Calculate pages
spage = ((address & PAGE_MASK) >> 4);
epage = (((address + length) & PAGE_MASK) >> 4);
if (epage == NUM_PAGES) epage = NUM_PAGES - 1;
npage = epage - spage;
printf("spage=%d,epage=%d\n",spage,epage);
printf("npage=%d,length=%d\n",npage,length);
//This memory must be written respecting 16bits boundaries
sf = (address&0x01) != 0;
ef = ((address+length)&0x01) != 0;
printf("sf=%d,ef=%d\n",sf,ef);
if (ef)
{
DS28E05_ReadMemory( address+length,1, &eb[1]);
eb[0] = buffer[length-1];
length++;
}
if (sf)
{
DS28E05_ReadMemory(address-1,1, &sb[0]);
sb[1] = buffer[0];
length++;
address--;
}
// Write pages
for (wpage = 0; wpage <= npage; wpage++)
{
wAddr = address + wBytes;
// Calculate segments to write
if ((length - wBytes) > (BYTES_PER_PAGE))
// Will we pass a page boudary
if (wAddr % (SEG_SIZE * BYTES_PER_SEG) == 0)
nseg = SEG_SIZE;
else
nseg = (BYTES_PER_PAGE - (wAddr % (BYTES_PER_PAGE))) >> 1;
else
nseg = ((length - wBytes) & SEG_MASK) >> 1;

printf("nseg=%d\n",nseg);

if( Reset() != 0 )
return ( 1 );
Write_Byte( Rom_Skip_Cmd );
Write_Byte(DS28E05_WRITE_MEMORY);
Write_Byte(wAddr);
Write_Byte(0xff);
// Write segments within page
for (wseg = 0; wseg < nseg; wseg++)
{
if (sf)
{
Write_Byte(sb[0]);
Write_Byte(sb[1]);
wBytes += 2;
rBytes++;
sf = 0;
}
else if (ef && (length - wBytes) <= 2)
{
Write_Byte(eb[0]);
Write_Byte(eb[1]);
wBytes += 2;
rBytes++;
ef = 0;
}
else
{
Write_Byte(buffer[rBytes]);
Write_Byte(buffer[rBytes+1]);
wBytes += 2;
rBytes += 2;
}

a = Read_Byte();
b = Read_Byte();

printf("Readback: %02x %02x (%c%c)\n", a, b, a, b);

Write_Byte(0xff);

delay_ms(16);

a = Read_Byte();

printf("Verification byte: %02x\n", a);

if(a !=0xAA)
goto error;
}

Reset();;
}

return 1;
error:
Reset();
return 0;
}

详细的程序,请到我的github仓库查找或者关注我的公众号索取。

12

Daniel

总结多年经验电子工程师的血泪和汗水
13 日志
GitHub E-Mail
© 2015 – 2019 Daniel
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Pisces v7.1.1
|