This is the 12th day of my participation in the August More Text Challenge. For details, see:August is more challenging
In the previous article, we mentioned the ADC continuous sampling mode of STM8. In order to improve the sampling accuracy and speed, STM8 SCM also provides the continuous sampling mode with cache. That is to say, THE ADC will continuously collect 8 data, put them in the cache, and read 8 data at a time from the cache. In this way, the average value of the 8 data can be calculated to make the sampling result more accurate.
Let’s take a look at the introduction to caching patterns in the official documentation.
As you can see from the document, to enable cache mode, you only need to set COUNT in register ADC_CR3 to 1 for DBUF. When the cache mode is enabled, the sampling results will not be stored in the ADC_DR register, but will be stored in the ADC_DB0R register to ADCDB7R register successively, and the data will be read for 8 consecutive times, and stored in these 8 registers. When you read data, you just read from each of these eight registers in turn.
The following code directly implements the continuous sampling mode with caching:
#include "adc.h"
#include "main.h"
u16 DATAH = 0; // The ADC converts the value 8 bits higher
u16 DATAL = 0; // The ADC converts the value 8 bits lower
_Bool ADC_flag = 0; //ADC conversion success flag
//AD channel pin initialization
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 3 ); // set PD3 to input current
PD_CR1 &= ~( 1 << 3 ); //PD3 is set to dangling input
}
/* ch for the MCU ADC channel by setting the ADON bit in the ADC_CR1 register to start ADC. When the ADON is set for the first time, the ADC wakes up from low power mode. The ADON bit must be set a second time using the write instruction to start the transformation. At the end of the transition, the ADC remains powered on and the user only needs to set the ADON bit once to start the next transition. When the conversion is complete, the conversion data is stored in the ADC_DR register and the EOC(End of conversion) flag is set. If EOCIE is set, an interrupt is generated
void ADC_CH_Init( u8 ch )
{
char l = 0;
ADC_CR1 = 0x00; //fADC = fMASTER/2, 8Mhz single conversion, disable conversion
ADC_CR1 |= ( 1 << 1 ); // Turn on the continuous conversion mode
ADC_CSR = ch; // Control the status register to select the desired AD input channel such as: PD2(AIN3)
ADC_CR2 = 0x00; // By default, the data is read high first and read low first
ADC_TDRL = ( 1 << ch ); // Disable the corresponding channel schmidt trigger function 1 to shift the left ch+1 bit
ADC_CR1 |= 0x01; // Enable ADC and start conversion
//ADC_CSR |= 0x20; //EOCIE Enables conversion end interrupt Enables EOC interrupt
ADC_CR3 |= ( 1 << 7 ); // Enable data cache
for( l = 0; l < 100; l++ ); // Delay to ensure that the ADC module is powered on for at least 7us
ADC_CR1 = ADC_CR1 | 0x01; // Enable ADC in the lowest position 1 of register CR1 again and start the conversion
}
u16 databuf[8] = {0};
// Collect the PD2 voltage
u16 ReadVol_CH3( void )
{
u16 voltage = 0;
while( ( ADC_CSR & 0x80) = =0 ); // Wait for the transition to finish
if( ADC_CSR & 0x80 )
{
ADC_CSR &= 0x7F;
/* When cache mode is enabled, data is stored in the ADC_DB0R ---- ADC_DB7R registers. If scan mode is enabled, these registers store the data of the corresponding channels. If scan mode is not enabled, these registers store the results of continuous conversions. So the cache stores all the data that the current channel reads continuously */
DATAH = ADC_DB0RH; // Read the top 8 bits of the ADC result
DATAL = ADC_DB0RL; // Read the lower 8 bits of the ADC result
voltage = ( DATAH << 2 ) + DATAL ; // Obtain data from 0 to 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;
}
Copy the code
Set in the initialization ADC_CR1 | = (1 < < 1); That is, set the first bit of register ADC_CR1 to 1.
In other words, the continuous transformation mode is enabled.
And then set ADC_CR3 | = (1 < < 7); That is, set bit 7 of register ADC_CR3 to 1.
When data conversion is complete, the EOC bit in the ADC_CSR register is set to 1. If the program determines that the EOC bit is 1, it can read data from the data cache register. That’s what the ReadVol_CH3() function in the code does.
In this case, the data can be read by querying the flag bit, or by interrupt.
Read the code in interrupt mode as follows:
#include "adc.h"
#include "main.h"
u16 DATAH = 0; // The ADC converts the value 8 bits higher
u16 DATAL = 0; // The ADC converts the value 8 bits lower
_Bool ADC_flag = 0; //ADC conversion success flag
//AD channel pin initialization
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 3 ); // set PD3 to input current
PD_CR1 &= ~( 1 << 3 ); //PD3 is set to dangling input
}
/* ch for the MCU ADC channel by setting the ADON bit in the ADC_CR1 register to start ADC. When the ADON is set for the first time, the ADC wakes up from low power mode. The ADON bit must be set a second time using the write instruction to start the transformation. At the end of the transition, the ADC remains powered on and the user only needs to set the ADON bit once to start the next transition. When the conversion is complete, the conversion data is stored in the ADC_DR register and the EOC(End of conversion) flag is set. If EOCIE is set, an interrupt is generated
void ADC_CH_Init( u8 ch )
{
char l = 0;
ADC_CR1 = 0x00; //fADC = fMASTER/2, 8Mhz single conversion, disable conversion
ADC_CR1 |= ( 1 << 1 ); // Turn on the continuous conversion mode
ADC_CSR = ch; // Control the status register to select the desired AD input channel such as: PD2(AIN3)
ADC_CR2 = 0x00; // By default, the data is read high first and read low first
ADC_TDRL = ( 1 << ch ); // Disable the corresponding channel schmidt trigger function 1 to shift the left ch+1 bit
ADC_CR1 |= 0x01; // Enable ADC and start conversion
ADC_CSR |= 0x20; //EOCIE Enables conversion end interrupt Enables EOC interrupt
ADC_CR3 |= ( 1 << 7 ); // Enable data cache
for( l = 0; l < 100; l++ ); // Delay to ensure that the ADC module is powered on for at least 7us
ADC_CR1 = ADC_CR1 | 0x01; // Enable ADC in the lowest position 1 of register CR1 again and start the conversion
}
u16 databuf[8] = {0};
// Collect the PD2 voltage
u16 ReadVol_CH3( void )
{
u16 voltage = 0;
if( ADC_flag )
{
ADC_flag = 0;
/* When cache mode is enabled, data is stored in the ADC_DB0R ---- ADC_DB7R registers. If scan mode is enabled, these registers store the data of the corresponding channels. If scan mode is not enabled, these registers store the results of continuous conversions. So the cache stores all the data that the current channel reads continuously */
DATAH = ADC_DB0RH; // Read the top 8 bits of the ADC result
DATAL = ADC_DB0RL; // Read the lower 8 bits of the ADC result
voltage = ( DATAH << 2 ) + DATAL ; // Obtain data from 0 to 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 interrupt service function interrupt number 22
#pragma vector = 24 // Add 2 to the interrupt number in the STVD
__interrupt void ADC_Handle( void )
{
ADC_CSR &= ~0x80; // Clear the end of conversion flag EOC
ADC_flag = 1; // Set the ADC interrupt flag to 1
}
Copy the code
When the data collection is complete, an interrupt is generated and a flag bit is set in the interrupt. The ReadVol_CH3() function finds flag position 1 and reads the sampled data directly.