ADC简介
ADC:
模数转换器
常见ADC类型
ADC电路类型 | 优点 | 缺点 |
并联比较型 | 转换速度最快 | 成本高、功耗高,分辨率低 |
逐次逼近型 | 结构简单,功耗低 | 转换速度较慢 |
并联比较型
分压部分+比较部分+编码部分
逐次逼近型
控制电路+数码寄存器+D/A转换器+电压比较
特点:分辨率和采样速度相互矛盾,
分辨率越高,采样速率越低
ADC的特性参数
分辨率(刻度划分)
表示ADC能辨别的最小模拟量,用二进制位数表示,比如:8、10、12、16位
转换时间
表示完成一次A/D转换所需要的时间,转换时间越短,采样速率越高
精度(物理量的精准程度)
最小刻度基础上叠加各种误差的参数,精度受ADC性能、温度和气压等影响
量化误差
用数字量近似表示模拟量,采用四舍五入原则,此过程产生的误差为量化误差
STM32各系列ADC的主要特征
主要特性 | F1 | F4 | F7 | H7 |
ADC类型 | 逐次逼近型 | |||
分辨率 | 12位 | 6/8/10/12位 | 6/8/10/12位 | 8/10/12/14/16位 |
ADC时钟频率 | 14MHz(max) | 36MHz(max) | ||
采样时间 | 采样时间越长, 转换结果相对越准确, 但是转换速度就越慢 | |||
转换时间 | 与ADC时钟频率、分辨率和采样时间等有关 | |||
供电电压 | VSSA :0V,VDDA :2.4V~3.6V(全速运行) | |||
参考电压 | VREF– :0V,VREF+一般为3.3V | |||
输入电压 | VREF–≤VIN≤VREF+ |
ADC工作原理
F1结构框图
F4结构框图
F1输入通道
ADC1 | IO | ADC2 | IO | ADC3 | IO |
通道0 | PA0 | 通道0 | PA0 | 通道0 | PA0 |
通道1 | PA1 | 通道1 | PA1 | 通道1 | PA1 |
通道2 | PA2 | 通道2 | PA2 | 通道2 | PA2 |
通道3 | PA3 | 通道3 | PA3 | 通道3 | PA3 |
通道4 | PA4 | 通道4 | PA4 | 通道4 | PF6 |
通道5 | PA5 | 通道5 | PA5 | 通道5 | PF7 |
通道6 | PA6 | 通道6 | PA6 | 通道6 | PF8 |
通道7 | PA7 | 通道7 | PA7 | 通道7 | PF9 |
通道8 | PB0 | 通道8 | PB0 | 通道8 | PF10 |
通道9 | PB1 | 通道9 | PB1 | 通道9 | 连接内部VSS |
通道10 | PC0 | 通道10 | PC0 | 通道10 | PC0 |
通道11 | PC1 | 通道11 | PC1 | 通道11 | PC1 |
通道12 | PC2 | 通道12 | PC2 | 通道12 | PC2 |
通道13 | PC3 | 通道13 | PC3 | 通道13 | PC3 |
通道14 | PC4 | 通道14 | PC4 | 通道14 | 连接内部VSS |
通道15 | PC5 | 通道15 | PC5 | 通道15 | 连接内部VSS |
通道16 | 连接内部温度传感器 | 通道16 | 连接内部VSS | 通道16 | 连接内部VSS |
通道17 | 连接内部Vrefint | 通道17 | 连接内部VSS | 通道17 | 连接内部VSS |
F1转换序列及其优先级
F1规则序列
规则序列寄存器控制关系汇总 | |||
寄存器 | 寄存器位 | 功能 | 取值 |
SQR3 | SQ1 [ 4 : 0 ] | 设置第1个转换的通道 | 通道0~17 |
SQ2 [ 4 : 0 ] | 设置第2个转换的通道 | 通道0~17 | |
SQ3 [ 4 : 0 ] | 设置第3个转换的通道 | 通道0~17 | |
SQ4 [ 4 : 0 ] | 设置第4个转换的通道 | 通道0~17 | |
SQ5 [ 4 : 0 ] | 设置第5个转换的通道 | 通道0~17 | |
SQ6 [ 4 : 0 ] | 设置第6个转换的通道 | 通道0~17 | |
SQR2 | SQ7 [ 4 : 0 ] | 设置第7个转换的通道 | 通道0~17 |
SQ8 [ 4 : 0 ] | 设置第8个转换的通道 | 通道0~17 | |
SQ9 [ 4 : 0 ] | 设置第9个转换的通道 | 通道0~17 | |
SQ10 [ 4 : 0 ] | 设置第10个转换的通道 | 通道0~17 | |
SQ11 [ 4 : 0 ] | 设置第11个转换的通道 | 通道0~17 | |
SQ12 [ 4 : 0 ] | 设置第12个转换的通道 | 通道0~17 | |
SQR1 | SQ13 [ 4 : 0 ] | 设置第13个转换的通道 | 通道0~17 |
SQ14 [ 4 : 0 ] | 设置第14个转换的通道 | 通道0~17 | |
SQ15 [ 4 : 0 ] | 设置第15个转换的通道 | 通道0~17 | |
SQ16 [ 4 : 0 ] | 设置第16个转换的通道 | 通道0~17 | |
SQL [ 3 : 0 ] | 设置规则序列要转换的通道数 | 0~15 |
F1注入序列
注入序列寄存器控制关系汇总 | |||
寄存器 | 寄存器位 | 功能 | 取值 |
JSQR | JSQ1 [ 4 : 0 ] | 设置第1个转换的通道 | 通道0~17 |
JSQ2 [ 4 : 0 ] | 设置第2个转换的通道 | 通道0~17 | |
JSQ3 [ 4 : 0 ] | 设置第3个转换的通道 | 通道0~17 | |
JSQ4 [ 4 : 0 ] | 设置第4个转换的通道 | 通道0~17 | |
JL [ 1 : 0 ] | 设置注入序列要转换的通道数 | 0~3 |
注入序列的转换顺序是从JSQx[ 4 : 0 ](x=4-JL[1:0])开始
F1触发源
ADON位触发转换(仅F1系列拥有)
当ADC_CR2寄存器的ADON位为1时,再单独给ADON位写1,只能启动规则组转换
外部触发
F4/F7触发源
F1转换时间
F4/F7转换时间
F1数据寄存器
F4/F7数据寄存器
F1/F4/F7中断
转换模式
CONT位 | 0 | 1 |
转换模式 | 单次转换模式 | 连续转换模式 |
转换组/转换模式 | 单次转换模式(只触发一次转换) | 连续转换模式(自动触发下一次转换) 注意:只有规则组才能触发该模式 |
规则组 | 转换结果被储存在ADC_DR EOC(转换结束)标志位被置1 如果设置了EOCIE位,则产生中断 然后ADC停止 | 转换结果被储存在ADC_DR EOC(转换结束)标志位被置1 如果设置了EOCIE位,则产生中断 |
注入组 | 转换结果被储存在ADC_DRJx JEOC(转换结束)标志位被置1 如果设置了JEOCIE位,则产生中断 然后ADC停止 | 转换结果被储存在ADC_DRJx JEOC(转换结束)标志位被置1 如果设置了JEOCIE位,则产生中断 自动注入:将JAUTO位置1 |
扫描模式
SCAN位 | 0 | 1 |
扫描模式 | 关闭扫描模式 | 使用扫描模式 |
关闭扫描模式 | 使用扫描模式 |
ADC只转换ADC_SQRx或 ADC_JSQR选中的第一个通道进行转换 | ADC会扫描所有被ADC_SQRx或 ADC_JSQR选中的所有通道 |
模式组合
单次转换模式(不扫描) | 只转换一个通道,而且是一次,需等待下一次触发 |
单次转换模式(扫描) | ADC_SQRx 和ADC_JSQR 选中的所有通道都转换一次 |
连续转换模式(不扫描) | 只会转换一个通道,转换完后会自动执行下一次转换 |
连续转换模式(扫描) | ADC_SQRx 和ADC_JSQR 选中的所有通道都转换一次,并自动进入下一轮转换 |
具体例子
单次转换模式(不扫描) | 使用ADC单通道,并要求进行一次转换 |
单次转换模式(扫描) | 使用ADC多通道,并要求所有通道都转换一次就停止 |
连续转换模式(不扫描) | 使用ADC单通道,并要求对该通道连续转换 |
连续转换模式(扫描) | 使用ADC多通道,并要求所有通道都转换一次后,自动启动下一轮转换 |
ADC相关寄存器
ADC_CR1(ADC控制寄存器1)
ADC_CR2(ADC控制寄存器2)
ADC_SMPR1(ADC采样时间寄存器1)
ADC_SMPR2(ADC采样时间寄存器2)
ADC_SQR1(ADC规则序列寄存器1)
ADC_SQR2(ADC规则序列寄存器2)
ADC_DR(ADC规则数据寄存器)
配置步骤
单通道ADC采集配置步骤
HAL库函数介绍
函数 | 主要寄存器 | 主要功能 |
HAL_ADC_Init() | CR1、CR2 | 配置ADC工作参数 |
HAL_ADCEx_Calibration_Start() | CR2 | ADC校准 |
HAL_ADC_MspInit() | 无 | 存放NVIC、CLOCK、GPIO初始化代码 |
HAL_RCCEx_PeriphCLKConfig() | RCC_CFGR | 设置扩展外设时钟,如:ADC、RTC等 |
HAL_ADC_ConfigChannel() | SQRx、SMPRx | 配置ADC相应通道的相关参数 |
HAL_ADC_Start() | CR2 | 启动A/D转换 |
HAL_ADC_PollForConversion() | SR | 等待规则通道转换完成 |
HAL_ADC_GetValue() | DR | 获取规则通道A/D转换结果 |
//相关结构体
typedef struct
{
ADC_TypeDef *Instance; /* ADC 寄存器基地址 */
ADC_InitTypeDef Init; /* ADC 参数初始化结构体变量 */
DMA_HandleTypeDef *DMA_Handle; /* DMA 配置结构体 */
……
} ADC_HandleTypeDef;
typedef struct
{
uint32_t DataAlign; /* 设置数据的对齐方式 */
uint32_t ScanConvMode; /* 扫描模式 */
FunctionalState ContinuousConvMode; /* 开启单次转换模式或者连续转换模式 */
uint32_t NbrOfConversion; /* 设置转换通道数目 */
FunctionalState DiscontinuousConvMode; /* 是否使用规则通道组间断模式 */
uint32_t NbrOfDiscConversion; /* 配置间断模式的规则通道个数 */
uint32_t ExternalTrigConv; /* ADC 外部触发源选择 */
} ADC_InitTypeDef;
typedef struct
{
uint32_t Channel; /* ADC 转换通道 */
uint32_t Rank; /* ADC 转换顺序 */
uint32_t SamplingTime; /* ADC 采样周期 */
} ADC_ChannelConfTypeDef;
//ADC.c
#include "ADC.h"
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_ChannelConfig; // ADC通道配置句柄
void ADC_Init()
{
ADC_Handler.Instance = ADC1; // ADC1
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_DISABLE; // 不开启扫描模式
ADC_Handler.Init.ContinuousConvMode = DISABLE; // 不开启连续模式
ADC_Handler.Init.NbrOfConversion = 1; // 通道数量1
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不开启间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 间断模式数量0
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发ADC
HAL_ADC_Init(&ADC_Handler); // ADC初始化,调用HAL_ADC_MspInit()
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_ChannelConfig.Channel = ADC_CHANNEL_1; // PA1 ,ADC1通道1
ADC_ChannelConfig.Rank = ADC_REGULAR_RANK_1; // 放在第一个转换位置
ADC_ChannelConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 239.5个转换周期,21us
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_ChannelConfig); // ADC1通道配置
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC1) // 判断是不是ADC1
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
RCC_PeriphCLKInitTypeDef RCC_ADC_CLK_InitStructure; // ADC时钟选择结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1时钟
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; // 开启模拟功能
GPIO_InitStructure.Pin = GPIO_PIN_1; // PA1
GPIO_InitStructure.Pull = GPIO_NOPULL; // 不上下拉
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // GPIOA初始化
RCC_ADC_CLK_InitStructure.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设时钟选择ADC
RCC_ADC_CLK_InitStructure.AdcClockSelection = RCC_ADCPCLK2_DIV6; // 6分频:12M
HAL_RCCEx_PeriphCLKConfig(&RCC_ADC_CLK_InitStructure); // 外设时钟配置
}
}
uint32_t ADC_GET()
{
HAL_ADC_Start(&ADC_Handler); // 开启ADC1
HAL_ADC_PollForConversion(&ADC_Handler, 10); // 等待ADC转化,10ms
return HAL_ADC_GetValue(&ADC_Handler); // 返回ADC获得值
}
uint32_t ADCx;
float temp;
void ADC_Show()
{
ADCx = ADC_GET();
LCD_ShowxNum(134, 110, ADCx, 5, 16, 0); // 显示ADCx
temp = (float)ADCx * 3.3 / 4096;
ADCx = temp;
LCD_ShowxNum(134, 130, ADCx, 1, 16, 0); // 显示整数部分
temp -= ADCx;
temp *= 1000;
LCD_ShowxNum(150, 130, temp, 3, 16, 0X80); // 显示及小鼠部分
}
//ADC.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "lcd.h"
void ADC_Init();
uint32_t ADC_GET();
void ADC_Show();
#endif
//main.c
//精英开发板
//PA1采集电位器电压
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "ADC.h"
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
LCD_ShowString(30, 110, 200, 16, 16, "ADC1_CH1_VAL:");
LCD_ShowString(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V");
ADC_Init();
while (1)
{
ADC_Show();
delay_ms(5);
}
}
单通道ADC采集(DMA读取)配置步骤
HAL库函数介绍
函数 | 主要寄存器 | 主要功能 |
HAL_ADC_Init() | CR1、CR2 | 配置ADC工作参数 |
HAL_ADCEx_Calibration_Start() | CR2 | ADC校准 |
HAL_ADC_MspInit() | 无 | 存放NVIC、CLOCK、GPIO初始化代码 |
HAL_RCCEx_PeriphCLKConfig() | RCC_CFGR | 设置扩展外设时钟,如:ADC、RTC等 |
HAL_ADC_ConfigChannel() | SQRx、SMPRx | 配置ADC相应通道的相关参数 |
HAL_DMA_Start_IT() | CCRx | 启动DMA、开启传输完成中断 |
HAL_ADC_Start_DMA() | CR2 | 触发ADC转换、使用DMA传输数据 |
//相关结构体
typedef struct
{
uint32_t Direction; /* 传输方向 */
uint32_t PeriphInc; /* 外设(非)增量模式 */
uint32_t MemInc; /* 存储器(非)增量模式 */
uint32_t PeriphDataAlignment; /* 外设数据宽度 */
uint32_t MemDataAlignment; /* 存储器数据宽度 */
uint32_t Mode; /* 操作模式 */
uint32_t Priority; /* DMA通道优先级 */
}DMA_InitTypeDef;
//ADC.c
#include "ADC.h"
DMA_HandleTypeDef DMA_Handler; // DMA句柄
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_Channelconfig; // ADC通道配置
uint8_t adc_dma_sta = 0; // ADC_DMA传输标志
uint16_t i;
uint16_t adcx;
uint32_t sum;
float temp;
uint16_t adc_dma_buf[ADC_DMA_BUF_SIZE];
void ADC_Init(uint32_t mar)
{
__HAL_RCC_DMA1_CLK_ENABLE(); // 使能DMA1时钟
DMA_Handler.Instance = DMA1_Channel1; // DMA1通道1
DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY; // DMA从外设到寄存器
DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // DMA寄存器数据长度:半字
DMA_Handler.Init.MemInc = DMA_MINC_ENABLE; // 寄存器地址增量
DMA_Handler.Init.Mode = DMA_NORMAL; // 不开启循环模式
DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // DMA外设数据长度:半字
DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不增量
DMA_Handler.Init.Priority = DMA_PRIORITY_HIGH; // 中断优先级高
HAL_DMA_Init(&DMA_Handler); // DMA初始化
__HAL_LINKDMA(&ADC_Handler, DMA_Handle, DMA_Handler); // 将DMA的结构体成员赋予ADC的DMA结构体
ADC_Handler.Instance = ADC1; // ADC1
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_DISABLE; // 不开启扫描模式
ADC_Handler.Init.ContinuousConvMode = ENABLE; // 开启连续模式
ADC_Handler.Init.NbrOfConversion = 1; // 转换通道数目1
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不开启间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 间断模式规则通道数目1
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // ADC软件触发
HAL_ADC_Init(&ADC_Handler); // ADC初始化,调用HAL_ADC_MspInit()
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_Channelconfig.Channel = ADC_CHANNEL_1; // ADC通道1
ADC_Channelconfig.Rank = ADC_REGULAR_RANK_1; // ADC准换顺序1
ADC_Channelconfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // ADC采样周期239.5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channelconfig); // ADC通道配置
HAL_DMA_Start_IT(&DMA_Handler, (uint32_t)&ADC1->DR, mar, 0); // DMA使能并开启中断,传输数量0
HAL_ADC_Start_DMA(&ADC_Handler, &mar, 0); // ADC使能DMA通道
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC1) // 判断是不是ADC1
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
RCC_PeriphCLKInitTypeDef RCC_ADC_CLKInitStructure; // ADC时钟配置结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; // 模拟功能
GPIO_InitStructure.Pin = GPIO_PIN_1; // PA1 ADC1 CHANNERL 1
GPIO_InitStructure.Pull = GPIO_NOPULL; // 不上下拉
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速,这里无所谓
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // PA1初始化
RCC_ADC_CLKInitStructure.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设时钟选择:ADC
RCC_ADC_CLKInitStructure.AdcClockSelection = RCC_ADCPCLK2_DIV6; // ADC时钟6分频
HAL_RCCEx_GetPeriphCLKConfig(&RCC_ADC_CLKInitStructure); // ADC时钟配置
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 3); // 开启DMA1通道1数据流中断
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); // 使能DMA1通道1数据流中断
}
}
void ADC_DMA_ENABLE(uint16_t cndtr)
{
__HAL_ADC_DISABLE(&ADC_Handler); // ADC失能
__HAL_DMA_DISABLE(&DMA_Handler); // DMA失能
while (DMA1_Channel1->CCR & (1 << 0)) // 等待DMA允许传输完成中断
;
DMA1_Channel1->CNDTR = cndtr; // 写入传输数量
__HAL_ADC_ENABLE(&ADC_Handler); // 使能ADC
__HAL_DMA_ENABLE(&DMA_Handler); // 使能DMA
HAL_ADC_Start(&ADC_Handler); // 开启ADC
}
void DMA1_Channel1_IRQHandler()
{
if (DMA1->ISR & (1 << 1)) // DMA1通道1完成了传输完成事件
{
adc_dma_sta = 1; // ADC_DMA标志
DMA1->IFCR |= 1 << 1; // 清除DMA1通道1传输完成标志
}
}
void ADC_SHOW()
{
if (adc_dma_sta == 1)
{
/* 计算DMA 采集到的ADC数据的平均值 */
sum = 0;
for (i = 0; i < ADC_DMA_BUF_SIZE; i++) /* 累加 */
{
sum += adc_dma_buf[i];
}
adcx = sum / ADC_DMA_BUF_SIZE; /* 取平均值 */
/* 显示结果 */
LCD_ShowxNum(134, 110, adcx, 4, 16, 0); /* 显示ADCC采样后的原始值 */
temp = (float)adcx * (3.3 / 4096); /* 获取计算后的带小数的实际电压值,比如3.1111 */
adcx = temp; /* 赋值整数部分给adcx变量,因为adcx为u16整形 */
LCD_ShowxNum(134, 130, adcx, 1, 16, 0); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
temp -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
temp *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
LCD_ShowxNum(150, 130, temp, 3, 16, 0X80); /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
adc_dma_sta = 0; /* 清除DMA采集完成状态标志 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE); // 准备下一次ADC读取
}
}
//ADC.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "lcd.h"
#define ADC_DMA_BUF_SIZE 100 /* ADC DMA采集 BUF大小 */
void ADC_Init(uint32_t mar);
void ADC_DMA_ENABLE(uint16_t cndtr);
void ADC_SHOW();
#endif
//main.c
//精英开发板
//PA1采集电位器电压,DMA采集
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "ADC.h"
extern uint16_t adc_dma_buf[ADC_DMA_BUF_SIZE];
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
ADC_Init((uint32_t)&adc_dma_buf);
LCD_ShowString(30, 110, 200, 16, 16, "ADC1_CH1_VAL:");
LCD_ShowString(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V"); /* 先在固定位置显示小数点 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE);
while (1)
{
ADC_SHOW();
}
}
多通道ADC采集(DMA读取)配置步骤
//ADC.c
#include "ADC.h"
DMA_HandleTypeDef DMA_handler; // DMA句柄
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_Channel_Config; // ADC通道配置
uint8_t ADC_DMA_STA; // ADC_DMA标志
void ADC_Init(uint32_t mar)
{
__HAL_RCC_DMA1_CLK_ENABLE(); // 使能DMA1时钟
DMA_handler.Instance = DMA1_Channel1; // DMA1通道1
DMA_handler.Init.Direction = DMA_PERIPH_TO_MEMORY; // DMA传输方向:外设向寄存器
DMA_handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // DMA寄存器数据长度:半字
DMA_handler.Init.MemInc = DMA_MINC_ENABLE; // DMA寄存器地址增量
DMA_handler.Init.Mode = DMA_NORMAL; // DMA不开启循环模式
DMA_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // DMA外设数据长度:半字
DMA_handler.Init.PeriphInc = DMA_PINC_DISABLE; // DMA外设地址不增量
DMA_handler.Init.Priority = DMA_PRIORITY_VERY_HIGH; // 优先级非常高
HAL_DMA_Init(&DMA_handler); // DMA初始化,,回调HAL_ADC_MspInit()
__HAL_LINKDMA(&ADC_Handler, DMA_Handle, DMA_handler); // 将DMA结构体成员赋予ADC结构体中的DMA
ADC_Handler.Instance = ADC1; // ADC1
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_ENABLE; // 使用扫描模式
ADC_Handler.Init.ContinuousConvMode = ENABLE; // 连续模式
ADC_Handler.Init.NbrOfConversion = 6; // 通道数量6
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不开启间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 间断模式的规则通道数0
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
HAL_ADC_Init(&ADC_Handler); // ADC初始化
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_Channel_Config.Channel = ADC_CHANNEL_0; // 通道0
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_1; // 顺序1
ADC_Channel_Config.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采样周期:239.5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
ADC_Channel_Config.Channel = ADC_CHANNEL_1; // 通道1
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_2; // 顺序2
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
ADC_Channel_Config.Channel = ADC_CHANNEL_2; // 通道2
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_3; // 顺序3
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
ADC_Channel_Config.Channel = ADC_CHANNEL_3; // 通道3
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_4; // 顺序4
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
ADC_Channel_Config.Channel = ADC_CHANNEL_4; // 通道4
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_5; // 顺序5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
ADC_Channel_Config.Channel = ADC_CHANNEL_5; // 通道5
ADC_Channel_Config.Rank = ADC_REGULAR_RANK_6; // 顺序6
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_Config); // ADC通道配置
HAL_DMA_Start_IT(&DMA_handler, (uint32_t)&ADC1->DR, mar, 0); // 使能DMA,开启数据流传输完成中断
HAL_ADC_Start_DMA(&ADC_Handler, &mar, 0); // 使能ADC,开启ADC-DMA通道
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC1) // 判断是不是ADC1
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
RCC_PeriphCLKInitTypeDef RCC_ADC_CLKInitStructure; // ADC时钟配置结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; // 模拟功能
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5; // PA0,PA1,PA2,PA3,PA4,PA5
GPIO_InitStructure.Pull = GPIO_NOPULL; // 不上下拉
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // GPIO结构体初始化
RCC_ADC_CLKInitStructure.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设时钟:ADC
RCC_ADC_CLKInitStructure.AdcClockSelection = RCC_ADCPCLK2_DIV6; // ADC时钟6分频
HAL_RCCEx_PeriphCLKConfig(&RCC_ADC_CLKInitStructure); // ADC时钟配置
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 3); // 设置DMA1通道1数据流传输完成中断
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); // 使能DMA1通道1数据流传输完成中断
}
}
void ADC_DMA_ENABLE(uint16_t cndtr)
{
__HAL_ADC_DISABLE(&ADC_Handler); // ADC失能
__HAL_DMA_DISABLE(&DMA_handler); // DMA失能
while (DMA1_Channel1->CCR & (1 << 0)) // 等待DMA允许传输完成中断
;
DMA1_Channel1->CNDTR = cndtr; // 写入DMA传输数量
__HAL_ADC_ENABLE(&ADC_Handler); // 使能ADC
__HAL_DMA_ENABLE(&DMA_handler); // 使能DMA
HAL_ADC_Start(&ADC_Handler); // 开启ADC
}
void DMA1_Channel1_IRQHandler()
{
if (DMA1->ISR & (1 << 1)) // 判断DMA1传输完成
{
ADC_DMA_STA = 1; // ADC_DMA标志
DMA1->IFCR |= 1 << 1; // 清除DMA1传输完成中断标志
}
}
uint16_t i, j;
uint16_t adcx;
uint32_t sum;
float temp;
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE]; /* ADC DMA BUF */
void ADC_SHOW()
{
if (ADC_DMA_STA == 1)
{
for (j = 0; j < 6; j++) /* 遍历6个通道 */
{
sum = 0; /* 清零 */
for (i = 0; i < ADC_DMA_BUF_SIZE / 6; i++) /* 每个通道采集了50次数据,进行50次累加 */
{
sum += g_adc_dma_buf[(6 * i) + j]; /* 相同通道的转换数据累加 */
}
adcx = sum / (ADC_DMA_BUF_SIZE / 6); /* 取平均值 */
/* 显示结果 */
LCD_ShowxNum(108, 110 + (j * 30), adcx, 4, 12, 0); /* 显示ADC采样后的原始值 */
temp = (float)adcx * (3.3 / 4096); /* 获取计算后的带小数的实际电压值,比如3.1111 */
adcx = temp; /* 赋值整数部分给adcx变量,因为adcx为u16整形 */
LCD_ShowxNum(108, 122 + (j * 30), adcx, 1, 12, 0); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
temp -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
temp *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
LCD_ShowxNum(120, 122 + (j * 30), temp, 3, 12, 0X80); /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
}
ADC_DMA_STA = 0; /* 清除DMA采集完成状态标志 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE); /* 启动下一次ADC DMA采集 */
}
}
//ADC.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "lcd.h"
void ADC_Init(uint32_t mar);
void ADC_DMA_ENABLE(uint16_t cndtr);
void ADC_SHOW();
#define ADC_DMA_BUF_SIZE 50 * 6 /* ADC DMA采集 BUF大小, 应等于ADC通道数的整数倍 */
#endif
//main.c
//精英开发板
//PA0,PA1,PA2,PA3,PA4,PA5采集电压,DMA读取
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "ADC.h"
extern uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE];
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
ADC_Init((uint32_t)&g_adc_dma_buf); /* 初始化ADC DMA采集 */
LCD_ShowString(30, 110, 200, 12, 12, "ADC1_CH0_VAL:");
LCD_ShowString(30, 122, 200, 12, 12, "ADC1_CH0_VOL:0.000V"); /* 先在固定位置显示小数点 */
LCD_ShowString(30, 140, 200, 12, 12, "ADC1_CH1_VAL:");
LCD_ShowString(30, 152, 200, 12, 12, "ADC1_CH1_VOL:0.000V"); /* 先在固定位置显示小数点 */
LCD_ShowString(30, 170, 200, 12, 12, "ADC1_CH2_VAL:");
LCD_ShowString(30, 182, 200, 12, 12, "ADC1_CH2_VOL:0.000V"); /* 先在固定位置显示小数点 */
LCD_ShowString(30, 200, 200, 12, 12, "ADC1_CH3_VAL:");
LCD_ShowString(30, 212, 200, 12, 12, "ADC1_CH3_VOL:0.000V"); /* 先在固定位置显示小数点 */
LCD_ShowString(30, 230, 200, 12, 12, "ADC1_CH4_VAL:");
LCD_ShowString(30, 242, 200, 12, 12, "ADC1_CH4_VOL:0.000V"); /* 先在固定位置显示小数点 */
LCD_ShowString(30, 260, 200, 12, 12, "ADC1_CH5_VAL:");
LCD_ShowString(30, 272, 200, 12, 12, "ADC1_CH5_VOL:0.000V"); /* 先在固定位置显示小数点 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE); /* 启动ADC DMA采集 */
while (1)
{
ADC_SHOW();
}
}
单通道ADC过采样
//ADC.c
#include "ADC.h"
DMA_HandleTypeDef DMA_Handler; // DMA句柄
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_Channel_config; // ADC通道配置
uint8_t ADC_DMA_STA = 0; // ADC_DMA传输完成标志
void ADC_Init(uint32_t mar)
{
__HAL_RCC_DMA1_CLK_ENABLE(); // 使能DMA1
DMA_Handler.Instance = DMA1_Channel1; // DMA1通道1
DMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY; // DMA传输方向:外设到寄存器
DMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // DMA寄存器数据长度:半字
DMA_Handler.Init.MemInc = DMA_MINC_ENABLE; // 寄存器地址增量
DMA_Handler.Init.Mode = DMA_NORMAL; // DMA不循环模式
DMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // DMA外设数据长度:半字
DMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE; // 外设地址不增量
DMA_Handler.Init.Priority = DMA_PRIORITY_HIGH; // 高优先级
HAL_DMA_Init(&DMA_Handler); // DMA初始化
__HAL_LINKDMA(&ADC_Handler, DMA_Handle, DMA_Handler); // 将DMA结构体赋予ADC结构体中的DMA
ADC_Handler.Instance = ADC1; // ADC1
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_DISABLE; // 不扫描模式
ADC_Handler.Init.ContinuousConvMode = ENABLE; // 连续模式
ADC_Handler.Init.NbrOfConversion = 1; // 转换通道数目:1
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 间断模式规则通道数目0
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
HAL_ADC_Init(&ADC_Handler); // ADC初始化,回调HAL_ADC_MspInit()
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_Channel_config.Channel = ADC_CHANNEL_1; // 通道1
ADC_Channel_config.Rank = ADC_REGULAR_RANK_1; // 顺序1
ADC_Channel_config.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; // 采样周期:239.5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_Channel_config); // ADC通道配置
HAL_DMA_Start_IT(&DMA_Handler, (uint32_t)&ADC1->DR, mar, 0); // 使能DMA,开启数据流传输完成中断
HAL_ADC_Start_DMA(&ADC_Handler, &mar, 0); // 使能ADC,开启ADC-DMA通道
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC1) // 判断是不是ADC1
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
RCC_PeriphCLKInitTypeDef RCC_ADC_CLK_InitStructure; // ADC时钟初始化结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1时钟
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; // 模拟功能
GPIO_InitStructure.Pin = GPIO_PIN_1; // PA1
GPIO_InitStructure.Pull = GPIO_NOPULL; // 不上下拉
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); // GPIO初始化
RCC_ADC_CLK_InitStructure.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设时钟:ADC
RCC_ADC_CLK_InitStructure.AdcClockSelection = RCC_ADCPCLK2_DIV6; // ADC时钟6分频
HAL_RCCEx_PeriphCLKConfig(&RCC_ADC_CLK_InitStructure); // ADC外设时钟配置
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 3, 3); // 设置DMA1通道1数据流传输完成中断
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); // 使能DMA1通道1数据流传输完成中断
}
}
void ADC_DMA_ENABLE(uint16_t cndtr)
{
__HAL_ADC_DISABLE(&ADC_Handler); // ADC失能
__HAL_DMA_DISABLE(&DMA_Handler); // DMA失能
while (DMA1_Channel1->CCR & (1 << 0)) // 等待DMA允许传输完成中断
;
DMA1_Channel1->CNDTR = cndtr; // 写入DMA1通道1数目
__HAL_ADC_ENABLE(&ADC_Handler); // 使能ADC
__HAL_DMA_ENABLE(&DMA_Handler); // 使能DMA
HAL_ADC_Start(&ADC_Handler); // 开启ADC
}
void DMA1_Channel1_IRQHandler()
{
if (DMA1->ISR & (1 << 1)) // 判断DMA1传输完成
{
ADC_DMA_STA = 1; // ADC_DMA标志
DMA1->IFCR |= 1 << 1; // 清除DMA1传输完成标志位
}
}
uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE]; /* ADC DMA BUF */
uint16_t i;
uint32_t adcx;
uint32_t sum;
float temp;
void ADC_SHOW()
{
if (ADC_DMA_STA == 1)
{
/* 计算DMA 采集到的ADC数据的平均值 */
sum = 0;
for (i = 0; i < ADC_DMA_BUF_SIZE; i++) /* 累加 */
{
sum += g_adc_dma_buf[i];
}
adcx = sum / (ADC_DMA_BUF_SIZE / ADC_OVERSAMPLE_TIMES); /* 取平均值 */
adcx >>= 4; /* 除以2^4倍, 得到12+4位 ADC精度值, 注意: 提高 N bit精度, 需要 >> N */
/* 显示结果 */
LCD_ShowxNum(134, 110, adcx, 5, 16, 0); /* 显示ADC采样后的原始值 */
temp = (float)adcx * (3.3 / 65536); /* 获取计算后的带小数的实际电压值,比如3.1111 */
adcx = temp; /* 赋值整数部分给adcx变量,因为adcx为u16整形 */
LCD_ShowxNum(134, 130, adcx, 1, 16, 0); /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
temp -= adcx; /* 把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111 */
temp *= 1000; /* 小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。 */
LCD_ShowxNum(150, 130, temp, 3, 16, 0X80); /* 显示小数部分(前面转换为了整形显示),这里显示的就是111. */
ADC_DMA_STA = 0; /* 清除DMA采集完成状态标志 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE); /* 启动下一次ADC DMA采集 */
}
}
//ADC.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#include "lcd.h"
#define ADC_OVERSAMPLE_TIMES 256 /* ADC过采样次数, 这里提高4bit分辨率, 需要256倍采样 */
#define ADC_DMA_BUF_SIZE ADC_OVERSAMPLE_TIMES * 10 /* ADC DMA采集 BUF大小, 应等于过采样次数的整数倍 */
void ADC_Init(uint32_t mar);
void ADC_DMA_ENABLE(uint16_t cndtr);
void ADC_SHOW();
#endif
//main.c
//精英开发板
//PA1采集电压,用过采样256倍分辨率提高4位,总共16位
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "ADC.h"
extern uint16_t g_adc_dma_buf[ADC_DMA_BUF_SIZE]; /* ADC DMA BUF */
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
ADC_Init((uint32_t)&g_adc_dma_buf); /* 初始化ADC DMA采集 */
LCD_ShowString(30, 110, 200, 16, 16, "ADC1_CH1_VAL:");
LCD_ShowString(30, 130, 200, 16, 16, "ADC1_CH1_VOL:0.000V"); /* 先在固定位置显示小数点 */
ADC_DMA_ENABLE(ADC_DMA_BUF_SIZE); /* 启动ADC DMA采集 */
while (1)
{
ADC_SHOW();
}
}
内部温度传感器
STM32内部温度传感器简介
主要特性 | F1 | F4 | F7 | H7 | |
温度范围 | -40~125℃ | ||||
精度(MAX) | ±2℃ | ±3℃ | |||
采样时间 | ≥17.1us | ≥10us | ≥9us | ||
ADC通道 | ADC1_IN16 | ADC1_IN16(F407) ADC1_IN18(F429) | ADC1_IN18 | ADC3_INP18 | |
上电控制位 | TSVREFE位 | VSENSEEN 位 |
F1温度计算方法
F4/F7温度计算方法
H7温度计算方法
//Temp.c
#include "TEMP.h"
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_ChannelConfig; // ADC通道配置句柄
void TEMP_Init()
{
ADC_Handler.Instance = ADC1; // ADC1
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_DISABLE; // 不开启扫描模式
ADC_Handler.Init.ContinuousConvMode = ENABLE; // 连续模式
ADC_Handler.Init.NbrOfConversion = 1; // 通道数量1
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 不间断模式规则通道数目0
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
HAL_ADC_Init(&ADC_Handler); // ADC初始化,回调HAL_ADC_MspInit()
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_ChannelConfig.Channel = ADC_CHANNEL_16; // ADC通道16
ADC_ChannelConfig.Rank = ADC_REGULAR_RANK_1; // 顺序1
ADC_ChannelConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采集周期:239.5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_ChannelConfig); // ADC通道配置
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC1) // 判断是不是ADC1
{
RCC_PeriphCLKInitTypeDef RCC_ADC_CLK_InitStructure; // ADC时钟初始化结构体
__HAL_RCC_ADC1_CLK_ENABLE(); // 使能ADC1
RCC_ADC_CLK_InitStructure.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设选择:ADC
RCC_ADC_CLK_InitStructure.AdcClockSelection = RCC_ADCPCLK2_DIV6; // ADC时钟6分频
HAL_RCCEx_PeriphCLKConfig(&RCC_ADC_CLK_InitStructure); // ADC时钟配置初始化
}
}
uint32_t ADC_GET()
{
HAL_ADC_Start(&ADC_Handler); // 开启ADC1
HAL_ADC_PollForConversion(&ADC_Handler, 10); // 等待ADC转化,10ms
return HAL_ADC_GetValue(&ADC_Handler); // 返回ADC获得值
}
uint16_t ADC_GET_TEMP()
{
uint32_t adcx;
uint16_t result;
double TEMP;
adcx = ADC_GET();
TEMP = adcx * 3.3 / 4096; // 电压值
TEMP = (1.43 - TEMP) / 0.0043 + 25; // 温度值
result = TEMP * 100; // 温度值摄氏度
return result;
}
void TEMP_SHOW()
{
uint16_t TEMP;
TEMP = ADC_GET_TEMP(); /* 得到温度值 */
if (TEMP < 0)
{
TEMP = -TEMP;
LCD_ShowString(30 + 10 * 8, 120, 16, 16, 16, "-"); /* 显示负号 */
}
else
{
LCD_ShowString(30 + 10 * 8, 120, 16, 16, 16, " "); /* 无符号 */
}
LCD_ShowxNum(30 + 11 * 8, 120, TEMP / 100, 2, 16, 0); /* 显示整数部分 */
LCD_ShowxNum(30 + 14 * 8, 120, TEMP % 100, 2, 16, 0X80); /* 显示小数部分 */
}
//Temp.h
#ifndef __TEMP_H
#define __TEMP_H
#include "sys.h"
#include "lcd.h"
void TEMP_Init();
uint32_t ADC_GET();
uint16_t ADC_GET_TEMP();
void TEMP_SHOW();
#endif
//main.c
//精英开发板
//采集ADC1通道16的电压,进而换算成温度
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "Temp.h"
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
TEMP_Init();
LCD_ShowString(30, 70, 200, 16, 16, "Temperature TEST");
LCD_ShowString(30, 120, 200, 16, 16, "TEMPERATE: 00.00C");
while (1)
{
TEMP_SHOW();
LED0 = 1;
}
}
光敏传感器实验
光敏二极管简介
//LightSensor.C
#include "LightSensor.h"
ADC_HandleTypeDef ADC_Handler; // ADC句柄
ADC_ChannelConfTypeDef ADC_ChannelConfig; // ADC通道配置
void ADC_Init()
{
ADC_Handler.Instance = ADC3; // ADC3
ADC_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
ADC_Handler.Init.ScanConvMode = ADC_SCAN_DISABLE; // 不开启扫描模式
ADC_Handler.Init.ContinuousConvMode = ENABLE; // 不开启连续模式
ADC_Handler.Init.NbrOfConversion = 1; // 通道数目1
ADC_Handler.Init.DiscontinuousConvMode = DISABLE; // 不间断模式
ADC_Handler.Init.NbrOfDiscConversion = 0; // 间断模式规则通道数目0
ADC_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 软件触发
HAL_ADC_Init(&ADC_Handler); // ADC初始化,回调HAL_ADC_MspInit()
HAL_ADCEx_Calibration_Start(&ADC_Handler); // ADC校准
ADC_ChannelConfig.Channel = ADC_CHANNEL_6; // ADC通道6
ADC_ChannelConfig.Rank = ADC_REGULAR_RANK_1; // 顺序1
ADC_ChannelConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采集周期:239.5
HAL_ADC_ConfigChannel(&ADC_Handler, &ADC_ChannelConfig); // ADC通道配置
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
if (hadc->Instance == ADC3) // 判断是不是ADC3
{
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
RCC_PeriphCLKInitTypeDef RCC_ADC_CLK_Init; // ADC时钟配置结构体
__HAL_RCC_GPIOF_CLK_ENABLE(); // 使能GPIOF时钟
__HAL_RCC_ADC3_CLK_ENABLE(); // 使能ADC3时钟
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; // 模拟功能
GPIO_InitStructure.Pin = GPIO_PIN_8; // PF9,ADC1通道6
GPIO_InitStructure.Pull = GPIO_NOPULL; // 不上下拉
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; // 高速
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
RCC_ADC_CLK_Init.PeriphClockSelection = RCC_PERIPHCLK_ADC; // 外设时钟:ADC
RCC_ADC_CLK_Init.AdcClockSelection = RCC_ADCPCLK2_DIV6; // ADC时钟6分频
HAL_RCCEx_PeriphCLKConfig(&RCC_ADC_CLK_Init); // ADC时钟配置
}
}
uint32_t ADC_GET()
{
HAL_ADC_Start(&ADC_Handler); // 开启ADC
HAL_ADC_PollForConversion(&ADC_Handler, 10); // 等待ADC转化,10ms
return HAL_ADC_GetValue(&ADC_Handler); // 返回ADC获得值
}
void LIGHT_SHOW()
{
uint32_t TEMP;
uint32_t LIGHT;
TEMP = ADC_GET();
TEMP /= 40;
if (TEMP > 100)
TEMP = 100;
LIGHT = 100 - TEMP; // 光照强度值
LCD_ShowxNum(30 + 10 * 8, 110, LIGHT, 3, 16, 0); /* 显示ADC的值 */
}
//LightSensor.h
#ifndef __LIGHTSENSOR_H
#define __LIGHTSENSOR_H
#include "sys.h"
#include "lcd.h"
void ADC_Init();
uint32_t ADC_GET();
void LIGHT_SHOW();
#endif
//main.c
//精英开发板
//采集PF8,ADC3通道6的电压,进而换算成0-100的光线强度
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "usmart.h"
#include "KEY.h"
#include "led.h"
#include "lcd.h"
#include "LightSensor.h"
int main(void)
{
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 初始化延时函数
uart_init(115200); // 初始化串口
KEY_Init(); // 初始化按键
LED_Init(); // 初始化LED
LCD_Init(); // 初始化LCD FSMC接口
usmart_dev.init(84); // 初始化USMART
POINT_COLOR = RED; // 画笔颜色:红色
LCD_ShowString(30, 50, 200, 16, 16, " YMZ ^_^");
ADC_Init();
LCD_ShowString(30, 110, 200, 16, 16, "LSENS_VAL:");
while (1)
{
LIGHT_SHOW();
}
}