基于stm32控制的电压测量监控系统
系统简介
本设计以ADC转换为基础,采用ARMCortex-M3内核STM32F103ZET6作为主控芯片来控制,通过串行通信来传送和接收信号,并定时将数据保存到E2PROM中的数字电压测量监控系统,现已广泛地应用于雷达、通信、测控、图像、仪表、医疗、音频等领域,显示出强大的生命力和广阔的应用前景。
【关键词】stm32单片机 数字电压 ADC转换 监控系统
1 绪论
数字电压表(DVM)一直以来都是一种运用模数转换变换成为数字量,也就是说说将连续的模拟量大小经过转换处理后,形成不能连续但是为数值的量,在通过相应的技术将数值呈现出来。另外,因为这种方式会带来各种相关技术及测量仪器等都可以将最终效果提高很多。本篇文章主要围绕单片机、模数转换仪器及数值显示电子电压表的内部原理结构进行说明。现如今,在电子电压测量领域中,各种单片机、转换器起到了非常大的作用,而且被广泛应用于工农及制造业的全自动化处理过程中,表现出非常大的市场潜力。在这种技术应用的的过程中,单片机的控制性是人们主要思考的问题,同时给人们已经成为生产生活中不可获取的部分。仅仅提及到的电压测量技术就是常见的一个示例,但是随着应用的广泛,大家对其的各种要求会更多。为了此项技术及研究成果能够更好的服务于我们的生产生活,就应该关注单片技术的更为精密的使用方法,使得一切都能够朝向更智能、更轻便的数字化道路发展。
1.1 背景
模数转换的思路发源于二战末时期,后来逐渐被广泛应用。在通信领域的广泛应用中,数字通信占据绝对领导地位。若我们需要将数字通信变为实践应用之时,那么就必须准备好发射端,以此将需要传递出的各种图片、声音等相对结构比较复杂的连续表现的信息,通过模拟转换为相对分离的数字变量后,传递发送之目的;而在接受的一端,也需要做转换,将接受到的连续数值信息,通过运算变换为连续的数值形态,还原为声音及图片,这个过程就是ADC转换。正因如此,产生了模拟数字转换和数字模拟转换电路。
在ADC的研究、设计和制造领域,一开始是国外比国内发展得更快,发展的也算较为全面,但又因为国内基本上都是集中在中低端的产品上面,所以更国外相比发展的较慢。
自上个世纪七十年代中期,终于研发出了第一款最为接近现代数模转换的仪器,成为现代第一款单片机数模转换器。后来到了九十年代开始,这种技术方法开始在各类便携式电子产品中大量被应用。我们发现,ADC的发展趋势主要向单片化、低功耗、高转换率、高分辨率的方向发展。
1.2 现状与发展
对于数字电压表具体应用时间为上个世纪的五十年代初,自被发明后,不断进行技术革新,目前早已实现了IC化效果,摒弃了最初的原始阶段的继电器形态,但是与此同时,其计算精度也明显提高到0.01%级别。另外,目前在各大实验中出现较多的高价样品等,再到工厂和矿山广泛使用的所谓低成本模型,可用作配电盘指示器的配电盘模型已经出现。
美国NLS公司于1952年研制的DVM比较法是世界上第一台DVM。这种数字式电压表在实现的技术中主要采用将各种输入的电压进行时间间隔的操作,以此来带动脉冲器的使用,输出结果又计数器来读取,和目前的计数器转换装置一样。其主要特点为能够直接对振荡器进行控制。在大量的电子元件器随着市场的变化,于上世纪的五十年代后期出现了应用步进开关的数字电压表的先例。最为显著的优势是,能够直接读取小数,而没有专门设置各种电路及打印输出的编码转换器,电路结构简单。缺点是步进开关的最大转速只有30ms /步,因此各种响应不足,大概需要将近一至三秒的时间来做专门测取,这个方法的驱动功率太大,使得器件的寿命受到了影响。
到了六十年代开始,晶体管的技术得到了改进,更为小型化的晶体管及电路的实现,使得这种曾经较为流行的此类方式逐渐被淡化。另外,六十年代初出现了同簧片或水银为主的继电器,再次从技术上提高了数模电压表的精密特性。相当于是,将常规的计测时间逐步减少更小级别,同步进开关相比,速度提高了十倍多,最大限制也是5位(99999)。
随着计算技术的飞速发展,各种不同特性的A/D转换器应运而生。其中,连续比较型A/D变换器作为一种高精度、高速的变换器,仍占据着重要的地位。积分A /D变换器作为一种高精度、抗干扰的变换器,在数字电压表领域得到了迅速地发展。
1.3 论文主要工作
本篇文章的设计思路主要有五个部分:量程自动转换、模数转换、STM32单片机、显示和通信。以其五个主要部分,来分析电压信号转换的内部流程。该处理流程主要为:将信号源接受后,进行数模转换模块的处理后,将模拟信号变化为间隔的数字信息,然后使用相关转置将这类数字信号输送到控制单元,存储于单片机中,信号经单片机微控制单元处理后,用液晶显示模块显示信号,并把第一次信息发送并保存到E2PROM芯片中。
第一章绪论。主要介绍了单片机测量电压系统开发背景、国内外发展现状、论文主要工作。
第二章方案与论证。应用设计好的不同方法,对处理过程中的每一模块进行功能论证,同时对处理的可行性做好分析,并且将技术实现的具体流程,关键环节及难点解决思路进行详细的说明,然后确定一类行之有效的方法。
第三章相关理论。主要介绍E2PROM、中断、电路原理图与PCB图。
第四章,主要完成硬件的设计工作。这期间需要做到的工作是,先做好内部原理结构的规划,使用AD勾勒出完全的结构图,然后将印制电路板设计完整,这个过程里最关键的是对元器件使用中的参数及测取方式做好备选,最后将思路转换为实现,进行电路板的焊接工作。
第五章,再来进行软件设计实现工作。这部分工作主要是将单片机的主程序实际完毕,将各部分的程序编写完整后,做相关测试以备后用。
第六章,对整个系统进行调试并试运行。对整个系统进行完整性实现后,将不同功能部分进行整合,来观测不同项目的成果。
2 系统方案的选择与论述
整个系统将处理器Cortex三代产的嵌入式-微控制器的集成电路技术应用到主芯片上,同时准备相关的外设及电路,以此来做好相关数据的采集、显示及传输工作,整个过程包含了信号的调理、ADC、LCD及USART,还有特定的供电模块的对接。这个过程中,数模转换及USART技术中都应用了采用STM32片内的AD外设和USART外设。基于STM32的电压采集系统的系统结构图如图2.1所示。

