基于STM32原子mini开发板的数字电压表 - 图文

更新时间:2023-10-14 04:38:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

基于STM32的数字电压表的设计

一、设计目的和作用

1. 培养综合运用所学知识、独立分析和解决实际问题的能力,培养创新意识和创新能力,并获得科学研究的基础训练。

2. AD转换的基础知识,学习了基于DMA专递方式的ADC采集软件的编制及控制流程。 3. 通过软硬件设计实现数字电压表的功能。

二、设计内容

1、将一模拟电压信号输入到A/D转换器的任一通道,定义为规则组;测量环境温度(可用内部温度传感器,也可用外接温度传感器),定义为注入组。 2、A/D转换器将输入的模拟电压值转换成数字量。

3、根据学习开发板所用A/D转换器的类型,将转换成的数字量通过一定的算法转换成相应的电压值。

4、将转换成电压值通过串口1显示,要求显示一位小数,并每隔1S显示一次温度。

三、设计原理

1、A/D变换原理

◆采样:

间隔一定时间对信号进行采样,用信号序列来代替原来时间上连续的信号。

均匀采样:

可完整地恢复原始信号,其中,T为采样时间间隔,fs表示采样频率,fm表示原始信号最大频率。 ◆量化:

把采集到的数值送到量化器编码成数字形式,每个样值代表一次采样所获得的信号的瞬时幅度。

A/D转换器一般为标量均匀量化。(量化还可分为:标量量化、矢量量化) 量化误差(与舍入方式相关):1LSB或 1/2LSB ◆编码:

A/D模拟/数字转换器一般采用二进制编码,A/D变换后的结果到此可以表示为一个以0、1二进制形式表示的比特流,单位时间内可以传输的二进制比特速率就是A/D之后的码速率,数值上等于采样频率与量化比特数值之乘积。

二进制编码:量化与字长的关系。

3、ADC的A/D转换方式

D0 D1D2D3D4D5D6D7数据输出A/D 模拟信号转换器

开始转换 SOC

结束转换 EOC

输出使能

在查询方式下,软件可通过读取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实时显示电压值,内部温度、外部温度

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(Flexible Static Memory Controller)即可变静态存储控制器,

是STM32系列中内部集成256KB以上Flash,后缀为xC、xD和xE的高存储密度微控制器特有的存储控制机制。

通过对特殊功能寄存器的设置,FSMC能够根据不同的外部存储器类型,发出相应的数据/地址/控制信号类型以匹配信号的速度,从而使得STM32系列微控制器不仅能够应用各种不同类型、不同速度的外部静态存储器,在STM32内部,FSMC的一端通过内部高速总线AHB连接到内核Cortex-M3,另一端则是面向扩展存储器的外部总线。内核对外部存储器的访问信号发送到AHB总线后,经过FSMC转换为符合外部存储器通信规约的信号,送到外部存储器的相应引脚,实现内核与外部存储器之间的数据交互。

F S M C起到桥梁作用,既能够进行信号类型的转换,又能够进行信号宽度和时序的调整,屏蔽掉不同存储类型的差异,使之对内核而言没有区别。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卡设备,每一个存储块上的存储器类型是由用户在配置寄存器中定义的。

8、DS18B20

四、设计程序(命令)清单以及程序流程图

1、主程序:

int main(void) { double temp1; float temp,ad; u32 ad1=0,a,b;

u8 i;

delay_init(); //延时函数初始化 uart_init(9600); //串口初始化为9600 LED_Init(); //IO口的初始化和配置 LCD_Init(); //LCD的配置 ADC_Configuration1();//ADC内部温度注入组的初始化 ADC_Configuration();//ADC电压采集规则组的初始化 DMA_Configuration();//DMA的初始化 LCD_Clear(WHITE); //清屏,LCD底色为白色 POINT_COLOR=RED; //字体的颜色为红色 LCD_ShowString(15,15,200,24,24,\ LCD_ShowString(0,60,200,24,24,\ . V\ LCD_ShowString(0,100,200,24,24,\ Temp: . C\ LCD_ShowString(0,140,200,24,24,\ . C\ while(1) {

/* ADC电压采集数据处理 ad=0; for(i=0;i<10;i++) { ad=ad+ADCData[i]; }

ad=3.26/4095.0*ad;

printf(\电压 =%0.4f V\\r\\r\\n\ ad=ad*10.0; LCD_ShowNum(100,60,ad/100,1,24); LCD_ShowNum(124,60,ad/10,2,24); delay_ms(950);

/* ADC内部温度采集数据处理

*/ */

ad1=0;

for(i=0;i<10;i++) {

ADC_SoftwareStartConvCmd(ADC1,ENABLE);

while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC));//转换完成JEOC被置位 ad1=ad1+ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1); }

ad1=ad1/10;

temp=(1.43-3.3/4095*ad1)/0.0043+25;

