2017-04-13 3 views
0

J'utilise les canaux ADC (résolution de 12 bits) d'un microcontrôleur STM32F0 pour lire les valeurs de tension dans trois points différents d'une carte. Ce que je veux faire est de lire les valeurs toutes les 2 secondes (j'ai 2 secondes pour lire les valeurs dans les trois points) et les envoyer par l'interface UART. Afin de sélectionner le canal ADC Je lis, je suis mise en œuvre des fonctions de lecture de tension comme suit:Comment lire plusieurs interfaces ADC toutes les n secondes par canal dans STM32 MCU?

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; 
} 

C'est la fonction pour la numérisation d'un canal ADC. Pour lire les deux autres canaux ADC, j'utilise la même procédure en changeant simplement la valeur de n sur la ligne chConfig.Channel = ADC_CHANNEL_n;n est le numéro de canal. Notez que chConfig est du même type de sConfig déclaré dans la fonction MX_ADC_Init(), mais chConfig est une variable globale, devrait-elle être déclarée en tant que variable locale dans chaque fonction? Le problème que j'ai est que la fonction readv1 lit une tension constante (je l'ai vérifiée avec un voltimètre) mais les chiffres affichés dans le terminal via UART changent beaucoup, entre 120 et 2400. Je ne suis pas sûr d'utiliser la ligne chConfig.Channel = ADC_CHANNEL_1; pour sélectionner un canal est bonne ou s'il y a une autre procédure à suivre. Comment pourrais-je lire correctement les valeurs de chaque ADC?

Pour faire l'analyse de l'ADC toutes les deux secondes j'utilise une minuterie de 8 MHz comme suit:

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); 
    } 
} 

Ceci est la fonction principale où j'initialiser les 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) 
    { 

    } 
} 
et

ci-dessous sont les fonctions d'initialisation de la minuterie et l'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); Pourquoi raeadv2() et readv3() prennent le paramètre volt1 mais readv1() non? Vous avez dit "Pour lire les deux autres canaux ADC, j'utilise la même procédure en changeant simplement la valeur de n dans la ligne chConfig.Channel = ADC_CHANNEL_n, où n est le numéro de canal." Essayez d'ajouter "volatile" pour la variable volt1. – Zhifei

Répondre

0

Je résolu le problème en modifiant les fonctions de la manière suivante:

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; 
} 

I ajouté les lignes I mentionnés dans les trois fonctions de lecture des canaux ADC. En fait, comme j'utilise la même procédure pour lire tous les canaux ADC, j'ai créé une fonction qui reçoit comme paramètre le numéro de canal.