图2.1 基于STM32的电压采集系统结构图
信号源产生的模拟电压信号,经过信号调理电路的处理,提高了测量信号的精度,并对信号进行隔离和滤波。将处理后的信号传送给ADC模块进行模数转换,然后发送至STM32微处理器,用LCD模块显示出来,同时通过USART通信接口传送至上位机。
2.1 A/D模数转换模块
模数转换主要是完成了数字量的转换实现,这个过程中应用了模数转换器来实现。这样于是就会引入两个概念模拟量和数字量。包含以下五种A/D器件的类型。
(1)积分型
所谓积分型模数转换器的原理结构是,对于输入进的电压被经过处理,变成为相应的时间及频率数值,接着应用各种仪器来获取该类数值。这种方式的优势为,电路结构相对简洁,在实现的效果上也较为清晰,只是在转换的精度实现上更多需要由积分时间来决定,整个转换效率不太高。早年时间里,单片机的模数转换方法大多数时候应用的是整型数值,目前已经逐渐变成为市场的主流产品系列。
(2)逐次逼近型
这类主次逼近算法,主要是由一个比较器及数模转换器在比较逻辑中生成的。基于Most Significant Bit,能够将每单位的比特数值同数模转换器的输出值进行对比,在做多次对比后产生输出值大小。整个电路的大小规模较为适中,具备高速,低能耗,同时低分辨率的特点,同时成本也被有效的控制,但是价格稍高。
(3)并行比较型/串并行比较型
这种方式的数模转换器中,应用多个比较器,但是仅有一个比较及转换结构,因此也被叫做Flash类型。由于其转换效率较高,n为转换工作需要运用2n-1个转换器,因此电路呈现的结构较大,价格上也必然较高,在应用中躲在视频的数模转换中应用及普及。串并结构的转换器的功能效果,只能在连续与比较类型之间。相对比较常用的模数转换装置一般具备两个N / 2位并行转换器,及一个数模转换装置。另外,还有三步、多步实现的数模转换器,这类分级转换器,基于时序的考虑,产生转换序列,以此也被称作为流水线式数模转换器。这种分级转置,往往还能够对多次转换的结果进行数字值的修调,因此性能较为稳固。同时,它的结构实现上来看,相对较小,但是却能具备更高的速度性。
(4)Z-A调制型
基于Z-A型的数模转换器,在结构上有分别为一个单位的积分器、比较器、1位DA和数字滤波器,共同组成。实现的原理上来看,就是非全整数,而是近似整数的实现效果,对输入部分的电压进行调整变化为脉冲信号,接着应用数字滤波的处理来得到相对完整的数字实现。电路结构中的数字实现,更为有利于单片集成效果,因而能够更方便的实现高度的分辨性。在应用中,主要用到音频及测量领域中
(5)电容阵列逐次比较型
在电容阵列结构中,会逐次比较而实现数模转换。内部结构中应用到了模数转换器中国的电容矩阵原理,因此也叫作电荷再分类型。对于一类相对较为典型的电阻阵列转换器,内部的电阻器值的选择尽量一致。对于单个芯片,生产出高精密的电阻很难。但是,运用电容阵列来实现,能够相对于电阻阵列,具备更好的性能,实现低沉本,但是却能具备高精密的特性。现实中,逐次比较型AD转换器,都是应用电容数组;但是要结合成本考虑的话,也会选择连续比较。
2.2 显示模块
第一种方案,选择LED显示。它不但功耗不高,而且体积不大,不但重量很轻,而且接口为数字接口,能够显示多种内容。
第二种方案,采用LED并行动态显示。也就是说,你们每个人一个接一个地打开显示器。每台显示器的灯会间隔时间亮一下。其硬件电路简单,但在相同的功率驱动下,显示亮度比静态显示低,并且占用更多的I / O口。
第三种方案,选择LED串行静态显示。通过这一方案来显示内容时,每显示一个字符,其对应发光二极管的状态固定,也就是说一直处于关闭状态或者打开状态。如此各显示位占用的硬件就会更多,但只有两个IO端口控制器的串行端口,这个软件很简单,高亮度和低成本。[4]
本论文设计选用自带显存的分辨率为的ILI9341驱动芯片的触摸2.8寸LCD显示屏。该显示屏能够对四线电阻触摸以及65K色显示进行支持,其选用的并口为十六位,触控IC为XPT2046。具有良好的驱动能力,应用较为广泛。
2.3 通信接口
第一种方案,接口选择并行通信手段。此手段特征为:需要传输线花费较高成本,拥有很快的通信速度,在短距离传输中十分适用。
第二种方案,接口选择串行通信手段。传输数据的每一位都是按顺序逐位发送或接收的。这种方法的特点是:由于一次只能传输一位,所以传输速度慢。但它只需要一条或两条传输线,所以它是经济的传输数据和占用较少的I / O端口。
本系统中采集后的数据需要发送给远端的数据接收上机位。结合本课题选用STM32微控制器,本系统设计选用USART作为数据通信接口。USART外设最高可实现115200bps传输速率的通用串口通信,USART是标准外设,无需编写驱动。
3 理论分析与计算
3.1 逐次逼近型ADC的理论分析与计算
3.1.1 逐次逼近型ADC电路的转换思想
作为一种广泛应用于直接A / D转换器的模数转换器电路,逐次逼近模数转换器的转换过程类似于天平称重,其转换思想是:从最重的磁重量试验,并与所称的物体相比较,如果该物体的重量大于所称的重量,则应保留该重量,否则应将其移走;对象的权值是通过将所有剩余权值的权值加到最小权值来获得的。按照此思想便能够得到逐次逼近型A / D转换器的工作原理,那就是对各类电压参考值和输入模拟信号展开对比,然后展开转换操作,令这一操作完成后获得的数字近似于输入模拟量。[5]
通过对逐次逼近ADC进行分析能够发现,其主要由电压比较器以及时序产生器等构成,图3.1显示了它的具体原理图情况。

