CubeMx
W tym celu po otwarciu odpowiedniego pliku można odrazu przejść do odpowiedniej zakładki w Peripheral. Opisywany mikrokontroler posiada trzy przetworniki ADC.
Rys. 1. Okno programu CubeMx
Następnie należy rozwinąć jedną z gałęzi przetwornika. Jak widać na rysunku 2, niektóre z wyjść są oznaczone na czerwono. Oznacza to, że piny do których są już przyporządkowane mają podłączone inne elementy, które przeszkadzają w jego obsłudze.
Rys. 2. Zakładka ADC
Aby wybrać piny które nas interesują należy kliknąć na ikonę zaznaczania przy wejściach przetwornika lub bezpośrednio na pin, z którego byśmy korzystali. Dla przykładu zaznaczę wejście IN1 i IN2. Po ich wybraniu kolory przy wyprowadzeniach PA1 oraz PA2 zmieniły się na zielony.
Rys. 3. Wybranie wyprowadzeń
Po wybraniu potrzebnych wyprowadzeń należy przejść do zakładki Clock Configuration w celu ustawienia zegara. Po wcześniejszym wybraniu źródła w Peripherals zakładka RCC. Ja wybrałem maksymalną częstotliwość taktowania, szczegóły jak ją ustawić znajdują się w poście [1] dla tej sekcji.
Gdy już to zostało ustawione należy przejść do zakładki Configuration i odpowiednio skonfigurować przetwornik.
Rys. 4. Zakładka configuration
Dalej należy kliknąć w przycisk ADC1 i przejść do ustawień.
Rys. 5. Ustawienie ADC
U samej górze znajduje się tryb pracy przetwornika. Poniżej należy wybrać wartość dzielnika dla zegara taktującego 2, 4, 6 lub 8. W kolejnym kroku do ustawienia jest rozdzielczość przetwornika. Następnie wyrównanie danych oraz tryby konwersji danych czy włączenie DMA. Dalej liczba konwersji, oraz ustawienie trybu wyzwalania zewnętrznego.
W kolejnych zakładkach znajduje się ustawienie przerwań, DMA czy ustawienie wybranych pinów dla konwertera.
Programowanie
Wygenerowany fragment kodu odpowiedzialny za ustawienie przetwornika:
- /* ADC1 init function */
- void MX_ADC1_Init(void)
- {
- ADC_ChannelConfTypeDef sConfig;
- /**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
- */
- hadc1.Instance = ADC1;
- hadc1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
- hadc1.Init.Resolution = ADC_RESOLUTION12b;
- hadc1.Init.ScanConvMode = DISABLE;
- hadc1.Init.ContinuousConvMode = DISABLE;
- hadc1.Init.DiscontinuousConvMode = DISABLE;
- hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
- hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
- hadc1.Init.NbrOfConversion = 1;
- hadc1.Init.DMAContinuousRequests = DISABLE;
- hadc1.Init.EOCSelection = EOC_SINGLE_CONV;
- HAL_ADC_Init(&hadc1);
- /**Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
- */
- sConfig.Channel = ADC_CHANNEL_1;
- sConfig.Rank = 1;
- sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
- HAL_ADC_ConfigChannel(&hadc1, &sConfig);
- }
Następnym elementem jest ustawienie pinów oraz włączenie taktowania. Ten fragment kodu został umieszczony w pliku stm32f4xx_hal_msp.c:
- void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- if(hadc->Instance==ADC1)
- {
- /* USER CODE BEGIN ADC1_MspInit 0 */
- /* USER CODE END ADC1_MspInit 0 */
- /* Peripheral clock enable */
- __ADC1_CLK_ENABLE();
- /**ADC1 GPIO Configuration
- PA1 ------> ADC1_IN1
- PA2 ------> ADC1_IN2
- */
- GPIO_InitStruct.Pin = ADC1_1_Pin|ADC1_2_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- /* USER CODE BEGIN ADC1_MspInit 1 */
- /* USER CODE END ADC1_MspInit 1 */
- }
- }
W celu dokonania pomiarów należy w głównej pętli programu wprowadzić następujący kod.
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- int ADC_Val = 0;
- /* USER CODE END 1 */
- /* 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_ADC1_Init();
- //Wywolanie funkcji wlaczajacej piny i zegar dla ADC
- HAL_ADC_MspInit(&hadc1);
- HAL_ADC_Start(&hadc1);
- ADC_Val = HAL_ADC_GetValue(&hadc1);
- /* USER CODE BEGIN 2 */
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
Powyżej funkcja główna wykonująca prosty pojedynczy pomiar.
Jeśli chce się wykonywać pomiary ciągiem, to należy wywołać następującą funkcje. Dodatkowo w funkcji policzone zostanie napięcie oraz temperatura. Dane zostaną przesłane przez UART do komputera.
- void adcConversion()
- {
- uint16_t ADC_Val = 0;
- float temp;
- float vsense;
- char buffer[50];
- const float V25 = 0.76;
- const float Avg_Slope=0.0025;
- const float SupplyVoltage = 3.0;
- const float ADCResolution = 4095.0;
- HAL_ADC_Start(&hadc1);
- ADC_Val = HAL_ADC_GetValue(&hadc1);
- vsense = (SupplyVoltage*ADC_Val)/ADCResolution;// Przeliczenie wartosci zmierzonej na napiecie
- temp = ((vsense-V25)/SupplyVoltage)+25;// Obliczenie temperatury
- sprintf((char*)buffer,"ADC Value1: %u; Vsense: %f Temperature: %f\r\n", ADC_Val, vsense, temp);
- HAL_UART_Transmit(&huart2,(uint8_t*)buffer,strlen((char*)buffer),0x1000);
- }