1.AD单通道(单次转换,非扫描模式)
1.1 接线图
1.2 AD.c
#include "stm32f10x.h" // Device header
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC时钟分频,6分频,72/6=12,12MHz小于14MHz
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//将IO口配置为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//查表得知PA0口为ADC通道0口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC规则组输入通道,因为IO口选择PA0,所以此处通道为ADC通道0,序列号,采样时间
//ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//采用多通道可以多次配置
//ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_Initstructure;
ADC_Initstructure.ADC_Mode = ADC_Mode_Independent;//ADC模式,单ADC模式,区别于双ADC模式
ADC_Initstructure.ADC_DataAlign = ADC_DataAlign_Right;//参数值右对齐
ADC_Initstructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发选择:不使用外部触发
ADC_Initstructure.ADC_ContinuousConvMode = DISABLE;//单次转换
ADC_Initstructure.ADC_ScanConvMode = DISABLE;//非扫描模式
ADC_Initstructure.ADC_NbrOfChannel = 1;//通道数为1
ADC_Init(ADC1,&ADC_Initstructure);
ADC_Cmd(ADC1, ENABLE);//开启ADC
ADC_ResetCalibration(ADC1);//校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获取所选ADC复位校准寄存器状态,等待校准完成。判断CR2_RSTCAL状态,经查阅参考手册
//ADC控制寄存器 2(ADC_CR2)得知当校准完成后,该位自动置0,置0后跳出循环,等待结束
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)== SET);//获取所选ADC校准状态,等待校准完成。原理同上
}
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件启动AD转换
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)== RESET);//获取EOC标志位,检查转换是否完成,检查ADC状态寄存器(ADC_SR)寄存器的EOC标志位
//经查阅参考手册得,转换结束位,该位由硬件在(规则或注入)通道组转换结束时设置,由软件清除或由读取ADC_DR时清除
//0:转换未完成;1:转换完成,所以在此处while循环中判断条件为EOC是否等于RESET,转换结束即可跳出循环
//ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//因为读取ADC_DR时自动清除EOC标志位,所以此处无需这条代码
return ADC_GetConversionValue(ADC1);//返回常规通道的最后一次ADCx转换结果数据。因为此代码是读取ADC_DR寄存器,读取后自动自动清除EOC标志位
}
需要注意:
- AD校准中,在等待校准完成时,while的判断条件,具体根据寄存器ADC_CR2描述来配合
- 在等待转换完成读取EOC标志位时的判断条件, 具体根据寄存器ADC_SR描述来配合
1.3 main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
uint16_t ADValue;
int main(void)
{
OLED_Init();
AD_Init();
OLED_ShowString(1,1,"ADValue:");
while (1)
{
ADValue = AD_GetValue();//将获取AD值赋给ADValue;
OLED_ShowNum(1,9,ADValue,4);
}
}
1.4 实验结果
- 通过调整旋钮来改变阻值,进而改变输出电压的大小,并通过AD转换输出
2. AD单通道配合ADC模拟看门狗
模拟看门狗可以检测通道的高低阈值,当ADC转换结果在阈值高线和阈值低线之间时,模拟看门狗可以触发进入中。
本实验通过看模拟看门狗检测通道,dangADC转换结果大于2000或者小于1000时,进入中断,并点亮一个LED灯
2.1 AD.c
#include "stm32f10x.h" // Device header
#include "LED.h"
#include "Delay.h"
uint16_t ADget;
uint16_t biaozhi;
void AD_Init(void)
{
LED_Init();
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC时钟分频,6分频,72/6=12,12MHz小于14MHz
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//将IO口配置为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//查表得知PA0口为ADC通道0口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//ADC规则组输入通道,因为IO口选择PA0,所以此处通道为ADC通道0,序列号,采样时间
//ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//采用多通道可以多次配置
//ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_Initstructure;
ADC_Initstructure.ADC_Mode = ADC_Mode_Independent;//ADC模式,单ADC模式,区别于双ADC模式
ADC_Initstructure.ADC_DataAlign = ADC_DataAlign_Right;//参数值右对齐
ADC_Initstructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发选择:不使用外部触发
ADC_Initstructure.ADC_ContinuousConvMode = ENABLE;//单次转换还是连续转换
ADC_Initstructure.ADC_ScanConvMode = DISABLE;//多通道还是单通道
ADC_Initstructure.ADC_NbrOfChannel = 1;//通道数为1
ADC_Init(ADC1,&ADC_Initstructure);
ADC_Cmd(ADC1, ENABLE);//开启ADC
ADC_AnalogWatchdogSingleChannelConfig(ADC1,ADC_Channel_0);//看门狗检测ADC1,通道0
ADC_AnalogWatchdogThresholdsConfig(ADC1,0x07D0,0x03E8);//上下限确定
ADC_AnalogWatchdogCmd(ADC1,ADC_AnalogWatchdog_SingleRegEnable);//ADC看门狗启动模式
ADC_ITConfig(ADC1,ADC_IT_AWD,ENABLE);//开启ADC中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC配置
NVIC_InitTypeDef NVIC_Initstructure;
NVIC_Initstructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_Initstructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initstructure.NVIC_IRQChannelPreemptionPriority =2;
NVIC_Initstructure.NVIC_IRQChannelSubPriority =2;
NVIC_Init(&NVIC_Initstructure);
ADC_ResetCalibration(ADC1);//校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获取所选ADC复位校准寄存器状态,等待校准完成。判断CR2_RSTCAL状态,经查阅参考手册
//ADC控制寄存器 2(ADC_CR2)得知当校准完成后,该位自动置0,置0后跳出循环,等待结束
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)== SET);//获取所选ADC校准状态,等待校准完成。原理同上
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件启动AD转换
}
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件启动AD转换
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)== RESET);//获取EOC标志位,检查转换是否完成,检查ADC状态寄存器(ADC_SR)寄存器的EOC标志位
// //经查阅参考手册得,转换结束位,该位由硬件在(规则或注入)通道组转换结束时设置,由软件清除或由读取ADC_DR时清除
// //0:转换未完成;1:转换完成,所以在此处while循环中判断条件为EOC是否等于RESET,转换结束即可跳出循环
// //ADC_ClearFlag(ADC1,ADC_FLAG_EOC);//因为读取ADC_DR时自动清除EOC标志位,所以此处无需这条代码
return ADC_GetConversionValue(ADC1);//返回常规通道的最后一次ADCx转换结果数据。因为此代码是读取ADC_DR寄存器,读取后自动自动清除EOC标志位
}
uint16_t ADC12_GET(void)//自定义函数,返回看门狗中断的状态
{
uint16_t zhongjianzhi;
zhongjianzhi = biaozhi;
biaozhi = 0;
return zhongjianzhi;
}
void ADC1_2_IRQHandler(void)
{
if(ADC_GetITStatus(ADC1,ADC_IT_AWD)== SET)//判断是否产生中断标志位
{
biaozhi = 1;
}
ADC_ClearITPendingBit(ADC1,ADC_IT_AWD);//清除标志位
}
中断里面的函数尽可能不要太复杂,可以再外面执行相应的功能
2.2 main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"
#include "LED.h"
uint16_t ADValue;
float Voltage;
uint16_t zhuangtai;
int main(void)
{
OLED_Init();
AD_Init();
LED_Init();
OLED_ShowString(1,1,"ADValue:");
OLED_ShowString(2,1,"Voltage:0.00V");
OLED_ShowString(3,1,"biaozhi:");
while (1)
{
zhuangtai = ADC12_GET();//将函数返回值赋值给zhuangtai
ADValue = AD_GetValue();//将获取AD值赋给ADValue;
Voltage = (float)AD_GetValue() / 4095 * 3.3;
OLED_ShowNum(1,9,ADValue,4);
OLED_ShowNum(2,9,Voltage,1);
OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);
OLED_ShowNum(3,9,zhuangtai,1);
if(zhuangtai==1)//进入看门狗中断,亮灯
{
LED1_ON();
}
else LED1_OFF();//未进入看门狗中断
}
}
2.3 led.c
#include "stm32f10x.h" // Device header
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
void LED1_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
}
void LED2_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
void LED2_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
void LED2_Turn(void)
{
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_2) == 0)
{
GPIO_SetBits(GPIOA, GPIO_Pin_2);
}
else
{
GPIO_ResetBits(GPIOA, GPIO_Pin_2);
}
}
2.4 实验现象
ADC模拟看门狗