This is the 15th day of my participation in the August More Text Challenge. For details, see:August is more challenging
There are altogether 5 ADC sampling channels in STM8S003, from AIN2 to AIN6. When multi-channel sampling, the ADC conversion mode needs to be set to single conversion mode. After each switchover of sampling channels, the ADC needs to be re-initialized, and the sampling results are read in interrupt.
I/O port initialization code
//AD channel pin initialization
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 2 ); // set PD2 to input AIN3
PD_CR1 &= ~( 1 << 2 ); //PD2 is set to dangling input
PD_DDR &= ~( 1 << 3 ); //PD3 is set to input AIN4
PD_CR1 &= ~( 1 << 3 ); //PD3 is set to dangling input
PC_DDR &= ~( 1 << 4 ); //PC4 is set to input AIN2
PC_CR1 &= ~( 1 << 4 ); //PC4 is set to dangling input
PD_DDR &= ~( 1 << 5 ); //PD5 is set to input AIN5
PD_CR1 &= ~( 1 << 5 ); //PD5 is set to dangling input
PD_DDR &= ~( 1 << 6 ); //PD6 is set to input AIN6
PD_CR1 &= ~( 1 << 6 ); //PD6 is set to dangling input
}
Copy the code
Set the I/O ports of the ADC to input mode.
Next, initialize the ADC functionality
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
}
Copy the code
Set the ADC to a single conversion mode and manually set the lowest position 1 of the CR1 register for each conversion.
Read the data after a successful conversion in an interrupt.
#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 interrupt, the converted sample value is stored in the DATAH and DATAL, and the sampling end flag bit ADC_flag is set. When the sampling function determines that the flag bit is 1, it reads the ADC sample value.
Sample value read function:
// Collect the voltage of 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 ; // 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;
}
Copy the code
The functions of some pins of MCU need to be opened by option word. The method of setting option word by ST Visual Programmer software is as follows:
In AFR7, set PC4 to the AIN2 feature in the option word.
The complete code for ADC is 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 << 2 ); // set PD2 to input AIN3
PD_CR1 &= ~( 1 << 2 ); //PD2 is set to dangling input
PD_DDR &= ~( 1 << 3 ); //PD3 is set to input AIN4
PD_CR1 &= ~( 1 << 3 ); //PD3 is set to dangling input
PC_DDR &= ~( 1 << 4 ); //PC4 is set to input AIN2
PC_CR1 &= ~( 1 << 4 ); //PC4 is set to dangling input
PD_DDR &= ~( 1 << 5 ); //PD5 is set to input AIN5
PD_CR1 &= ~( 1 << 5 ); //PD5 is set to dangling input
PD_DDR &= ~( 1 << 6 ); //PD6 is set to input AIN6
PD_CR1 &= ~( 1 << 6 ); //PD6 is set to dangling input
}
//ADC input channel initialization entry parameter indicates channel selection
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 voltage of 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 ; // 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;
}
// Collect the PD2 voltage 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; // If the channel does not need to be switched, it only needs to be initialized once. After each time the data is read, the next conversion needs to be manually enabled
};
return voltage;
}
// Collect the PD3 voltage value 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 ; // 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;
}
// Collect the PD5 voltage value AIN5
u16 ReadVol_CH5( void )
{
u16 voltage = 0;
ADC_CH_Init( 4 );
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;
}
// Collect the PD6 voltage value AIN6
u16 ReadVol_CH6( void )
{
u16 voltage = 0;
ADC_CH_Init( 5 );
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
The main function code is as follows:
#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 clock frequency of the primary clock source
CLK_CKDIVR = 0x00; // The CPU clock is 0 and the system clock is 0
}
void main( void )
{
u8 i=0;
__asm( "sim" ); // Disable interrupt
SysClkInit();
delay_init( 16 );
LED_GPIO_Init();
ADC_GPIO_Init();
__asm( "rim" ); // Enable interrupt
while( 1 )
{
LED = ~LED;
// After the channel switch, the first batch of sampled data is still the data of the previous channel
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); }}Copy the code