图3.1 逐次比较型ADC原理图
3.1.2 工作原理
逐次逼近型ADC工作原理为:在电路1上出现首个时钟脉冲时,对电路进行控制,令位置最高的定时发生器为1,而此外的定时发生器都为0.然后经有数据寄存器,在数模转换器中输入。接着比较输入、输出电压,此处输出电压用表示,输入电压用v1表示,若是输入电压不低于输出电压,那么比较器的输出值则是1,反之,若是前者低于后者,那么输出值则是0.在数据寄存器上储存进行比较后获得的结果,其具体储存位置在这一寄存器的位上。当出现下一个CP时,在移位寄存器中,位置从高到低分别为1、0,若是其最高位置对1进行了保存,此时就有。此时需要将两类值进行对比,这两类值首先是;其次是v1。若是前者的值不超过后者,那么,反之,。若是其最高位置对0进行了保存,此时就有。此时需要将两类值进行对比,这两类值首先是;其次是VO’。若是前者的值不超过后者,那么,反之,,继续根据这一方式来进行对比,从而得到所需要的输出数字量。
3.1.3 逐次比较型ADC转换器电路举例
通过图3.2能够了解到逐次比较型ADC的工作原理,该电路中存在5个数据寄存器,它的值主要从输出。其中的移位寄存器能够展开两类操作,这两类操作一个是串出;一个是并行,其其并行置数端以及高位串行输入分别为F、S。

