The previous section introduces how to use FwLib_STC8 in Keil5 and PlatformIO environments. Next, we will focus on the STC8H series and introduce ADC (analog-to-digital conversion) in combination with the demonstration use cases in the demo.
ADC analog-to-digital conversion of STC8G and STC8H
The ADC part of STC8G and STC8H is basically the same in register settings, but the channel numbers, channel quantities and accuracy corresponding to different models are different.
Number of channels and accuracy
The number of channels and accuracy of each series corresponding to STC8G/STC8H are as follows.
The channel selection uses the lower 4 bits of the register ADC_CONTR, corresponding to the various series of STC8G/STC8H. The channels corresponding to the values of this register are as follows
Alignment format of conversion results
The ADC sampling accuracy cannot actually be set. The sampling is performed with the maximum accuracy of the current model, and the results are stored in the two registers [ADC_RES, ADC_RESL]. In order to facilitate the use of results of different accuracy in different occasions, the results can be set to left-aligned or right-aligned.
When set to left-aligned, you can only take the value of ADC_RES (8 bits) and ignore the last two bits.
When the bit is set to right-align, according to the actual accuracy, the lower 4 bits (12-bit accuracy) or lower 2 bits (10-bit accuracy) of ADC_RES can be taken and added to ADC_RESL to get the final result.
Time consumption for conversion
A complete ADC conversion time = Tsetup + Tduty + Thold + Tconvert
Tsetup: Channel switching time for conversion, can be set to 1 or 2 ADC clock cycles
Tduty: The sampling time of the conversion, the default is the minimum 11 ADC clocks, the maximum is 32 ADC clock cycles
Thold: Channel selection hold time, can be selected as 1, 2, 3, 4 ADC clock cycles
Tconvert: The conversion time is fixed, 10-bit precision is 10 ADC clocks, 12-bit precision is 12 ADC clocks
The above time units are all ADC clock cycles. The number of system clocks (SYSCLK) occupied by each ADC clock cycle can be set. Using the lower three bits of the ADCCFG register, it can be set from a minimum of 2 system clock cycles to a maximum of 32 system clock cycles.
For the highest conversion frequency, a global limit is written on DS
The speed of 10-bit ADC cannot exceed 500KHz
The speed of 12-bit ADC cannot exceed 800KHz
The conversion sampling time cannot be less than 10, and it is recommended to set it to 15
Hardware Connection
There are two types of ADC hardware connections for STC8G/STC8H: with AVcc, AGRND and without AVcc, AGRND
带 AVcc, AGrnd
The high-end model STC8H3K64S2 series, for example, has these two pins, which correspond to the voltage reference value and ground reference value of the conversion target. For ordinary use, these two can be directly connected to VCC and GND, and the connection is
AGrnd -> GND
AVcc -> VCC
AVref -> VCC
Vcc -> VCC
Gnd -> GND
ADC1 -> sampling point
Without AVcc,AGrnd
Low-end models and STC8G series do not have these two pins. You only need to connect AVref. The sampling point is connected to the MCU ground. The connection is
AVref -> VCC
Vcc -> VCC
Gnd -> GND
ADC1 -> Test voltage
Demonstration use case description
The following demonstration use cases are based on FwLib_STC8. The source code is located in the FwLib_STC8/demo/adc directory. You can download or view it yourself. Due to version evolution, the code may differ from the code in the repository. The latest version in the repository shall prevail.
For information on how to run the demo, please refer to the configuration instructions for Keil C51 and VSCode PlatformIO described earlier.
Use ADC1 for 8-bit ADC conversion, active polling mode
In the following example, the active query method is used to perform ADC conversion on the P1.1 port every 0.1 seconds with an accuracy of 8 bits, and the result is output to the serial port
main.c code
#include "fw_hal.h"
void main(void)
{
uint8_t res;
// Adjust the system frequency. If you use STC-ISP to set the frequency, you need to comment out this line
SYS_SetClock();
// For result output
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// Set ADC1 (GPIO P1.1) to high impedance input
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
// Channel used: ADC1
ADC_SetChannel(0x01);
// Set ADC clock = SYSCLK / 2 / (1+1) = SYSCLK / 4
ADC_SetClockPrescaler(0x01);
// Set the result to left-align, just need to take the value of ADC_RES
ADC_SetResultAlignmentLeft();
// Turn on ADC power
ADC_SetPowerState(HAL_State_ON);
while(1)
{
// Start conversion
ADC_Start();
// Wait for two system clocks
NOP();
NOP();
// Check if the conversion result flag is set
while (!ADC_SamplingFinished());
// Clear the result flag
ADC_ClearInterrupt();
// Read the result
res = ADC_RES;
// Output through serial port 1
UART1_TxString("Result: ");
UART1_TxHex(res);
UART1_TxString("rn");
// Wait 100ms and convert again
SYS_Delay(100);
}
}
Use ADC1 for 10-bit/12-bit ADC conversion, interrupt mode
In the following example, the ADC of P1.1 port is continuously converted using interrupts, with a precision of 10 bits (or 12 bits, depending on the MCU model), and the result is output to the serial port every 0.1 seconds.
#include "fw_hal.h"
// 16-bit variable used to record the conversion result
uint16_t res;
// Method for handling interrupts, using macro definitions to ensure compatibility between Keil C51 and SDCC
INTERRUPT(ADC_Routine, EXTI_VectADC)
{
// Clear the interrupt bit first
ADC_ClearInterrupt();
// The lower 8 bits of the result
res = ADC_RESL;
// High 8 bits of the result
res |= (ADC_RES & 0x0F) << 8;
// Start again to make the ADC convert continuously,
ADC_Start();
}
void main(void)
{
// Set the system frequency
SYS_SetClock();
// Result output
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// Set P11 to high impedance input mode
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
// Channel used: ADC1
ADC_SetChannel(0x01);
// ADC clock = SYSCLK / 2 / (1+15) = SYSCLK / 32
ADC_SetClockPrescaler(0x0F);
// Right-aligned to facilitate conversion to double-byte results
ADC_SetResultAlignmentRight();
// Enable global interrupt and ADC interrupt
EXTI_Global_SetIntState(HAL_State_ON);
EXTI_ADC_SetIntState(HAL_State_ON);
// Turn on ADC power
ADC_SetPowerState(HAL_State_ON);
// Start ADC conversion
ADC_Start();
while(1)
{
//Conversion result output
UART1_TxString("Result: ");
UART1_TxHex(res >> 8);
UART1_TxHex(res & 0xFF);
UART1_TxString("rn");
SYS_Delay(100);
}
}
Use ADC1 and ADC2 dual channels for conversion, interrupt mode
The following is a more practical example, which performs multi-channel ADC conversion in the form of interrupts. It can be used for wireless car remote control, dual-channel audio sampling, etc.
#include "fw_hal.h"
// Used to record the channel number of the current sampling
uint8_t pos;
// Record the sampling results of each channel
uint16_t res[2];
//Interrupt handling method
INTERRUPT(ADC_Routine, EXTI_VectADC)
{
ADC_ClearInterrupt();
//Record sampling results
res[pos] = ADC_RESL;
res[pos] |= (ADC_RES & 0x0F) << 8;
// Switch to the next channel
pos = (pos+1) & 0x1;
if (pos == 0)
{
/**
* When the sampling frequency is high, adding these two sentences can improve the accuracy. The mechanism is to switch to open-drain mode to clear the residual voltage on the sampling port
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_InOut_OD);
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
*/
ADC_SetChannel(0x01);
}
else
{
/**
* Uncomment these lines in high speed ADC
GPIO_P1_SetMode(GPIO_Pin_2, GPIO_Mode_InOut_OD);
GPIO_P1_SetMode(GPIO_Pin_2, GPIO_Mode_Input_HIP);
*/
ADC_SetChannel(0x02);
}
ADC_Start();
}
// The following code is basically the same as the previous one, so I won't comment it in detail.
void main(void)
{
SYS_SetClock();
// For debug print
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// Channel: ADC1
ADC_SetChannel(0x01);
// ADC Clock = SYSCLK / 2 / (1+15) = SYSCLK / 32
ADC_SetClockPrescaler(0x0F);
// Right alignment, high 2-bit in ADC_RES, low 8-bit in ADC_RESL
ADC_SetResultAlignmentRight();
// Enable interrupts
EXTI_Global_SetIntState(HAL_State_ON);
EXTI_ADC_SetIntState(HAL_State_ON);
// Turn on ADC power
ADC_SetPowerState(HAL_State_ON);
// Set ADC1(P1.1), ADC2(P1.2) HIP
GPIO_P1_SetMode(GPIO_Pin_1|GPIO_Pin_2, GPIO_Mode_Input_HIP);
// Start ADC
ADC_Start();
while(1)
{
UART1_TxString("Result: ");
UART1_TxHex(res[0] >> 8);
UART1_TxHex(res[0] & 0xFF);
UART1_TxChar(' ');
UART1_TxHex(res[1] >> 8);
UART1_TxHex(res[1] & 0xFF);
UART1_TxString("rn");
SYS_Delay(100);
}
}
Finish
The above is a demonstration of the use case of STC8H using the FwLib_STC8 package library for ADC conversion. In actual use, the delay time accuracy in the active polling mode is not high.
If there is a requirement for the accuracy of the sampling time interval, it is recommended to use the interrupt form.
Previous article:STC8H Development (IV): Introduction and Precautions of FwLib_STC8 Package Library
Next article:STC8H Development (Part 2): Configuring and using the FwLib_STC8 package library in Linux VSCode
- Popular Resources
- Popular amplifiers
- Learn ARM development(16)
- Learn ARM development(17)
- Learn ARM development(18)
- Embedded system debugging simulation tool
- A small question that has been bothering me recently has finally been solved~~
- Learn ARM development (1)
- Learn ARM development (2)
- Learn ARM development (4)
- Learn ARM development (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Detailed explanation of intelligent car body perception system
- How to solve the problem that the servo drive is not enabled
- Why does the servo drive not power on?
- What point should I connect to when the servo is turned on?
- How to turn on the internal enable of Panasonic servo drive?
- What is the rigidity setting of Panasonic servo drive?
- How to change the inertia ratio of Panasonic servo drive
- What is the inertia ratio of the servo motor?
- Is it better for the motor to have a large or small moment of inertia?
- What is the difference between low inertia and high inertia of servo motors?
- 1. [Learning LPC1768 library functions] LED experiment
- [Bing Dwen Dwen Award List] 2022 Digi-Key Innovation Design Competition
- Have you ever done this kind of impedance marking that makes people collapse and go to the hospital?
- Transimpedance amplifier circuit, question about the maximum optical power that a photodiode can receive
- stm32cubemx always fails to install the packages of various mcu
- DIY an I2C level conversion board
- I hope this book "PCB Design Secrets" will be passed on to you!
- [National Technology Low Power Series N32L43x Evaluation] 3. Key Driver + SPI_LCD Screen Driver
- A comic book about CircuitPython and Mu
- Is there any ADR3433 chip that can be replaced by PINTOPIN?