完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
基于STM32F4的多通道ADC采集
单片机源程序如下: #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "fliter.h" #include "adc.h" #include "oled.h" extern u8 AD_Flag; //AD转换完成标志位 extern u16 ADC_ConvertedValue[NOFCHANEL]; //用于存放ADC的转换值 extern float ADC_Final_DisplayValue[NOFCHANEL]; //用于存放最终显示值 extern u16 ADC_filter_Value[NOFCHANEL]; int main() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 ADC_X_Init(); //ADC初始化 LED_Init(); //LED灯初始化 OLED_Init(); //OLED初始化 /************一开始的显示*************/ OLED_ShowCHinese(12,0,0,1); //输 OLED_ShowCHinese(24,0,1,1); //入 OLED_ShowCHinese(36,0,4,1); //电 OLED_ShowCHinese(48,0,5,1); //压 OLED_ShowCHinese(60,0,10,1); //: OLED_ShowCHinese(12,12,2,1); //输 OLED_ShowCHinese(24,12,3,1); //出 OLED_ShowCHinese(36,12,6,1); //电 OLED_ShowCHinese(48,12,7,1); //流 OLED_ShowCHinese(60,12,10,1); //: OLED_ShowString(12,24,"DAC:",12); OLED_Refresh_Gram();//更新显示到OLED while(1) { AD_Flag=AD_voltage; ADC_filter_Value[0]=middleValueFilter(); AD_Flag=AD_current; ADC_filter_Value[1]=middleValueFilter(); AD_Flag=AD_DAC; ADC_filter_Value[2]=middleValueFilter(); ADC_Final_DisplayValue[0] =(double) ADC_filter_Value[0]/4096*3.3*6; //电压检测 ADC_Final_DisplayValue[1] =(double) ADC_filter_Value[1]/4096*3.3; //电流检测 ADC_Final_DisplayValue[2] =(double) ADC_filter_Value[2]/4096*3.3; //DAC检测 OLED_ShowFloatNum_12(72,0,ADC_Final_DisplayValue[0],2,12); OLED_ShowFloatNum_12(72,12,ADC_Final_DisplayValue[1],2,12); OLED_ShowFloatNum_12(72,24,ADC_Final_DisplayValue[2],2,12); OLED_Refresh_Gram();//更新显示到OLED delay_ms(500); } } #include "usart.h" #include "adc.h" #include "delay.h" #include "fliter.h" #include "led.h" extern u8 AD_Flag; //AD转换完成标志位 extern u16 ADC_ConvertedValue[NOFCHANEL]; //用于存放ADC的转换值 extern float ADC_Final_DisplayValue[NOFCHANEL]; //用于存放最终显示值 u16 ADC_filter_Value[NOFCHANEL]; extern u16 ADC_ConvertedValue[NOFCHANEL]; // 软件延时 void Delay_ruan(__IO uint32_t nCount) { for(; nCount != 0; nCount--); } //中位值滤波 //方法:连续采样N次(N取奇数)把N次采样值按大小排列取中间值为本次有效值 //优点:能有效克服因偶然因素引起的波动干扰;对温度、液位等变化缓慢的被测参数有良好的滤波效果 //缺点:对流量,速度等快速变化的参数不宜 #define N 30 u16 middleValueFilter() //会获取30个ADC转换值,然后取中间的一个作为本次采样周期的输出值 { u16 value_buf[N]; u16 i,j,k,temp; for( i = 0; i < N; ++i) { value_buf = getValue(); } for(j = 0 ; j < N-1; ++j) { for(k = 0; k < N-j-1; ++k) { //从小到大排序,冒泡法排序 if(value_buf[k] > value_buf[k+1]) { temp = value_buf[k]; value_buf[k] = value_buf[k+1]; value_buf[k+1] = temp; } } } return value_buf[(N-1)/2]; } /*******************获得ADC转换的值*******************/ u16 getValue() { Delay_ruan(5); //软件延时一下再获取ADC的值,但是这个时间怎么确定呢? if(AD_Flag==AD_voltage) //获取ADC电压的值 { return ADC_ConvertedValue[0]; //因为ADC1的数据数据寄存器地址连接到了ADC_ConvertedValue数组上,所以ADC1采集到的值会传输到数组中, } if(AD_Flag==AD_current) //获取ADC采集电流的值 { return ADC_ConvertedValue[1]; } if(AD_Flag==AD_DAC) //获取DAC的值 { return ADC_ConvertedValue[2]; } } //**************疑问*************// //ADC1用了两个通道,我怎么知道什么时候电流或者电压的值存放到数组里?是否存到了对应的位置? //因为存储地址是连续的,所以ADC采集获得的值会根据顺序存入到数组中 |
|
|
|
#include "adc.h"
#include "delay.h" u8 AD_Flag; //AD转换完成标志位 u16 ADC_ConvertedValue[NOFCHANEL]={0}; //用于存放ADC的转换值 float ADC_Final_DisplayValue[NOFCHANEL]; //用于存放最终显示值 /*********************IO口复用为ADC******************/ void ADC_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; //结构体定义 /*=====================通道1======================*/ /********** 使能 GPIO 时钟****/ RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE); /********配置 IO************/ GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //引脚复用时,作为ADC或者DAC,不能选复用,必须选模拟输入,其他的都是复用 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; /*******初始化IO口*********/ GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure); /*=====================通道2======================*/ /********** 使能 GPIO 时钟****/ RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE); /********配置 IO************/ GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //引脚复用时,作为ADC或者DAC,不能选复用,必须选模拟输入,其他的都是复用 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; /*******初始化IO口*********/ GPIO_Init(ADC_GPIO_PORT2, &GPIO_InitStructure); /*=====================通道3=======================*/ /********** 使能 GPIO 时钟****/ RCC_AHB1PeriphClockCmd( ADC_GPIO_CLK3,ENABLE); /********配置 IO************/ GPIO_InitStructure.GPIO_Pin =ADC_GPIO_PIN3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //引脚复用时,作为ADC或者DAC,不能选复用,必须选模拟输入,其他的都是复用 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; /*******初始化IO口*********/ GPIO_Init(ADC_GPIO_PORT3, &GPIO_InitStructure); } /***********配置ADC和DMA*************/ void ADC_Mode_Config(void) { DMA_InitTypeDef DMA_InitStructure; // DMA初始化结构体 ADC_InitTypeDef ADC_InitStructure; // ADC初始化结构体 ADC_CommonInitTypeDef ADC_CommonInitStructure; /*-------------------DMA Iint 结构体参数 初始化---------------------*/ /************开启DMA时钟*************************/ RCC_AHB1PeriphClockCmd(DMAX_CLK, ENABLE); // 外设基址为:ADC 数据寄存器地址 DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC_X->DR; //外设的数据寄存器地址怎么确定,(u32)&name->DR(name为外设名) // 存储器地址,实际上就是一个内部SRAM的变量 DMA_InitStructure.DMA_Memory0BaseAddr =(u32)ADC_ConvertedValue; //存放ADC转换值的数组地址(可以理解为存放ADC转换值的寄存器与这个数组直接连接在一起) // 数据传输方向为外设到存储器 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //确定方向很重要 // 缓冲区大小为,指一次传输的数据量 DMA_InitStructure.DMA_BufferSize = NOFCHANEL; //存放ADC转换值的数组的数据量 // 外设寄存器只有一个,地址不用递增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 存储器地址固定(这里明明写的是增加,为什么还说固定,是错误了么) DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //(这里应该是增加,因为要把多个数据存到一个数组里,地址应该是变化的) // // 外设数据大小为半字,即两个字节 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //这里指的是一个数据的大小,STM32是32位的,所以一个字是32位,半字是16位 // 存储器数据大小也为半字,跟外设数据大小相同 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //外设数据大小是不是要和存储器数据大小相同?是的 // 循环传输模式 (ADC要不断采集数据,所以要循环模式) DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响 DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 禁止DMA FIFO ,使用直连模式 DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; // FIFO 大小,FIFO模式禁止时,这个不用配置 DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; // 选择 DMA 通道,通道存在于流中 DMA_InitStructure.DMA_Channel =DMA_Channel__x; //初始化DMA流,流相当于一个大的管道,管道里面有很多通道 DMA_Init(DMA_Stream__x, &DMA_InitStructure); /****使能DMA流*********/ DMA_Cmd(DMA_Stream__x, ENABLE); /*-------------ADC_X 初始化------------------*/ /***************使能ADC时钟*****************************/ RCC_APB2PeriphClockCmd(ADC_CLK_ENABLE, ENABLE); /*-------------------ADC Common 结构体 参数 初始化---------------*/ // 独立ADC模式 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; // 时钟为fpclk x分频 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // 禁止DMA直接访问模式 ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // 采样时间间隔 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles; //初始化ADC Common 结构体 ADC_CommonInit(&ADC_CommonInitStructure); /* -------------------ADC Init 结构体 参数 初始化-----------------*/ // ADC 分辨率 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; // 扫描模式,多通道采集需要 ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 连续转换 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //禁止外部边沿触发 ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //外部触发通道,本例子使用软件触发,此值随便赋值即可 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; //数据右对齐 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //转换通道NOFCHANEL个 ADC_InitStructure.ADC_NbrOfConversion = NOFCHANEL; /******ADC 结构体初始化*********/ ADC_Init(ADC_X, &ADC_InitStructure); /*----------------配置 ADC 通道转换顺序和采样时间周期-----------------*/ // 配置 ADC 通道转换顺序和采样时间周期 ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL1, 1, ADC_SampleTime_56Cycles); //ADC通道1引脚是GPIOB_Pin_0 ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL2, 2, ADC_SampleTime_56Cycles); //ADC通道2引脚是GPIOB_Pin_1 ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL3, 3, ADC_SampleTime_56Cycles); //ADC通道3引脚是GPIOA_Pin_6 // 使能DMA请求 after last transfer (Single-ADC mode) ADC_DMARequestAfterLastTransferCmd(ADC_X, ENABLE); /*************使能ADC DMA*************/ ADC_DMACmd(ADC_X, ENABLE); /*************使能ADC******************/ ADC_Cmd(ADC_X, ENABLE); //开始adc转换,软件触发 ADC_SoftwareStartConv(ADC_X); } void ADC_X_Init(void) { ADC_GPIO_Config(); ADC_Mode_Config(); } |
|
|
|
只有小组成员才能发言,加入小组>>
3275 浏览 9 评论
2950 浏览 16 评论
3454 浏览 1 评论
8982 浏览 16 评论
4043 浏览 18 评论
1092浏览 3评论
564浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
561浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2297浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1854浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-19 10:45 , Processed in 1.181983 second(s), Total 81, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号