图3.2 4位逐次比较型A/D转换器的逻辑电路
当AD的启动脉冲来了之后,接着FF0至FF4都变为零,Q5变为1,此时由于Q5的电平已经是高电平,所以移位寄存器中出现时钟脉冲,同时G2门被打开。受到首个脉冲的影响,移位寄存器由之前的转变为,此时便出现这样一种情况,即。其中QA最低电平为数据寄存器最高位置,也就是说。通过D/A令受到转换,从而变成模拟电压,此电压用VO表示,将V1和VO进行对比,并将对比结果传输至。
当出现下一个脉冲之后,移位寄存器S的电平已经是高电平,而之前的QA=0也转变为,此时,之前的则转变为,在FF4CP端出现了正跳变脉冲,它促使Q4对VC进行了存储。而因为其他触发器并未出现正跳变脉冲,所以这些触发器并不会受到VC信号的影响。当时,D/A转换器的新数据得以生成,此时将V1和VO进行对比,并且在第3次出现时钟脉冲时在Q3中储存对比结果。继续进行此操作,直到、转变为、,此时表示已经完成转换操作,封闭G2。在这样的情况下,电路输出端数字量越大,v1的值越大。能够发现,逐次比较型A/D位数和转换费时成正比关系,和时钟频率成反比关系,此转换器不但拥有较高的精度,而且转换效率也很高。
3.2 IIC 总线的结构及工作原理
作为多主机总线,IIC总线主要由两类信号线组成,首先是SCL;其次是SDA,前者属于时钟线,后者属于数据线。凡是需要和IIC总线相接的SDA都需要和总线SDA数据线相接。主机可以利用上述两类信号线来实现对数据的传输,其中主机不但能够决定何时开始信息传输,还能够决定何时结束信息传输,不但能够决定传输何种信息,还能够决定向哪里传输信息。图3.2显示了IIC总线具体结构情况。

图3.2 IIC总线的结构
通过对IIC总线进行分析能够发现,该总线选择的寻址手段为纯软件寻址手段,即当主机将信号发出时,会对数据传输的具体方向进行制定,被控设备会接收到地址字节信息。此处的地址字节主要由八位构成,一位是,还有七位都源于地址。当地址字节被发出后,总线设备会将自身地址和其中的七位地址进行对比,若是这些地址一样,那么就说明它属于主机寻址的设备,并由来自发射机或来自接收机的读写位决定。[6]
一般来说,不论是SPI接口,还是IIC总线,它们都属于硬件设备,实际上此说法是不对的。严格来看,这两者应当是软硬件的组合,分为物理层四线结构和协议层主机、从、时钟极性、时钟相位。
(1)IIC的物理层
前面已经提到,作为多主机总线,IIC总线主要由两类信号线组成,首先是SCL;其次是SDA,前者属于时钟线,后者属于数据线。若是出现超过一个主机在同一时刻对总线提出请求的情况,那么总线便能够避免数据受损,而总线电容400pf会限制和总线相连的IC的具体数量,将IIC的传输速率用V来表示,那么通常,最高。

