完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
1.环境介绍
平台:AT32F415单片机,雅特力公司的AT32系列单片机其实跟STM32系列单片机大同小异,包括库函数等基本都是一样的,所以这款代码无论是AT32还是STM32都是适用的。 开发环境:MDK V5 for arm 简介:在实际的项目开发中,经常会用到多路ADC检测,所以特意在32的库函数之上做了2次封装,形成一个模块化的代码,以便于下次项目便捷开发 2.代码模块化思路 2.1在adc.h文件中枚举用到的adc通道 typedef enum { ADC1_CHAN2, ADC1_CHAN4, ADC1_CHAN1, ADC1_CHAN5, ADC1_CHAN11, ADC1_CHAN10, NUM_ADC1CHN }ENUM_ADC1CHN; typedef enum { //如果有用到ADC2的检测通道,在后面添加枚举类型变量即可 ADC2_CHAN1=NUM_ADC1CHN, //... //.. NUM_ADCCHN }ENUM_ADC2CHN; #define NUM_ADC2CHN (NUM_ADCCHN-NUM_ADC1CHN) #if(NUM_ADC2CHN) #define NUM_ADC 2 #else #define NUM_ADC 1 #endif 因为现在用到的这个型号的单片机有两组ADC,所以特意根据用到的adc不同,对枚举类型做了区分 2.2 将每个adc通道的实际用途进行映射 //ADC通道配置,将ADC通道与实际功能应用的对应上 //added by zhl 2020/6/30 for v1.01 #define ADC_CHNTEMP1 ADC1_CHAN5 #define ADC_CHNTEMP2 ADC1_CHAN1 #define ADC_CHNCURRE1 ADC1_CHAN10 #define ADC_CHNCURRE2 ADC1_CHAN11 #define ADC_CHNERR1 ADC1_CHAN4 #define ADC_CHNERR2 ADC1_CHAN2 这样,当在app逻辑层需要对哪个adc通道进行操作时,直接用ADC_CHNTEMP1 这些宏定义去获取,这样就做到了bsp层和app层的分离,后续adc通道有变动时,只需要在bsp层进行修改,其它其它地方都不用动,方便又省事。 2.3在adc.c文件中定义几个全局变量,用来做配置和数据存储功能 /定义存放ADC转换结果的数组 u16 gu16_ADCResult[NUM_ADCCHN]={0,0,0,0,0,0}; //项目中各个ADC通道引脚对应关系 //AD1_IN2:PA2,AD1_IN4:PA4, ,,,,异常检测 //AD1_IN1:PA1,AD1_IN5:PA5,,,,温度检测 //AD1_IN11:PC11,AD1_IN10:PC10,,,电流检测 GPIO_Type* gs_ADCPort[NUM_ADCCHN] = {GPIOA,GPIOA, GPIOA,GPIOA, GPIOC,GPIOC}; u16 gu16_ADCPins[NUM_ADCCHN] = {GPIO_Pins_2,GPIO_Pins_4, GPIO_Pins_1,GPIO_Pins_5, GPIO_Pins_11,GPIO_Pins_10}; u8 gu8_ADCChnnal[NUM_ADCCHN] = {ADC_Channel_2,ADC_Channel_4, ADC_Channel_1,ADC_Channel_5, ADC_Channel_11,ADC_Channel_10}; 在现在这个项目中我其实没有用到ADC2中的检测通道,但是前面的枚举类型中,为了演示要怎么定义adc2上的检测通道,我有写一个ADC2_CHAN1,所以这边最后会对不上,这是小问题,懂了的话自然就明白是怎么回事,根据自己项目的实际情况,进行配置就行。 2.4实现几个功能函数 void AT32F415_ADCConfig() { u8 i=0; ADC_InitType ADC_InitStructure; GPIO_InitType GPIOType; ADC_Type* adcx=NULL; if(NUM_ADC1CHN == 0) { return; } //循环配置ADC各个通道的各个引脚 for (i = 0; i < NUM_ADCCHN; i++) { //输入:PB0->N_TC/PB1->FLW_DTC GPIO_StructInit(&GPIOType); GPIOType.GPIO_Pins = gu16_ADCPins; GPIOType.GPIO_Mode = GPIO_Mode_IN_ANALOG;//引脚模式配置为模拟输入模式 GPIOType.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz; GPIO_Init(gs_ADCPort,&GPIOType); } //先对ADC1进行配置 adcx = ADC1; ADC_Reset(adcx); //使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_ADC1,ENABLE); /* ADC1 configuration ------------------------------------------------------*/ ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式 ADC_InitStructure.ADC_ScanMode = ENABLE;//扫描开启 ADC_InitStructure.ADC_ContinuousMode = DISABLE;//不连续 ADC_InitStructure.ADC_ExternalTrig = ADC_ExternalTrig_None;//不用外部触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//adc转换数据右对齐 ADC_InitStructure.ADC_NumOfChannel = NUM_ADC1CHN; //当前adc的通道数量 ADC_Init(adcx, &ADC_InitStructure); for (i = 0; i < NUM_ADC1CHN; i++) { /* ADC1 regular channels configuration */ ADC_RegularChannelConfig(adcx, gu8_ADCChnnal, (i+1), ADC_SampleTime_239_5); } //如果规则通道数大于1,要开启ADC间断模式,分别读取转换的结果 if(NUM_ADC1CHN>1) { ADC_DiscModeChannelCountConfig(adcx, 1); //对 ADC 规则组通道配置间断模式,每次转换一个通道 ADC_DiscModeCtrl(adcx, ENABLE); //使能指定的 ADC 规则组通道的间断模式 } /* Enable ADC1 */ ADC_Ctrl(adcx, ENABLE); /* Enable ADC1 reset calibration register */ ADC_RstCalibration(adcx); /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(adcx)); /* Start ADC1 calibration */ ADC_StartCalibration(adcx); /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(adcx)); /* Start ADC1 Software Conversion */ //ADC_SoftwareStartConvCtrl(ADC1, ENABLE); //如果也用到了ADC2的通道,就也对ADC2进行配置 if(NUM_ADC2CHN == 0) { return; } adcx = ADC2; ADC_Reset(adcx); //使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_ADC2,ENABLE); /* ADC1 configuration ------------------------------------------------------*/ ADC_StructInit(&ADC_InitStructure); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanMode = ENABLE; ADC_InitStructure.ADC_ContinuousMode = DISABLE; ADC_InitStructure.ADC_ExternalTrig = ADC_ExternalTrig_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NumOfChannel = NUM_ADC2CHN; ADC_Init(adcx, &ADC_InitStructure); for (i = NUM_ADC1CHN; i < NUM_ADCCHN; i++) { /* ADC1 regular channels configuration */ ADC_RegularChannelConfig(adcx, gu8_ADCChnnal, (i-NUM_ADC1CHN+1), ADC_SampleTime_239_5); } //如果规则通道数大于1,要开启ADC间断模式,分别读取转换的结果 if(NUM_ADC2CHN>1) { ADC_DiscModeChannelCountConfig(adcx, 1); //对 ADC 规则组通道配置间断模式,每次转换一个通道 ADC_DiscModeCtrl(adcx, ENABLE); //使能指定的 ADC 规则组通道的间断模式 } /* Enable ADC1 */ ADC_Ctrl(adcx, ENABLE); /* Enable ADC1 reset calibration register */ ADC_RstCalibration(adcx); /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(adcx)); /* Start ADC1 calibration */ ADC_StartCalibration(adcx); /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(adcx)); /* Start ADC1 Software Conversion */ //ADC_SoftwareStartConvCtrl(ADC1, ENABLE); } 对于多个adc通道获取转换结果的处理办法,我使用的是开启adc的间断转换,这样每次adc开启转换后,只会采集一次当前通道的数据,就会停止,然后下次再开启转换,才会再去得到下一个通道的转换结果,然后继续停止。如果想要转换不受程序控制一直转换,可以采用DMA+ADC的模式,网上资料很多,这里不再赘述。 2.启动adc转换函数 //启动指定的adc void ADC_StartTran(u8 adcx) { if(adcx==1) { ADC_SoftwareStartConvCtrl(ADC1, ENABLE); } else if(adcx==2) { ADC_SoftwareStartConvCtrl(ADC2, ENABLE); } } 2.获取adc采样结果的函数 void ADC_GetTranResult(u8 adcx) { u8 i=0,j=0; u8 channalNum=0; ADC_Type* pst_ADCx=NULL; //根据adc不同,判断是在处理ADC1还是ADC2 switch (adcx) { case 1: channalNum=NUM_ADC1CHN; pst_ADCx=ADC1; break; case 2: channalNum=NUM_ADC2CHN; pst_ADCx=ADC2; break; default: break; } //总共采集ADC_FILTER_TIMES次ADC值 for(i=0;i //将每次采集到的每个通道的值求和 for(j=0;j ADC_StartTran(adcx);//开启转换 while(!ADC_GetFlagStatus(pst_ADCx,ADC_FLAG_EC)); if(adcx==1) { gu16_ADCResult[j] += ADC_GetConversionValue(pst_ADCx); //返回最近一次 ADCx 规则组的转换结果 } else if(adcx==2) { gu16_ADCResult[j+NUM_ADC1CHN] += ADC_GetConversionValue(pst_ADCx); //返回最近一次 ADCx 规则组的转换结果 } } } //求平均值 for(i=0;i if(adcx==1) { gu16_ADCResult = gu16_ADCResult/ADC_FILTER_TIMES; } else if(adcx==2) { gu16_ADCResult[i+NUM_ADC1CHN] = gu16_ADCResult[i+NUM_ADC1CHN]/ADC_FILTER_TIMES; } } } 3.获取单个通道的采样结果的函数 //获得一个通道的ADC结果 u16 ADC_GetOneChnVal(u8 channal) { return (gu16_ADCResult[channal]); } 4.清除单个通道采样结果的函数 void ADC_ClearChanlVal(u8 channal) { gu16_ADCResult[channal] = 0; } 每次启动adc,然后调用ADC_GetOneChnVal(),获取到指定adc通达的转换结果后,要调用ADC_ClearChanlVal(),将存储在全局变量数组gu16_ADCResult[]中对应的值清除掉,不然下次再次计算会在原来结果基础上相加求和求平局,会导致数值变大。 3.其它 后续我还会继续更新led模块,pwm模块,串口模块,adc模块的模块化代码的文章。如果想交流各种遇到的问题,可以加qq群869630744,一起交流一起进步。 |
|
|
|
只有小组成员才能发言,加入小组>>
2545 浏览 0 评论
1142浏览 2评论
741浏览 1评论
495浏览 0评论
256浏览 0评论
417浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-18 09:57 , Processed in 1.480190 second(s), Total 80, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号