stm8s单片机实现多通道转换

今天在使用stm8s单片机的AD功能,单片机上有AN0到AN9十个通道。想只用其中的三路AN5到AN7。

//ADC初始化
void ADC_Init(void)
{
 ADC_CR1 = 0x50;
 ADC_CR2 = 0x38;
 ADC_TDRL = 0xE0;  //禁止施密特触发
}

unsigned int Read_ADC_Temp(unsigned channel)
{
 unsigned int i,ADtemp;
 ADC_Init();
 //ADC_CSR = 0x00;
 ADC_CSR = channel;
 ADC_CR1 = 0x01;           // CR1寄存器的最低位置1,使能ADC转换
 for(i = 0;i < 300;i ++);       // 延时一段时间,至少7uS,保证ADC模块的上电完成
 ADC_CR1 = ADC_CR1 | 0x01; // 再次将CR1寄存器的最低位置1
               // 使能ADC转换
 while(!(0x80&ADC_CSR)); // 等待ADC结束
 ADtemp = (unsigned int)(ADC_DRH<<8) | ADC_DRL;
 ADC_CR1 = 0x00;
 return ADtemp;
}

当单独使用某个通道时

adtemp = read_a2d_dis(0x07);

printf("%d ",adtemp);

读出的数值是正确的。接地是0接到VDDA上是1023。

但是

adtemp = read_a2d_dis(0x07);

adtemp1 = read_a2d_dis(0x06);

printf("%d ",adtemp);

printf("%d ",adtemp1);

切换通道后,读出的数据不对,接到地时分别是768,254。切换通道后重新初始化也不行。一开始以为是每次采样读玩数据后应该延时。后来在读取数据的时候分别延时1S还是不行。测得硬件的电压也是正确的。datasheet上设置的也都对的。后来无奈,就多读几次,看看结果是不是一样。

后来发现只要在同一个通道连续读两次。取出的结果是正确的。

unsigned int read_a2d_dis(unsigned char channel)
{
 unsigned int tempTab[5];
 unsigned int i,j,temp;
 temp = 0;
 for(i = 0;i < 5;i ++)
 {
  tempTab[i] = Read_ADC_Temp(channel); 
 }
 for(j=0;j<5;j++)
 {
  for (i=0;i<5-j;i++)
  {
   if (tempTab[i]>tempTab[i+1]) 
   {
    temp=tempTab[i];
    tempTab[i]=tempTab[i+1];
    tempTab[i+1]=temp;
   }
  }
 }
 return tempTab[2]; 
}

做了如上修改后,一共读五个数据,取中位数。才养值没有问题,但是为什么必须在切换通道的时候要读两次才能得到正确的数据依然没有找到答案。只是怀疑是否是切换通道后,单片机将数据存储到ADC_DRH,和ADC_DRL里时移位寄存器发生了错位。只能在以后慢慢寻找答案。

