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