ADC single conversion on STM32

2019-05-07 03:42发布

问题:

I'm studying ADC programming on STM32 F103x and starting with the simplest case - single conversion. The internal temperature sensor (connected to ADC1) value is measured and sending it to COM port by using USART. A target seems clear but when I try to download source code to flash, it doesn't send any data to COM port. USART function works well, I guess the problems come from ADC configuration part because I'm being hung in loop of waiting complete conversion:

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //Wail for conversion complete

Here is my source code so far.

/* Includes ------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>

    uint16_t AD_value;
    const uint16_t V25 = 1750; //when V25=1.41V
    const uint16_t Avg_Slope = 5; //when avg_slc
    uint16_t TemperatureC;

//Define output device
PUTCHAR_PROTOTYPE
{
    USART_SendData(USART1, (uint8_t) ch);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
    {}
    return ch;
}

void Usart1Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

    /* COnfig PA9 for USART Tx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* COnfig PA10 for USART Rx as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* USARTx configured as follow:
        - BaudRate = 9600 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
    */  
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    /* USART configuration */
    USART_Init(USART1, &USART_InitStructure);
    USART_Cmd(USART1, ENABLE);  

}

int main(void)
{

    ADC_InitTypeDef ADC_InitStructure;
    Usart1Init();

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //ADCCLK = PCLK22/6 = 72/6=12MHz
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //Enable ADC1 Clock

    /* ADC1 configuration */
    ADC_DeInit(ADC1); //Power-on default
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //Independent conversion mode (single)
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Convert single channel only
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Convert 1 time
    ADC_InitStructure.ADC_ExternalTrigConv = DISABLE; //No external triggering
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //Right 12-bit data alignment
    ADC_InitStructure.ADC_NbrOfChannel = 1; //single channel conversion
    ADC_Init(ADC1, &ADC_InitStructure);
    ADC_TempSensorVrefintCmd(ENABLE); //wake up temperature sensor
    ADC_Cmd(ADC1, ENABLE); //Enable ADC1
    ADC_ResetCalibration(ADC1); //Enable ADC1 reset calibration register
    while(ADC_GetResetCalibrationStatus(ADC1)); //check the end of ADC1 reset calibration register  
    ADC_StartCalibration(ADC1); //Start ADC1 calibration
    while(ADC_GetCalibrationStatus(ADC1)); //Check the end of ADC1 calibration
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_1Cycles5); //Select 1.5 cycles conversion for channel 16
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //Start ADC1 software conversion
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //Wail for conversion complete
    AD_value = ADC_GetConversionValue(ADC1); //Read ADC value
    ADC_ClearFlag(ADC1, ADC_FLAG_EOC); //Clear EOC flag

    printf("\r\n ADC value: %d \r\n", AD_value);
    TemperatureC = (uint16_t)((V25-AD_value)/Avg_Slope+25);
    printf("Temperature: %d%cC\r\n", TemperatureC, 176);
    while (1)
    {}  
}

Any ideas are appreciated!

回答1:

i'll try to explain what's going on with source code.

1- definition of disable is zero : typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;

2- so when you write "ADC_InitStructure.ADC_ExternalTrigConv = DISABLE;" you actually assign it to zero like this "ADC_InitStructure.ADC_ExternalTrigConv = 0;

3- this means your assigning the EXTSEL of ADC_CR2 register to zero.

4-if EXTSEL is zero, adc conversion depends on the timers to start.

5-if you want adc to be started by software, EXTSEL must be 0x000E0000;

6- and as you can guess the value of "ADC_ExternalTrigConv_None" is defined as 0x000E0000;

so while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); code will hung up here because it depens on the timers to start, it cannot end if it is not started.



回答2:

Problem solved! It's my fault to disable external trigger. Instead of using:

ADC_InitStructure.ADC_ExternalTrigConv = DISABLE;

It shoud be like this:

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

What a silly!



回答3:

I will not invent a wheel here by saing that you are hanging in one of those three while() loops. Make some output before each of then then you will know where you are hanging.

If you have debugger (it is present on every ST development board, and possibly you are using it to download program) don't hesitate to use it :)