赞
踩
最近在学习ADC的采样,目前学的还是比较顺利的,没有遇到过于困难的问题。按照野火的教程按部就班的学就行,在滤波方面比较欠缺,咨询了一群大佬。然后在上面做一些改良。
- #define ADC_PIN ( GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 )
-
- static void ADCx_GPIO_Config(void);
- static void ADCx_Mode_Config(void);
-
- static void ADCx_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStucture;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
-
- //模拟输入
- GPIO_InitStucture.GPIO_Pin = ADC_PIN;
- GPIO_InitStucture.GPIO_Mode = GPIO_Mode_AIN;
- GPIO_Init(GPIOA, &GPIO_InitStucture);
-
- }
-
- static void ADCx_Mode_Config(void) //ADC1
- {
- ADC_InitTypeDef ADC_InitStucture;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
-
- ADC_InitStucture.ADC_Mode = ADC_Mode_Independent; //模式
- ADC_InitStucture.ADC_ScanConvMode = ENABLE; //扫描模式
- ADC_InitStucture.ADC_ContinuousConvMode = ENABLE; //连续转换模式
- ADC_InitStucture.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //触发模式
- ADC_InitStucture.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐模式
- ADC_InitStucture.ADC_NbrOfChannel = 4; //通道数量
- ADC_Init(ADC1, &ADC_InitStucture);
-
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); //8分频 72M/8 = 9M
- ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1 , ADC_SampleTime_55Cycles5); //规则通道转换
- ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2 , ADC_SampleTime_55Cycles5); //规则通道转换
- ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3 , ADC_SampleTime_55Cycles5); //规则通道转换
- ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4 , ADC_SampleTime_55Cycles5); //规则通道转换
- //ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5 , ADC_SampleTime_55Cycles5); //规则通道转换
- //ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6 , ADC_SampleTime_55Cycles5); //规则通道转换
- //ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7 , ADC_SampleTime_55Cycles5); //规则通道转换
- //ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8 , ADC_SampleTime_55Cycles5); //规则通道转换
-
- ADC_DMACmd(ADC1, ENABLE);//DMA启动//ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);//开启中断
-
- ADC_Cmd(ADC1, ENABLE); //使能ADCx
-
- ADC_StartCalibration(ADC1);//开始校准
- while(ADC_GetCalibrationStatus(ADC1));//等待校准完成
-
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件中断
-
- }
-
- void ADC_InitConfig(void)
- {
- ADCx_GPIO_Config();
- ADCx_Mode_Config();
- }
这边是采用了四个ADC通道A0、A1、A2、A3。
由于是四通道的ADC,在配置上就需要开启连续转换模式、扫描模式,通道数量也要明确标识。
然后是数据转换,每个通道需要设定转换顺序(顺序要求根据项目)。
DAM传输的需要开启DAM使能,如果中断的要开启中断使能。(这边不清楚什么时候开始DMA传输,需要看一下规格书)
- static void DMA_Config(void);
-
- static void DMA_Config(void)
- {
- DMA_InitTypeDef DMA_InitStruct;
-
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,ENABLE);
-
- DMA_DeInit(DMA1_Channel1);
- DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&( ADC1->DR );
- DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)ADC_Value.adc_Buff_value;
- DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//从外设读
- DMA_InitStruct.DMA_BufferSize = 4;
- 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_InitStruct.DMA_M2M = DMA_M2M_Disable;
- DMA_Init(DMA1_Channel1, &DMA_InitStruct);
-
- DMA_Cmd(DMA1_Channel1, ENABLE);
- DMA_ClearFlag(DMA1_FLAG_TC1);
- }
-
- void DMA1_Init(void)
- {
- DMA_Config();
- }
有几点需要注意的:
1、DMA的读取方向:外设->寄存器
2、数据数量:几个ADC通道就有几个(这里是4)
3、外设地址不增加;寄存器地址增加
- typedef struct
- {
- uint16_t adc0_value[8];
- uint16_t adc1_value[8];
- uint16_t adc2_value[8];
- uint16_t adc3_value[8];
- uint16_t adc4_value[8];
- uint16_t adc5_value[8];
- uint16_t adc6_value[8];
- uint16_t adc7_value[8];
- uint16_t adc_Buff_value[4]; //缓存池
- float adc_add_convertvalue[4]; //8位累加过滤
- float adc_convertvalue[4]; //电压值
- float adc_res_convertvalue[4]; //电阻值
- float adc_tem_convertvalue[4]; //温度
- }ADC_ValueConfig;
因为ADC的DR寄存器每次只能缓存一组数据,当数据进来后会保存到缓存adc_Buff_value中。4组ADC一次保存进去,随后ADC进入轮寻模式。
- ADC_ValueConfig ADC_Value;
-
- int main()
- {
- uint8_t i;
-
- DMA1_Init();
- ADC_InitConfig();
-
- while(1)
- {
- ADC_Value.adc_add_convertvalue[0] = ADC_Value.adc_add_convertvalue[1] = ADC_Value.adc_add_convertvalue[2] =ADC_Value.adc_add_convertvalue[3] = 0;
-
- for( i = 0; i < 8; i++ )
- {
- ADC_Value.adc0_value[i] = lowV_0(ADC_Value.adc_Buff_value[0]);
- ADC_Value.adc1_value[i] = lowV_1(ADC_Value.adc_Buff_value[1]);
- ADC_Value.adc2_value[i] = lowV_2(ADC_Value.adc_Buff_value[2]);
- ADC_Value.adc3_value[i] = lowV_3(ADC_Value.adc_Buff_value[3]);
- }
-
- for( i = 0; i < 8; i++ )
- {
- ADC_Value.adc_add_convertvalue[0] += ADC_Value.adc0_value[i];
- ADC_Value.adc_add_convertvalue[1] += ADC_Value.adc1_value[i];
- ADC_Value.adc_add_convertvalue[2] += ADC_Value.adc2_value[i];
- ADC_Value.adc_add_convertvalue[3] += ADC_Value.adc3_value[i];
- }
-
- ADC_Value.adc_convertvalue[0] = ( float )( ( ADC_Value.adc_add_convertvalue[0] )/4096*3300 )/8;
- ADC_Value.adc_convertvalue[1] = ( float )( ( ADC_Value.adc_add_convertvalue[1] )/4096*3300 )/8;
- ADC_Value.adc_convertvalue[2] = ( float )( ( ADC_Value.adc_add_convertvalue[2] )/4096*3300 )/8;
- ADC_Value.adc_convertvalue[3] = ( float )( ( ADC_Value.adc_add_convertvalue[3] )/4096*3300 )/8;
-
- ADC_Value.adc_res_convertvalue[0] = ( 200000*ADC_Value.adc_convertvalue[0] ) / ( 3300 - ADC_Value.adc_convertvalue[0] );
- ADC_Value.adc_res_convertvalue[1] = ( 200000*ADC_Value.adc_convertvalue[1] ) / ( 3300 - ADC_Value.adc_convertvalue[1] );
- ADC_Value.adc_res_convertvalue[2] = ( 200000*ADC_Value.adc_convertvalue[2] ) / ( 3300 - ADC_Value.adc_convertvalue[2] );
- ADC_Value.adc_res_convertvalue[3] = ( 200000*ADC_Value.adc_convertvalue[3] ) / ( 3300 - ADC_Value.adc_convertvalue[3] );
-
- ADC_Value.adc_tem_convertvalue[0] = 1/( (log(ADC_Value.adc_res_convertvalue[0]/10000))/3950.0 + 1.0/(273.15+25.0) ) - 273.15;
- ADC_Value.adc_tem_convertvalue[1] = 1/( (log(ADC_Value.adc_res_convertvalue[1]/10000))/3950.0 + 1.0/(273.15+25.0) ) - 273.15;
- ADC_Value.adc_tem_convertvalue[2] = 1/( (log(ADC_Value.adc_res_convertvalue[2]/10000))/3950.0 + 1.0/(273.15+25.0) ) - 273.15;
- ADC_Value.adc_tem_convertvalue[3] = 1/( (log(ADC_Value.adc_res_convertvalue[3]/10000))/3950.0 + 1.0/(273.15+25.0) ) - 273.15;
-
-
- DMA_ClearFlag(DMA1_FLAG_TC1);
- }
- }
adc0_value每次会存储通道0的八个数据
adc_add_convertvalue[ 0]通道0的八个数据求和
adc_convertvalue[0 ]求出数据的平均数
adc_res_convertvalue[0]将平均数转换为电阻值(根据实际电路计算,下面给出这个的电路参考)
adc_tem_convertvalue[0 ] 根据公式换算出温度
- unsigned int lowV_0( unsigned int com )
- {
- static unsigned int iLastData; //上一次值
- unsigned int iData; //本次计算值
- float dPower = 0.3; //滤波系数
- iData = ( com * dPower ) + ( 1 - dPower ) * iLastData; //计算
- iLastData = iData; //存贮本次数据
- return iData; //返回数据
- }
直接套用就行,理论知识大致如下
算法实现的公式如下:
y(n) = q*x(n) + (1-q)*y(n-1)
其中Y(n)为输出,x(n)为输入,y(n-1)为上一次输出值,其中q为滤波系数。取值范围为0--1.
也就是说若q=0.5时,这个公式代表的意思就是取本次采样值的50%,加上上一次采样值的50%,做为本次的采样结果。也就是说每次的采样结果都和上一次的采样结果相关。
根据电压值反推NTC当前的阻值即可。
NTC 热敏电阻温度计算公式:Rt = R *EXP(B*(1/T1-1/T2))
其中,T1和T2指的是K度,即开尔文温度。
Rt 是热敏电阻在T1温度下的阻值。
R是热敏电阻在T2常温下的标称阻值。100K的热敏电阻25℃的值为100K(即R=100K)。T2=(273.15+25)
EXP是e的n次方
B值是热敏电阻的重要参数
通过转换可以得到温度T1与电阻Rt的关系T1=1/(ln(Rt/R)/B+1/T2) (所以对应只有一个Rt未知数即可求出T1实时温度)
对应的摄氏温度t=T1-273.15,同时+0.5的误差矫正。
OK,ADC这块基本就算结束了
还有电源方面、485通讯以及内部FLASH要学习一下
加油鱼仔,你是最棒的
NTC原文链接:https://blog.csdn.net/qq_42660303/article/details/84145382
低通滤波器原文链接:https://blog.csdn.net/qq_20222919/article/details/105098071
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。