图3.3 典型的IIC接口
(2)IIC的协议层
IIC最重要的便是协议层,该层主要由四部分构成,首先是应答位;其次是数据位;然后是停止信号;最后是起始信号。通常一次通信出现的应答位和数据位数量分别为1、8个。其具体情况为:
a.数据的有效性
在这种情况下,IIC总线会从数字字节最高位置着手,通过串行模式来实现对数据信息的传输。各数据都有一个时钟脉冲和SCL数据对应。当时钟线电平为高电平时,低电平为0,高电平为1。若是时钟线电平为低电平,便可以对数据线电平状态进行调整。IIC数据有效性具体情况见图3.4。

图3.4 IIC的数据有效性图
b.起始和结束条件
起始条件指的是SCL跳转为高→低,结束条件则相反,它指的是SCL跳转低→高,此处不论是结束信号,还是起始信号,其发出者都是主机,若是和I2C总线相连的设备有硬件接口能够到达这一总线,那么要想检测到这两类信号可谓是轻而易举。通常当出现启动条件时,总线会变得十分繁忙,而当出现停止条件时,总线就会闲下来。这两类条件具体情况见图3.5。

图3.5 起始和结束条件的描述
4 系统硬件设计
本设计基于stm32单片机控制,来进行电压测量监控系统的设计,然后通过串口实现对电压值的发送以及系统相应配置参数的接收操作,并将接收的数据在E2PROM里进行保存。
4.1 STM最小系统
此次设计的系统的主控系统为单片机,该单片机作为由ST企业设计的微控制器,其设计目的是满足嵌入式应用需求。[7]微控制器是将微机的主要部分集成为一个芯片的单片机。STM32单片机具有多种通用的通信接口,如USART、I2C、SPI等。它可以连接许多传感器和控制许多设备。

图4.1 单片机最小系统
所谓单片机最小系统,指的是能够工作的元件最少的单片机系统,例如复位电路以及供电电路等都属于这类系统。
4.2 电源电路
要想令系统的运行足够稳定,就必须确保电源模块足够稳定,所以电子设计第一步需要做的,便是确保能够将稳定的电源模块提供给系统。[8]

图4.2 电源电路图
此处的单片机电源拥有三类保护电路,即过压、过热以及限流保护电路,其供电为+5V电源供电,由于这一单片机使用了基准电压源(此电压源不存在较大的温度漂移,而且噪声也很低),所以其稳定性较高。
4.3 ADC接口电路图
作为模拟数字转换器[9],逐次逼近型ADC的通道数量为十八,能够对两类信号源进行测量,首先是内部信号源,其次是外部信号源。同时A/D转换的执行模式十分丰富,例如扫描模式以及单次模式等等,最后可以在数据寄存器里保存ADC结果。

图4.3 ADC接口电路图
5 系统软件设计
5.1 单片机程序开发环境
硬件系统和软件系统是组成完整控制系统的两个重要组件。在上一章介绍了硬件电路的系统设计方案之后,本章通过设计支持硬件平台的软件程序充分演示了系统的设计功能。如果要编写可以实现此目的的软件程序,则必须编写写入微控制器的程序。本设计在开发环境为ARM软件的Keil uVision5的环境中使用STM32F103ZET6芯片,控制中心选择ARM来开发软件程序。其中,ARM的Keil uVision5的开发环境是一个更好的开发环境,ARM是目前STM32微控制器系统开发中最常用的主流软件。下面的图5.1显示了使用Keil uVision5软件进行程序开发的流程图

