需求描述
基于寄存器操作,菜鸡可变电阻器的电压,并通过串口把电压数据发送到电脑端。
硬件电路设计

PC0口为ADC的10通道,范围是0~3.3V。只需要一个ADC,使用独立模式即可。

使用到的寄存器
扫描模式
代码
/* 3. 禁用扫描模式(只有一个通道,不需要扫描) */
ADC1->CR1 &= ~ADC_CR1_SCAN;寄存器


连续转换
代码
/* 4. 启用连续转换(转换不会停止) */
ADC1->CR2 |= ADC_CR2_CONT;寄存器


转换结果数据对齐方式
代码
/* 5. 转换结果右对齐 0:右对齐 1: 左对齐*/
ADC1->CR2 &= ~ADC_CR2_ALIGN;寄存器


规则通道外部触发转换模式
代码
/* 6. 禁用规则通道外部触发 */
ADC1->CR2 &= ~ADC_CR2_EXTTRIG;寄存器


配置启动规则转换的外部事件
代码
/* 7. 使用软件启动转换 111=软件启动*/
ADC1->CR2 |= ADC_CR2_EXTSEL;寄存器


规则组长度
代码
/* 8. 规则转换序列长度(有几个通道需要转换)000:1个 001:2个 ... */
ADC1->SQR1 &= ~ADC_SQR1_L;寄存器


给规则组设置转换序列
SQRx寄存器一共有三个,前面我们设置了规则组的长度,假如我们设置长度为3,则要给SQ1、2、3分辨设置我们要读取的通道,随后我们启动ADC采集的时候,他会按着SQ1、2、3的顺序读取通道。
代码
/* 9. 规则转换序列中的第一个转换 通道10, 就是SQR3[4:0]=01010 */
ADC1->SQR3 &= ~ADC_SQR3_SQ1; /* [4:0]位置为0 */
ADC1->SQR3 |= (10 << 0); /* 设置最后5位 */寄存器


设置采样时间
代码
/* 10. 通道10采样时间 设置7.5个周期=001*/
ADC1->SMPR1 &= ~ADC_SMPR1_SMP10_2;
ADC1->SMPR1 &= ~ADC_SMPR1_SMP10_1;
ADC1->SMPR1 |= ADC_SMPR1_SMP10;寄存器

启动ADC
代码
/* 1. 启动 ADC1 ADON:0->1 是从断电模式下唤醒*/
ADC1->CR2 |= ADC_CR2_ADON;寄存器


AD校准
代码
/* 2. 启用AD校准, 校准完成之后该位会自动清0*/
ADC1->CR2 |= ADC_CR2_CAL;寄存器


启动转换
代码
/* 5. 开始转换 规则通道 */
ADC1->CR2 |= ADC_CR2_SWSTART;寄存器


寄存器实现
adc.h
#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h"
// 初始化
void ADC1_Init(void);
// 开启转换
void ADC1_StartConvert(void);
// 返回转换后的模拟电压值
double ADC1_ReadV(void);
#endifadc.c
#include "adc.h"
// 初始化
void ADC1_Init(void)
{
// 1. 时钟配置
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
// CFGR:ADCPRE - 10,6分频,得到 12MHz
RCC->CFGR |= RCC_CFGR_ADCPRE_1;
RCC->CFGR &= ~RCC_CFGR_ADCPRE_0;
// 2. GPIO工作模式,PC0,模拟输入,00 00
GPIOC->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0);
// 3. ADC配置
// 3.1 工作模式:禁用扫描模式
ADC1->CR1 &= ~ADC_CR1_SCAN;
// 3.2 启用连续转换模式(单曲循环)、
ADC1->CR2 |= ADC_CR2_CONT;
// 3.3 数据右对齐(默认)
ADC1->CR2 &= ~ADC_CR2_ALIGN;
// 3.4 设置通道10的采样时间,001 - 7.5个时钟周期
ADC1->SMPR1 &= ~ADC_SMPR1_SMP10;
ADC1->SMPR1 |= ADC_SMPR1_SMP10_0;
// 3.5 规则组通道序列配置
// 3.5.1 规则组中的通道个数 L
ADC1->SQR1 &= ~ADC_SQR1_L;
// 3.5.2 将通道号 10 保存到序列中的第一位
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= 10 << 0;
// 3.5 选择软件触发AD转换
// ADC1->CR2 |= ADC_CR2_EXTTRIG;
// ADC1->CR2 |= ADC_CR2_EXTSEL; // 选择的就是SWSTART控制AD转换
}
// 开启转换
void ADC1_StartConvert(void)
{
// 1. 上电唤醒
ADC1->CR2 |= ADC_CR2_ADON;
// 2. 执行校准
ADC1->CR2 |= ADC_CR2_CAL;
// 等待校准完成
while (ADC1->CR2 & ADC_CR2_CAL)
{}
// 3. 启动转换
// ADC1->CR2 |= ADC_CR2_SWSTART;
ADC1->CR2 |= ADC_CR2_ADON;
// 4. 等待转换完成
while ((ADC1->SR & ADC_SR_EOC) == 0)
{}
}
// 返回转换后的模拟电压值
double ADC1_ReadV(void)
{
return ADC1->DR * 3.3 / 4095;
}main.c
#include "usart.h"
#include "adc.h"
#include "delay.h"
int main(void)
{
// 初始化
USART_Init();
ADC1_Init();
printf("Hello, world!\n");
// 开启AD转换
ADC1_StartConvert();
while(1)
{
// 向串口发送打印转换结果
printf("V = %.2f\n", ADC1_ReadV());
Delay_ms(1000);
}
}HAL库实现
HAL库设置


添加的其他代码
main函数
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// 启动ADC转换
HAL_ADC_Start(&hadc1);
while (1)
{
float v = HAL_ADC_GetValue(&hadc1) / 4095.0 * 3.3;
printf("电压=%.2fV\r\n", v);
HAL_Delay(1000);
}
}