/*************** 深圳市赛亿科技开发有限公司 ******************** * 文件名 : adc * 描述 :多通道AD采集(源文件) * 实验平台 :STM8S105开发板 * 库版本 :V1.0 * 作者 :hcr * QQ :630054913 * 修改时间 :2014-9-20 *******************************************************************************/ #include "adc.h" u16 AdcData_Buff[10]; //AD采集缓存 u16 AdcValue_Channel1; //通道1值 u16 AdcValue_Channel2; //通道2值 u16 AdcValue_Channel3; //通道3值 float Adc_V1; //通道1值电压值 float Adc_V2; //通道2值电压值 float Adc_V3; //通道3值电压值 /************************************************************************** * 函数名:Adc_Task(void) * 描述 :AD不通通道选择 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :10ms调用 *************************************************************************/ void Adc_Task(void) { static u8 Adc_Channel = 1; static u8 Adc_Timer = 0; static u16 Adc_GetValue; switch(Adc_Channel)//通道选择 { case 1: //通道1 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel1=AdcData_Buff[5]; //取中间值 Adc_V1 = (3.28*AdcValue_Channel1)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 2; //另一通道 AdcChannel_Start(ADC1_CHANNEL_2); //ADC,通道2启动 } break; case 2: //通道2 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel2=AdcData_Buff[5]; //取中间值 Adc_V2 = (3.28*AdcValue_Channel2)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 3; //另一通道 AdcChannel_Start(ADC1_CHANNEL_3); //ADC,通道3启动 } break; case 3: //通道3 Adc_GetValue = ADC1_GetConversionValue(); //获取ADC转换AdcData_Buff[Adc_Timer]=Adc_GetValue; //保存采样值 if(Adc_Timer8) { Adc_Timer = 0; //复位 Temp_Choose(); //冒泡法求中间值 AdcValue_Channel3=AdcData_Buff[5]; //取中间值 Adc_V3 = (3.28*AdcValue_Channel3)/1023; //算出实际电压 AdcData_Clean(); //清除缓存数据 Adc_Channel = 1; //另一通道 AdcChannel_Start(ADC1_CHANNEL_1); //ADC,通道1启动 } break; default: break; } } /************************************************************************** * 函数名:ADC_Init(void) * 描述 :ADC1初始化 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :系统初始化调用 *************************************************************************/ void ADC_Init(void) { ADC1_DeInit(); //恢复ADC1寄存器为默认值 ADC1_PrescalerConfig(ADC1_PRESSEL_FCPU_D2); //预分频2 ADC1_ITConfig(ADC1_IT_EOCIE,DISABLE); //使能中断 ADC1_Cmd(ENABLE); //启动ADC AdcChannel_Start(ADC1_CHANNEL_1); /* //恢复ADC1寄存器为默认值 ADC1->CSR = 0x00; ADC1->CR1 = 0x00; ADC1->CR2 = 0x00; ADC1->CR3 = 0x00; ADC1->TDRH = 0x00; ADC1->TDRL = 0x00; ADC1->HTRH = 0x03; ADC1->HTRL = 0xFF; ADC1->LTRH = 0x00; ADC1->LTRL = 0x00; ADC1->AWCRH = 0x00; ADC1->AWCRL = 0x00; ADC1->CR1 |= ADC1_PRESSEL_FCPU_D2; //选择2分频 ADC1->CR2 |= ADC1_ALIGN_RIGHT; //右对齐 ADC1->CR1 |= ADC1_CR1_CONT; //连续转换模式 ADC1->CSR |= ADC1_IT_EOCIE; //使能中断 ADC1->CR1 |= ADC1_CR1_ADON; //启动ADC */ } /************************************************************************** * 函数名:AdcChannel_Start(void) * 描述 :选择通道启动 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void AdcChannel_Start(ADC1_Channel_TypeDef ADC1_Channel) { ADC1_ConversionConfig(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_Channel,ADC1_ALIGN_RIGHT);/*配置通道转换功能,连续右对齐*/ ADC1_StartConversion();//启动转换 /* ADC1->CSR &= (uint8_t)(~0x0F); // Clear the ADC1 channels ADC1->CSR |= ADC1_Channel; // Select the ADC1 channel ADC1->CR1 |= ADC1_CR1_ADON; //启动ADC */ } /************************************************************************** * 函数名:AdcData_Clean(void) * 描述 :清除缓存数据 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void AdcData_Clean(void) { u8 j; for(j=0;j<10;j++) AdcData_Buff[j]=0; } /************************************************************************** * 函数名:Temp_Choose(void) * 描述 :冒泡法取中间值 * 输入 :无 * 输出 :无 * 返回 :无 * 调用 :外部调用 *************************************************************************/ void Temp_Choose(void)//冒泡法求中间值 { u8 i_Adc = 0; u8 j_Adc = 0; u16 Data_Buf; for(j_Adc=0;j_Adc<9;j_Adc++) { for(i_Adc=0;i_AdcAdcData_Buff[i_Adc+1]) { Data_Buf=AdcData_Buff[i_Adc]; AdcData_Buff[i_Adc]=AdcData_Buff[i_Adc+1]; AdcData_Buff[i_Adc+1]=Data_Buf; } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值