图5.1 Keil uVision5软件开发流程图
Keil软件可用于完成整个研发过程,包括编辑,编译,连接,调试和仿真。
使用Keil uVision5进行基于Keil uVision4 IDE的编程可以使许多新功能添加到设计的程序中。例如,如果要增强对Cortex-M核心微控制器的开发支持,可以使用Keil uVision5对其进行增强,还可以在设计程序的开发形式和开发界面中对Keil uVision4进行相应的改进。

图5.2 Keil uVision5开发界面图
5.2 主程序设计
ADC采集程序用作该程序的主要部分。逐次逼近12位的模数转换器用于转换STM32 ADC。使用的通道数为18,并且内部和外部信号源相互组合。使用单,连续,扫描或不连续模式在每个通道中执行A / D转换操作。在16位数据寄存器中,使用左对齐或右对齐模式存储ADC的结果。然后确定输入电压是否超过用户定义的高/低阈值,并且可以由具有特定功能的模拟看门狗检测到。
在STM32中以最大1Mhz的速率对ADC进行转换操作,即在1us的转换时间内(此数据是在ADC时钟为ADCCLK = 14M,1.5个采样周期时获得的),请注意不要使ADC时钟超过14M,否则将导致精度降低。
在使用STM32操作获得2个通道组的ADC转换结果后(即,可以安排具有更多通道的常规通道组和具有更少通道的注入通道组),常规常规操作过程为常规通道,并且中断功能是进样通道。中断程序的存在的含义是,当正常程序正常运行时,可以用来中断程序的运行。类似地,将喷射通道组布置为具有少量通道的功能具有中断具有少量通道的常规通道组的功能。注入通道的转换完成后,常规通道可以继续转换。

