ADC is one on the most famous peripheral on a microcontroller.
In this tutorial we will see that it's possible to retrieve data from a potentiometer and send them in an array.
You are certainly wondering how to use a such thing on a STM32?
That's a good question.
To see this, let's use the STM32F103ZE-SK board, and guess what?
There is already a potentiometer on it!
What a wonderful world (that's what Louis Armstrong would have said) isn't it?
(If you didn't have a potentiometer on your board, you could weld it or use a breadboard.)
In the code below, we will retrieve data caught by the ADC from the angle of our potentiometer.
But first of all, we have to know that in this board, the potentiometer is linked with the GPIOC and the pin 4.
The ADC has to be configured with the ADC1 and the channel 14.
Let's see now how to catch values from this famous ADC.
The ADC in the STM32F103ZE-SK has 12-bit.
It means that the maximum value available is 2^12 = 4096.
So we can handle 4096 different values, from 0 to 4095.
Notice that all values with the ADC are in hexadecimal:
But what we would want is to have a value in volt, of course.
For example, if the potentiometer was at the minimum (turned on the left), its value would have been 0 (or almost).
And if the potentiometer was turned at maximum on the right, its value would have been 4095 (or 0xFFF).
Our board is powered by a tension of 3.3V.
So let's use a cross-multiplication to transform our hexadecimal value into a volt one.
So, each value caught by our ADC will be multiplied by this number.
And the result will be a voltage.
For example if the ADC retrieved 2700, the voltage would have been:
And in our example the array will be filled with a value each second during 32 seconds.
So it's up to you to move the potentiometer and see that all values will be catched depending of the angle of our potentiometer.
Let's see this in details.
#include "stm32f10x.h" #include "stxng.h" #define ARRAY_SIZE 32 /** * Classic delay */ void badprogDelay(u32 myTime) { u32 i; RCC_ClocksTypeDef RCC_Clocks; RCC_GetClocksFreq(&RCC_Clocks); // i = myTime * 68 i = myTime * (RCC_Clocks.SYSCLK_Frequency >> 20); for (; i != 0; i--) ; } /** * Initialization of ADC and the poentiomenter's GPIO */ float badprogADC() { /// declaring GPIO stuff GPIO_InitTypeDef GPIO_InitStructure; // declaring ADC struct ADC_InitTypeDef ADC_InitStructure; // deinit ADC ADC_DeInit(ADC1); // enabling clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // enabling ADC clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // C - Init the GPIO with the structure - Testing ADC GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOC, &GPIO_InitStructure); // init ADC struct ADC_StructInit(&ADC_InitStructure); // setting the ADC struct ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; // init adc ADC_Init(ADC1, &ADC_InitStructure); // enable ADC ADC_Cmd(ADC1, ENABLE); // start ADC1 calibration and check the end ADC_StartCalibration(ADC1); // configure ADC_IN14 ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_7Cycles5); // start ADC -> retrieve the ADC value from the potentiometer // and add it into ADC1->DR with: // ADCx->CR2 |= CR2_EXTTRIG_SWSTART_Set; // this without using ADC1->DR o_O // CR2 = Configuration Register2 -> it seems to be a config with // a binary number -> for example 1000010100101010 which sets all // registers with default values ADC_SoftwareStartConvCmd(ADC1, ENABLE); // check the end of the ADC1 calibration // setting ADC1->DR with: // if ((ADCx->CR2 & CR2_CAL_Set) != (uint32_t)RESET) while (ADC_GetCalibrationStatus(ADC1) == SET) ; // convert valueADC to valueVolt -> valueADC * (MAX VOLT / 2^12) // and also : // ADC_SoftwareStartConvCmdsoftwareS, // ADC_GetCalibrationStatus // with // return (uint16_t) ADCx->DR; uint16_t valueADC = ADC_GetConversionValue(ADC1); // convert the "uint_16 valueADC" into a "float valueVolt" // Volt = 3.3 // ADC = 12 bits, so 2^12 = 4096 float valueVolt = valueADC * (3.3 / 4095); return valueVolt; } /** * Init the array with '\0'; */ void badprogInitArray(float *myArray, int size) { int i = 0; while (i < size) { myArray[i] = '\0'; ++i; } } /******************************************************************************* * Main, what else? *******************************************************************************/ int main(void) { float theArray[ARRAY_SIZE]; int i = 0; // init with 0 the whole array badprogInitArray(theArray, ARRAY_SIZE); // our beautiful infinite loop while i < 32 while (-2013) { if (i < ARRAY_SIZE) { theArray[i] = badprogADC(); badprogDelay(100000); // 1 sec ++i; } } return 0; }
A great way to start capturing analog data all around you.
Good job, you've made it!
Comments
Hai Lai (not verified)
Thursday, October 24, 2019 - 4:26pm
Permalink
What is the sampling rate for
What is the sampling rate for ADC_SampleTime_7Cycles5?
navadeep (not verified)
Wednesday, February 3, 2021 - 7:57am
Permalink
Why is stxng.h? It isn't
Why is stxng.h? It isn't available as default header in CubeIDE
Add new comment