STM8学习笔记---ADC多通道采样

STM8S003单片机ADC采样通道总共有5个,从AIN2---AIN6,多通道采样时需要将ADC转换设置为单次转换模式,每次切换采样通道后,需要重新初始化 ADC,采样结果在中断中读取。

IO口初始化代码

//AD通道引脚初始化
void ADC_GPIO_Init( void )
{
    PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入     AIN3
    PD_CR1 &= ~( 1 << 2 );              //PD2 设置为悬空输入
    
    PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      AIN4
    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
    
    PC_DDR &= ~( 1 << 4 );              //PC4 设置为输入      AIN2
    PC_CR1 &= ~( 1 << 4 );              //PC4 设置为悬空输入
    
    PD_DDR &= ~( 1 << 5 );              //PD5 设置为输入     AIN5 
    PD_CR1 &= ~( 1 << 5 );              //PD5 设置为悬空输入
    
    PD_DDR &= ~( 1 << 6 );              //PD6 设置为输入     AIN6 
    PD_CR1 &= ~( 1 << 6 );              //PD6 设置为悬空输入
    
}

将ADC的IO口都设置为输入模式,悬空输入。

下来初始化ADC功能

void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
    ADC_CSR  = ch + 1;                  //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
    ADC_TDRL = ( 1 << ( ch + 1 ) );     //禁止相应通道 施密特触发功能 1左移ch+1位
    ADC_CR1 |= 0x01;                    //使能ADC并开始转换
    ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}

将ADC设置为单次转换模式,每次转换时需要手动将CR1寄存器最低位置1.

在中断中读取转换成功后的数据。

#pragma vector = 24                              // IAR中的中断号,要在STVD中的中断号上加2
__interrupt void ADC_Handle( void )
{
    ADC_CSR &= ~0x80;                            // 转换结束标志位清零  EOC
    //默认左对齐 读数据时先读高高8位 再读低8位
    DATAH = ADC_DRH;                             // 读出ADC结果的高8位
    DATAL = ADC_DRL;                             // 读出ADC结果的低8位
    ADC_flag = 1;                                // ADC中断标志 置1
}

中断中将转换后的采样值存储在DATAH,和DATAL中,并置位采样结束标志位ADC_flag,采样函数判断标志位为1时,就去读取ADC采样值。

采样值读取函数:

//采集PC4电压值  AIN2
u16 ReadVol_CH2( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 1 );
    while( ADC_flag == 0 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ;        //得到十位精度的数据  0--1024
        //ADC_CR1 = ADC_CR1 | 0x01;               // 再次将CR1寄存器的最低位置1  启动下一次转换
    };
    return voltage;
}

单片机有些引脚的功能需要通过选项字开启,通过ST Visual Programmer软件设置选项字方法如下:

在AFR7中,将选项字中将PC4设置为AIN2功能。

adc完整代码如下:

#include "adc.h"
#include "main.h"

u16  DATAH = 0;                          //ADC转换值高8位
u16  DATAL = 0;                          //ADC转换值低8位
_Bool ADC_flag = 0;                      //ADC转换成功标志


//AD通道引脚初始化
void ADC_GPIO_Init( void )
{
    PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入     AIN3
    PD_CR1 &= ~( 1 << 2 );              //PD2 设置为悬空输入
    
    PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      AIN4
    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
    
    PC_DDR &= ~( 1 << 4 );              //PC4 设置为输入      AIN2
    PC_CR1 &= ~( 1 << 4 );              //PC4 设置为悬空输入
    
    PD_DDR &= ~( 1 << 5 );              //PD5 设置为输入     AIN5 
    PD_CR1 &= ~( 1 << 5 );              //PD5 设置为悬空输入
    
    PD_DDR &= ~( 1 << 6 );              //PD6 设置为输入     AIN6 
    PD_CR1 &= ~( 1 << 6 );              //PD6 设置为悬空输入
    
}

