In many embedded projects, we have to deal with signals directly from nature, like temperature, pressure, current, etc... Theses signals are analog by default and in most of cases we use sensors that converts these analog signals to analog electrical voltage to be injected in the microcontroller to do some work.
Unfortunately, microcontrollers are digital and just can't deal with analog signals so these signals must be converted again to digital signals that is comprehensible by the microcontroller.
For this purpose, microcontroller's manufacturers usually incorporate an ADC into the microcontroller. ADC is actually stands for Analog to Digital Converter. This module is omnipresent in most of microcontrollers.
I'm going to use the STM32F4 discovery board to interface an analog input provided by a potentiometer and visualize the received data with the watch feature while debugging the program.
#include "stm32f4xx_adc.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" int ConvertedValue = 0; //Converted value readed from ADC void adc_configure(){ ADC_InitTypeDef ADC_init_structure; //Structure for adc confguration GPIO_InitTypeDef GPIO_initStructre; //Structure for analog input pin //Clock configuration RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//The ADC1 is connected the APB2 peripheral bus thus we will use its clock source RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN,ENABLE);//Clock for the ADC port!! Do not forget about this one ;) //Analog pin configuration GPIO_initStructre.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0 GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down GPIO_Init(GPIOC,&GPIO_initStructre);//Affecting the port with the initialization structure configuration //ADC structure configuration ADC_DeInit(); ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Right;//data converted will be shifted to right ADC_init_structure.ADC_Resolution = ADC_Resolution_12b;//Input voltage is converted into a 12bit number giving a maximum value of 4096 ADC_init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1 (actually I'm not sure about this one :/) ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion ADC_init_structure.ADC_NbrOfConversion = 1;//I think this one is clear :p ADC_init_structure.ADC_ScanConvMode = DISABLE;//The scan is configured in one channel ADC_Init(ADC1,&ADC_init_structure);//Initialize ADC with the previous configuration //Enable ADC conversion ADC_Cmd(ADC1,ENABLE); //Select the channel to be read from ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_144Cycles); } int adc_convert(){ ADC_SoftwareStartConv(ADC1);//Start the conversion while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion return ADC_GetConversionValue(ADC1); //Return the converted data } int main(void){ adc_configure();//Start configuration while(1){//loop while the board is working ConvertedValue = adc_convert();//Read the ADC converted value } }
Hi, thanks for that code.
RépondreSupprimerI have try it and it works well. I'm trying to make simple guitar effect from that board, but i get problem, with unacceptable high pitch noise from ADC even if I don't attach another circuit on it, did you get same problem with me?
Do you mean the DAC or the ADC?
RépondreSupprimerHi Mazen,
RépondreSupprimerThe noise came from ADC, the value i got from ADC is not stabil on 4 bit LSB. I will give you the source code if you want.
salemu alaykom mazen,
RépondreSupprimeri have stm32f4 and i try to understand it , i did some codes and it's work like blinking leds as my first project :) ...
can you tell me about ADC what's its utility ??
thank you
ADC stands for analog to digital converter, the STM32 can work only with digital numbers (1s and 0s) but the real world is not digital.
Supprimermany sensors gives a analog voltage proportional to a real world unit like temperature or current, this data is then transferred to the ADC that will give a digital data to the microcontroller
hi , i have tried to compile this code but this gives an error
RépondreSupprimer".\Flash\Blinky.axf: Error: L6218E: Undefined symbol RCC_AHB1PeriphClockCmd (referred from blinky.o)." .
i have included the libraries needed for it i.e
("stm32f4xx_adc.h","stm32f4xx_gpio.h","stm32f4xx_rcc.h") .
please help me asap. thank you
you have to include also #include "stm32f4xx_dma.h"
Supprimeri include in total:
#include "stm32f4xx_adc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_dma.h"
and coocox compile correctly.
pablo
Hoola Muy bueno el ejemplo!
RépondreSupprimerAhora quiero introducir 3 señales analógicas...
cómo configuro el ADC ??
Muchas gracias!!
Hi,
RépondreSupprimerThanks for your example, it's very helpful. But i still have a question about the timer synchronization,you write this line ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;//
that's mean that your conversion is done by an external trigger, the timer1 in this case but instead you used ADC_SoftwareStartConv(ADC1);a software conversion.
Actually, I'm not sure about that one in particular. It would be great if you help to understand what does it do exactly
SupprimerWell, i understand what is doing, when we put ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion ( ADC with No external trigger for regular conversion ), that's mean the conversion is started only by software even if you put ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1.
RépondreSupprimerHowever, when we put : ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigEventEdge_RisingEdge (or ADC_ExternalTrigEventEdge_FallingEdge or ADC_ExternalTrigEventEdge_BothEdge), in this case the ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;take effect and the Timer1 must be configured to generate an interrupt to start conversion.
Below a code how a Timer is configured to trigger the ADC (i'm using Discovery 3) :
Configure Timer/Counter 3
Generate interrupt every 100µs @ 72 MHZ Timer clock
*----------------------------------------------------------------------------*/
void TIM2_Configuration(void)
{
/*TIM2 input clock (TIM2CLK) is set to 2 * APB1 clock (PCLK1),
since APB1 prescaler is different from 1.
TIM1CLK = 2 * PCLK1
PCLK1 = HCLK / 2
=> TIM1CLK = 2 * (HCLK / 2) = HCLK = SystemCoreClock */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Enable Timer2 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 10000) - 1; // 10 000 Hz Sample Rate(100 µs)
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel2 & 3 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 10; // Some arbitary width
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
/* Enable TIM2 counter */
TIM_Cmd(TIM2, ENABLE);
//------------- add by khalid
/* Enable TIM1 outputs */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
Absolutely wonderful explanation.
SupprimerMany thanks
Thank you so much for this code!!
RépondreSupprimerHi man,
RépondreSupprimerthanks to share first of all (Y)
I need to know the max voltage at the PC0 Pin (ADC Input)
since I see that the max voltage of the Resistor is connected to 5V
I guess that it is 5V
at the same time I read in forums that it should be something like 3.3V
could you answer me please
thanks in advance for any answer
And Once again thanks for sharing and BRAVO (fr)
yes it's 5v
RépondreSupprimerHii
RépondreSupprimerHiii Mazen can u tell me where to find converted digital value for adc code. Im using keil compiler for stm32f4..can i see this value in data regiater or dma
RépondreSupprimer