分类 电路&嵌入式 下的文章 - 我的学记|刘航宇的博客
首页
📊归档
⏳时光机
📬留言
🐾友链
推荐
🎓843课程班
🖼️相册
🎵音乐
🏞️壁纸
搜 索
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
10,103 阅读
2
论文写作中如何把word里面所有数字和字母替换为新罗马字体
6,015 阅读
3
【高数】形心计算公式讲解大全
5,485 阅读
4
【1】基于STM32CubeMX-STM32GPIO端口开发
4,125 阅读
5
如何判断运放是工作在线性区还是非线性区
3,914 阅读
🌻微语&随笔
励志美文
我的随笔
写作办公
📖电子&通信
电路&嵌入式
通信&信息处理
编程&脚本笔记
🗜️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
搜 索
标签搜索
嵌入式
ASIC/FPGA
VLSI
SOC设计
机器学习
天线设计
C/C++
EDA&虚拟机
小实验
软件算法
信号处理
电子线路
通信&射频
随笔
笔试面试
硬件算法
Verilog
软件无线电
Python
DL/ML
刘航宇Hangyu Liu
嵌入式系统&数字IC爱好者博客
累计撰写
295
篇文章
累计收到
517
条评论
首页
栏目
🌻微语&随笔
励志美文
我的随笔
写作办公
📖电子&通信
电路&嵌入式
通信&信息处理
编程&脚本笔记
🗜️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
页面
📊归档
⏳时光机
📬留言
🐾友链
推荐
🎓843课程班
🖼️相册
🎵音乐
🏞️壁纸
用户登录
登录
电路&嵌入式(共64篇)
找到
64
篇与
电路&嵌入式
相关的结果
2022-10-11
读懂史密斯圆图
史密斯圆图能干啥用?史密斯圆图,就是做高频电路之间的阻抗匹配用的。所谓阻抗是电路对电的阻碍能力,它是个矢量,也就是说阻抗值是个复数。这里面既包括实部电阻成分一即与电力 "顶牛儿”的那部分阻力;也包括虚部电抗成分一就是把电力拉偏的那部分阻力。两者加一块,就叫阻抗。阻抗匹配,是电路之间连接的一-个基本要求,简单讲就是输入阻抗和输出阻抗大致相当,方向相反。如果阻抗不匹配呢?轻者电路工作效率低,重者.工作异常或直接烧毁。具体到高频电路来说,这些危害不仅都有,而且比数字电路、低频模拟电路上的危害要严重得多。那高频电路的阻抗匹配是啥标准呢?就是让输入端电阻和输出端电阻是纯阻性,而且最好等于509或752 。那原来阻抗不匹配,现在咋弄它就匹配了呢?就是在两个电路之间,接上电容、电感、传输线,微带线、变压器之类的东西。把阻抗值矫正到阻抗相等面来。史密斯圆图的主要用途,一是计算接到电路里的那些电容器、电感器的参数值的。二是用来显示某一电路的频率一阻抗特性的。史密斯圆图怎么用?史密斯圆图,它相当于一个地图,它上面每一个点, 都代表一个复数形式的阻抗值,而其圆心叫做匹配点,它代表了实部50om,虚部0om的理想阻抗,那就是我们要到达的地方。做阻抗匹配,就是规划一条从阻抗点走到匹配点的线路。然后呢?然后就是利用这些点位之间的差值做计算了。这个事儿我就不讲了。因为过去用纸本史密斯圆图才需要自己算,现在有很多专用软件能替我们做,不仅能算刚才我提到的那个匹配元件的电容量、电感量,还能算出谐振电路的Q值,驻波比,衰减量等等,这就用不着咱们算了,诸位知道这些概念是啥意思,就行了!至于具体怎么用史密斯圆图软件?怎么看这些数据?怎么评价匹配的效果?别着急,我们后边再聊。史密斯圆图第二节史密斯圆图该咋看?简言之,是看一线、两弧和两圆。我们说过,史密斯圆图上的每个点,都有实部值和虚部值,那么图上的线,其实也只有两种,一是等实部线,二是等虚部线。读史密斯圆图,就是先沿等虚部线,找到实部值,再沿着等实部线找到虚部值。那么一线和两弧,都是等虚部线;两圆,是等实部线!接下来我们就从一线讲起,说说史密斯圆图的刻度划分刻度值线一一根特殊的等虚部线史密斯圆图被一条名为电阻线的蓝色横线分成 上下两个半区,上半部分叫电感区, 那里所有点的虛部值都为正;下半部分叫电容区,那里所有点的虚部值都为负。而电阻线本身的虚部阻抗值不正不负,他上面每一个点的阻抗值均为0欧。所以电阻线是一根特殊的虚部线,它是我们查找实部值的一把尺子。电阻线上有三个点,最左侧的叫短路点,他表示实部值0欧姆,虚部值也为0欧姆的情况;最右侧的叫断路点,他表示实部值无穷大,虚部值也为0欧姆的情况;而中间点,也就是圆心那是匹配点,那里的阻值是“标准阻值”,一般情况下他是50欧姆。“三点” 是史密斯圆图的基点,也是我们校正天线分析仪的起点,一定记住。归一化处理但是请注意!虽然电阻线是一把测量实部阻值的尺子,但是这把尺子上标的不一定是实部阻值。纸本的史密斯圆图标注的是阻抗值/标准阻值的比值,这叫归-化处理,这个值叫归-化阻抗值。下图中的小红字标的是阻抗值,而大红字标的是归一化阻抗值9。咱们先说图.上的大红字,那就是归一化之后的阻抗值。如果我们是在纸本史密斯圆图上标图,那第一步应该把阻抗值转换成归一化阻抗值。以标准阻抗50欧姆为例。我们要找100欧姆的实部值,就去电阻线上找归一化阻抗值为100欧姆/50欧姆=2的点,而图上显示"0.2" 归一化阻抗值的地方,其实际阻抗值就是0.2*50欧姆= 10欧姆,而匹配点的归一化阻抗值永远为1,这是归一化阻抗标注法的一个识别标志。为什么要用归一化阻抗值标注刻度呢?因为很多时候,我们不是要把电路匹配到50欧姆上,而是要匹配到75欧姆或者300欧姆等阻抗上。请看下图,这是75欧姆标准电阻时,史密斯原图上的情况,其中电阻线下方写的红字是阻抗值。电阻线上方的写的红字是归一化阻抗值。第二套刻度一一导纳值和归一化导纳值等电阻线是一把度量实部值的尺子,它有阻抗值和归一化阻抗值和两种标注方法,其实在电脑版史密斯圆图的等电阻线上,还有一套刻度。就是用大绿字标注的归一化导纳值和用小绿字标注的导纳值。有人想问导纳值是啥?导是电阻值的倒数,纳是电抗值的倒数,导纳加一块就是导纳值,它是阻抗值的倒数,导纳值的单位是西门子,写作“S",1S等于= 1000mS。给导纳值做归一化,也就是将导纳值除以0.02S标准导纳值(0.02S, 其实就是1/50欧姆)。这两种标法的值,是等价的。例如,电阻线上25Ω那个点,它的导纳值为1/25Ω=0.04S,它的归一化导纳值就是0.04S/0.02S为=2。导纳值既然和阻抗值完全等价,用法也一样,那我们要这个玩意做啥呢?简单讲,我们在标注初始阻抗点时,要根据红色的阻抗值坐标系做,而在做阻抗匹配时,则要用到绿色的导纳值坐标系。两圆两弧---等实部圆和等虚部弧两圆---两种等实部线讲特殊的电阻线--也就是0欧姆等虚部线之后,我们看看与电阻线相切的那些圆形。这些圆圈都是等实部线,那上面每一条线的实部值都相等。其中红色的圆圈都叫阻抗圆,而绿色的圆圈都叫导纳圆,我们在电阻线.上找到实部阻抗值或者实部导纳值之后,就要沿着阻抗圆或者电纳圆去找虚部值。其中电阻线以上的点是正值,代表阻抗点的虚部值呈现感性,电阻线以下的点是负值,代表阻抗点的虚部值呈现容性。和看电阻线的规矩一-样,我们在标注初始阻抗值时只看红色的。两弧---两种等虚部线那么虚部值到那去查?从断路点发出,向史密斯圆图边界放射的红线叫等电抗弧;而从短路点发出,向史密斯圆图边界反射的绿线都叫等电纳弧9。这些都是等虚部线,我们找到实部值后,就是沿着实部线9到找到特定值的等虚部线,那虚部线的值标哪儿了呢,在史密斯圆图的外边界上。和刚才-个规矩,我们标初始阻抗值时是根据红色数字做的。总结一下,到底怎么读图?总结一下,到底怎么读图?第一步,用阻抗值除以标准电阻,得到归一化实部阻抗值和归一化虚部阻抗值。第二步,在等电阻线上,找到归一化实部阻抗值对应的阻抗圆。第三步,沿着阻抗圆,向上或向下旋转,找与归一化虚部阻抗值对应的等电抗弧。第四步,做个记号,就算OK。 举个栗子~! 1002-j50Ω滴点在哪儿?第一步,计算归一化实部阻抗值为100Ω/50Ω=2;归一化虚部阻抗值为-50Ω/50Ω=-1。第二步,在等电阻线上,找到归一化阻抗值为2的阻抗圆。第三步,沿着归一化阻抗值为2的阻抗圆下旋,转到-1 那个电抗弧上。第四步,做个记号!我标的是X。那如果图.上标的是阻抗值呢?如果是在电脑上识图,图上直接标注的阻抗值,那就更方便了,实部阻抗值标在阻抗圆上,虚部阻抗值写在电抗弧末端。我们标图的时候,不用换算,先根据实部阻抗值找到对应的阻抗圆,再沿着阻抗圆去查对应虚部阻抗值的电抗弧,然后做个记号,就OK啦~例如:我要查100Ω+j50Ω的点,先找到100Ω阻抗圆,然后沿着它的轨迹上旋,到达虚部值为502的地方,然后做个标记,就是Y点。归一化导纳值呢?简单讲,导纳值坐标系和阻抗值的查法、标注方法完全一样。第一步,用导纳值除以标准导纳值,得到归一化导纳值,第二步,在等电阻线上,找到归一化实部导纳值对应的那个导纳圆。第三步,沿着导纳圆向上或向下旋转,找与归一化虚部导纳值对应的等电纳弧。第四步,做个记号,就算OK。 再举个栗子 0.04S+j0.02S的点在哪儿?第一步,计算归一化实部导纳值为0.04S/0.02S=2;归一化虚部导纳值为0.02S/0.02S=1.第二步,在等电阻线上,找到归一化导纳值为2的导纳圆。第三步,沿着归一化导纳值为2的导纳圆上旋,转到导纳值为1的那个电纳弧上。第四步,做个记号!即Z。那如果图上标的是导纳值呢?那也简单,先根据实部导纳值找到对应的导纳圆,再沿着导纳圆去查对应虚部导纳值的电纳弧,然后做个记号,就OK啦~.例如:我要查0.04S-j0.02S的点,先找到0.04S导纳圆,然后沿着它的轨迹下旋,到达虚部值为-0.02S的地方,然后做个标记,那就是S点。好了~!关于怎么查史密斯圆图的事儿,我讲完了,接下来请大家做点练习,看看是否理解了。下一次我们学习如何用史密斯圆图做阻抗匹配。读图练习第一题,1点的阻抗值为50Ω+j50N,请问1点在图上什么位置?第二题,2点的归一化阻抗值为0.5+j0.5,请问2点在图.上什么位置?第三题,3点导纳值为0.04S-j0.02S,请问3点在图上什么位置?第四题,4点归一化导纳值为0.5-j0.2,请问4点在图上什么位置?请把上图打印出来,试着标一下,然后再看文末那个答案。 答案 史密斯圆图第三节怎么用史密斯圆图软件做阻抗匹配史密斯圆图软件做阻抗匹配有六句口诀:先设参数,后选起点,下容上感,左并右串,顺着圆走,往圆心转。smithV3.1软件的界面,然后按着口诀顺序,一点点说。然后举个设计例子,最后讲讲注意事项。软件界面简介打开SmithV3.1,首先看到左侧-一个有个史密斯圆图,那是我们的操作区域。这里我要着重强调一下,电脑软件上标的都是实际阻抗值,而不是归一化阻抗值,所以我们做阻抗匹配的时候不用换算数据了,但是要在匹配之前设置好频率值和标准电阻值,否则做出来的数据会和现实完全对不上的。右侧有几个重要窗口,最顶上的是Schematic窗口,当我们在左侧史密斯圆图上用鼠标做匹配的时候,这个窗口里会显示相应的电路图,比如我图.上画的这个匹配路径对应到电路上,就是先双联13.9p电容,再并联23.4nH电感。下方这个Cursor窗口也很重要哦。它里面标注的是光标所在点的具体参数,这其中最重要的当然是VSWR驻波比、和Z阻抗值, Zo标准电阻值, Freq频率值。 这其中后两项参数是需要我们在做匹配之前要手工输入的。先设参数,再选起点,先设参数:就是要设置工作频率和标准阻抗这两个值。再选起点:就是要把阻抗点的具体位置设到史密斯圆图.上。我们点击这个图标,然后在这个页面的左下角General这输入标准阻抗值50Ω,在datapoint那儿输入工作频率,默认设置是500MHz。然后我们点击按钮,软件都会弹出这个窗口。我们在这选中impedance (Ω), 并在下面两个空里填写阻抗点的实部阻抗值和虚部阻抗值,这就样就设好起点了.然后呢?然后就该我们添加元件了。下容上感,左并右串我们点击工具栏的这个部分,就可以在阻抗点上连接电容或电感了。怎么接线呢?这有两句口诀:下容上感,左并右串。那我们参照下图看一看。”下容上感”,是说史密斯圆图的电阻线上方是电感区,下方是电容区,因此呢,我们要往下移动阻抗点,就得接电容;要往上移动阻抗点,就得接电感。那具体是串电容还是并电容,又或者是串电感还是并电感呢?我们来看下一-句左并右串。“左并右串”,是说如果我们要沿着左侧这组蓝色的导纳圆移动阻抗点,就点击“并联元件”,也就是点工具栏上这两个按钮;如果我们要沿着右侧这组红色的阻抗圆移动阻抗点,就点击“串联元件”,就点工具栏上的这两个按钮顺着圆走,往圆心转那我们究竟怎么走到标准阻抗点呢?那第五句和第六句说的问题。所谓“顺着圆走”,是说顺着右侧的50阻抗圆或顺着左侧那个20mS导纳圆走,为什么呢?因为这两个圆都与匹配点相切,所以无论我们走什么路径去匹配点,都得经过其中-一个圆,而“往圆心转”是说我们无论沿着.上面哪条弧线旋转,最终都是往史密斯圆图的中心旋转。等我们把阻抗点挪到自己认为合适的位置后,右侧Schemat窗口里也就画出来了我们的阻抗匹配电路。一个栗子某功率放大器的要放大100M信号,其输入阻抗值为252+j352,而信号源阻抗为50Q,现在要在两者之间接一个匹配电路,为此我要如此操作。先设参数:我们点击这个图标,然后在这个页面的左下角General这输入标准阻抗值50Ω,在Datapoint那儿输入工作频率100MHz。然后点ok按钮。再选起点:我们点击按钮,软件都会弹出这个窗口我们在这选中impedance,然后在下面的两个空里填入实部值25欧姆、虚部值+35欧姆,点ok就行了。这时候我们发现,史密斯圆图上会出现一个方形坐标点DP1.下容上感,左并右串。顺着圆走,往圆心转那接下来,我们就要通过连接元件,改变阻抗点的阻抗了。由于DP1位于史密斯圆图的电感区,所以我们要让他往下转,那旋转是有很多路径,我们先说最简单的,从DP1直接转到20mS导纳圆上,在顺着20mS导纳圆上继续下旋到圆心。当然这是我们的设想,实际不一定能实现,我们就先以此为目标,试试看吧。那由于我是要向下移动阻抗点,也就是向电容区移动阻抗点,所以我要连接电容。由于我是沿着右侧的25欧姆阻抗线向下移动,左并右串,所以我应该选串联电容,也就是点我们点了串联电容按钮之后,会发现光标不能自由移动了,它只能是沿着红色的25欧姆阻抗圆移动,这就是smithV3.1软件的便利之处,他能防止我们走错路。那我们按软件限定的路线,沿着25欧姆阻抗圆下旋,发现有两次机会转到20mS导纳线上,我选哪一次呢?我们设想中是选第一次机会,但是我看到右侧Schenatic窗口里,要添加的串联电容是155pf就改主意了,因为这是个非标容量,说白了我让谁买也买不来这型号的电容。于是我继续沿着25欧姆阻抗圆向下旋转,到第二个交汇点去碰碰运气。那我到达25欧姆阻抗线与20mS导纳线第二次相交的地方一看,发现右侧Schenatic窗口里显示的是串联的是26p电容,这个参数与27p极为接近,那这容量的电容有地方买,所以我就在这儿点下鼠标左键,图片上就出现了DP2点。那接下来,我是要由DP2沿着20mS导纳圆上旋对吧?因为下容上感,所以我们要接电感,因为左并右串,我们要沿着左侧圆走,所以要并联电感,那我们点和第一步一样,我们还是要沿着电脑规划的线路边走边看,走到圆心时,我们发现右侧Schemat窗口里,显示的电感值是80nH左右,这个电感没啥制作难度,所以我就再次点击鼠标左键,史密斯圆图中心附近就会多出来一个DP3。 也就是路径4这个图。那我们到了这个DP3又意味着什么呢?我们别挪动光标,我们把鼠标停在DP3上,把视线挪到Cursor这个小窗上,在这我们会看到Q值0.005, VSWR1.03等参数。显然,VSWR约等于1,是个很好的结果,实际小信号的SWR匹配到1 .5就以很好了。而大功率的通讯设备,需要尽量往小了做,做到1.2以下。两个问题首先,我们还可以有别的匹配路径么?当然可以,条条大路通罗马。刚才我们走的路径是先串后并,用了一一个电容一个电感,走20mS导纳圆到的中点,也就是图上的路径1。那如果我们改走右边的509阻抗圆行么?行啊,完全可以。我们可以先并联16pf电容,再串联51pf电容。这就是路径2。那还有别的路可走么?有啊,比如我们可以选用阻抗匹配变压器,也就是先串联47pf电容,下旋到电阻线,再使用1:1 .4的阻抗变压器,沿着等Q值弧线(也就是从短路点、断路点之间的蓝色弧线,参见文末的图例)向右移动到圆心,这就是路径39。那还有别的么?有啊,我们还可以接电阻,走等虚部弧。比如我们可以走路径4,即先串联电阻,从DP1进到右边50Q阻抗圆.上,然后再串电容沿着50Q阻抗圆继续下旋,这也是可以的。只不过要注意两个问题,第- -点, 我们接电阻走等虚部线的时候,虽然匹配上了,但是会增加电路损耗的。第二点,由于现实中可没有合用的负阻元件卖,所以我们做匹配时绝不能沿着等虚部线退着走,也就是说不能接负阻器件,这- -点smith3.1软件考虑到了,他会限制我们那么做,但是其他软件或纸本的史密斯圆图就得注意这问题。其次,如果我们做匹配时转不到史密斯圆图的正中心(不太可能),或者实际制作中对不到史密斯圆图中心(很常见),那又 意味着什么?请看下图,图上这些棕色圆圈是等VSWR圆,也就是等驻波比圆,这个驻波比圆的特点是越靠近圆心,驻波比越小,比如圆心那- -点是1.也就是说输入端送出进去多少信号,负载端就吸收多少信号,能量一点没糟践;驻波比1.5, 意味着有4%的功率撞到输出端又撞回输入端了。驻波比29,就意味着有11%的能量撞回去了。通常来说,小信号阻抗匹配电路对驻波比要求比较低,达到1.5就算良好匹配了。如果体积有限制,还可以进一步放宽一些。 但是如果是强信号,电台天线那种场合,SWR控制的就比较严格了,大功率电台,通信基站要控制在1.2以内。
2022年10月11日
1,646 阅读
0 评论
4 点赞
高速电路系统-传输线阻抗匹配
传输线反射系数●当传输线的传播的信号到达某个阻抗不连续点时,信号会发生反射,●就像水流通过不同口径的管道接口时,水面产生波动一样。●根据反射电压和入射电压的比值, 可以定义传输线上的反射系数。$\Gamma=\frac}}=\frac$信号反射分析在信号跳变的瞬间,源端和负载端的电压变化信号阻抗匹配设计优点:RS无需电源,低功耗,对于驱动高容性负载起到限流作用,有效的避免了一些噪声。缺点:信号源加电阻占空间,对扇出不好。(C)优点RC隔直流,消除直流损耗。电容有充电时间,RC饱和时间大于2倍传输线延迟,也就是源端发射信号到RC电路之前没有饱和。调试办法在射频电路中进行阻抗匹配测试时,可按照如下步骤进行射频匹配网络调试:1:校准矢量网络分析仪2:用矢网测量开口线,保存S1P文件。在ADS中新建工程,按照如下原理图,插入开口线的S1P文件,使用ADS调谐调整微带线的长度,使开口线位于smith圆图的最右边使其处于开路状态,更新原理图参数。3:测量前级的输出阻抗将开口线焊接在焊点1的位置,利用矢网测量出前级网络的输出阻抗,保存S1P文件,利用上面抵消开口线参数影响后更新后ADS原理图,插入前级网络S1P文件,在ADS里读出对应频率点的阻抗Z14:测量下级的输出阻抗将开口线焊接在焊点2的位置,利用矢网测量出后级网络的输出阻抗,保存S1P文件,利用上面抵消开口线参数影响后更新后ADS原理图,插入后级网络S1P文件,在ADS里读出对应频率点的阻抗Z25:利用ADS的Smith Chart Utility 进行阻抗匹配将前级网络的输出阻抗Z1取共轭,负载网络的输入阻抗为Z2,代入到Utility进行阻抗匹配,最后将匹配后的元件值焊接到板子上进行测试
2022年10月10日
322 阅读
0 评论
2 点赞
2022-04-20
HAL库开发stm32 DHT11传感器
PB1引脚设置output即可,不想用PB1,修改引脚办法,修改dht11.c文件中的所有端口和引脚现象dht11.h#ifndef __HT11_H_ #define __HT11_H_ #include "main.h" #include "stm32f1xx_hal.h" //函数原型 //void delay_us(uint8_t); //微妙延时函数,启用了一个定时器。因为DHT11通讯过程涉及微妙延时 void GPIO_Input(void); //GPIO 状态转变的函数 CUBEMX默认的GPIO初始化我只开启了相关总线的使能 //把GPIO状态(输入 输出)封装成了两个函数 void GPIO_Output(void); void DHT11_Rst(void); //主机开始采集的信号 uint8_t DHT11_Check(void); //检查DHT是否回应 uint8_t DHT11_Init(void); //初始化函数 uint8_t DHT11_ReadBit(void); //读取一位 uint8_t DHT11_ReadByte(void); //读取一个字节 uint8_t DHT11_ReadData(uint8_t *); //读取数据(40个位) #endif dht11.c#include "dht11.h" #define CPU_FREQUENCY_MHZ 72 // CPU主频,根据实际进行修改 static void delay_us(uint32_t delay) { int last, curr, val; int temp; while (delay != 0) { temp = delay > 900 ? 900 : delay; last = SysTick->VAL; curr = last - CPU_FREQUENCY_MHZ * temp; if (curr >= 0) { do { val = SysTick->VAL; } while ((val < last) && (val >= curr)); } else { curr += CPU_FREQUENCY_MHZ * 1000; do { val = SysTick->VAL; } while ((val <= last) || (val > curr)); } delay -= temp; } } void GPIO_Input(void) { GPIO_InitTypeDef GPIO_InitStruct = ; /*Configure GPIO pin : PB1 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void GPIO_Output(void) { GPIO_InitTypeDef GPIO_InitStruct = ; /*Configure GPIO pin : PB1 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } void DHT11_Rst(void) //主机开始信号 { GPIO_Output(); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET); HAL_Delay(20); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET); delay_us(30); } uint8_t DHT11_Check(void) { uint8_t retry = 0; GPIO_Input(); while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) && retry <100) //等待回应拉位低电平 { retry++; delay_us(1); } if(retry >= 100)return 1;else retry = 0; //当变量值大于100 返回1 说明无响应 返回 0 则为正确响应 while(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) && retry <100) //等待变为高电平 { retry++; delay_us(1); } if(retry >= 100)return 1; return 0; } uint8_t DHT11_Init(void) { DHT11_Rst(); return DHT11_Check(); } uint8_t DHT11_ReadBit(void) //读取一个位 { uint8_t retry = 0; while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) && retry <100) //等待变为低电平 { retry++; delay_us(1); } retry = 0; while(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) && retry <100) //等待变为高电平 { retry++; delay_us(1); } delay_us(40); //40us 后如果为低电平 数据为0 高电平数据为1 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1))return 1;else return 0; } uint8_t DHT11_ReadByte(void) //读取一个字节 返回值位采集值 { uint8_t i,dat; dat = 0; for(i = 0;i < 8;i++) { dat <<= 1; //数据左移一位 dat |= DHT11_ReadBit(); //每读取到一个位 放到dat的最后一位 } return dat; } uint8_t DHT11_ReadData(uint8_t *h) { uint8_t buf[5]; uint8_t i; DHT11_Rst(); if(DHT11_Check() == 0){ for(i = 0;i < 5;i++) { buf[i] = DHT11_ReadByte(); } if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4]) { *h = buf[0]; h++; *h = buf[2]; } }else return 1; return 0; } main.c添加//你自己要完成OLED显示出温度湿度哈,这个我就不写代码了,不然真的是再喂饭了呜呜 #include "dht11.h" //引入头文件 #include "stdio.h" uint8_t data[2]; //定义一个数据数组 uint8_t buff1[]="dht11 ok\r\n"; uint8_t buff2[]="dht11 error"; uint8_t str_buff[64]; //int main 死循环外面 if(DHT11_Init() == 0) { //这里显示了“温度”“湿度等字符” HAL_UART_Transmit(&huart1,buff1,sizeof(buff1),10000); } else{ //OLED_ShowStr(0,0,"DHT11 error!",1); HAL_UART_Transmit(&huart1,buff2,sizeof(buff2),10000); } HAL_Delay(1000); while (1) { if(DHT11_ReadData(data) == 0) { //显示相关数据 sprintf((char *)str_buff,"温度%d%d;湿度%d%d\r\n",data[0] /10 ,data[0] %10,data[1] /10,data[1] /10); HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000); } HAL_Delay(1000); //DHT11每次采集一定要间隔1s //你自己要完成OLED显示出温度湿度哈,这个我就不写代码了,不然真的是再喂饭了呜呜! }
2022年04月20日
701 阅读
0 评论
13 点赞
2022-04-12
【视频课程】STM32系统开发与protues仿真快速入门课
STM32系统开发与protues仿真快速入门课,上课层次分明,包含gpio与按键开发,中断,定时器,AD/DA转化,传感器,串口通信,远程通信技术,OLED液晶显示等等,由间到难,条理清晰。GPIO&键盘扫描定时器&OLED串口&TIM+串口传感器基础&OLED动态显示传感器原理&ADC基础OLED动态显示本节OLED配置允许不设置PB12-P15 output,直接基本三步后可以创建工程文件解决1us实现办法关于传感器代码移植,可以下载网上开源的驱动文件xx.h和xx.c文件,类似OLED驱动文件一样分别添加到工程文件夹中的Inc和Src中,最后用keill5打开用ADD进行文件添加!此处忘了可以回放第二节课OLED课delay_ms实现static inline void delay_ms(uint32_t delay) { HAL_Delay(delay); }delay_us实现#define CPU_FREQUENCY_MHZ 72 // CPU主频,根据实际进行修改 static void delay_us(uint32_t delay) { int last, curr, val; int temp; while (delay != 0) { temp = delay > 900 ? 900 : delay; last = SysTick->VAL; curr = last - CPU_FREQUENCY_MHZ * temp; if (curr >= 0) { do { val = SysTick->VAL; } while ((val < last) && (val >= curr)); } else { curr += CPU_FREQUENCY_MHZ * 1000; do { val = SysTick->VAL; } while ((val <= last) || (val > curr)); } delay -= temp; } } 远程通信&结语串口调试工具综合视频
2022年04月12日
1,092 阅读
0 评论
14 点赞
西北大学数字电子技术个人考研笔记
本笔记是我考研期间依据数字电子技术考点重要性写的,希望能帮到各位学弟学妹,本笔记免费公开! 警告 若个人或辅导机构 擅自复制本文直接或间接盈利 、请向我举报,举报方式见下面,本人以 著作权法 追查! 本站域名由sciarm.com更变为ee.ac.cn 和下文页面中信息不冲突举报方式1.邮箱hyliu@ee.ac.cn2.点击博客中留言或私聊都可
2022年04月07日
1,200 阅读
0 评论
18 点赞
2022-04-07
西北大学模拟电子技术个人考研笔记
本笔记是我考研期间依据模拟电子技术考点重要性写的,希望能帮到各位学弟学妹,本笔记免费公开! 警告 若个人或辅导机构 擅自复制本文直接或间接盈利 、请向我举报,举报方式见下面,本人以 著作权法 追查到底!同时核查该机构/个人 是否有非法出书情况 、是否有 出版权与书号 , 一并交于公安机关追查 ! 本站域名由sciarm.com更变为ee.ac.cn 和下文页面中信息不冲突举报方式-请携带证据举报1.邮箱hyliu@ee.ac.cn2.点击博客中留言或私聊都可
2022年04月07日
1,390 阅读
0 评论
30 点赞
2022-03-13
数字电路基础-最大项与最小项
目录1.定义最小项:n个变量的逻辑乘,即与形式,每个变量以原变量或者反变量的形式出现一次。n个变量共有2n个最小项。用m表示,如ABC,表示为m0。最大项:n个变量的逻辑和,即或形式,每个变量以原变量或者反变量的形式出现一次。n个变量共有2n个最大项。用M表示,如A+B+C,表示为M0。如下为三变量最小项和最大项的表示方法: 2.性质对于n个变量来说,若给定这些变量确定的值,那么2n个最小项中仅有一组值为1,其余全为0;2n个最大项中仅有一组值为0,其余全为1.全部最小项之和恒等于1;全部最大项之积恒等于0。(可由第一条性质中看出)任意两个最小项之积等于0;任意两个最大项之和等于1。(可由第一条性质中看出)若干个最小项的和等于其余最小项和的反。简单可以记做为卡诺图上分成两部分,他们之间为反关系。3.关系最小项的反是最大项,最大项的反是最小项。
2022年03月13日
990 阅读
0 评论
6 点赞
SIM900A发送与接受短信
目录一.SMS简介SMS(Short Messaging Service)中文名称短信服务,短信是当下每一部手机上必备的功能之一,顾名思义,它是在手机之间发送文字信息或从个人计算机或手持设备向手机发送信息的一种方式,其文本信息的最大发送量为160个字符(字母、数字或者拉丁字母中的字符),对于中文一般最大发送量为70个字符。这里我想用SIM900A模块实现短信的收发。 二.短信的控制模式与编码先说一下:我采用的是Text Mode下使用GSM编码收发英文短信、使用UCS2编码收发中文短信对于短信的控制一共有三种模式:Block Mode、基于AT指令的Text Mode、基于AT指令的PDU Mode 。目前手机中默认使用PDU Mode,通过PDU编码的短信可以是文字、声音或者图像。Text Mode只能用于发送ANSI范围的字符,发送方式比较简单。SIM900A模块只提供Text Mode 和PDU Mode。中文短信中,所有汉字和字符都是采用UNICODE编码。1.Text ModeText Mode下,发送及接收到的数据均以ASCII码的显示来表示,可以发送指令"AT+CMGF=1",将GSM短信发送方式更改为文本模式。文本模式下接收的数据会自动解码,比如你收到一条短信息,GSM会返回:+CMGR: “REC UNREAD”,"+8613806XXXXXX",“11/10/21,13:22:13+32”hello (短信内容会自动换行)不需要自己解码,便可得到短信的发送者、发送时间和短信内容,比较容易操作。理论上Text Mode下,是只能够收发英文短信,但是SIM900A模块可以在Text Mode下使用UCS2编码,从而可以发送接收中文短信。2.PDU ModePDU相当于一个数据包,它由SMS的信息组成,作为一种数据单元,必须包含源地址、目的地址、有效时间、数据格式、协议类型、正文、正文长度(可达140字节),这些信息都以十六进制表示。PUD Mode被所有手机支持,可以使用任何字符集,其编码方式分为:7bit、8bit、UCS2。7-bit编码用于发送普通的ASCII字符,它将一串7-bit的字符(最高位为0)编码成8-bit的数据,每8个字符可“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;而UCS2编码用于发送Unicode字符。在这三种编码方式下,PDU串的用户信息(TP-UD)段最大容量(可以发送的短消息的最大字符数)分别是160、140和70。这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符。理论上发送中文短信需要使用PDU Mode的UCS2编码,上面也说了,SIM900A模块可以使用Text Mode发送UCS2编码,而且PDU Mode比Text Mode更加复杂,所以我采用了Text Mode收发中英文短信。PDU Mode的详细讲解可以借鉴此博客:点击链接跳转3.GSM编码在GSM编码模式下,收发消息的内容和电话号码,都是以ASCII字符的形式显示的,发送英文短信时使用十分方便。所以我使用GSM编码来收发英文短信。4.UCS2编码谈到UCS2编码就不得不说UNICODE,UNICODE又叫统一码、万国码,是计算机科学领域里的一项行业标准,包括字符集、编码方案等。UNICODE 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。简单来说,UNICODE编码可以表示世界上任意一种语言(有点夸张),自然也可以表示中文。而UCS2编码是UNICODE的一种,UCS2中每个字符都占俩个字节。使用UCS2编码后,发送短信的手机号码、短信内容都要经过UCS2编码转换才可以,但UCS2编码发送的消息在手机上可以直接显示为中文。所以,需要UCS2与中文的转换软件,如下,可以实现中文和UCS2的双向转换 三.收发英文短信1.AT+CPMS查询短信数量2.AT+CNMI设置新消息提示类型3.AT+CMGF选择短信模式4.AT+CSCS设置编码 5.AT+CSMP设置短信文本模式使用Text Mode的GSM编码时,短信文本模式设置为:AT+CSMP=17,167,0,240(消息显示在终端)AT+CSMP=17,167,0,241(消息存储在SIM卡中) 6.AT+CMGS发送消息到指定手机号使用Text Mode的GSM编码时,直接AT+CMGS="手机号"即可,然后,在>后输入要发送的内容(不要勾选发送新行),最后发送HEX(十六进制)的:1A 即可。如图,我使用本机向本机发送了一条短信,而且,本机收到短信后在终端中显示出来了。 这是SIM公司给出的例子:CTRL-Z 代表十六进制:1A使用SIM900A向本机发送一条英文短信的完整步骤如下: 四.收发中文短信收发中文短信利用的是Text Mode下的UCS2编码。相比于收发英文短信,收发中文短信需要修改的地方有:修改编码:AT+CSCS=“UCS2”修改短信文本模式:AT+CSMP=17,167,0,24(短消息显示在终端,25:存储在SIM中)手机号码要用UNICODE码发送的消息要用UNICODE码(有专门的转换软件)这是SIM公司给出的例子: 我要发送信息:可爱的小白鼠,女朋友收到后回复消息,用软件将UNICODE码转换为中文,串口操作界面如示: 发消息如示: 收消息如示: 这是我的SIM900A
2022年02月16日
511 阅读
0 评论
1 点赞
HAL_STM32_DS18B20开发
1.设置一个如PA0作为DS18B20模块接口2.添加下面2个文件,注意程序已经集成us延时ds18b20.c#include "ds18b20.h" static inline void delay_ms(uint32_t delay) { HAL_Delay(delay); } #define CPU_FREQUENCY_MHZ 72 // CPU主频,根据实际进行修改 static void delay_us(uint32_t delay) { int last, curr, val; int temp; while (delay != 0) { temp = delay > 900 ? 900 : delay; last = SysTick->VAL; curr = last - CPU_FREQUENCY_MHZ * temp; if (curr >= 0) { do { val = SysTick->VAL; } while ((val < last) && (val >= curr)); } else { curr += CPU_FREQUENCY_MHZ * 1000; do { val = SysTick->VAL; } while ((val <= last) || (val > curr)); } delay -= temp; } } //复位DS18B20 void DS18B20_Rst(void) { DS18B20_IO_OUT(); //SET PA0 OUTPUT DS18B20_DQ_OUT=0; //拉低DQ delay_us(750); //拉低750us DS18B20_DQ_OUT=1; //DQ=1 delay_us(15); //15US } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 uint8_t DS18B20_Check(void) { uint8_t retry=0; DS18B20_IO_IN();//SET PA0 INPUT while (DS18B20_DQ_IN&&retry<200) { retry++; delay_us(1); }; if(retry>=200)return 1; else retry=0; while (!DS18B20_DQ_IN&&retry<240) { retry++; delay_us(1); }; if(retry>=240)return 1; return 0; } //从DS18B20读取一个位 //返回值:1/0 uint8_t DS18B20_Read_Bit(void) // read one bit { uint8_t data; DS18B20_IO_OUT();//SET PA0 OUTPUT DS18B20_DQ_OUT=0; delay_us(2); DS18B20_DQ_OUT=1; DS18B20_IO_IN();//SET PA0 INPUT delay_us(12); if(DS18B20_DQ_IN)data=1; else data=0; delay_us(50); return data; } //从DS18B20读取一个字节 //返回值:读到的数据 uint8_t DS18B20_Read_Byte(void) // read one byte { uint8_t i,j,dat; dat=0; for (i=1;i<=8;i++) { j=DS18B20_Read_Bit(); dat=(j<<7)|(dat>>1); } return dat; } //写一个字节到DS18B20 //dat:要写入的字节 void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t testb; DS18B20_IO_OUT();//SET PA0 OUTPUT; for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if (testb) { DS18B20_DQ_OUT=0;// Write 1 delay_us(2); DS18B20_DQ_OUT=1; delay_us(60); } else { DS18B20_DQ_OUT=0;// Write 0 delay_us(60); DS18B20_DQ_OUT=1; delay_us(2); } } } //开始温度转换 void DS18B20_Start(void)// ds1820 start convert { DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0x44);// convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 uint8_t DS18B20_Init(void) { DS18B20_Rst(); return DS18B20_Check(); } //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short DS18B20_Get_Temp(void) { uint8_t temp; uint8_t TL,TH; short tem; DS18B20_Start (); // ds1820 start convert DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7) { TH=~TH; TL=~TL; temp=0;//温度为负 }else temp=1;//温度为正 tem=TH; //获得高八位 tem<<=8; tem+=TL;//获得底八位 tem=(float)tem*0.625;//转换 if(temp)return tem; //返回温度值 else return -tem; } ds18b20.h#ifndef __DS18B20_H #define __DS18B20_H #include "main.h" #include "stm32f1xx_hal.h" //#include "delay.h" #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) #define GPIOA_ODR_Addr (GPIOA_BASE+12) #define GPIOB_ODR_Addr (GPIOB_BASE+12) #define GPIOC_ODR_Addr (GPIOC_BASE+12) #define GPIOD_ODR_Addr (GPIOD_BASE+12) #define GPIOE_ODR_Addr (GPIOE_BASE+12) #define GPIOF_ODR_Addr (GPIOF_BASE+12) #define GPIOG_ODR_Addr (GPIOG_BASE+12) #define GPIOA_IDR_Addr (GPIOA_BASE+8) #define GPIOB_IDR_Addr (GPIOB_BASE+8) #define GPIOC_IDR_Addr (GPIOC_BASE+8) #define GPIOD_IDR_Addr (GPIOD_BASE+8) #define GPIOE_IDR_Addr (GPIOE_BASE+8) #define GPIOF_IDR_Addr (GPIOF_BASE+8) #define GPIOG_IDR_Addr (GPIOG_BASE+8) #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //IO方向设置 #define DS18B20_IO_IN() #define DS18B20_IO_OUT() //IO操作函数 #define DS18B20_DQ_OUT PAout(0) //数据端口 PA0 #define DS18B20_DQ_IN PAin(0) //数据端口 PA0 uint8_t DS18B20_Init(void); //初始化DS18B20 short DS18B20_Get_Temp(void); //获取温度 void DS18B20_Start(void); //开始温度转换 void DS18B20_Write_Byte(uint8_t dat);//写入一个字节 uint8_t DS18B20_Read_Byte(void); //读出一个字节 uint8_t DS18B20_Read_Bit(void); //读出一个位 uint8_t DS18B20_Check(void); //检测是否存在DS18B20 void DS18B20_Rst(void); //复位DS18B20 #endif程序进行调用使用温度=DS18B20_Get_Temp();进行调用数值,可见精度达到要求了
2022年02月03日
827 阅读
3 评论
9 点赞
2022-01-31
【10】基于STM32CubeMX-STM32ADC与OLED开发
目录实训案例:ADC与OLED综合训练在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能:【1】 上电开机后,首选在OLED上显示“强国图志”图片,然后让LED1与LED2依次点亮,然后熄灭,进行灯光检测。灯光检测结束后,OLED切换至数据显示界面,分3行:第1行显示:“ sciarm.com ”第2行显示:“采样值:”第3行显示:“电压值:”【2】在主程序中,采用查询的方式,每隔0.3秒对ADC_IN0通道的光敏传感器进行一次电压数据采集,并将采样到的12位数据换算成对应的实际电压值。LED1作为A/D采样指示灯,每采样一次闪烁一下。【3】每进行完一次光敏传感器的数据采样和电压换算后,将其结果更新到OLED显示屏中相应的位置。如果光敏传感器的电压值小于1.3V,则将LED2灯点亮,反之,将LED2灯关闭。//首先需要进行OLED的底层驱动函数移植,生成相应的文字和图片数据 /* USER CODE BEGIN Includes */ //====引入OLED底层驱动的头文件======== #include "XMF_OLED_STM32Cube.h" #include "stdio.h" /* USER CODE END Includes */extern unsigned char BMP1[]; #define LED1_ON() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_SET) #define LED2_ON() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_SET) #define LED1_OFF() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_RESET) #define LED2_OFF() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_RESET) uint16_t ADC0_Value = 0; uint16_t ADC_Volt = 0; uint8_t str_buff[64];//LED灯流水点亮检测 void LED_Check() { LED1_ON(); HAL_Delay(500); LED2_ON(); HAL_Delay(500); LED1_OFF(); HAL_Delay(500); LED2_OFF(); HAL_Delay(500); }//显示开机LOGO图片 void OLED_display_pic() { OLED_Clear(); OLED_DrawBMP(0,0,128,8,BMP1); }//显示数据显示界面 void OLED_display_info() { OLED_Clear(); OLED_ShowString(6,0,(uint8_t *)"sciarm.com"); HAL_Delay(200); OLED_ShowCHinese(0,3,24); OLED_ShowCHinese(18,3,25); OLED_ShowCHinese(36,3,26); OLED_ShowString(54,3,(uint8_t *)":"); HAL_Delay(200); OLED_ShowCHinese(0,6,16); OLED_ShowCHinese(18,6,17); OLED_ShowCHinese(36,6,26); OLED_ShowString(54,6,(uint8_t *)":"); HAL_Delay(200); }//更新ADC采样数据与换算结果 void OLED_display_dat() { sprintf((char*)str_buff, "%4d", ADC0_Value); OLED_ShowString(64,3,(uint8_t *)str_buff); sprintf((char*)str_buff, "%d.%d%dV", ADC_Volt/100, (ADC_Volt%100/10), ADC_Volt%10); OLED_ShowString(64,6,(uint8_t *)str_buff); }//ADC采样过程与灯光自动控制 void Get_ADC0_Value() { HAL_ADC_Start(&hadc1); if(HAL_OK == HAL_ADC_PollForConversion(&hadc1, 30)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); ADC_Volt = ADC0_Value * 330 / 4096; if(ADC_Volt < 130) { LED2_ON(); } else { LED2_OFF(); } } HAL_ADC_Stop(&hadc1); }/* USER CODE BEGIN 2 */ OLED_Init(); //初始化OLED OLED_display_pic(); //显示开机LOGO图片 LED_Check(); //灯光检测 OLED_display_info(); //显示数据界面 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { LED1_ON(); //ADC采样指示灯点亮 Get_ADC0_Value(); //进行一次ADC采样及逻辑处理 OLED_display_dat(); //更新OLED中的采样数据 HAL_Delay(200); //延时0.2秒 LED1_OFF(); //ADC采样指示灯关闭 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
2022年01月31日
729 阅读
0 评论
12 点赞
2022-01-29
【9】基于STM32CubeMX-STM32OLED开发
目录必备文件关于OLED的概述OLED:Organic Light-Emitting Display,有机发光显示。OLED具备自发光、厚度薄、视角广、功耗低、对比度高、响应速度快、可用于挠曲性面板、使用温度范围广、构造及其制作过程较简单等优异特性,并认为是一种比液晶显示更为先进的新一代平板显示技术。以目前的技术,OLED的尺寸还难以大型化,但是分辨率却可以做得很高。基于STM32的OLED应用,要做那些事情:【1】移植OLED的底层驱动函数库。【2】准备需要的中文字符和图片等数据。【3】调用OLED驱动库中的底层函数进行应用开发。OLED开发相关资源下载基于STM32CubeMX的OLED屏驱动程序库(内含4个文件)【1】XMF_OLED_STM32Cube.c:驱动程序的源文件。【2】XMF_OLED_STM32Cube.h:驱动程序的头文件。【3】XMF_OLED_Font.h:字库数据文件。【4】XMF_OLED_BMP.h:图片数据文件。基于STM32CubeMX的OLED底层驱动函数移植【1】将4个驱动文件拷贝到工程文件中,和main.c放在同一目录,并将XMF_OLED_STM32Cube.c添加到工程代码文件中,并在main.c中引入头文件XMF_OLED_STM32Cube.h。【2】根据所选用的芯片型号,修改XMF_OLED_STM32Cube.h头文件中所以用的芯片头文件。【3】根据硬件电路原理图中,修改XMF_OLED_STM32Cube.h中OLED的引脚定义。【4】查看OLED_Init(void)初始化函数的源码,根据电路接口和应用需要进行修改。OLED驱动库中常用的函数void OLED_Init(void); //OLED初始化函数 void OLED_Clear(void); //OLED清屏函数//显示英文字符串函数 void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *p); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:*p,字符串指针 返回值:void,无。//显示中文字符函数 void OLED_ShowCHinese(unsigned char x,unsigned char y,unsigned char no); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:no,待显示中文字符在数组Hzk[][32]中的位置。 返回值:void,无。//显示图片函数 void OLED_DrawBMP( unsigned char x0, unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); 参数1:x0,起点列坐标,0~127 参数2:y0,起点行坐标,0~7 参数3:x1,图片的列范围,1~128 参数4:y1,图片的行范围,1~8 参数5:BMP[],待显示图片数据的数组。 返回值:void,无。实训案例:STM32控制OLED显示要点字库软件中行前后缀不需要括号在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能:【1】用取字模软件生产一张图片数据,作为开机界面在OLED上显示。【2】0.5秒后进入信息界面, 第1行显示网址“sciarm.com”, 第2行显示中文“小蜜蜂笔记”,第3行显示日期“2022-02-18”。//用取字模软件生成开机LOGO图片数据,并拷贝到XMF_OLED_BMP.h的数组中。 const unsigned char BMP1[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //此处省略64×62个字节元素 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };//用取字模软件生成所需中文字符数据,保持到XMF_OLED_Font.h中的Hzk[]数组。 const unsigned char Hzk[][32]={ , ,/*"小",0*/ /* (16 X 16 , 宋体 )*/ , ,/*"蜜",1*/ /* (16 X 16 , 宋体 )*/ , ,/*"蜂",2*/ /* (16 X 16 , 宋体 )*/ , ,/*"笔",3*/ /* (16 X 16 , 宋体 )*/ , ,/*"记",4*/ /* (16 X 16 , 宋体 )*/ };extern unsigned char BMP1[]; void OLED_display_pic() { OLED_Clear(); OLED_DrawBMP(0,0,128,8,BMP1); }void OLED_display_info() { OLED_Clear(); OLED_ShowString(6,0,(uint8_t *)"sciarm.com"); OLED_ShowCHinese(10,3,0); //小 OLED_ShowCHinese(28,3,1); //蜜 OLED_ShowCHinese(46,3,2); //蜂 OLED_ShowCHinese(64,3,3); //笔 OLED_ShowCHinese(82,3,4); //记 OLED_ShowString(24,6,(uint8_t *)"2022-02-18"); }//在mian()函数中添加下面的代码: /* USER CODE BEGIN 2 */ OLED_Init(); //OLED初始化 OLED_display_pic(); //显示图片 HAL_Delay(500); //延时0.5秒 OLED_display_info(); //显示信息 /* USER CODE END 2 */
2022年01月29日
1,143 阅读
16 评论
11 点赞
2022-01-26
【8】基于STM32CubeMX-STM32ADC开发基础
目录STM32的ADC资源概述STM32F103ZE芯片(144脚)中有ADC1、ADC2、ADC3共3个12位逐次逼近型模数转换器,具有18个测量通道,可测量16个外部和2个内部信号源(内部温度和内部参考电压)。这2个内部信号源只能连接到ADC1。ADC的各个通道的A/D转换可以单次、连续、扫描或间断模式执行。A/D转换结果以左对齐或右对齐的方式,存储在16位规则组或者注入组数据寄存器中。按照A/D转换的组织形式来划分,ADC的模拟输入通道分为规则组和注入组两种。ADC可以对一组最多16个通道按照指定的顺序逐个进行转换,这组指定的通道称为规则组。在实际应用中,可能需要中断规则组的转换,临时对某些通道进行转换,好像这些通道注入了原来的规则组,故称注入组,最多由4个通道组成。ADC启动与停止相关的HAL库函数//查询,阻塞方式,启动ADC HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); //查询,阻塞方式,停止ADC HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); //中断,非阻塞方式,启动ADC HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc); //中断,非阻塞方式,停止ADC HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);ADC转换结果读取的HAL库函数uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); 参数1:hadc,ADC实例指针。 返回值:uint32_t,ADC转换结果。查询方式,阻塞式A/D转换HAL库函数HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); 参数1:hadc,ADC实例指针。 参数2:Timeout,超时时间。 返回值:HAL_StatusTypeDef,函数执行状态。应用实例:用查询的方式,进行一次A/D采样并将结果读出。 uint16_t ADC_Value = 0; //以查询的方式启动ADC HAL_ADC_Start(&hadc); //等待一次规则组的ADC转换完成,并将结果读出 if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); }中断方式,非阻塞式A/D转换HAL库函数应用实例:用中断的方式,进行一次A/D采样并将结果读出。 uint16_t ADC_Value = 0; //以中断的方式启动ADC HAL_ADC_Start_IT(&hadc); //重写ADC转换完成中断回调函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { ADC0_Value = HAL_ADC_GetValue(&hadc1); }实训案例:ADC单次数据采样与电压换算在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】将ADC_IN0设置为12位ADC,右对齐,启用中断。【2】分别用查询和中断这2种方式,每隔0.5秒采样一次ADC的数据。【3】将每次读取到的ADC采样值转换为对应电压值,发送到上位机。【4】LED1作为采样指示灯,在ADC转换过程中点亮,其余时间熄灭。要点配置串口没有接收中断,不需要对NVIC进行使能#include "stdio.h" #define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET) #define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET) uint16_t ADC0_Value = 0, ADC0_Volt = 0; uint8_t str_buff[64];void UR1_Send_Info() { sprintf((char *)str_buff,"采样值:%d,电压值:%d.%d%dV\r\n",ADC0_Value,ADC0_Volt/100,(ADC0_Volt%100)/10,ADC0_Volt%10); HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000); }用查询,阻塞的方式来实现void Get_ADC_Value() { HAL_ADC_Start(&hadc1); LED1_ON(); if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); ADC0_Volt = ADC0_Value * 330 / 4096; } UR1_Send_Info(); LED1_OFF(); HAL_ADC_Stop(&hadc1); }//在mian()函数中添加以下代码: /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Get_ADC_Value(); //启动一个阻塞式的ADC转换并读取数据 // UR1_Send_Info(); //向上位机发生采样值和电压值 HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */用中断,非阻塞的方式来实现void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance == ADC1) { ADC0_Value = HAL_ADC_GetValue(&hadc1); //读取ADC转换结果 ADC0_Volt = ADC0_Value * 330 / 4096; //将采样值换算成电压值 UR1_Send_Info(); //向上位机发生ADC采样信息 LED1_OFF(); //关闭LED1采样指示灯 } }//在mian()函数中添加以下代码: /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_ADC_Start_IT(&hadc1); //启动一个非阻塞式的ADC转换并读取数据 LED1_ON(); //点亮LED1采样指示灯 HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
2022年01月26日
880 阅读
1 评论
9 点赞
1
2
3
...
6