简介
- STM32F103 拥有 1~3 个 ADC,这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。
- ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。
- 各通道的 A/D 转换可以单次、连续、扫描或间断模式执行
ADC 的转换分为 2 个通道组:
规则通道相当于你正常运行的程序
注入通道 就相当于中断
ADC 在单次转换模式下,只执行一次转换,该模式可以通过 ADC_CR2 寄存器
的 ADON 位(只适用于规则通道)启动,也可以通过外部触发启动(适用于规则通道和注入通道),这是 CONT 位为 0。
以规则通道为例,一旦所选择的通道转换完成,转换结果将被存在 ADC_DR 寄存器中,EOC(转换结束)标志将被置位,如果设置了 EOCIE,则会产生中断。然后 ADC 将停止,直到下次启动。
ADC单通道:
要求进行一次ADC转换:配置为单次模式使能,扫描模式失能。这样ADC的这个通道,转换一次后,就停止转换。
要求进行连续ADC转换:配置为连续模式使能,扫描模式失能。这样ADC的这个通道,转换一次后,接着进行下一次转换,不断连续。
ADC多通道:必须是扫描模式
要求进行一次ADC转换:配置为单次模式使能,扫描模式使能。这样ADC的多个通道,按照配置的顺序依次转换一次后,就停止转换。
要求进行连续ADC转换:配置为连续模式使能,扫描模式使能。这样ADC的多个通道,按照配置的顺序依次转换一次后,接着进行下一次转换,不断连续。
因此,得出结论:
扫描模式只在多通道的条件下有效,来使得各个通道按照配置循序依次转换。
而单次模式无论在单通道还是多通道下只对这些或者这个通道进行一次转换,
连续模式无论是在单通道还是多通道下都对这些或者这个通道不断进行连续的转换。
adc.c文件
#include "adc.h"
#include "delay.h"
//初始化ADC1
//这里我们仅以规则通道为例
//我们默认仅开启通道1
void Adc_Init(void)
{
//先初始化IO口
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
GPIOA->CRL&=0XFFFFFF0F;//PA1 anolog输入
RCC->APB2ENR|=1<<9; //ADC1时钟使能
RCC->APB2RSTR|=1<<9; //ADC1复位
RCC->APB2RSTR&=~(1<<9);//复位结束
RCC->CFGR&=~(3<<14); //分频因子清零
//SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
//否则将导致ADC准确度下降!
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF; //工作模式清零
ADC1->CR1|=0<<16; //独立工作模式 不开启双ad模式
ADC1->CR1&=~(1<<8); //非扫描模式
ADC1->CR2&=1<<1; //单次转换模式
ADC1->CR2&=~(7<<17);
ADC1->CR2|=7<<17; //软件控制转换
ADC1->CR2|=1<<20; //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
ADC1->CR2&=~(1<<11); //右对齐
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1|=0<<20; //1个转换在规则序列中 也就是只转换规则序列1
//设置通道1的采样时间
ADC1->SMPR2&=~(3*1); //通道1采样时间清空
ADC1->SMPR2|=7<<(3*1); //通道1 239.5周期,提高采样时间可以提高精确度
ADC1->CR2|=1<<0; //开启AD转换器
ADC1->CR2|=1<<3; //使能复位校准
while(ADC1->CR2&1<<3); //等待校准结束
//该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
ADC1->CR2|=1<<2; //开启AD校准
while(ADC1->CR2&1<<2); //等待校准结束
//该位由软件设置以开始校准,并在校准结束时由硬件清除
}
//获得ADC1某个通道的值
//ch:通道值 0~16
//返回值:转换结果
u16 Get_Adc(u8 ch)
{
//设置转换序列
ADC1->SQR3&=0XFFFFFFE0;//规则序列1 通道ch
ADC1->SQR3|=ch;
ADC1->CR2|=1<<22; //启动规则转换通道
while(!(ADC1->SR&1<<1));//等待转换结束
return ADC1->DR; //返回adc值
}
//获取通道ch的转换值,取times次,然后平均
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
adc.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
#define ADC_CH1 1 //通道1(连接在PA1)
void Adc_Init(void); //ADC通道初始化
u16 Get_Adc(u8 ch); //获得某个通道值
u16 Get_Adc_Average(u8 ch,u8 times);//得到某个通道10次采样的平均值
#endif
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "adc.h"
int main(void)
{
u16 adcx;
float temp;
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,115200); //串口初始化为115200
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); //初始化LCD
Adc_Init(); //ADC初始化
POINT_COLOR=RED;//设置字体为红色
//显示提示信息
POINT_COLOR=BLUE;//设置字体为蓝色
LCD_ShowString(30,130,200,16,16,"等于ADC_CH0_VAL:");
LCD_ShowString(30,150,200,16,16,"ADC_CH0_VOL:0.000V");
while(1)
{
adcx=Get_Adc_Average(ADC_CH1,50);//取adc1通道1的pa1口50次取平均
LCD_ShowxNum(126,130,adcx,4,16,0);//显示ADC的值
if(adcx>=1500)//adc的值大于1500则检测到白色
LCD_ShowString(30,200,200,16,16,"FIND IT!");
else //低于1500检测到黑线
LCD_ShowString(30,200,200,16,16,"no ");
//adcx=Get_Adc(ADC_CH1);
LED0=!LED0;
delay_ms(250);
}
}