图5.3 ADC转换程序设计图
初始化,即系统已开机。第一步,选择A / D转换器作为单片机。 在第二步中,在发送信号之后,将执行A / D转换,并对收集的数据进行处理和存储,然后将其显示在LCD上,然后再次执行重复的操作。 执行下一个采集。
关键代码:
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分2组
LCD_Init();
USART1_Init(115200);
ADCx_Init();
while(1)
i++;
if(i%20==0) LCD1=!LCD1;
if(i%50==0)
value=Get_ADC_Value(ADC_Channel_1,20);
printf("检测AD值为:%d\r\n",value);
vol=(float)value*(3.3/4096);
printf("检测电压值为:%.2fV\r\n",vol);
delay_ms(10);
配置好ADC程序后通过使用ADC规则组239.5个周期ADC1来设置序列和采样的特定时间以及指定的通道,可以通过延长采样时间来提高程序的精度。启动可以指定要转换的ADC1的软件。转换后,选择中断优先级分组,分成两组,然后开始检测电压,并显示到屏幕上。
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(115200);
KEY_Init();
AT24CXX_Init();
while(AT24CXX_Check()) //检测AT24C02是否正常
printf("AT24C02检测不正常!\r\n");
delay_ms(500);
printf("AT24C02检测正常!\r\n");
while(1)
key=KEY_Scan(0);
if(key==KEY_UP_PRESS)
k++;
if(k>255)
k=255;
AT24CXX_WriteOneByte(0,k);
printf("写入的数据是:%d\r\n",k);
if(key==KEY0_PRESS)
k=AT24CXX_ReadOneByte(0);
printf("读取的数据是:%d\r\n",k);
i++;
if(i%20==0)
LED1=!LED1;
delay_ms(10);
#include "IO.h"
u16 LED_MODE = 0XFFFF;
u8 B1_ALA_Flag = 1;
u8 B2_Set_Flag = 0;
u8 ALA_hour = 0,ALA_min = 0,ALA_sec = 0;
u8 B3_Select_Flag = 0;
void USART2_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
void USART2_SendString(u8 *str)
{
u8 index = 0;
do
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == 0);
index++;
}while(str[index] != 0);
}
void RTC_Init(u8 HH,u8 MM,u8 SS)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSICmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == 0);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(40000 - 1);
RTC_WaitForLastTask();
RTC_SetCounter(HH * 3600 + MM * 60 + SS);
RTC_WaitForLastTask();
}
void ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign= ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
u16 Get_Adc(void)
{
ADC_RegularChannelConfig( ADC1, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(ADC_GetFlagStatus( ADC1, ADC_FLAG_EOC) == 0);
return ADC_GetConversionValue(ADC1);
}
void _24c02_Write(u8 address,u8 dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
u8 _24c02_Read(u8 address)
{
u8 dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat = I2CReceiveByte();
I2CWaitAck();
I2CStop();
return dat;
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = 0xff00;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIOC->ODR = LED_MODE;
GPIOD->ODR |= (1<<2);
GPIOD->ODR &=~(1<<2);
}
void KEY_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
6 系统测试
6.1 电压测量功能的测试
Keil软件用于编译源程序,Proteus软件用于模拟。 设计电路并编程后,进行电压的测量。在经过反复实验采集数据分析,得到误差分析如表6.1所示。
单位:V 一组 二组 三组 四组 五组 六组 七组 八组 九组 十组
输入电压 0.36 0.76 1.32 1.56 1.88 2.28 2.6 3 3.32 3.72
实际有效值 0.27 0.54 0.9 1.12 1.41 1.69 1.94 2.24 2.51 2.81
测量有效值 0.28 0.56 0.94 1.18 1.47 1.7 1.96 2.23 2.52 2.96
误差 3.60% 3.60% 4.30% 5.10% 4.10% 0.60% 1.00% 0.40% 0.40% 5.10%
表6.1 实验数据
在本实验中,指定用于AD转换芯片输入的参考电压为4.2V,并且指定测量最大值为4V的正弦波信号。从本实验的结果数据可以看出,测量结果的误差越大。输入信号的最大值越接近参考电压。[11]
6.2 数据误差分析
在实验开始时,校正过程未正确显示在程序的显示子例程中,并且模拟结果的准确性未达到要求的水平。例如,当屏幕显示2.40时,标准电压表在5V范围内的显示值为2.53V;在5V范围内,标准电压表的显示值为2.53V。当电压显示值在10V范围内为3.92时,标准电压表显示4.09V,并且偏差更大。根据上述情况在程序中更正该值。尝试根据标准电压表的标准进行校正后,发现如果在5V范围内测量模拟电压时使用5V范围,或者在5至10V范围内测量电压使用10V范围,则可以相对准确数据,准确度可以达到两位小数;例如在5V条件下:测得的电压显示为2.80,标准电压表的显示值为2.83V;测量电压显示为3.71,标准电压显示为3.68V。10V时:测得的电压显示为6.83V,标准电压表的显示值为6.84V;测得的电压显示为7.33,标准电压表的显示值为7.27V。在所有通道显示中,全部获得保留到小数点后两位的精确值。同时,发现如果使用不合适的范围来检测电压,则将获得较低的精度。
6.3 串口通信功能的测试
当计算机与MCU交互或MCU与MCU交互时,通常使用MCU串行端口。进行由USART1进行的简单串行端口发送和接收实验,以实现开发板从串行端口助手接收和发送数据。并在接收到数据字符后,对该字符+1,然后将其发送给窗口助手。 并通过屏幕显示。
7 总结与展望
在单片机的最小系统中,可以实现交流电压的实时监控和电源电压的监控,并且可以在显示屏上实时显示设备交流电压的有效值。同时确保测量精度。
经过一段时间的努力,电压监控stm32微控制器系统已基本完成。在设计的初期,出现了很多问题,但是在老师和同学的帮助下,我逐渐对电路设计微控制器的使用有了更深入的了解,并说这些问题已得到适当解决。在使用了我学到的几乎所有MCU知识之后,我设计并编写了一个相对简单的MCU程序。感到惭愧之后,我重新学习了所有的编程技术,并运用它们来提高我的编程能力并加深了单片机的知识。在了解了许多前辈的设计和功能设计之后,我积累了很多经验。
可以通过积分有效值的导数来测量单片机的有效值,并且只要其原理是连续进行N次采样时间转换,就应该通过连续采样转换获得每个采样值的瞬时值。在不提及AD转换精度的情况下,基于其原理,可以保证采样时间间隔的精度,并且所获得数据的有效值的精度也很高。但是,该算法的编程要求太繁琐,因此本文采用近似算法,采用简单的计算方法,即第一区间的最大值来获得有效值。
更多推荐
所有评论(0)