1、华南理工大学广州学院题目: 基于STM32的数字电压表的设计姓 名: 学 号: 系 别: 班 级: 指导老师: 完成时间: 1、设计目的 1. 培养综合运用所学知识、独立分析和解决实际问题的能力,培养创新意识和创新能力,并获得科学研究的基础训练。2. 掌握 AD 转换的基础知识,学习基于 DMA 专递方式的 ADC 采集软件的编制及控制流程。3. 通过软硬件设计实现数字电压表的功能。2、设计内容1、将一模拟电压信号输入到 A/D 转换器的任一通道。 2、A/D 转换器将输入的模拟电压值转换成数字量。 3、根据学习开发板所用 A/D 转换器的类型,将转换成的数字量通过一定的算法转换成相应的电压值
2、。 4、将转换成电压值通过学习开发板上的 LCD 显示屏进行显示,要求显示一位小数。3、设计原理1、A/D 变换原理采样:间隔一定时间对信号进行采样,用信号序列来代替原来时间上连续的信号。均匀采样:可完整地恢复原始信号,其中,T 为采样时间间隔, fs 表示采样频率,fm表示原始信号最大频率。量化:把采集到的数值送到量化器编码成数字形式,每个样值代表一次采样所获得的信号的瞬时幅度。A/D 转换器一般为标量均匀量化。 (量化还可分为:标量量化、矢量量化)量化误差(与舍入方式相关):1LSB 或 1/2LSB编码:A/D 模拟/数字转换器一般采用二进制编码, A/D 变换后的结果到此可以表示为一个
3、以 0、1 二进制形式表示的比特流,单位时间内可以传输的二进制比特速率就是 A/D 之后的码速率,数值上等于采样频率与量化比特数值之乘积。二进制编码:量化与字长的关系。3、ADC 的 A/D 转换方式在查询方式下,软件可通过读取 ADC 模块转换完毕引脚 EOC 的状态或状态寄存器中的转换完成标志位判断本次 A/D 是否结束;若结束则从数据总线或数据寄存器中读取 A/D 结果数据。2、ADC 模拟/数字转换器:STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。AD
4、C 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。3、转换特点:STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为1us(ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到 ),不能让 ADC 的时钟超过14M,否则将导致结果准确度下降。4、STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于运行的程序,而注入通道就相当于中断。在程序正常执行的时候,中断是可以打断程序正常执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。规则组设置后,可以按照设置的通道顺序对
5、各通道D 0D 1D 2D 3D 4D 5D 6D 7数据输出开始转换 S O C结束转换 E O C输出使能模拟信号A / D转换器进行依次采集。方便于对多路 ADC 通道的自动采集。注入组最多设置 4 个通道,简单来讲就是需要触发才能采集设置的通道 ADC 值。本设计选择了采用规则组,设置了一个通道进行自动采集。5、此设计显示电压的特点:本设计测量电压值范围为 0-3.3V 的电压,显示误差为0.001V。LCD 实时显示电压值, MicroSD 卡对数据进行同步存储。系统原理框图如图 1 所示。6、DMA 请求:在这次设计中用到了 ADC 转换结果采用 DMA 传递方式。直接存储器存取用
6、来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU 任何干预,通过 DMA 数据可以快速地移动。这就节省了 CPU 的资源来做其他操作。7、LCD 控制电路(1)本设计所使用的 LCD 为3寸,400X240分辨率。LCD 模块使用 STM32的FSMC 接口控制。3TFT 显示屏焊接在奋斗显示转接板上,在屏上贴有触摸屏,通过40芯的接口与 V3或者 MINI 连接。40芯接口定义如下:对要显示在 LCD 上的数据进行写入寄存器,其时序图如下:图(a) 写入寄存器时序图对要显示在 LCD 上的数据进行读取,其时序图如下:图(a) 读出寄存器时序图(2)FSMC(Flexi
7、ble Static Memory Controller)即可变静态存储控制器,是 STM32系列中内部集成256KB 以上 Flash,后缀为 xC、xD 和 xE 的高存储密度微控制器特有的存储控制机制。通过对特殊功能寄存器的设置,FSMC 能够根据不同的外部存储器类型,发出相应的数据/地址/控制信号类型以匹配信号的速度,从而使得 STM32系列微控制器不仅能够应用各种不同类型、不同速度的外部静态存储器,在 STM32内部,FSMC 的一端通过内部高速总线 AHB 连接到内核 Cortex-M3,另一端则是面向扩展存储器的外部总线。内核对外部存储器的访问信号发送到 AHB 总线后,经过 F
8、SMC 转换为符合外部存储器通信规约的信号,送到外部存储器的相应引脚,实现内核与外部存储器之间的数据交互。F S M C 起到桥梁作用,既能够进行信号类型的转换,又能够进行信号宽度和时序的调整,屏蔽掉不同存储类型的差异,使之对内核而言没有区别。FSMC可以连接 NOR/PSRAM/NAND/PC 卡等设备,并且拥有 FSMC_A25:0共26条地址总线,FSMC15:0共16条数据总线。另外,FSMC 扩展的存储空间被分成8个块。通过地址线选择操作的块。这样,LCD 将被看作一个拥有一块地址空间的存储器进行操作。从FSMC的角度看,可以把外部存储器划分为固定大小为256M字节的四个存储块。 存
9、储块1用于访问最多4个NOR闪存或PSRAM存储设备。这个存储区被划分为4个NOR/PSRAM区并有4个专用的片选。 存储块2和3用于访问NAND闪存设备,每个存储块连接一个NAND闪存。 存储块 4 用于访问 PC 卡设备,每一个存储块上的存储器类型是由用户在配置寄存器中定义的。4、设计程序(命令)清单以及程序流程图1、主程序:int main(void) u16 len, c2len,c3len,c4len;u8 c = “ Voltage “;u8 c2 = “ “;u8 c3 = “ “;u8 c4 = “ . V “;u16 bkColor;len = sizeof(c)-1; /计
10、算字节数长度 sizeof()c2len = sizeof(c2)-1;c3len = sizeof(c3)-1;c4len = sizeof(c2)-1;bkColor = White;RCC_Configuration(); /系统时钟配置为 72MHzUsart1_Init(); /串口 1 初始化 ADC_Configuration(); /ADC 初始化FSMC_LCD_Init(); /FSMC 总线配置 lcd_Init(); /液晶初始化/ lcd_PutChar(10,10,g,0x0000,0xffff);/ LCD_test();USART_OUT(USART1,“rn
11、USART1 print AD_value - rn“); while (1) if (ticks+ = 900000) /间隔时间显示转换结果ticks = 0;Clock1s = 1;if (Clock1s) Clock1s = 0;USART_OUT(USART1,“The current AD value = %d rn“, ADC_ConvertedValue); /串口显示字符段 /Delay(0xAFFFFf);Precent = (ADC_ConvertedValue*100/4096);/ 算出百分比,2 的 12 次幂为 0xfffVoltage = Precent*33;
12、 / Voltage 为实际电压值的 1000 倍.c43=(Voltage/1000+0) ; / 取千位数的整数部分c45=(Voltage%1000)/100+0) ; /对千位数取余数后再取其百位的整数部分c46=(Voltage%100)/10)+0) ; /对百位数取余数后再取其十位的整数部分c47=(Voltage%10)+0) ; /对百位数取余数后再取其个位的整数部分lcd_PutStr_16x24_Center(0, c3, c4len,Black, bkColor);lcd_PutStr_16x24_Center(Line1, c, len,Black, bkColor)
13、;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,“The v value = %d.%d%d%d Vrn“, c43=(Voltage/1000),c45=(Voltage%1000)/100),c46=(Voltage%100)/10,c47=(Voltage%10)
14、;/显示实际电压值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。void ADC_Configuration(void)ADC_InitTypeDef ADC_
15、InitStructure;GPIO_InitTypeDef GPIO_InitStructure;DMA_InitTypeDef DMA_InitStructure;/设置 AD 模拟输入端口为输入 1 路 AD 规则通道GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOC, /* Enable DMA clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* Enable ADC
16、1 and GPIOC clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);/* DMA channel1 configuration -*/使能 DMADMA_DeInit(DMA1_Channel1);DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; /DMA 通道 1 的地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32) /DMA 传送地址DMA_InitStructure.DMA_DIR = DMA_DI
17、R_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 位
18、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, /* 允许 DMA1 通道 1 传输结束中断 */DMA_ITConfig(DMA1_Chann
19、el1,DMA_IT_TC, ENABLE);/使能 DMA 通道 1DMA_Cmd(DMA1_Channel1, ENABLE); /ADC 配置ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; /ADC1 工作在独立模式ADC_InitStructure.ADC_ScanConvMode = ENABLE; /模数转换工作在扫描模式(多通道)还是单次(单通道)模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; /模数转换工作在扫描模式(多通道)还是单次(单通道)模式ADC_InitSt
20、ructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;/转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;/ADC 数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1; /规定了顺序进行规则转换的 ADC 通道的数目。这个数目的取值范围是 1 到 16ADC_Init(ADC1, /* ADC1 regular channels configuration 规则模式通道配置*/ /ADC1 规则通道配置ADC_Re
21、gularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5); /通道 11 采样时间 55.5 周期/使能 ADC1 DMA ADC_DMACmd(ADC1, ENABLE);/使能 ADC1ADC_Cmd(ADC1, ENABLE);/ 初始化 ADC1 校准寄存器ADC_ResetCalibration(ADC1);/检测 ADC1 校准寄存器初始化是否完成while(ADC_GetResetCalibrationStatus(ADC1);/开始校准 ADC1ADC_StartCalibration(ADC1)
22、;/检测是否完成校准while(ADC_GetCalibrationStatus(ADC1);/ADC1 转换启动ADC_SoftwareStartConvCmd(ADC1, ENABLE); 3、程序流程图:STARTADC、串口、液晶初始化启动 A/D 转换5、运行步骤、结果,保存截屏,实物图1、运行步骤、结果:步骤:(1)对程序编译并且下载到 STM32 开发板;(2)按下复位键,记录所测到的内部电压值 U 内部 ;(3)用跳线把外部 20 个 GPIO 电压源端口分别接入到 CANERA 的 14 口,读取 ADC 状态A/D 转换结束?读取 A/D 转换结束处理 A/D 转换写入寄存
23、 FSMC启动 LCD读出寄存器FSMC,LCD 显示启动串口串口数据传输电压值显示结束从而测量外部电压 U 外部 GPIO1U 外部 GPIO20(4)在每次接入一个外部 GPIO 电压源时,都复位一次并且记录所测到电压值 U 外部 GPIO1U 外部 GPIO20。结果:(1)内部电压值: U 内部 = 1.683V(2)外部端口电压值:外部端口 U 外部 GPIO1 U 外部 GPIO2 U 外部 GPIO3 U 外部 GPIO4 U 外部 GPIO5电压值 3.267V 0.000V 3.267V 3.267V 3.267V外部端口 U 外部 GPIO6 U 外部 GPIO7 U 外部
24、 GPIO8 U 外部 GPIO9 U 外部GPIO10电压值 3.267V 3.267V 1.617V 1.650V 0.429V外部端口 U 外部GPIO11U 外部GPIO12U 外部GPIO13U 外部GPIO14U 外部GPIO15电压值 1.650V 1.650V 2.409V 3.267V 0.000V外部端口 U 外部GPIO16U 外部GPIO17U 外部GPIO18U 外部GPIO19U 外部GPIO20电压值 1.617V 1.617V 1.617V 3.267V 0.000V2、保存截屏:测试到的个别电压值在串行助手显示结果如下:(1)内部电压值:(2)外部端口 1 电
25、压值:(3)外部端口 8 电压值:(4 )外部端口 10 电压值:(5)外部端口 13 电压值:3、实物图:上图显示结果如下图:六、设计的收获与体会今个学期刚刚接触到 STM32,经过黄金杨老师的介绍,我真正的体会到了 STM32 的强大之处,STM32 采用 Contex-M3 内核,是 32 位的,比起 8 位的 51单片机好多了,并且其处理数据速度非常快, flash,ram 也是很大的,还有16 位的 FSMC 总线等等的强项,这是 51 单片机望而不及的。老师刚刚定好课程设计的题目的时候,正好黄老师在跟我们讲解 STM32的 AD 模数转换,这里的 STM32F103X 是一个 12
26、 位的逐次逼近型的 ADC 模块,所以说它的采样精度是很高的 ,同时自己以前还没有做过有关于 AD 的模块,所以我决定亲自尝试做一个简单的 STM32 数字电压表。首先自己根据上一次做过的 ADC 实验拿出来慢慢的看 main.c 的 ADC、DMA、GPIO、RCC、USART 配置对照着库函数理解,其实这些配置基本上都是固定的,只不过根据自己的需要或者硬件的不同而配置不同而已。利用库函数可以减少了编程的复杂性,更有利于开发更多的产品,相对于采用寄存器来编程好多了,所以说利用固件库来写程序是很重要的。在我刚开始编程的时候,我首先先在以前那个 ADC 实验,把采样到的电压值准确的在串口线上显示
27、出来,显示出采样到的电压值,其实就是要将采样值经过转化后(采样值最高为 4096,采样最高电压都为 3.3V)利用相应的比例算出测量的电压值,所以利用以前 C 语言学到的知识,先求出千位、然后再求百位、十位、个位(采样的精度为 0.001) ,我认为这是关键性的一步,然后在LCD 上显示就容易些了。搞定了在串口上的显示电压后,紧接着就是让电压值在 LCD 上显示了,在这里,LCD 的配置,函数,我觉得是很难理解的,故根据以往的经验,要先看看使用的 LCD 的文档,读懂时序图,理解 LCD 的命令表,这是深入了解 LCD 的关键,另外 LCD 的初始化可以在库函数里面找到。功夫不负有心人,我足足花了一个星期,终于把程序编好了,在期间,自己不懂的东西,就问同学或者网上学习,说真的,在课程设计期间自己学到的东西是最多的。这个课程设计可能就是大学四年最后一个课程设计了,所以我每次做课程设计的时候,我都会格外的用心,或许这是出于自己的兴趣爱好吧。故在以后的路,我会继续保持着这种好习惯。课程设计评语优秀 良好 中等 及格 不及格出勤方案设计安装调试答辩完成情况报告总成绩指导教师评语