STM8单片机ADC带缓存的连续采样模式

  在上一篇文章中说了STM8的ADC连续采样模式,为了提高采样的精度和速率,STM8单片机还提供了带缓存的连续采样模式,也就是说ADC会连续采集8个数据,放在缓存中,读取数据时可以一次从缓存中读取8个数据,这样就可以通过8个数据数据计算平均值,使得采样的结果更加准确。

下面看一下官方文档中的对缓存模式的介绍。

image.png

  通过文档中可以看出,要开启缓存模式,只需要将ADC_CR3寄存器中的COUNT为DBUF设置为1,就可以开启缓存模式了。
  当开启缓存模式后,采样的结果将不会存放在ADC_DR寄存器中,而是会将结果依次存放在ADC_DB0R寄存器到ADCDB7R寄存器,连续读取8次数据,存储在这8个寄存器中。读取数据的时候,依次从这8个寄存器中读取就行。

下面直接通过代码来实现带缓存功能的连续采样模式:

#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 << 3 );              //PD3 设置为输入      电流
    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
}
/*
ch 为单片机ADC通道
通过置位ADC_CR1寄存器的ADON位来开启ADC。当第一次置位ADON时,ADC从低功耗模式唤醒。
为了启动转换必须第二次使用写指令来置位ADON位。
在转换结束时,ADC会保持在上电状态,用户只需要置位ADON位一次来启动下一次转换。
转换完成后,转换数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置位,如果EOCIE被置位将产生一个中断
ADC输入通道初始化入口参数表示通道选择
*/
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
    
    ADC_CR1 |= ( 1 << 1 );              //开启连续转换模式
    
    ADC_CSR  = ch;                      //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
    ADC_TDRL = ( 1 << ch );             //禁止相应通道 施密特触发功能 1左移ch+1位
    ADC_CR1 |= 0x01;                    //使能ADC并开始转换

    //ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
    ADC_CR3 |= ( 1 << 7 );              //数据缓存使能

    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}

u16 databuf[8] = {0};
//采集PD2电压值
u16 ReadVol_CH3( void )
{
    u16 voltage = 0;

    while( ( ADC_CSR & 0x80 ) == 0 );      //等待转换结束
    if( ADC_CSR & 0x80 )
    {
        ADC_CSR &= 0x7F;
        /*
        使能缓存模式后,数据会存储在 ADC_DB0R ---- ADC_DB7R 寄存器中
        如果使能了扫描模式那么这几个寄存器存储的就是对应通道的数据
        如果没有使能扫描模式,那么这几个通道就存储的是连续转换的结果
        这里没有使用扫描模式,所以缓存器中存储的都是当前通道连续读取的数据
        */
        DATAH = ADC_DB0RH;                    // 读出ADC结果的高8位
        DATAL = ADC_DB0RL;                    // 读出ADC结果的低8位
        voltage = ( DATAH << 2 ) + DATAL ;    //得到十位精度的数据  0--1024
        databuf[0] = voltage;

        DATAH = ADC_DB1RH;
        DATAL = ADC_DB1RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[1] = voltage;

        DATAH = ADC_DB2RH;
        DATAL = ADC_DB2RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[2] = voltage;

        DATAH = ADC_DB3RH;
        DATAL = ADC_DB3RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[3] = voltage;

        DATAH = ADC_DB4RH;
        DATAL = ADC_DB4RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[4] = voltage;

        DATAH = ADC_DB5RH;
        DATAL = ADC_DB5RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[5] = voltage;

        DATAH = ADC_DB6RH;
        DATAL = ADC_DB6RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[6] = voltage;

        DATAH = ADC_DB7RH;
        DATAL = ADC_DB7RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[7] = voltage;
    }

    return voltage;
}

在初始化中设置 ADC_CR1 |= ( 1 << 1 ); 也就是将ADC_CR1寄存器的第一位设置为1。

image.png

也就是使能了连续转换模式。

然后设置ADC_CR3 |= ( 1 << 7 ); 也就是将ADC_CR3寄存器的第7位设置为1.

image.png

也就是开启了ADC的数据缓存功能,当数据转换完成之后,ADC_CSR寄存器的EOC位会置1,此时如果程序判断到EOC位为1时,就可以去数据缓存寄存器读取数据了。也就是代码中ReadVol_CH3()函数实现的功能。

image.png

这里是通过查询标志位的方法读取数据,也可以通过中断的方式读取数据。

通过中断方式读取代码如下:

#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 << 3 );              //PD3 设置为输入      电流
    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
}
/*
ch 为单片机ADC通道
通过置位ADC_CR1寄存器的ADON位来开启ADC。当第一次置位ADON时,ADC从低功耗模式唤醒。
为了启动转换必须第二次使用写指令来置位ADON位。
在转换结束时,ADC会保持在上电状态,用户只需要置位ADON位一次来启动下一次转换。
转换完成后,转换数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置位,如果EOCIE被置位将产生一个中断
ADC输入通道初始化入口参数表示通道选择
*/
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
    
    ADC_CR1 |= ( 1 << 1 );              //开启连续转换模式
    
    ADC_CSR  = ch;                      //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
    ADC_TDRL = ( 1 << ch );             //禁止相应通道 施密特触发功能 1左移ch+1位
    ADC_CR1 |= 0x01;                    //使能ADC并开始转换

    ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
    ADC_CR3 |= ( 1 << 7 );              //数据缓存使能

    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}

