基于STM32的数字电压表的设计文档格式.docx
《基于STM32的数字电压表的设计文档格式.docx》由会员分享,可在线阅读,更多相关《基于STM32的数字电压表的设计文档格式.docx(12页珍藏版)》请在冰豆网上搜索。
A/D模拟/数字转换器一般采用二进制编码,A/D变换后的结果到此可以表示为一个以0、1二进制形式表示的比特流,单位时间可以传输的二进制比特速率就是A/D之后的码速率,数值上等于采样频率与量化比特数值之乘积。
二进制编码:
量化与字长的关系。
3、ADC的A/D转换方式
在查询方式下,软件可通过读取ADC模块转换完毕引脚EOC的状态或状态寄存器中的转换完成标志位判断本次A/D是否结束;
若结束则从数据总线或数据寄存器中读取A/D结果数据。
2、ADC模拟/数字转换器:
STM32的ADC是12位逐次逼近型的模拟数字转换器。
它有18个通道可测量16个外部和2个部信号源。
各通道的A/D转换可以单次、连续、扫描或间断模式执行。
ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
3、转换特点:
STM32的ADC最大的转换速率为1Mhz,也就是转换时间为1us(ADCCLK=14M,采样周期为1.5个ADC时钟下得到),不能让ADC的时钟超过14M,否则将导致结果准确度下降。
4、STM32将ADC的转换分为2个通道组:
规则通道组和注入通道组。
规则通道相当于运行的程序,而注入通道就相当于中断。
在程序正常执行的时候,中断是可以打断程序正常执行的。
同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。
规则组设置后,可以按照设置的通道顺序对各通道进行依次采集。
方便于对多路ADC通道的自动采集。
注入组最多设置4个通道,简单来讲就是需要触发才能采集设置的通道ADC值。
本设计选择了采用规则组,设置了一个通道进行自动采集。
5、此设计显示电压的特点:
本设计测量电压值围为0-3.3V的电压,显示误差为±
0.001V。
LCD实时显示电压值,MicroSD卡对数据进行同步存储。
系统原理框图如图1所示。
6、DMA请求:
在这次设计中用到了ADC转换结果采用DMA传递方式。
直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。
无须CPU任何干预,通过DMA数据可以快速地移动。
这就节省了CPU的资源来做其他操作。
7、LCD控制电路
(1)本设计所使用的LCD为3寸,400X240分辨率。
LCD模块使用STM32的FSMC接口控制。
3TFT显示屏焊接在奋斗显示转接板上,在屏上贴有触摸屏,通过40芯的接口与V3或者MINI连接。
40芯接口定义如下:
对要显示在LCD上的数据进行写入寄存器,其时序图如下:
图(a)写入寄存器时序图
对要显示在LCD上的数据进行读取,其时序图如下:
图(a)读出寄存器时序图
(2)FSMC(FlexibleStaticMemoryController)即可变静态存储控制器,是STM32系列中部集成256KB以上Flash,后缀为xC、xD和xE的高存储密度微控制器特有的存储控制机制。
通过对特殊功能寄存器的设置,FSMC能够根据不同的外部存储器类型,发出相应的数据/地址/控制信号类型以匹配信号的速度,从而使得STM32系列微控制器不仅能够应用各种不同类型、不同速度的外部静态存储器,在STM32部,FSMC的一端通过部高速总线AHB连接到核Cortex-M3,另一端则是面向扩展存储器的外部总线。
核对外部存储器的访问信号发送到AHB总线后,经过FSMC转换为符合外部存储器通信规约的信号,送到外部存储器的相应引脚,实现核与外部存储器之间的数据交互。
FSMC起到桥梁作用,既能够进行信号类型的转换,又能够进行信号宽度和时序的调整,屏蔽掉不同存储类型的差异,使之对核而言没有区别。
FSMC可以连接NOR/PSRAM/NAND/PC卡等设备,并且拥有FSMC_A[25:
0]共26条地址总线,FSMC[15:
0]共16条数据总线。
另外,FSMC扩展的存储空间被分成8个块。
通过地址线选择操作的块。
这样,LCD将被看作一个拥有一块地址空间的存储器进行操作。
从FSMC的角度看,可以把外部存储器划分为固定大小为256M字节的四个存储块。
●存储块1用于访问最多4个NOR闪存或PSRAM存储设备。
这个存储区被划分为4个NOR/PSRAM区并有4个专用
的片选。
●存储块2和3用于访问NAND闪存设备,每个存储块连接一个NAND闪存。
●存储块4用于访问PC卡设备,每一个存储块上的存储器类型是由用户在配置寄存器中定义的。
四、设计程序(命令)清单以及程序流程图
1、主程序:
intmain(void)
{u16len,c2len,c3len,c4len;
u8c[]="
Voltage"
;
u8c2[]="
"
u8c3[]="
u8c4[]="
.V"
u16bkColor;
len=sizeof(c)-1;
//计算字节数长度sizeof()
c2len=sizeof(c2)-1;
c3len=sizeof(c3)-1;
c4len=sizeof(c2)-1;
bkColor=White;
RCC_Configuration();
//系统时钟配置为72MHz
Usart1_Init();
//串口1初始化
ADC_Configuration();
//ADC初始化
FSMC_LCD_Init();
//FSMC总线配置
lcd_Init();
//液晶初始化
//lcd_PutChar(10,10,'
g'
0x0000,0xffff);
//LCD_test();
USART_OUT(USART1,"
\r\nUSART1printAD_value--------------------------\r\n"
);
while
(1)
{
if(ticks++>
=900000){//间隔时间显示转换结果
ticks=0;
Clock1s=1;
}
if(Clock1s){
Clock1s=0;
ThecurrentADvalue=%d\r\n"
ADC_ConvertedValue);
//串口显示字符段
//Delay(0xAFFFFf);
Precent=(ADC_ConvertedValue*100/4096);
//算出百分比,2的12次幂为0xfff
Voltage=Precent*33;
//Voltage为实际电压值的1000倍.
c4[3]=(Voltage/1000+'
0'
);
//取千位数的整数部分
c4[5]=((Voltage%1000)/100+'
//对千位数取余数后再取其百位的整数部分
c4[6]=(((Voltage%100)/10)+'
//对百位数取余数后再取其十位的整数部分
c4[7]=((Voltage%10)+'
//对百位数取余数后再取其个位的整数部分
lcd_PutStr_16x24_Center(0,c3,c4len,Black,bkColor);
lcd_PutStr_16x24_Center(Line1,c,len,Black,bkColor);
lcd_PutStr_16x24_Center(Line2,c3,c3len,Black,bkColor);
lcd_PutStr_16x24_Center(Line3,c4,c4len,Black,bkColor);
lcd_PutStr_16x24_Center(Line4,c2,c2len,Black,bkColor);
USART_OUT(USART1,"
Thevvalue=%d.%d%d%dV\r\n"
c4[3]=(Voltage/1000),c4[5]=((Voltage%1000)/100),c4[6]=(Voltage%100)/10,c4[7]=(Voltage%10));
//显示实际电压值
LCD_test();
}
}
}
2、ADC配置:
ADC_Configuration函数用于配置ADC1的通道11,因为只用了ADC1所以采用了ADC独立模式,设置通道11进入规则组,规则组里的通道只有1个,就是通道1,转换用了扫描方式,软件触发,转换结果采用DMA方式传递到2字节长度的缓存区里(ADC_ConvertedValue),默认的ADCCLK为36MHz,采样周期是55.5+12.5时钟周期,相当于采样时间是间隔(68/36)us。
voidADC_Configuration(void)
{
ADC_InitTypeDefADC_InitStructure;
GPIO_InitTypeDefGPIO_InitStructure;
DMA_InitTypeDefDMA_InitStructure;
//设置AD模拟输入端口为输入1路AD规则通道
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_Init(GPIOC,&
GPIO_InitStructure);
/*EnableDMAclock*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
/*EnableADC1andGPIOCclock*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
/*DMAchannel1configuration----------------------------------------------*/
//使能DMA
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr=ADC1_DR_Address;
//DMA通道1的地址
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&
ADC_ConvertedValue;
//DMA传送地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
//传送方向
DMA_InitStructure.DMA_BufferSize=1;
//传送存大小,100个16位
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
//传送存地址递增
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
//ADC1转换的数据是16位
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
//传送的目的地址是16位宽度
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
//循环
DMA_InitStructure.DMA_Priority=DMA_Priority_High;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
DMA_Init(DMA1_Channel1,&
DMA_InitStructure);
/*允许DMA1通道1传输结束中断*/
//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
//使能DMA通道1
DMA_Cmd(DMA1_Channel1,ENABLE);
//ADC配置
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
//ADC1工作在独立模式
ADC_InitStructure.ADC_ScanConvMode=ENABLE;
//模数转换工作在扫描模式(多通道)还是单次(单通道)模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
//模数转换工作在扫描模式(多通道)还是单次(单通道)模式
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
//转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
//ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel=1;
//规定了顺序进行规则转换的ADC通道的数目。
这个数目的取值围是1到16
ADC_Init(ADC1,&
ADC_InitStructure);
/*ADC1regularchannelsconfiguration[规则模式通道配置]*/
//ADC1规则通道配置
ADC_RegularChannelConfig(ADC1,ADC_Channel_11,1,ADC_SampleTime_55Cycles5);
//通道11采样时间55.5周期
//使能ADC1DMA
ADC_DMACmd(ADC1,ENABLE);
//使能ADC1
ADC_Cmd(ADC1,ENABLE);
//初始化ADC1校准寄存器
ADC_ResetCalibration(ADC1);
//检测ADC1校准寄存器初始化是否完成
while(ADC_GetResetCalibrationStatus(ADC1));
//开始校准ADC1
ADC_StartCalibration(ADC1);
//检测是否完成校准
while(ADC_GetCalibrationStatus(ADC1));
//ADC1转换启动
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
3、
程序流程图:
五、运行步骤、结果,保存截屏,实物图
1、运行步骤、结果:
步骤:
(1)对程序编译并且下载到STM32开发板;
(2)按下复位键,记录所测到的部电压值U部;
(3)用跳线把外部20个GPIO电压源端口分别接入到CANERA的14口,从而测量外部电压U外部GPIO1—U外部GPIO20
(4)在每次接入一个外部GPIO电压源时,都复位一次并且记录所测到电压值U外部GPIO1—U外部GPIO20。
结果:
(1)部电压值:
U部=1.683V
(2)外部端口电压值:
外部端口
U外部GPIO1
U外部GPIO2
U外部GPIO3
U外部GPIO4
U外部GPIO5
电压值
3.267V
0.000V
U外部GPIO6
U外部GPIO7
U外部GPIO8
U外部GPIO9
U外部GPIO10
1.617V
1.650V
0.429V
U外部GPIO11
U外部GPIO12
U外部GPIO13
U外部GPIO14
U外部GPIO15
2.409V
U外部GPIO16
U外部GPIO17
U外部GPIO18
U外部GPIO19
U外部GPIO20
2、保存截屏:
测试到的个别电压值在串行助手显示结果如下:
(2)外部端口1电压值:
(3)外部端口8电压值:
(4)外部端口10电压值:
(5)外部端口13电压值:
3、实物图:
上图显示结果如下图:
六、设计的收获与体会
今个学期刚刚接触到STM32,经过黄金老师的介绍,我真正的体会到了STM32的强大之处,STM32采用Contex-M3核,是32位的,比起8位的51单片机好多了,并且其处理数据速度非常快,flash,ram也是很大的,还有16位的FSMC总线等等的强项,这是51单片机望而不及的。
老师刚刚定好课程设计的题目的时候,正好黄老师在跟我们讲解STM32的AD模数转换,这里的STM32F103X是一个12位的逐次逼近型的ADC模块,所以说它的采样精度是很高的,同时自己以前还没有做过有关于AD的模块,所以我决定亲自尝试做一个简单的STM32数字电压表。
首先自己根据上一次做过的ADC实验拿出来慢慢的看main.c的ADC、DMA、GPIO、RCC、USART配置对照着库函数理解,其实这些配置基本上都是固定的,只不过根据自己的需要或者硬件的不同而配置不同而已。
利用库函数可以减少了编程的复杂性,更有利于开发更多的产品,相对于采用寄存器来编程好多了,所以说利用固件库来写程序是很重要的。
在我刚开始编程的时候,我首先先在以前那个ADC实验,把采样到的电压值准确的在串口线上显示出来,显示出采样到的电压值,其实就是要将采样值经过转化后(采样值最高为4096,采样最高电压都为3.3V)利用相应的比例算出测量的电压值,所以利用以前C语言学到的知识,先求出千位、然后再求百位、十位、个位(采样的精度为0.001),我认为这是关键性的一步,然后在LCD上显示就容易些了。
搞定了在串口上的显示电压后,紧接着就是让电压值在LCD上显示了,在这里,LCD的配置,函数,我觉得是很难理解的,故根据以往的经验,要先看看使用的LCD的文档,读懂时序图,理解LCD的命令表,这是深入了解LCD的关键,另外LCD的初始化可以在库函数里面找到。
功夫不负有心人,我足足花了一个星期,终于把程序编好了,在期间,自己不懂的东西,就问同学或者网上学习,说真的,在课程设计期间自己学到的东西是最多的。
这个课程设计可能就是大学四年最后一个课程设计了,所以我每次做课程设计的时候,我都会格外的用心,或许这是出于自己的兴趣爱好吧。
故在以后的路,我会继续保持着这种好习惯。
课程设计评语
完
成
情
况
优秀
良好
中等
及格
不及格
出勤
方案设计
安装调试
答辩
报告
总
绩
指
导
教
师
评
语