OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2486|回复: 1

求组!STM32F103 ADC1/ADC2双通道同时采集返回结果错误

[复制链接]

1

主题

2

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-5-28
在线时间
3 小时
发表于 2020-3-15 00:16:57 | 显示全部楼层 |阅读模式
1金钱
如题,STM32F103 ADC1/ADC2+DMA1双通道同时采集,ADC1和ADC2各采集3个通道 ,返回结果有2个通道总是错误,单次采集时每组数据都正常,
因单次采集数据小数点后一位跳动较大,采集1000次数据相加在求平均值 ,发现其中两组数据出错,贴上程序,请大神帮看看是哪里问题,谢谢!

unsigned int ADC_DectValue[3000];     //ADC采集缓存
void ADC_init(void)
{
  ADC_InitTypeDef ADC_InitStructure;
  DMA_InitTypeDef DMA_InitStructure;
   
  /* 配置DMA1 通道 1 */
  DMA_DeInit(DMA1_Channel1);              //将DMA的通道1寄存器重设为缺省值
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)ADC1_DR_Address;        //定义DMA外设基地址 (ADC1的基地址)
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_DectValue;               //定义DMA内存基地址(在主程序里申明,此处引用)
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                       //外设作为数据传输的来源

  //定义指定DMA通道的DMA缓存的大小,单位为数据单位。根据传输方向,
  //数据单位等于结构中参数DMA_PeripheralDataSize或者参数DMA_MemoryDataSize的值
  DMA_InitStructure.DMA_BufferSize = 3000;  //此值为完整一轮DMA传输的次数
   //用来设定外设地址寄存器递增与否
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;       //外设ADC1地址寄存器不变
  //DMA_MemoryInc用来设定内存地址寄存器递增与否
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                //内存地址寄存器递增
  //DMA_PeripheralDataSize设定了外设数据宽度
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//数据宽度为32位(因为ADC1和ADC2同时采集数据,所以2个16位合并为32位数据)
  //DMA_MemoryDataSize设定了外设数据宽度
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;        //数据宽度为32位
  //DMA_Mode设置了CAN的工作模式
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                        //工作在循环缓存模式
  //DMA_Priority设定DMA通道x的软件优先级
  DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道x拥有高优先级
  //DMA_M2M使能DMA通道的内存到内存传输
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
  DMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道x寄存器
  /* Get Current Data Counter value before transfer begins */
  CurrDataCounterBegin = DMA_GetCurrDataCounter(DMA1_Channel1);
  /* Enable DMA1 Channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE); // 使能或者失能指定的通道x

  //DCIN1--> PC0   //DC输入端1
  //DCIN2--> PC1   //DC输入端2
  //BATTV--> PC2   //电瓶电压检测
  //BATTA--> PC3   //电源电流检测
  //TEMP --> PC4   //电瓶温度检测
  //ADCA --> PC5   //负载电流检测
  /* 配置ADC1参数 */
  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;   //ADC1和ADC2工作在同步规则模式
  //ADC_ScanConvMode规定了模数转换工作在扫描模式(多通道)还是单次(单通道)模式。
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;       //连续扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //使用外部触发来启动规则通道的模数转
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //转换由软件而不是外部触发启动
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 3;  //规定了顺序进行规则转换的ADC通道的数目。这个数目的取值范围是1到16
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 规则通道配置 */
  //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
  //输入参数1 ADCx:x可以是1或者2来选择ADC外设ADC1或ADC2
  //输入参数2 ADC_Channel:被设置的ADC通道
  //输入参数3 Rank:规则组采样顺序。取值范围1到16。
  //输入参数4 ADC_SampleTime:指定ADC通道的采样时间值
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);    //V2输入端电压
  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);    //V1输入端电压
  ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5);    //电瓶电压检测
  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);

  /* 配置ADC2参数 */
  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;        //ADC1和ADC2工作在同步规则模式
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;            //连续扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;      //使用外部触发来启动规则通道的模数转
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //转换由软件而不是外部触发启动
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //ADC数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 3;  //规定了顺序进行规则转换的ADC通道的数目。这个数目的取值范围是1到16
  ADC_Init(ADC2, &ADC_InitStructure);

  /* ADC2 规则通道配置 */

  ADC_RegularChannelConfig(ADC2, ADC_Channel_13,1, ADC_SampleTime_239Cycles5);    //电瓶充电电流
  ADC_RegularChannelConfig(ADC2, ADC_Channel_14,2, ADC_SampleTime_239Cycles5);    //电瓶温度检测
  ADC_RegularChannelConfig(ADC2, ADC_Channel_15,3, ADC_SampleTime_239Cycles5);    //负载电流检测

  ADC_ExternalTrigConvCmd(ADC2, ENABLE);   //使能ADC2的经外部触发启动注入组转换功能

  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
  /* Enable Vrefint channel17 */
  ADC_TempSensorVrefintCmd(DISABLE);//失能温度传感器和内部参考电压通道
  /* 使能ADC1转接复位寄存器  */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register 检查复位校准寄存器的结束 */
  while(ADC_GetResetCalibrationStatus(ADC1));
  /* Start ADC1 calibaration 启动ADC1校准 */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration 检查ADC1校准结束 */
  while(ADC_GetCalibrationStatus(ADC1));

  /* 使能ADC2 */
  ADC_Cmd(ADC2, ENABLE);
  /*启用ADC2复位校准寄存器 */   
  ADC_ResetCalibration(ADC2);
  /* 等待ADC2复位校准寄存器的结束 */
  while(ADC_GetResetCalibrationStatus(ADC2));
  /* 启动ADC2校准 */
  ADC_StartCalibration(ADC2);
  /*等待ADC2校准结束 */
  while(ADC_GetCalibrationStatus(ADC2));

  /*启动ADC1辅助软件转换 */
  ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能ADC的软件转换启动功能
  /* Test on Channel 1 DMA_FLAG_TC flag */
  while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));
  /* 清除通道1 DMA_FLAG_TC 标志 */
  DMA_ClearFlag(DMA1_FLAG_TC1);
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  ADC_SoftwareStartConvCmd(ADC2, ENABLE);
}
/**********************************************************************************
ADC1和ADC2采集值输出
***********************************************************************************/
void adcvolout(void)
{
   unsigned int ADCBuff[6];      //ADC采集缓存
  unsigned int a,b=3000,c=1000;
  float ref = 3.281;            //基准电压值(实测3.3V供电电压)

for(a=0;a<b;a+=3)
  {
   ADCBuff[0] += (ADC_DectValue[a]&0x0000FFFF);      //V2电压
   ADCBuff[1] += (ADC_DectValue[a]/65536);           //电瓶温度
  }
for(a=1;a<b;a+=3)
  {
   ADCBuff[2] += (ADC_DectValue[a]&0x0000FFFF);      //V1电压
     ADCBuff[3] += (ADC_DectValue[a]/65536);          //负载电流
  }
for(a=2;a<b;a+=3)
  {
   ADCBuff[4] += (ADC_DectValue[a]&0x0000FFFF);      //电瓶电压
   ADCBuff[5] += (ADC_DectValue[a]/65536);           //充电电流
  }
  
  ADCBuff[0] = ADCBuff[0]/c;    //1000次数据相加后求平均值
  ADCBuff[1] = ADCBuff[1]/c;
  ADCBuff[2] = ADCBuff[2]/c;
  ADCBuff[3] = ADCBuff[3]/c;
  ADCBuff[4] = ADCBuff[4]/c;
  ADCBuff[5] = ADCBuff[5]/c;
  
  printf("V2电压:\n");
  printf("%d\r\n",ADCBuff[0]);
  printf("电瓶温度:\n");
  printf("%d\r\n",ADCBuff[1]);
  printf("V1电压:\n");
  printf("%d\r\n",ADCBuff[2]);
  printf("负载电流:\n");
  printf("%d\r\n",ADCBuff[3]);
  printf("电瓶电压:\n");
  printf("%d\r\n",ADCBuff[4]);
  printf("充电电流:\n");
  printf("%d\r\n",ADCBuff[5]);
  printf("\r\n");
  

    //计算出各路显示值
DCIN1 = (float)ADCBuff[0]/4096*ref*13;   //V2电压   
DCIN0 = (float)ADCBuff[2]/4096*ref*13;     //V1电压                  
BATTV = (float)ADCBuff[4]/4096*ref*10.1;   //电瓶电压
BATTA = (float)ADCBuff[5]/4096*ref*32;     //充电电流               
//TEMP  = ADCBuff[1]/4096*3.2;             //电瓶温度(LM35未用)     
ADCA  = (float)ADCBuff[3]/4096*ref*32;     //负载电流               
}

串口返回数据:
V2电压:134232    (错误数据,电压输入为0V)
电瓶温度:2
V1电压:0
负载电流:0
电瓶电压:536877   (错误数据,电压输入为0V
充电电流:0

V2电压:134232
电瓶温度:2
V1电压:0
负载电流:0
电瓶电压:536877
充电电流:0

V2电压:134232
电瓶温度:2
V1电压:0
负载电流:0
电瓶电压:536877
充电电流:0

V2电压:134232
电瓶温度:2
V1电压:0
负载电流:0
电瓶电压:536877
充电电流:0

adc.rar

2.82 KB, 下载次数: 10

程序源码

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

2

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2019-5-28
在线时间
3 小时
 楼主| 发表于 2020-3-15 22:21:05 | 显示全部楼层
已解决,unsigned int ADCBuff[6]={0,0,0,0,0,0};  //ADC采集缓存,//注意初始化数组初始值
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-22 16:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表