ADC的DMA多通道数据采集(雨滴传感器+光敏传感器)
程序员文章站
2022-04-18 08:09:42
...
AADC1跟ADC3可以用DMA,因为多通道,然而ADC只有一个数据寄存器,因此可以用DMA开一个数组来存数据
ADC1只能用DMA1的通道1
ADC3只能用DMA2的通道5
最近在学模拟量的测试,我用了光敏传感器和雨滴传感器,跟上一篇的光敏传感器差不多,只不过这里多了DMA的初始,可以实现独立ADC的多通道数据采集。
adc.h
#ifndef ADC_H
#define ADC_H
#include "sys.h"
void ADC3_Init(void);
//u16 ADC3_Get(u8 ch);
u16 ADC3_GetLightValue(void);
u16 ADC3_GetYuDiValue(void);
//u16 ADC3_GetSmogValue(void);
#endif /* ADC_H */
adc.c
#include "adc.h"
#include "delay.h"
#include "usart.h"
//ADC3使用的是DMA2的通道5
u16 ADC_ConversionValue[2] = {0,0};
void ADC3_Init(void)
{
DMA_InitTypeDef DMA_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); //开启时钟
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE); //复位
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE); //关闭
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //时钟分频,ADC不能超过14Mhz,不然会不精准,系统内部时钟是72Mhz,所以要分频
//DMA设置
DMA_DeInit(DMA2_Channel5);
DMA_InitStruct.DMA_PeripheralBaseAddr = (u32)(&ADC3->DR);//外设的基地址
DMA_InitStruct.DMA_MemoryBaseAddr = (u32)&ADC_ConversionValue; //内存存储地址,即数据的基地址
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//数据来源于外设
DMA_InitStruct.DMA_BufferSize = 2;//缓冲区大小,数组的长度
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//只有一个外设,地址不增
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址递增,即数组地址增
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据大小为半字,也就是两个字节
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存大小为半字,也就是两个字节
DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;//循环传输
DMA_InitStruct.DMA_Priority = DMA_Priority_High;//DMA通道优先级为高,当使用一个DMA通道是,优先级不影响
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //外设到内存模式
DMA_Init(DMA2_Channel5, &DMA_InitStruct);
DMA_Cmd(DMA2_Channel5, ENABLE);
//ADC设置
ADC_DeInit(ADC3);
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //模数转换工作在多通道模式
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //转换结果右对齐,放在低12位
ADC_InitStruct.ADC_NbrOfChannel = 2; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC3, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);//规则通道,ADC3,通道4,第一个转换,采样时间为55.5周期
ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 2, ADC_SampleTime_55Cycles5);//规则通道,ADC3,通道5,第一个转换,采样时间为55.5周期
// ADC_RegularChannelConfig(ADC3, ADC_Channel_6, 3, ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC3, ENABLE); //使能ADC的DMA请求
ADC_Cmd(ADC3, ENABLE);
ADC_ResetCalibration(ADC3); //重置指定的ADC3的复位寄存器
while(ADC_GetResetCalibrationStatus(ADC3)); //获取ADC3重置校准寄存器的状态,设置状态则等待
ADC_StartCalibration(ADC3); //开启精准计算
while(ADC_GetCalibrationStatus(ADC3));
ADC_SoftwareStartConvCmd(ADC3, ENABLE); //使能指定的ADC3的软件转换启动功能
}
u16 ADC3_GetLightValue(void)
{
// printf("ADC_ConversionValue[0]:%d\r\n", ADC_ConversionValue[0]);
return (u16)ADC_ConversionValue[0];
}
u16 ADC3_GetYuDiValue(void)
{
// printf("ADC_ConversionValue[1]:%d\r\n", ADC_ConversionValue[0]);
return (u16)ADC_ConversionValue[1];
}
//
//u16 ADC3_GetSmogValue(void)
//{
// printf("ADC_ConversionValue[1]:%d\r\n", ADC_ConversionValue[0]);
// return (u16)ADC_ConversionValue[2];
//}
光敏传感器
lightsensor.h
lightsensor.c
#include "lightsensor.h"
#include "adc.h"
#include "delay.h"
#include "led.h"
#include "usart.h"
//extern u16 ADC_ConversionValue[2] = {0,0};
//光敏传感器PF6/ADC3_IN4
void LighrSensor_Init(void) //初始化GPIO
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; //采用ADC的时候,这里要用模拟输入模式
GPIO_Init(GPIOF, &GPIO_InitStruct);
ADC3_Init();
}
//光敏传感器模拟值0-100
u8 LightSensor_Val(void)
{
u32 temp = 0;
u8 t;
for(t=0;t<LightSensor_read_time;t++) // LightSensor_read_time:采集次数
{
// temp += ADC3_Get(LSENS_ch); //多次采集的数据和
temp =temp + ADC3_GetLightValue();
// printf("temp:%d\r\n", temp);
delay_ms(5);
}
temp /= LightSensor_read_time; // 平均值:多次采集的数据和除以采集次数
printf("temp:%d\r\n", temp);
if(temp > 4000)
{
temp = 4000;
}else
{
LED1 = 0;
}
return (u8)(100-(temp/40)); //模拟量输出范围为 0-100
}
雨滴传感器
mdrh.h
#ifndef __MHRD_H
#define __MHRD_H
#include "sys.h"
#define YU_DO PAin(5)// PB5
void DO_Init(void);//这个是雨滴传感器作为TTL的高低电平初始化
void MHRD_AO_Init(void);//这个雨滴传感器的模拟初始化
u8 YuDi_Val(void);
#endif /* __MHRD_H */
mdrh.c
#include "mhrd.h"
#include "adc.h"
#include "delay.h"
#include "beep.h"
//PA5 - DO 低电平有效
void DO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //DO-->PA.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOA.5
GPIO_SetBits(GPIOA,GPIO_Pin_5); //PB.5 输出高,关闭
}
void MHRD_AO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); //使能PF端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //AO-->PF.7 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOF, &GPIO_InitStructure); //根据设定参数初始化GPIOF7
ADC3_Init();
}
//雨滴传感器模拟值0-200
u8 YuDi_Val(void)
{
u32 temp = 0;
u8 t;
for(t=0;t<10;t++) // LightSensor_read_time:采集次数
{
// temp += ADC3_Get(LSENS_ch); //多次采集的数据和
temp += ADC3_GetYuDiValue();
delay_ms(5);
}
temp /= 10; // 平均值:多次采集的数据和除以采集次数
if(temp > 4000)
{
temp = 4000;
BEEP(1); //蜂鸣器响,这个是用来检测没有水的时候,蜂鸣器会响,雨滴的值为0
}else
{
BEEP(0);
}
return (u8)(200-(temp/20)); //模拟量输出范围为 0-200
}
上一篇: 拉压力传感器安装使用与接线
下一篇: 初级程序员实战面试宝典(一)