catalogue
- STC8H development (I): configure and use fwlib in Keil5_ STC8 packaging Library (Graphic explanation)
- STC8H development (II): configuring and using fwlib in Linux VSCode_ STC8 packaging Library (Graphic explanation)
- STC8H development (III): Based on fwlib_ Introduction and demonstration of analog-to-digital conversion ADC of STC8
Earlier, we introduced the use of fwlib in Keil5 and PlatformIO environments_ STC8. Next, mainly STC8H series, ADC (analog-to-digital conversion) is introduced in combination with the demonstration 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 setting, but the channel number, channel number and accuracy corresponding to different models are different
Number and accuracy of channels
The channel number and accuracy of each series corresponding to STC8G/STC8H are as follows
Product line | ADC resolution | Number of ADC channels |
---|---|---|
STC8H1K08 series | 10 bits | 9 channels |
STC8H1K28 series | 10 bits | 12 channels |
STC8H3K64S4 series | 12 bits | 12 channels |
STC8H3K64S2 series | 12 bits | 12 channels |
STC8H8K64U series | 12 bits | 15 channels |
STC8H2K64T series | 12 bits | 15 channels |
STC8H4K64TLR series | 12 bits | 15 channels |
STC8H4K64TLCD series | 12 bits | 15 channels |
STC8H4K64LCD series | 12 bits | 15 channels |
Channel selection uses register ADC_ The lower 4 bits of contr correspond to each series of STC8G/STC8H. The channels corresponding to the values of this register are as follows
STC8H1K28 | STC8H1K08 | STC8H3K64S4 STC8H3K64S2 |
STC8H8K64U STC8H2K64T STC8H4K64TLR |
STC8H4K64TLCD STC8H4K64LCD |
STC8G1K08A | STC8G1K08 STC8G1K08T |
STC8G2K64S4 STC8G2K64S2 |
|
---|---|---|---|---|---|---|---|---|
0000 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P3.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 |
0001 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P3.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 |
0010 | P1.2/ADC2 | N/A | P1.2/ADC2 | P5.4/ADC2 | P5.4/ADC2 | P3.2/ADC2 | P1.2/ADC2 | P1.2/ADC2 |
0011 | P1.3/ADC3 | N/A | N/A | P1.3/ADC3 | P1.3/ADC3 | P3.3/ADC3 | P1.3/ADC3 | P1.3/ADC3 |
0100 | P1.4/ADC4 | N/A | N/A | P1.4/ADC4 | P1.4/ADC4 | P5.4/ADC4 | P1.4/ADC4 | P1.4/ADC4 |
0101 | P1.5/ADC5 | N/A | N/A | P1.5/ADC5 | P1.5/ADC5 | P5.5/ADC5 | P1.5/ADC5 | P1.5/ADC5 |
0110 | P1.6/ADC6 | N/A | P1.6/ADC6 | P1.6/ADC6 | P6.2/ADC6 | N/A | P1.6/ADC6 | P1.6/ADC6 |
0111 | P1.7/ADC7 | N/A | P1.7/ADC7 | P1.7/ADC7 | P6.3/ADC7 | N/A | P1.7/ADC7 | P1.7/ADC7 |
1000 | P0.0/ADC8 | P3.0/ADC8 | P0.0/ADC8 | P0.0/ADC8 | P0.0/ADC8 | N/A | P3.0/ADC8 | P0.0/ADC8 |
1001 | P0.1/ADC9 | P3.1/ADC9 | P0.1/ADC9 | P0.1/ADC9 | P0.1/ADC9 | N/A | P3.1/ADC9 | P0.1/ADC9 |
1010 | P0.2/ADC10 | P3.2/ADC10 | P0.2/ADC10 | P0.2/ADC10 | P0.2/ADC10 | N/A | P3.2/ADC10 | P0.2/ADC10 |
1011 | P0.3/ADC11 | P3.3/ADC11 | P0.3/ADC11 | P0.3/ADC11 | P0.3/ADC11 | N/A | P3.3/ADC11 | P0.3/ADC11 |
1100 | N/A | P3.4/ADC12 | P0.4/ADC12 | P0.4/ADC12 | P0.4/ADC12 | N/A | P3.4/ADC12 | P0.4/ADC12 |
1101 | N/A | P3.5/ADC13 | P0.5/ADC13 | P0.5/ADC13 | P0.5/ADC13 | N/A | P3.5/ADC13 | P0.5/ADC13 |
1110 | N/A | P3.6/ADC14 | P0.6/ADC14 | P0.6/ADC14 | P0.6/ADC14 | N/A | P3.6/ADC14 | P0.6/ADC14 |
1111 | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref |
Alignment format of conversion results
In fact, the ADC sampling accuracy cannot be set. The sampling uses the maximum accuracy of the current model, and the results are stored in the [ADC_RES, ADC_RESL] registers To facilitate the use of results with different accuracy in different occasions, you can set the results to left alignment or right alignment
- When left alignment is set, only ADC can be taken_ Res value (8 bits), ignoring the last two bits
- When setting bit right alignment, ADC can be taken according to the actual accuracy_ Lower 4 bits (12 bit precision) or lower 2 bits (10 bit precision) of res, plus ADC_RESL gets the final result
Conversion time consumption
A complete ADC conversion time is = Tsetup + Tduty + Thold + Tconvert
- Tsetup: converted channel switching time, which can be set to 1 or 2 ADC clock cycles
- Tduty: the sampling time of conversion. The default is the lowest 11 ADC clocks and the highest is 32 ADC clock cycles
- Thord: hold time for channel selection. You can select 1, 2, 3 or 4 ADC clock cycles
- Tconvert: the conversion time is fixed, the 10bit accuracy is 10 ADC clocks, and the 12bit accuracy is 12 ADC clocks
The above time units are ADC clock cycles. The number of system clock (SYSCLK) occupied by each ADC clock cycle can be set. Using the lower three bits of ADCCFG register, it can be set from the lowest 2 system clock cycles to the highest 32 system clock cycles
For the highest frequency of conversion, a global limit is written on DS
- The speed of 10 bit ADC shall not be higher than 500KHz
- The speed of 12 bit ADC shall not be higher than 800KHz
- The sampling time for conversion cannot be less than 10. It is recommended to set it to 15
Hardware connection
There are two kinds of ADC hardware connections for STC8G/STC8H: with avcc and agrnd and without avcc and agrnd
With AVcc,AGrnd
The high-end model STC8H3K64S2 series, for example, will have these two pin pins, which correspond to the voltage reference value and ground reference value of the conversion target respectively For ordinary use, these two can be directly connected to VCC and GND
AGrnd -> GND AVcc -> VCC AVref -> VCC Vcc -> VCC Gnd -> GND ADC1 -> Sampling point
Without AVcc,AGrnd
The low-end model and STC8G series do not have these two pin s. They only need to be connected to AVref. The sampling point is connected to MCU in common. The connection is
AVref -> VCC Vcc -> VCC Gnd -> GND ADC1 -> Test voltage
Demonstration use case description
The following demonstration case is based on FwLib_STC8 , the source code is located in FwLib_STC8/demo/adc Directory, you can download or view it yourself Due to version evolution, the code may be different from the code in the warehouse, and the latest version in the warehouse shall prevail
For how to run the demonstration case, please refer to the configuration instructions of Keil C51 and VSCode PlatformIO described earlier
ADC1 is used for 8-bit ADC conversion and active polling mode
In the following example, P1.1 is queried every 0.1 seconds by active query 1 port for ADC conversion, with an accuracy of 8 bits, and output the result to the serial port
main.c code
#include "fw_hal.h" void main(void) { uint8_t res; // Adjust the system frequency. If STC-ISP is used to set the frequency, this line needs to be commented out SYS_SetClock(); // For result output UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200); // Set ADC1(GPIO P1.1) as high resistance input GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP); // Use channel: ADC1 ADC_SetChannel(0x01); // Set ADC clock = SYSCLK / 2 / (1+1) = SYSCLK / 4 ADC_SetClockPrescaler(0x01); // To set the left alignment of the result, you only need to take the value ADC_RES ADC_SetResultAlignmentLeft(); // Turn on the ADC ADC_SetPowerState(HAL_State_ON); while(1) { // Start conversion ADC_Start(); // Wait for two system clocks NOP(); NOP(); // Check whether the conversion result flag bit is set while (!ADC_SamplingFinished()); // Clear result flag bit ADC_ClearInterrupt(); // Read results res = ADC_RES; // Output through serial port 1 UART1_TxString("Result: "); UART1_TxHex(res); UART1_TxString("\r\n"); // Wait for 100ms before switching again SYS_Delay(100); } }
ADC1 is used for 10 bit / 12 bit ADC conversion in interrupt mode
In the following example, P1.0 is interrupted 1 port carries out ADC continuous conversion, the accuracy is 10 bits (or 12 bits, different MCU models have different accuracy), and the result is output to the serial port every 0.1 seconds
#include "fw_hal.h" // 16 bit variables are used to record the conversion results uint16_t res; // The method of handling interrupts uses macro definitions to ensure the compatibility between Keil C51 and SDCC INTERRUPT(ADC_Routine, EXTI_VectADC) { // Clear the middle break first ADC_ClearInterrupt(); // Result lower 8 bits res = ADC_RESL; // The result is 8 bits higher res |= (ADC_RES & 0x0F) << 8; // Start again to make the ADC convert continuously, ADC_Start(); } void main(void) { // Set system frequency SYS_SetClock(); // Result output UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200); // Set P11 high resistance input mode GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP); // Use channel: 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 the ADC 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("\r\n"); SYS_Delay(100); } }
Use ADC1 and ADC2 dual channels for conversion and interrupt mode
The following is a more practical example. Multi channel ADC conversion in the form of interrupt can be used for wireless car remote control, dual channel audio sampling, etc
#include "fw_hal.h" // The channel number used to record the current sample uint8_t pos; // Record the sampling results of each channel uint16_t res[2]; // Interrupt processing 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 the 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 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("\r\n"); SYS_Delay(100); } }
end
The above is how STC8H uses FwLib_STC8 package library ADC conversion demonstration case description In practical use, the delay time accuracy under the active polling mode is not high,
If the accuracy of sampling interval is required, it is recommended to use the form of interrupt