printf(\温度 =%0.4f ℃\\r\\r\\n\ b=temp*10.0;

LCD_ShowNum(100,100,b/10,2,24); LCD_ShowNum(136,100,(b),1,24); delay_ms(950);

/* DS18B20数据处理 */ temp1=DS18B20_Get_wd();//获取DS18B20的温度 printf(\℃\\r\\r\\n\ temp1=temp1*10; a=temp1; LCD_ShowNum(100,140,temp1/10,2,24); LCD_ShowNum(136,140,(a),1,24); delay_ms(950); } }

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_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, &GPIO_InitStructure); /* Enable DMA clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/* Enable ADC1 and GPIOC clock */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);

/* DMA channel1 configuration ----------------------------------------------*/ //使能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); /* ADC1 regular channels configuration [规则模式通道配置]*/ //ADC1 规则通道配置

ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5); //通道11采样时间 55.5周期 //使能ADC1 DMA 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、内部温度的配置:

void ADC_Configuration1(void) { ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode=ENABLE; 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_InjectedSequencerLengthConfig(ADC1,1);//转换的长度,几个ADC ADC_InjectedChannelConfig(ADC1,ADC_Channel_16,1,ADC_SampleTime_239Cycles5);//注入组:通道16,采样时间 ADC_TempSensorVrefintCmd(ENABLE); ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_None);//软件启动ADC触发 ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartInjectedConvCmd(ADC1, ENABLE); }

4、串口配置

void uart_init(u32 bound){ //GPIO端口设置

GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, //使能USART1,GPIOA时钟

USART_DeInit(USART1); //复位串口1 //USART1_TX PA.9

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9

//USART1_RX PA.10

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10

//Usart1 NVIC 配置

ENABLE);

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器

//USART 初始化设置

USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;

USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//

//收发模式

无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_Init(USART1, &USART_InitStructure); //初始化串口 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断 USART_Cmd(USART1, ENABLE); //使能串口 }

void USART1_IRQHandler(void) {

if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { USART_SendData(USART1,USART_ReceiveData(USART1)); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); } }

5、DS18B20的配置

void DS18B20_IO_IN(void) {

GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=IO_DS18B20;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIO_DS18B20,&GPIO_InitStructure);}

void DS18B20_IO_OUT(void) {

PIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=IO_DS18B20;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_Init(GPIO_DS18B20,&GPIO_InitStructure);}

u8 DS18B20_Read_Byte(void) {

u8 i=0,TempData=0; for(i=0;i<8;i++) {TempData>>=1;

DS18B20_IO_OUT();//输出 DS18B20_DQ_Low; //拉低 delay_us(4);//延时4微妙 DS18B20_DQ_High; delay_us(10);//延时10微妙 DS18B20_IO_IN();

if(GPIO_ReadInputDataBit(GPIO_DS18B20,IO_DS18B20)==1) {

TempData|=0x80;//读数据 从低位开始 }

delay_us(45);//延时45微妙

}

return TempData;

}void DS18B20_Write_Byte(u8 dat) { u8 i=0;

DS18B20_IO_OUT();//输出 for(i=0;i<8;i++) {

DS18B20_DQ_Low; //拉低

delay_us(15);//延时15微妙 if((dat&0x01)==1) {

DS18B20_DQ_High;

else {

DS18B20_DQ_Low;

delay_us(60);//延时60微妙 DS18B20_DQ_High;

dat>>=1;//准备下一位数据的发送void DS18B20_Reset(void) { DS18B20_IO_OUT();//输出 DS18B20_DQ_Low;

delay_us(480);//延时480微妙

DS18B20_DQ_High;

delay_us(480);//延时480微妙

}

}

}}

}double DS18B20_Get_wd(void) {

temp=TH;temp=(temp<<8)+TL;

if((temp&0xF800)==0xF800)//负温度判断 { else { } return wd;

wd=temp*0.0625; temp=~temp; temp=temp+1; wd=temp*(-0.0625);} u8 TL=0,TH=0; u16 temp=0; double wd=0;

DS18B20_Reset();//复位

DS18B20_Write_Byte(0xCC); //跳过ROM命令 DS18B20_Write_Byte(0x44); //温度转换命令 delay_ms(800);//延时800毫秒 DS18B20_Reset();//复位

DS18B20_Write_Byte(0xCC); //跳过ROM命令 DS18B20_Write_Byte(0xBE); //读温度命令 TL=DS18B20_Read_Byte();//LSB TH=DS18B20_Read_Byte();//MSB

流程图:

五、运行步骤、结果,保存截屏,实物图

1、LCD显示电压voltage显示的是外部的模拟量输入的电压,temp显示是STM32内部的温度,DS18B20是外部温度

串口打印:每隔一秒打印一组数据

六、设计的收获与体会

课程设计评语

出勤 方案设计 安装调试 答辩 报告 总 成 绩 指 导 教 师 评 语 优秀 良好 中等 及格 不及格 完 成 情 况

本文来源:https://www.bwwdw.com/article/fymf.html

Top