//ADC输入通道初始化入口参数表示通道选择
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
    ADC_CSR  = ch + 1;                  //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
    ADC_TDRL = ( 1 << ( ch + 1 ) );     //禁止相应通道 施密特触发功能 1左移ch+1位
    ADC_CR1 |= 0x01;                    //使能ADC并开始转换
    ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}


//采集PC4电压值  AIN2
u16 ReadVol_CH2( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 1 );
    while( ADC_flag == 0 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ;        //得到十位精度的数据  0--1024
        //ADC_CR1 = ADC_CR1 | 0x01;               // 再次将CR1寄存器的最低位置1  启动下一次转换
    };
    return voltage;
}

//采集PD2电压值  AIN3
u16 ReadVol_CH3( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 2 );
    while( ADC_flag == 0 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ;
        //ADC_CR1 = ADC_CR1 | 0x01;              //当通道不需要切换时,只需初始化一次,以后每次读取完数据后,需要手动开启下一次转换
    };
    return voltage;
}
//采集PD3电压值  AIN4
u16 ReadVol_CH4( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 3 );
    while( ADC_flag == 0 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ;       //得到十位精度的数据  0--1024
        //ADC_CR1 = ADC_CR1 | 0x01;              // 再次将CR1寄存器的最低位置1  启动下一次转换
    };
    return voltage;
}

//采集PD5电压值  AIN5
u16 ReadVol_CH5( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 4 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据  0--1024
        //ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换
    };
    return voltage;
}

//采集PD6电压值  AIN6
u16 ReadVol_CH6( void )
{
    u16 voltage = 0;
    ADC_CH_Init( 5 );
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据  0--1024
        //ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换
    };
    return voltage;
}

//AD中断服务函数 中断号22
#pragma vector = 24                              // IAR中的中断号,要在STVD中的中断号上加2
__interrupt void ADC_Handle( void )
{
    ADC_CSR &= ~0x80;                            // 转换结束标志位清零  EOC
    //默认左对齐 读数据时先读高高8位 再读低8位
    DATAH = ADC_DRH;                             // 读出ADC结果的高8位
    DATAL = ADC_DRL;                             // 读出ADC结果的低8位
    ADC_flag = 1;                                // ADC中断标志 置1
}

主函数代码如下:

#include "iostm8s103F3.h"
#include "main.h"
#include "led.h"
#include "adc.h"
#include "delay.h"

u16 val_ch2 = 0, val_ch3 = 0, val_ch4 = 0, val_ch5 = 0, val_ch6 = 0;

void SysClkInit( void )
{
    CLK_SWR = 0xe1;                             //HSI为主时钟源  16MHz CPU时钟频率
    CLK_CKDIVR = 0x00;                          //CPU时钟0分频,系统时钟0分频
}

void main( void )
{
    u8 i=0;
    __asm( "sim" );                             //禁止中断
    SysClkInit();
    delay_init( 16 );
    LED_GPIO_Init();
    ADC_GPIO_Init();
    __asm( "rim" );                             //开启中断
    while( 1 )
    {
        LED = ~LED; 
        
        //通道切换后,采样的第一笔数据仍然为上一通道的数据
        for(i=0;i<10;i++)
        val_ch2 = ReadVol_CH2();
        delay_ms( 100 );
        
         for(i=0;i<10;i++)
        val_ch3 = ReadVol_CH3();
        delay_ms( 100 );
        
         for(i=0;i<10;i++)
        val_ch4 = ReadVol_CH4();
        delay_ms( 100 );
        
         for(i=0;i<10;i++)
        val_ch5 = ReadVol_CH5();
        delay_ms( 100 );
        
        for(i=0;i<10;i++)
        val_ch6 = ReadVol_CH6();
        delay_ms( 100 );     
    }
}

/*************** 深圳市赛亿科技开发有限公司 ******************** * 文件名 : 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; } } } }
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值