基于STM32的简易数字电压表.docx
《基于STM32的简易数字电压表.docx》由会员分享,可在线阅读,更多相关《基于STM32的简易数字电压表.docx(26页珍藏版)》请在冰豆网上搜索。
![基于STM32的简易数字电压表.docx](https://file1.bdocx.com/fileroot1/2023-6/10/db5d6341-bd52-4b54-ad65-9f578708b028/db5d6341-bd52-4b54-ad65-9f578708b0281.gif)
基于STM32的简易数字电压表
课程设计报告
学院(系):
机械电子工程学院
专业:
测控技术与仪器
学生姓名:
学号:
课程设计题目:
简易数字电压表
起迄日期:
课程设计地点:
指导教师:
第1章简易数字电压表设计方案论证1
1.1简易数字电压表的应用意义1
1.2本次课程设计的目的1
1.3简易数字电压表设计的要求及技术指标1
1.4设计方案论证2
1.5总体设计方案框图及分析2
第2章简易数字电压表各单元电路设计2
2.1A/D转换及数据处理2
2.2串口通信7
2.3LCD显示电路设计7
第3章电路原理图和PCB板的设计8
第4章系统软件程序设计9
第5章设计总结16
参考文献17
摘要
本文以ARM系列的STM32芯片为核心设计了一个简易数字电压表。
简易数字电压表采用模数转换思想来实现,通过硬件电路和软件程序相结合,可输出自定义测量电压,通过调节模数转换电位器使在一定范围内可任意改变。
输出的电压格式和精度的改变通过软件控制,输出电压的大小的改变通过硬件实现。
介绍了的生成原理、硬件电路和软件部分的设计原理。
该简易数字电压表具有体积小、价格低、性能稳定、功能齐全的优点。
关键词:
简易数字电压表;STM32F103;AD转换;
第一章简易数字电压表设计方案论证
1.1简易数字电压表的应用意义
数字电压表简称DMV,它是采用数字化测量技术设计的电压表。
数字电压表的优良特性深受人们的青睐。
具体有以下的应用特点:
a)显示清晰直观,读数准确。
b)准确度高。
c)分辨率高。
d)测量范围宽。
e)扩展能力强。
f)测量速度快。
g)输入阻抗高。
h)集成度高、微功耗。
h)抗干扰能力强
1.2本次课程设计的目的
1)了解STM32f103内部A/D转换性能及编程方法。
2)学会使用A/D转换器进行电压信号采集。
3)了解uCosII系统工作原理。
1.3简易数字电压表设计的要求及技术指标
设计要求:
利用STM32F103内部A/D及2.8寸TFT液晶屏,设计完成一个数字电压表。
要求:
数字电压表可测量0-5V输入电压,电压值通过液晶屏显示。
工作原理及设计思路:
简易数字电压表的设计由A/D转换.数据处理及显示控制等组成。
利用STM32F103内部A/D转换器将模拟电压转换成数字量,经STM32F103计算将数字量转换成对应的电压值,并通过液晶屏输出。
1.4.设计方案论证
数字电压表的基本组成部分是A/D变换器+电子计数器。
通常,被测直流电压经A/D转换器变为与之成正比的闸门时间,在此闸门时间内计数,用数字显示被测电压值。
可见A/D变换器是DVM的核心部件。
本课设上采用的是单片A/D转换器(含模拟电路与数字电路)集成在一片芯片上,配以LCD或LED数字器件后能显示A/D转换结果的集成电路。
它们均属于大规模的集成电路,能以最简的方式构成DVM。
在此采用ICL7106A/D转换器。
但由于STM32F103内部集成了A/D转换器,所以不需要外围的A/D转换器,这就体现了STM32得集成特性。
1.5总体设计方案框图及分析
第二章简易数字电压表各单元电路设计
简易数字电压表的设计由A/D转换.数据处理及显示控制等组成。
由于STM32F103集成了A/D转换.数据处理部分,所以可以集中在一起研究,所以分成了两部分。
2.1A/D转换及数据处理
1)基本型号介绍
首先我们先研究STM32系列芯片的基本知识。
由图1可知STM32F103ZET6有144个引脚,所以我们来了解他的基本型号与代码之间的关系。
图1
STM32系列产品命名规则示例:
STM32F103C8T6Axxx
产品系列STM32=基于ARM®s22的32位微控制器产品类型
F=通用类型产品子系列
101=基本型
102=USB基本型,USB2.0全速设备
103=增强型
105或107=互联型引脚数目
T=36脚C=48脚R=64脚V=100脚Z=144脚
闪存存储器容量4=16K字节的闪存存储器6=32K字节的闪存存储器8=64K字节的闪存存储器B=128K字节的闪存存储器C=256K字节的闪存存储器D=384K字节的闪存存储器E=512K字节的闪存存储器
封装H=BGAT=LQFPU=VFQFPNY=WLCSP
温度范围6=工业级温度范围,-40°C~85°C7=工业级温度范围,-40°C~105°C内部代码A或者空(详见产品数据手册)
选项xxx=已编程的器件代号(3个数字)TR=卷带式包装
2)STM32系列的最小系统设计和独立的A/D转换器供电和参考电压
最小系统主要包括调试接口.震荡电路.引导设置.复位电路和供电系统。
电路由稳定的电源VDD供电。
值得注意的是,如果使用ADC,VDD的范围必须在2.4-3.6V;如果没有使用ADC,VDD的范围为2-3.6V。
启动模式选项:
由开关SW(BOOT0)和SW(BOOT1)配置。
如图2所示
图2
复位电路:
复位信号是低有效,复位源包括复位按钮JP3和连在连接器上的调试工具。
如图3
图3
时钟源:
两个时钟源被用于这个微控制器。
LSEX1用于嵌入式RTC的32.768kHz晶振;
HSEX2用于STM32F103微控制器的8MHz晶振。
如图4所示
图4
去耦电容:
去耦电容就是起到一个电池的作用,满足驱动电路电流的变化,避免相互间的耦合干扰。
由11个100nf的陶瓷电容和一个钽电容组成。
如图5所示
图5
独立的A/D转换器供电和参考电压:
为了提高转换的精确度,ADC使用一个独立的电源供电,过滤和屏蔽来自印刷电路板上的毛刺干扰。
●ADC的电源引脚为VDDA
●独立的电源地VSSA如果有VREF-引脚(根据封装而定),它必须连接到VSSA。
100脚和144脚封装:
为了确保输入为低压时获得更好精度,用户可以连接一个独立的外部参考电压ADC到VREF+和VREF-脚上。
在VREF+的电压范围为2.4V~VDDA。
如图6所示
图6
3)STM32系列的内ADC转换逻辑
12位ADC是一种逐次逼近型模拟数字转换器。
它有多达18个通道,可测量16个外部和2个内部信号源。
各通道的A/D转换可以单次、连续、扫描或间断模式执行。
ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
ADC主要特征●12位分辨率●转换结束、注入转换结束和发生模拟看门狗事件时产生中断●单次和连续转换模式●从通道0到通道n的自动扫描模式●自校准●带内嵌数据一致性的数据对齐●采样间隔可以按通道分别编程●规则转换和注入转换均有外部触发选项●间断模式●双重模式(带2个或以上ADC的器件)●ADC转换时间:
─STM32F103xx增强型产品:
时钟为56MHz时为1μs(时钟为72MHz为1.17μs)─STM32F101xx基本型产品:
时钟为28MHz时为1μs(时钟为36MHz为1.55μs)─STM32F102xxUSB型产品:
时钟为48MHz时为1.2μs─STM32F105xx和STM32F107xx产品:
时钟为56MHz时为1μs(时钟为72MHz为1.17μs)●ADC供电要求:
2.4V到3.6V●ADC输入范围:
VREF-≤VIN≤VREF+●规则通道转换期间有DMA请求产生。
我们需要打开一个ADC输入端口,使外部的模拟量被采集,这样才能通过内部的ADC转换器和驱动电路来实现转换成数字量。
采集模拟量的电路如图7所示
图7
控制逻辑有三个作用:
第一,识别积分器的工作状态,适时发出控制信号,使A/D转换正常进行;第二,判定输入电压极性并控制LCD的负极性显示。
2.2串口通信
由于微控制器的控制是通过编程语言来控制的,所以需要外设的串口来实现编程语言的读写。
通用异步收发器(UART)是一种串行接口,一般微处理器中都包含这种外设接口。
异步串行接口提供了一种简单的途径,使两个器件无需共享同一个时钟信号就能进行通信。
如果再加入一个合适的电平转换器MAX232,串口就能能用在RS232和RS485等网络中实现通信,或者与计算机的COM端口连接。
串口只需两根信号线(RX和TX)即可实现,而且只要两端器件都采用同样的位格式和波特率,那么它们无需其它任何对方的信息就可以成功传输数据。
电路图如图8所示
图8
2.3LCD显示电路设计
由于STM32是一种高集成芯片,所以在显示液晶屏电路上就少了很多附带的驱动电路,我们选用采用自带驱动模块的液晶屏,这样就少了外围驱动电路。
LCD的显示电路如图9所示
图9
第三章电路原理图与PCB板设计
我们用电路板绘图软件protel,绘制电路原理图并生成PCB板,在绘制完原理图生成PCB板的布线与原件的排列方面有很多值得注意的问题,如地线与电源线必须加粗,尽量避免出现绕线的现象,因为这样就增加了信号传输的时间,尽量减少线的使用,相同器件尽量布在一起,这样方便以后电路板的焊接等等规则。
根据要求和以上的分析得到的原理图与PCB板图如图10所示
第四章系统软件程序设计
我们采用的是Kilc-4编写与烧入软件,在Kilc-4中建立项目并建立c语言文件,在文件中编写c语言程序,编写完毕后在软件中的选项flash中的configureflashtools中设置参数,设置成适合Cortex-M3嵌入式处理器STM32合适的参数。
最后编译检查程序的正确与否,如果可以创建目标文件则可以烧入微控制器中,否则检查是否有错误或是警告,排除错误或是警告,最终实现创建目标,最后烧入火牛开发板,检验程序是否符合设计要求,看液晶显示屏上的检测电压是否随着模拟输入电位器的旋转改变而改变。
简易数字电压表的控制程序为:
显示程序.c:
#include
#include"sys.h"
#include"usart.h"
#include"delay.h"
#include"led.h"
#include"lcd.h"
#include"adc.h"
intmain(void)
{
u16adcx;
floattemp;
floattemperate;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72);//延时初始化
//uart_init(72,9600);//串口1初始化
LED_Init();
LCD_Init();
Adc_Init();
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,50,"FireBullSTM32");
LCD_ShowString(60,70,"1");
LCD_ShowString(60,110,"2011/12/26");//显示时间
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(60,130,"TEMP_VAL:
");
LCD_ShowString(60,150,"TEMP_VOL:
0.000V");
while
(1)
{
adcx=Get_Temp();
LCD_ShowNum(132,130,adcx,4,16);//显示ADC的值
temp=(float)adcx*(3.3/4096);
temperate=temp;//保存温度传感器的电压值
adcx=temp;
LCD_ShowNum(132,150,adcx,1,16);//显示电压值整数部分
temp-=(u8)temp;//减掉整数部分
LCD_ShowNum(148,150,temp*1000,3,16);//显示电压小数部分
}
}
初始化程序.c:
#include"sys.h"
#include"usart.h"
//MiniSTM32开发板
//串口1初始化
//正点原子ALIENTEK
//2010/5/27
//V1.3
//支持适应不同频率下的串口波特率设置.
//加入了对printf的支持
//增加了串口接收命令功能.
//////////////////////////////////////////////////////////////////
//加入以下代码,支持printf函数,而不需要选择useMicroLIB
#if1
#pragmaimport(__use_no_semihosting)
//标准库需要的支持函数
struct__FILE
{
inthandle;
/*Whateveryourequirehere.Iftheonlyfileyouareusingis*/
/*standardoutputusingprintf()fordebugging,nofilehandling*/
/*isrequired.*/
};
/*FILEistypedef’dinstdio.h.*/
FILE__stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(intx)
{
x=x;
}
//重定义fputc函数
intfputc(intch,FILE*f)
{
USART1->DR=(u8)ch;
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
returnch;
}
#endif
//end
//////////////////////////////////////////////////////////////////
#ifdefEN_USART1_RX//如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8USART_RX_BUF[64];//接收缓冲,最大64个字节.
//接收状态
//bit7,接收完成标志
//bit6,接收到0x0d
//bit5~0,接收到的有效字节数目
u8USART_RX_STA=0;//接收状态标记
voidUSART1_IRQHandler(void)
{
u8res;
if(USART1->SR&(1<<5))//接收到数据
{
res=USART1->DR;
if((USART_RX_STA&0x80)==0)//接收未完成
{
if(USART_RX_STA&0x40)//接收到了0x0d
{
if(res!
=0x0a)USART_RX_STA=0;//接收错误,重新开始
elseUSART_RX_STA|=0x80;//接收完成了
}else//还没收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x40;
else
{
USART_RX_BUF[USART_RX_STA&0X3F]=res;
USART_RX_STA++;
if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
#endif
//初始化IO串口1
//pclk2:
PCLK2时钟频率(Mhz)
//bound:
波特率
//CHECKOK
//091209
voiduart_init(u32pclk2,u32bound)
{
floattemp;
u16mantissa;
u16fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp;//得到整数部分
fraction=(temp-mantissa)*16;//得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2;//使能PORTA口时钟
RCC->APB2ENR|=1<<14;//使能串口时钟
GPIOA->CRH=0X444444B4;//IO状态设置
RCC->APB2RSTR|=1<<14;//复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位
//波特率设置
USART1->BRR=mantissa;//波特率设置
USART1->CR1|=0X200C;//1位停止,无校验位.
#ifdefEN_USART1_RX//如果使能了接收
//使能接收中断
USART1->CR1|=1<<8;//PE中断使能
USART1->CR1|=1<<5;//接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
ADC驱动.c:
#include
#include"adc.h"
#include"delay.h"
//ADC驱动代码
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3
voidAdc_Init(void)
{
//先初始化IO口
RCC->APB2ENR|=1<<2;//使能PORTA口时钟
GPIOA->CRL&=0XFFFF0000;//PA0123anolog输入
//通道10/11设置
RCC->APB2ENR|=1<<9;//ADC1时钟使能
RCC->APB2RSTR|=1<<9;//ADC1复位
RCC->APB2RSTR&=~(1<<9);//复位结束
RCC->CFGR&=~(3<<14);//分频因子清零
//SYSCLK/DIV2=12MADC时钟设置为12M,ADC最大时钟不能超过14M!
//否则将导致ADC准确度下降!
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF;//工作模式清零
ADC1->CR1|=0<<16;//独立工作模式
ADC1->CR1&=~(1<<8);//非扫描模式
ADC1->CR2&=~(1<<1);//单次转换模式
ADC1->CR2&=~(7<<17);
ADC1->CR2|=7<<17;//软件控制转换
ADC1->CR2|=1<<20;//使用用外部触发(SWSTART)!
!
!
必须使用一个事件来触发
ADC1->CR2&=~(1<<11);//右对齐
ADC1->CR2|=1<<23;//使能温度传感器
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1&=0<<20;//1个转换在规则序列中也就是只转换规则序列1
//设置通道0~3的采样时间
ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空
ADC1->SMPR2|=7<<9;//通道3239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2|=7<<6;//通道2239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2|=7<<3;//通道1239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2|=7<<0;//通道0239.5周期,提高采样时间可以提高精确度
ADC1->SMPR1&=~(7<<18);//清除通道16原来的设置
ADC1->SMPR1|=7<<18;//通道16239.5周期,提高采样时间可以提高精确度
ADC1->CR2|=1<<0;//开启AD转换器
ADC1->CR2|=1<<3;//使能复位校准
while(ADC1->CR2&1<<3);//等待校准结束
//该位由软件设置并由硬件清除。
在校准寄存器被初始化后该位将被清除。
ADC1->CR2|=1<<2;//开启AD校准
while(ADC1->CR2&1<<2);//等待校准结束
//该位由软件设置以开始校准,并在校准结束时由硬件清除
}
//获得ADC值
//ch:
通道值0~3
u16Get_Adc(u8ch)
{
//设置转换序列
ADC1->SQR3&=0XFFFFFFE0;//规则序列1通道ch
ADC1->SQR3|=ch;
ADC1->CR2|=1<<22;//启动规则转换通道
while(!
(ADC1->SR&1<<1));//等待转换结束
returnADC1->DR;//返回adc值
}
//得到ADC采样内部温度传感器的值
//取10次,然后平均
u16Get_Temp(void)
{
u16temp_val=0;
u8t;
for(t=0;t<10;t++)
{
temp_val+=Get_Adc(TEMP_CH);
delay_ms(5);
}
returntemp_val/10;
}
延时程序.c:
#include
#include"delay.h"
//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms
//2010/5/27
//V1.2
//修正了中断中调用出现死循环的错误
//防止延时不准确,采用dowhile结构!
staticu8fac_us=0;//us延时倍乘数
staticu16fac_ms=0;//ms延时倍乘数
//初始化延迟函数
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:
系统时钟
voiddelay_init(u8SYSCLK)
{
SysTick->CTRL&=0xfffffffb;//bit2清空,