u16 databuf[8] = {0};
//采集PD2电压值
u16 ReadVol_CH3( void )
{
    u16 voltage = 0;

    if( ADC_flag )
    {
        ADC_flag = 0;
        /*
        使能缓存模式后,数据会存储在 ADC_DB0R ---- ADC_DB7R 寄存器中
        如果使能了扫描模式那么这几个寄存器存储的就是对应通道的数据
        如果没有使能扫描模式,那么这几个通道就存储的是连续转换的结果
        这里没有使用扫描模式,所以缓存器中存储的都是当前通道连续读取的数据
        */
        DATAH = ADC_DB0RH;                    // 读出ADC结果的高8位
        DATAL = ADC_DB0RL;                    // 读出ADC结果的低8位
        voltage = ( DATAH << 2 ) + DATAL ;    //得到十位精度的数据  0--1024
        databuf[0] = voltage;

        DATAH = ADC_DB1RH;
        DATAL = ADC_DB1RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[1] = voltage;

        DATAH = ADC_DB2RH;
        DATAL = ADC_DB2RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[2] = voltage;

        DATAH = ADC_DB3RH;
        DATAL = ADC_DB3RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[3] = voltage;

        DATAH = ADC_DB4RH;
        DATAL = ADC_DB4RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[4] = voltage;

        DATAH = ADC_DB5RH;
        DATAL = ADC_DB5RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[5] = voltage;

        DATAH = ADC_DB6RH;
        DATAL = ADC_DB6RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[6] = voltage;

        DATAH = ADC_DB7RH;
        DATAL = ADC_DB7RL;
        voltage = ( DATAH << 2 ) + DATAL ;
        databuf[7] = voltage;     
    }
    return voltage;
}


//AD中断服务函数 中断号22
#pragma vector = 24                     // IAR中的中断号,要在STVD中的中断号上加2
__interrupt void ADC_Handle( void )
{
    ADC_CSR &= ~0x80;                   // 转换结束标志位清零  EOC
    ADC_flag = 1;                       // ADC中断标志 置1
}

当数据采集完成后,就会产生一次中断,然后在中断中设置一个标志位,然后ReadVol_CH3()函数发现标志位置1后,就直接读取采样的数据。

要实现PWM触发ADC采样,可以按照以下步骤进行操作: 1. 配置PWM输出:将STM32H7的定时器配置为PWM模式,设置输出频率和占空比。 2. 配置ADC采样:将STM32H7的ADC模块配置为合适的采样时钟、采样时间和转换位数等参数。 3. 配置ADC触发源:将ADC模块的触发源设置为PWM触发模式,选择定时器作为触发源,同时设置触发极性和触发模式。 4. 启动ADC采样:在程序中启动ADC采样,等待ADC转换完成,并将数据存储到指定的缓存区中。 以下是一个简单的代码示例: ```c #include "stm32h7xx_hal.h" #define ADC_CHANNEL 0 // ADC采样通道 // 配置PWM输出 void PWM_Configuration(void) { TIM_HandleTypeDef htim; TIM_OC_InitTypeDef sConfig; htim.Instance = TIM1; htim.Init.Prescaler = 0; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 1000; // PWM频率为1kHz htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim); sConfig.OCMode = TIM_OCMODE_PWM1; sConfig.Pulse = 500; // 占空比50% sConfig.OCPolarity = TIM_OCPOLARITY_HIGH; sConfig.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim, &sConfig, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); } // 配置ADC采样 void ADC_Configuration(void) { ADC_HandleTypeDef hadc; ADC_ChannelConfTypeDef sConfig; hadc.Instance = ADC1; hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.ScanConvMode = DISABLE; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.NbrOfDiscConversion = 0; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; hadc.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; HAL_ADC_Init(&hadc); sConfig.Channel = ADC_CHANNEL; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; sConfig.Offset = 0; HAL_ADC_ConfigChannel(&hadc, &sConfig); } int main(void) { PWM_Configuration(); ADC_Configuration(); while (1) { HAL_ADC_Start(&hadc); HAL_ADC_PollForConversion(&hadc, 100); uint16_t adc_value = HAL_ADC_GetValue(&hadc); // 将采样结果处理或存储到缓存区中 } } ``` 在以上代码中,我们使用了定时器1作为PWM输出,输出频率为1kHz,占空比为50%。同时,我们使用了ADC1模块进行采样,将采样通道设置为ADC_CHANNEL,触发源为定时器1的CC1输出。 在主循环中,我们使用了HAL_ADC_Start函数启动ADC采样,使用HAL_ADC_PollForConversion函数等待采样完成,并使用HAL_ADC_GetValue函数获取采样结果。可以根据实际需求对采样结果进行处理或存储到缓存区中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值