2017-04-13 111 views
0

我正在使用STM32F0微控制器的ADC通道(12位分辨率)來讀取板上三個不同點的電壓值。我想要做的是每2秒讀取一次數值(我有2秒時間讀取三點數值)並通過UART接口發送。爲了選擇哪個ADC通道我讀我實施電壓讀數功能如下:如何在STM32 MCU中每通道每n秒讀取幾個ADC接口?

uint16_t readv1(void){ 
    //Here I try to read ADC_CHANNEL_1 
    //chConfig and txtbuff are global variables: 
    //ADC_ChannelConfTypeDef chConfig; 
    //char txtbuff[64]; 

    chConfig.Channel = ADC_CHANNEL_1; 
    HAL_ADC_ConfigChannel(&hadc, &chConfig); 
    uint32_t vref = HAL_ADC_GetValue(&hadc); 
    uint16_t vref2 = (uint16_t) vref; 
    sprintf(TextBuffer, "%u\n", vref2); 
    HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF); 

    return vref2; 
} 

這是用於掃描一個ADC通道的功能。爲了讀取其他兩個ADC通道,我使用相同的步驟,只需更改行中的n的值,其中n是通道號。請注意,chConfigMX_ADC_Init()函數中聲明的sConfig屬於同一類型,但chConfig是全局變量,它應該在每個函數內聲明爲局部變量嗎?

我遇到的問題是,readv1函數讀取恆定電壓(我用伏特計檢查過),但通過UART在終端上顯示的數字變化很大,介於120和2400之間。我不確定是否使用用於選擇頻道的線路chConfig.Channel = ADC_CHANNEL_1;是好的,或者是否有任何其他程序要遵循。我怎樣才能正確讀取每個ADC的值?

爲了做到掃描我使用的是8 MHz的計時器每隔兩秒如下的ADC:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ 
    if (htim->Instance==TIM3){ 
     //Here I call the functions which read the voltage values of different ADC channels 
     volt1 = readv1(); 
     readv2(volt1); 
     readv3(volt1); 
    } 
} 

這是主要的功能,其中我初始化periphericals:

int main(void) 
{ 

    /* MCU Configuration----------------------------------------------------------*/ 

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 
    HAL_Init(); 

    /* Configure the system clock */ 
    SystemClock_Config(); 

    /* Initialize all configured peripherals */ 
    MX_GPIO_Init(); 
    MX_USART4_UART_Init(); 
    MX_ADC_Init(); 
    MX_TIM3_Init(); 

    /* USER CODE BEGIN 2 */ 
    HAL_ADC_Start_IT(&hadc); 
    HAL_TIM_Base_Start_IT(&htim3); 
    /* USER CODE END 2 */ 

    /* Infinite loop */ 
    /* USER CODE BEGIN WHILE */ 
    while (1) 
    { 

    } 
} 

以下是定時器和ADC的初始化函數:

/* TIM3 init function */ 
static void MX_TIM3_Init(void) 
{ 

    TIM_ClockConfigTypeDef sClockSourceConfig; 
    TIM_MasterConfigTypeDef sMasterConfig; 

    htim3.Instance = TIM3; 
    htim3.Init.Prescaler = 8000; 
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP; 
    htim3.Init.Period = 1999; 
    htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
    htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; 
    if (HAL_TIM_Base_Init(&htim3) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 
    if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; 
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 
    if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

} 


/* ADC init function */ 
static void MX_ADC_Init(void) 
{ 

    ADC_ChannelConfTypeDef sConfig; 

    /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 
    */ 
    hadc.Instance = ADC1; 
    hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; 
    hadc.Init.Resolution = ADC_RESOLUTION_12B; 
    hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; 
    hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; 
    hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; 
    hadc.Init.LowPowerAutoWait = DISABLE; 
    hadc.Init.LowPowerAutoPowerOff = DISABLE; 
    hadc.Init.ContinuousConvMode = ENABLE; 
    hadc.Init.DiscontinuousConvMode = DISABLE; 
    hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; 
    hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; 
    hadc.Init.DMAContinuousRequests = DISABLE; 
    hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; 
    if (HAL_ADC_Init(&hadc) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    /**Configure for the selected ADC regular channel to be converted. 
    */ 
    sConfig.Channel = ADC_CHANNEL_0; 
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; 
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; 
    if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    /**Configure for the selected ADC regular channel to be converted. 
    */ 
    sConfig.Channel = ADC_CHANNEL_1; 
    if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    /**Configure for the selected ADC regular channel to be converted. 
    */ 
    sConfig.Channel = ADC_CHANNEL_2; 
    if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

    /**Configure for the selected ADC regular channel to be converted. 
    */ 
    sConfig.Channel = ADC_CHANNEL_4; 
    if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) 
    { 
    Error_Handler(); 
    } 

} 
+0

volt1 = readv1(); readv2(volt1); readv3(volt1); 爲什麼raeadv2()和readv3()使用參數volt1但readv1()不? 你說:「爲了讀取另外兩個ADC通道,我使用相同的過程,只需改變行chConfig.Channel = ADC_CHANNEL_n中的n值,其中n是通道編號。」 嘗試爲volt1變量添加「volatile」。 – Zhifei

回答

0

我解決了這個問題通過修改功能如下:

uint16_t readv1(void){ 
    chConfig.Channel = ADC_CHANNEL_1; 

    // I added these two lines after the ADC channel selection 
    chConfig.Rank = ADC_RANK_CHANNEL_NUMBER; 
    chConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; 
    // The first one will configure the ADC channel as enabled 
    // The second one is the sampling time (1.5) 

    HAL_ADC_ConfigChannel(&hadc, &chConfig); 

    // Then I added these two instructions: 
    HAL_ADC_Start_IT(&hadc); 
    HAL_ADCEx_Calibration_Start(&hadc); 
    // The first one starts the ADC in interruption mode 
    // The second one calls the calibration function 

    uint32_t vref = HAL_ADC_GetValue(&hadc); 

    // Finally I added these three last instructions: 
    HAL_ADC_Stop_IT(&hadc); 
    chConfig.Rank = ADC_RANK_NONE; 
    HAL_ADC_ConfigChannel(&hadc, &chConfig); 
    // The first one stops the ADC 
    // The second one will configure the ADC channel as disabled 
    // The third one sets the channel with the new parameters 

    uint16_t vref2 = (uint16_t) vref; 
    sprintf(TextBuffer, "%u\n", vref2); 
    HAL_UART_Transmit(&huart4, (uint8_t*)txtbuff, strlen(txtbuff), 0xFFFFFFFF);  

    return vref2; 
} 

我加入我的三個功能讀ADC通道提到的線。實際上,由於我使用相同的程序讀取所有ADC通道,我創建了一個函數,該函數接收通道編號作爲參數。