This is the 10th day of my participation in the August More Text Challenge. For details, see:August is more challenging

STM8S003 MCU internal ADC is 12 bits, A/D conversion of each channel can perform A single and continuous conversion mode.

The single conversion mode means that after each conversion, the ADC stops the conversion and manually turns on the second conversion if it needs to continue.

Continuous conversion mode means that after each conversion, the system will automatically enable the second conversion. There is no need to manually set the second conversion. In other words, the continuous conversion mode only needs to be enabled once.

ADC block diagram is as follows:

The sequence diagram of ADC conversion is as follows:

The following code is used to implement the ADC’s single conversion mode:

#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 is the corresponding pin of SCM
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz single conversion, disable conversion
    ADC_CSR  = ch + 1;                  // 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 + 1));// 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
    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
}

// Collect the PD3 voltage
u16 ReadVol_CH3( void )
{
    u16 voltage = 0;
    if( ADC_flag )
    {
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ; // Obtain data from 0 to 1024
        ADC_CR1 = ADC_CR1 | 0x01;          // Start the next conversion again with the lowest position 1 of the CR1 register
    };
    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
    // By default, the high 8 bits are read before the low 8 bits are read
    DATAH = ADC_DRH;                    // Read the top 8 bits of the ADC result
    DATAL = ADC_DRL;                    // Read the lower 8 bits of the ADC result
    ADC_flag = 1;                       // Set the ADC interrupt flag to 1
}
Copy the code

In ADC start for the first time needs a stable time, so at the time of initialization, it takes time to wait for the ADC is stable and stable after can begin the ADC conversion, here to read the conversion result using interrupt, when an ADC conversion into will generate an interrupt, then read the result of the transformation in the interrupt, setting flags at the same time. The program loops to read the flag bit. When the flag bit is 1, the conversion is complete and the result of the conversion can be printed. Then set the lowest value of register ADC_CR1 to 1 manually to enable the next conversion.

The ADC_CR1 register is as follows:

The ADON bit is the conversion switch of the ADC. Write 1 to the ADON bit in single mode to turn on the conversion.

Only one channel is used here. As can be seen from the top ADC block diagram, there are many channels in an ADC. How to do if you want to collect multiple channels?

#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 is the corresponding pin of SCM
void ADC_CH_Init( u8 ch )
{
    char l = 0;
    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz single conversion, disable conversion
    ADC_CSR  = ch + 1;                  // 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 + 1));// 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
    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
}

// Collect the PD3 voltage
u16 ReadVol_CH3( void )
{
    u16 voltage = 0;
    // This is very fast if it is called only once during program initialization.
    // If initialization is called each time, the speed will be 1/10 of the original
    ADC_CH_Init( 3 );
    while( ( ADC_CSR & 0x80) = =0 );      // Wait for the transition to finish
    if( ADC_CSR & 0x80 )
    {
        DATAH = ADC_DRH;                    // Read the top 8 bits of the ADC result
        DATAL = ADC_DRL;                    // Read the lower 8 bits of the ADC result
        voltage = ( DATAH << 2 ) + DATAL ; // Obtain data from 0 to 1024
        ADC_CR1 = ADC_CR1 | 0x01;          // Start the next conversion again with the lowest position 1 of the CR1 register
        ADC_CSR &= 0x7F;
    };
    return voltage;
}

// Collect the PD2 voltage
u16 ReadVol_CH4( void )
{
    u16 voltage = 0;
    // This is very fast if it is called only once during program initialization.
    // If initialization is called each time, the speed will be 1/10 of the original
    ADC_CH_Init( 2 );
    while( ( ADC_CSR & 0x80) = =0 );      // Wait for the transition to finish
    if( ADC_CSR & 0x80 )
    {
        DATAH = ADC_DRH;                    // Read the top 8 bits of the ADC result
        DATAL = ADC_DRL;                    // Read the lower 8 bits of the ADC result
        voltage = ( DATAH << 2 ) + DATAL ; // Obtain data from 0 to 1024
        ADC_CR1 = ADC_CR1 | 0x01;          // Start the next conversion again with the lowest position 1 of the CR1 register
        ADC_CSR &= 0x7F;
    };
    return voltage;
Copy the code

If multiple channels need to be converted, then after one channel is converted, it needs to be reinitialized to switch the channel. Since the ADC needs to stabilize after switching channels, switching sampling data back and forth between multiple channels is much slower than sampling data from a single channel, because switching channels requires a period of time for the ADC to stabilize.

When reading data, call the corresponding function directly in the main function.

#include "iostm8s103F3.h"
#include "led.h"
#include "adc.h"
#include "stdio.h"

void SysClkInit( void )
{
    CLK_SWR = 0xe1;       //HSI 16MHz CPU clock frequency of the primary clock source
    CLK_CKDIVR = 0x00;    // The CPU clock is 0 and the system clock is 0
}

void main( void )
{
    u16 val1 = 0;
    u16 i=0;
    SysClkInit();
    __asm( "sim" );                       // Disable interrupt
    LED_GPIO_Init();
    ADC_CH_Init( 3 );
    __asm( "rim" );                       // Enable interrupt
    while( 1 )
    {
        LED = !LED;
        val1 = ReadVol_CH3();
    }
}
Copy the code