이번 포스팅에서는 ADC를 이용하여 전압을 측정하여 시리얼 통신으로 값을 표기하는 활동을 해보겠습니다.
총 3가지로 해볼것이다.
- Polling
- Interrupt
- DMA
USART2로 통신포트는 사용할 것이고, 그것은 이전 포스팅에서 알수 있다.
Polling 먼저 해보겠다.
그리고 배선은 다음과 같이 해주고, 저항은 전부 10k옴이다.
(3.3V 2.2V 1.1V가 나오게끔하기 위해 10k옴을 직렬연결했다)
다음은 ADC를 설정하겠다.
총 3개를 사용할거고, 채널은 0,1,4를 사용하겠다. ( 3, 2은 USART2 RX, TX 에서 사용중)
밑처럼 체크해주면 알아서 핀을 설정해준다 ( 외쳐 갓 IDE )
3개를 적용해야하니 위처럼 3으로 바꾸고 채널을 설정해주자
여기서 저것들이 무엇인지 궁금할 수 있다.
설명 | |
Scan Conversion Mode | ADC가 여러 채널의 입력을 순차적으로 변환할지 여부를 결정. 여러 입력 값을 읽으려면 Scan Mode를 Enable로 설정해야 하고, 각 채널의 순서를 Rank로 지정해야 합니다 |
Continuous Conversion Mode | ADC 변환을 반복적으로 실행할지 여부를 결정 Enable: ADC가 한 번 시작되면 계속해서 변환을 반복합니다. 사용 예: 센서 데이터가 지속적으로 변하며 실시간으로 값을 읽어야 할 때. Disable: 한 번 변환 후 멈춥니다. 사용 예: 특정 시점에만 데이터를 읽고, 불필요한 변환을 피하고 싶을 때. |
Rank | Scan Mode가 활성화되었을 때, 각 채널이 변환될 순서를 결정 단일 채널을 사용할 때는 Rank 설정이 필요 없습니다 |
Sampling Time | ADC가 신호를 샘플링(읽기)하는 데 걸리는 시간 노이즈가 많거나 신호가 느리게 변화할 경우, 더 긴 샘플링 시간을 설정하세요. |
설정을 해줬다면 적용하고 코드를 작성하자
일단 Polling 방식 먼저 해볼 것이다.
Polling 방식으로 채널을 선택해서 사용하려면 함수 수정을 해야한다.
위에 ADC_ChannelConfTypeDef sConfig = {0}; 를 없애고 밑에 빨간줄은 1로 만들어라
아래는 완성 코드이다.
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
그리고 따로 함수를 만들어준다.
아래를 추가해주자
uint32_t adc[3];
float volt[3];
int __io_putchar(int ch){
HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 0xFFFF);
return ch;
}
uint32_t Adc_Channel0(void){
uint32_t Temp_Adc;
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
Temp_Adc = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return Temp_Adc;
}
uint32_t Adc_Channel1(void){
uint32_t Temp_Adc;
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
Temp_Adc = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return Temp_Adc;
}
uint32_t Adc_Channel4(void){
uint32_t Temp_Adc;
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
Temp_Adc = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return Temp_Adc;
}
추가 해주고, while에 다음 코드를 추가해준다
/* USER CODE BEGIN WHILE */
while (1)
{
adc[0] = Adc_Channel0();
adc[1] = Adc_Channel1();
adc[2] = Adc_Channel4();
volt[0] = (float)adc[0]*3.3/4096.0;
volt[1] = (float)adc[1]*3.3/4096.0;
volt[2] = (float)adc[2]*3.3/4096.0;
printf("Volt[0]=%f,Volt[1]=%f,Volt[2]=%f\r\n", volt[0],volt[1],volt[2]);
HAL_Delay(100);
}
여기서 printf에서 부동소수점을 쓰려면
위 같은 설정을 통해 설정을 해주고,
#include "stdio.h"
int __io_putchar(int ch){
HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, 0xFFFF);
return ch;
}
을 추가해준다.
이제 실행시키고 포트를 열어 확인하면 아래와 같은 결과를 맞이한다.
다음은 인터럽트를 사용해서 진행해보겠다
'STM32' 카테고리의 다른 글
MCU Internal 온도 측정하기 (0) | 2024.11.24 |
---|---|
STM32F407VE - 기초 6) ADC-2 (0) | 2024.11.24 |
STM32F407VE - 기초 4) USART-2 (0) | 2024.11.22 |
STM32F407VE - 기초 3) USART (0) | 2024.11.21 |
STM32F407VE - 기초 2) EXTI (0) | 2024.11.20 |